Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Preparing Ring content
Preparing Ring content
Preparing Ring content
Ring news is a full publishing surface: members author articles, promote to the main page when enabled, and readers engage on /news/[slug] and /[username]/[slug]. Article bodies are Markdown (contentFormat: markdown) authored in NewsRichEditor (WikiRichEditor core + news toolbar). Shortcodes [[embed:]] / [[mood:]] / [[video:]] expand on public pages. TipTap stays only as deferred TipTapNewsAdapter for a slash / command palette — embeds, Mood, video, and generate-image already ship via the Markdown path.
Use the Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter filters content blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
Migrations, promotion workflow, scoring, and Telegram callbacks.
Per-user blog paths and public article URLs.
Grok drafts Markdown articles, featured images, TTS, locale fan-out.
Postgres Markdown + wikilinks vault — separate from the news CMS.
| Surface | What it does |
|---|---|
| NewsRichEditor | WikiRichEditor + toolbar: Embed URL, Mood, Video, Generate image; paste lone URL → [[embed:]]; preserveNewsShortcodes |
| Shortcodes | [[mood:ID]] → <ring-mood-player>; [[embed:URL]] → <ring-embed> / iframe; [[video:SRC]] → <video>; gen-image →  |
| TipTapNewsAdapter (deferred) | Slash / palette UX only — file retained, not mounted on ArticleEditor |
| My News | /my-news — dashboard, charts, create/edit, Proposed amendments |
| Create / Revise | /news/create; Revise → /news/[slug]/revise → pending-revision |
| Amendments | Author hunk preview → Accept applies body / Reject closes |
/my-news) or /news/create.Members improve accuracy without silent overwrite. Authors stay in control of the live article.
| Action | Who |
|---|
Same-workflow: member blogs share public article surfaces with news.
Deep-dive: promotion, Telegram, and News Kingdom migrations.
Next-step: Grok generates Markdown drafts into the same news CMS.
See-also: publications TipTap editor — not the news Markdown CMS.
News Kingdom migrations (002 / 003) and promotion remain required for paid main-page flows. NewsRichEditor Markdown + shortcodes + pending-revision ship without changing NewsStatus (draft | published | archived | deleted).
Ring news is a full publishing surface: members author articles, promote to the main page when enabled, and readers engage on /news/[slug] and /[username]/[slug]. Article bodies are Markdown (contentFormat: markdown) authored in NewsRichEditor (WikiRichEditor core + news toolbar). Shortcodes [[embed:]] / [[mood:]] / [[video:]] expand on public pages. TipTap stays only as deferred TipTapNewsAdapter for a slash / command palette — embeds, Mood, video, and generate-image already ship via the Markdown path.
Use the Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter filters content blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
Migrations, promotion workflow, scoring, and Telegram callbacks.
Per-user blog paths and public article URLs.
Grok drafts Markdown articles, featured images, TTS, locale fan-out.
Postgres Markdown + wikilinks vault — separate from the news CMS.
| Surface | What it does |
|---|---|
| NewsRichEditor | WikiRichEditor + toolbar: Embed URL, Mood, Video, Generate image; paste lone URL → [[embed:]]; preserveNewsShortcodes |
| Shortcodes | [[mood:ID]] → <ring-mood-player>; [[embed:URL]] → <ring-embed> / iframe; [[video:SRC]] → <video>; gen-image →  |
| TipTapNewsAdapter (deferred) | Slash / palette UX only — file retained, not mounted on ArticleEditor |
| My News | /my-news — dashboard, charts, create/edit, Proposed amendments |
| Create / Revise | /news/create; Revise → /news/[slug]/revise → pending-revision |
| Amendments | Author hunk preview → Accept applies body / Reject closes |
/my-news) or /news/create.Members improve accuracy without silent overwrite. Authors stay in control of the live article.
| Action | Who |
|---|
Same-workflow: member blogs share public article surfaces with news.
Deep-dive: promotion, Telegram, and News Kingdom migrations.
Next-step: Grok generates Markdown drafts into the same news CMS.
See-also: publications TipTap editor — not the news Markdown CMS.
News Kingdom migrations (002 / 003) and promotion remain required for paid main-page flows. NewsRichEditor Markdown + shortcodes + pending-revision ship without changing NewsStatus (draft | published | archived | deleted).
Ring news is a full publishing surface: members author articles, promote to the main page when enabled, and readers engage on /news/[slug] and /[username]/[slug]. Article bodies are Markdown (contentFormat: markdown) authored in NewsRichEditor (WikiRichEditor core + news toolbar). Shortcodes [[embed:]] / [[mood:]] / [[video:]] expand on public pages. TipTap stays only as deferred TipTapNewsAdapter for a slash / command palette — embeds, Mood, video, and generate-image already ship via the Markdown path.
Use the Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter filters content blocks; sidebar visibility is curated in lib/docs/audience-curated-docs.ts.
Migrations, promotion workflow, scoring, and Telegram callbacks.
Per-user blog paths and public article URLs.
Grok drafts Markdown articles, featured images, TTS, locale fan-out.
Postgres Markdown + wikilinks vault — separate from the news CMS.
| Surface | What it does |
|---|---|
| NewsRichEditor | WikiRichEditor + toolbar: Embed URL, Mood, Video, Generate image; paste lone URL → [[embed:]]; preserveNewsShortcodes |
| Shortcodes | [[mood:ID]] → <ring-mood-player>; [[embed:URL]] → <ring-embed> / iframe; [[video:SRC]] → <video>; gen-image →  |
| TipTapNewsAdapter (deferred) | Slash / palette UX only — file retained, not mounted on ArticleEditor |
| My News | /my-news — dashboard, charts, create/edit, Proposed amendments |
| Create / Revise | /news/create; Revise → /news/[slug]/revise → pending-revision |
| Amendments | Author hunk preview → Accept applies body / Reject closes |
/my-news) or /news/create.Members improve accuracy without silent overwrite. Authors stay in control of the live article.
| Action | Who |
|---|
Same-workflow: member blogs share public article surfaces with news.
Deep-dive: promotion, Telegram, and News Kingdom migrations.
Next-step: Grok generates Markdown drafts into the same news CMS.
See-also: publications TipTap editor — not the news Markdown CMS.
News Kingdom migrations (002 / 003) and promotion remain required for paid main-page flows. NewsRichEditor Markdown + shortcodes + pending-revision ship without changing NewsStatus (draft | published | archived | deleted).
| Public render |
NewsMarkdownView — shortcodes → Markdown → sanitize → restore widgets |
| Collab (gated) | Y.Text newsMarkdown on collab:news:{articleId} when NEXT_PUBLIC_COLLAB_ENABLED=true |
| Create / edit own | Member+ (and admins) |
| Propose revision on published | Member+ (author uses Edit) |
| Accept / reject amendments | Article author or platform admin |
| Invite co-editors by email | Scaffolded APIs only (501) — not a full UI yet |
| Live Markdown collab | Needs NEXT_PUBLIC_COLLAB_ENABLED=true + native WSS |
features/news/lib/render-news-markdown.ts| Public pipeline (below) |
features/news/lib/news-markdown-view.tsx | Public article body component |
features/news/components/article-editor.tsx | Form; mounts NewsRichEditor; Preview → NewsMarkdownView |
features/news/components/editor/tiptap-news-editor.tsx | TipTapNewsAdapter — slash / backlog only |
features/news/components/editor/rich-text-editor.tsx | Re-exports TipTapNewsAdapter (not used by CRUD) |
app/api/news/embed-preview/route.ts | POST OG metadata for embed hydration |
app/_actions/news.ts / news-service.ts | Persist contentFormat: 'markdown' |
Autosave: dirty-gated debounce (~3s) PUT /api/news/[id] with { content } (Markdown). Explicit Save appends a version commit with contentFormat: 'markdown'.
renderNewsMarkdownToHtml order (mandatory):
simpleMarkdownToHtmlsanitizeMarkdownHtml (MD-only allowlist)ring-embed / ring-mood-player / <video>)sanitizeNewsHtml — final belt for iframes + custom elementsNewsRichEditor calls useNewsMarkdownCollab (features/news/lib/use-news-markdown-collab.ts). Gate: isNewsCollabEnabled() → NEXT_PUBLIC_COLLAB_ENABLED=true (news-collab-gate.ts). Channel: useCollaboration('news:{articleId}') → collab:news:{articleId}; Y.Text key newsMarkdown. Not TipTap Collaboration.
Route helper (constants/routes.ts) | Path |
|---|---|
ROUTES.MY_NEWS | /my-news |
ROUTES.NEWS_CREATE | /news/create |
ROUTES.NEWS_REVISE(slug) | /news/[slug]/revise |
ROUTES.MY_NEWS_AMENDMENTS(articleId) | /my-news/[articleId]/amendments |
ROUTES.MY_NEWS_AMENDMENT_PREVIEW(...) | /my-news/[articleId]/amendments/[revisionId] |
UI: app/[locale]/(protected)/my-news/, components/wrappers/my-news-wrapper.tsx.
Collection: news_revisions via DatabaseService.
| Method | Route | Behavior |
|---|---|---|
GET | /api/news/[id]/revisions?status=pending-revision | List |
POST | /api/news/[id]/revisions | { proposedContent } → pending-revision |
GET | /api/news/revisions/[revisionId] | One revision |
PATCH | /api/news/revisions/[revisionId] | { action: 'accept' | 'reject' } |
Service: features/news/services/revision-service.ts · Permissions: news-collaboration-permissions.ts · Diff UI: revision-diff.ts + revision-hunk-preview.tsx.
| Piece | Status |
|---|---|
lib/database/schema/news-collaboration.sql | Conceptual schema notes |
GET/POST /api/news/[id]/collaborators | 501 stub |
GET/POST /api/news/collaboration/invite/[token] | 501 stub |
Roles owner|admin|editor|reviewer|viewer | Types only |
features/news/services/news-service.ts — CRUD, stats, page views. Promotion / Telegram: News Kingdom. AI drafts: Generative newsroom (article-generator.ts prompts Markdown).
Depends-on: Tunnel / Yjs channels behind NEXT_PUBLIC_COLLAB_ENABLED.
| Public render |
NewsMarkdownView — shortcodes → Markdown → sanitize → restore widgets |
| Collab (gated) | Y.Text newsMarkdown on collab:news:{articleId} when NEXT_PUBLIC_COLLAB_ENABLED=true |
| Create / edit own | Member+ (and admins) |
| Propose revision on published | Member+ (author uses Edit) |
| Accept / reject amendments | Article author or platform admin |
| Invite co-editors by email | Scaffolded APIs only (501) — not a full UI yet |
| Live Markdown collab | Needs NEXT_PUBLIC_COLLAB_ENABLED=true + native WSS |
features/news/lib/render-news-markdown.ts| Public pipeline (below) |
features/news/lib/news-markdown-view.tsx | Public article body component |
features/news/components/article-editor.tsx | Form; mounts NewsRichEditor; Preview → NewsMarkdownView |
features/news/components/editor/tiptap-news-editor.tsx | TipTapNewsAdapter — slash / backlog only |
features/news/components/editor/rich-text-editor.tsx | Re-exports TipTapNewsAdapter (not used by CRUD) |
app/api/news/embed-preview/route.ts | POST OG metadata for embed hydration |
app/_actions/news.ts / news-service.ts | Persist contentFormat: 'markdown' |
Autosave: dirty-gated debounce (~3s) PUT /api/news/[id] with { content } (Markdown). Explicit Save appends a version commit with contentFormat: 'markdown'.
renderNewsMarkdownToHtml order (mandatory):
simpleMarkdownToHtmlsanitizeMarkdownHtml (MD-only allowlist)ring-embed / ring-mood-player / <video>)sanitizeNewsHtml — final belt for iframes + custom elementsNewsRichEditor calls useNewsMarkdownCollab (features/news/lib/use-news-markdown-collab.ts). Gate: isNewsCollabEnabled() → NEXT_PUBLIC_COLLAB_ENABLED=true (news-collab-gate.ts). Channel: useCollaboration('news:{articleId}') → collab:news:{articleId}; Y.Text key newsMarkdown. Not TipTap Collaboration.
Route helper (constants/routes.ts) | Path |
|---|---|
ROUTES.MY_NEWS | /my-news |
ROUTES.NEWS_CREATE | /news/create |
ROUTES.NEWS_REVISE(slug) | /news/[slug]/revise |
ROUTES.MY_NEWS_AMENDMENTS(articleId) | /my-news/[articleId]/amendments |
ROUTES.MY_NEWS_AMENDMENT_PREVIEW(...) | /my-news/[articleId]/amendments/[revisionId] |
UI: app/[locale]/(protected)/my-news/, components/wrappers/my-news-wrapper.tsx.
Collection: news_revisions via DatabaseService.
| Method | Route | Behavior |
|---|---|---|
GET | /api/news/[id]/revisions?status=pending-revision | List |
POST | /api/news/[id]/revisions | { proposedContent } → pending-revision |
GET | /api/news/revisions/[revisionId] | One revision |
PATCH | /api/news/revisions/[revisionId] | { action: 'accept' | 'reject' } |
Service: features/news/services/revision-service.ts · Permissions: news-collaboration-permissions.ts · Diff UI: revision-diff.ts + revision-hunk-preview.tsx.
| Piece | Status |
|---|---|
lib/database/schema/news-collaboration.sql | Conceptual schema notes |
GET/POST /api/news/[id]/collaborators | 501 stub |
GET/POST /api/news/collaboration/invite/[token] | 501 stub |
Roles owner|admin|editor|reviewer|viewer | Types only |
features/news/services/news-service.ts — CRUD, stats, page views. Promotion / Telegram: News Kingdom. AI drafts: Generative newsroom (article-generator.ts prompts Markdown).
Depends-on: Tunnel / Yjs channels behind NEXT_PUBLIC_COLLAB_ENABLED.
| Public render |
NewsMarkdownView — shortcodes → Markdown → sanitize → restore widgets |
| Collab (gated) | Y.Text newsMarkdown on collab:news:{articleId} when NEXT_PUBLIC_COLLAB_ENABLED=true |
| Create / edit own | Member+ (and admins) |
| Propose revision on published | Member+ (author uses Edit) |
| Accept / reject amendments | Article author or platform admin |
| Invite co-editors by email | Scaffolded APIs only (501) — not a full UI yet |
| Live Markdown collab | Needs NEXT_PUBLIC_COLLAB_ENABLED=true + native WSS |
features/news/lib/render-news-markdown.ts| Public pipeline (below) |
features/news/lib/news-markdown-view.tsx | Public article body component |
features/news/components/article-editor.tsx | Form; mounts NewsRichEditor; Preview → NewsMarkdownView |
features/news/components/editor/tiptap-news-editor.tsx | TipTapNewsAdapter — slash / backlog only |
features/news/components/editor/rich-text-editor.tsx | Re-exports TipTapNewsAdapter (not used by CRUD) |
app/api/news/embed-preview/route.ts | POST OG metadata for embed hydration |
app/_actions/news.ts / news-service.ts | Persist contentFormat: 'markdown' |
Autosave: dirty-gated debounce (~3s) PUT /api/news/[id] with { content } (Markdown). Explicit Save appends a version commit with contentFormat: 'markdown'.
renderNewsMarkdownToHtml order (mandatory):
simpleMarkdownToHtmlsanitizeMarkdownHtml (MD-only allowlist)ring-embed / ring-mood-player / <video>)sanitizeNewsHtml — final belt for iframes + custom elementsNewsRichEditor calls useNewsMarkdownCollab (features/news/lib/use-news-markdown-collab.ts). Gate: isNewsCollabEnabled() → NEXT_PUBLIC_COLLAB_ENABLED=true (news-collab-gate.ts). Channel: useCollaboration('news:{articleId}') → collab:news:{articleId}; Y.Text key newsMarkdown. Not TipTap Collaboration.
Route helper (constants/routes.ts) | Path |
|---|---|
ROUTES.MY_NEWS | /my-news |
ROUTES.NEWS_CREATE | /news/create |
ROUTES.NEWS_REVISE(slug) | /news/[slug]/revise |
ROUTES.MY_NEWS_AMENDMENTS(articleId) | /my-news/[articleId]/amendments |
ROUTES.MY_NEWS_AMENDMENT_PREVIEW(...) | /my-news/[articleId]/amendments/[revisionId] |
UI: app/[locale]/(protected)/my-news/, components/wrappers/my-news-wrapper.tsx.
Collection: news_revisions via DatabaseService.
| Method | Route | Behavior |
|---|---|---|
GET | /api/news/[id]/revisions?status=pending-revision | List |
POST | /api/news/[id]/revisions | { proposedContent } → pending-revision |
GET | /api/news/revisions/[revisionId] | One revision |
PATCH | /api/news/revisions/[revisionId] | { action: 'accept' | 'reject' } |
Service: features/news/services/revision-service.ts · Permissions: news-collaboration-permissions.ts · Diff UI: revision-diff.ts + revision-hunk-preview.tsx.
| Piece | Status |
|---|---|
lib/database/schema/news-collaboration.sql | Conceptual schema notes |
GET/POST /api/news/[id]/collaborators | 501 stub |
GET/POST /api/news/collaboration/invite/[token] | 501 stub |
Roles owner|admin|editor|reviewer|viewer | Types only |
features/news/services/news-service.ts — CRUD, stats, page views. Promotion / Telegram: News Kingdom. AI drafts: Generative newsroom (article-generator.ts prompts Markdown).
Depends-on: Tunnel / Yjs channels behind NEXT_PUBLIC_COLLAB_ENABLED.