# Wiki Mode / Multi-Editor — Technical Implementation _Generated 2025-08-22_ ## Data Model **BlogSettings** - `wikiEnabled: boolean` (optional; missing = false) - `editorWhitelist: Name[]` (optional; empty = global allow) - `editorBlacklist: Name[]` (optional) **Post (revision)** - `originPostId: Id` (first ancestor; fallback to id if missing) - `parentPostId?: Id` - `lineageBlogId: BlogId` (owner’s blog id; fallback to route blog id) - `authorName: Name` (registered name) - `updatedAt: ISO timestamp` (fallback to QDN timestamp if missing) - `published: boolean` ## Authorization (by Name) 1. Owner always allowed. 2. Blacklist blocks regardless. 3. Whitelist non-empty → only listed Names (minus blacklist). 4. Whitelist empty → all Names allowed (minus blacklist). ## canEdit(viewerName, settings, ownerName) - Returns true if viewerName is Owner, or if wiki enabled and viewerName passes the whitelist/blacklist rules. ## Canonical Resolver (client) 1. Resolve origin id. 2. Collect revisions with same origin + blog lineage, published = true. 3. Filter by authorization (authorName vs blog settings). 4. Pick newest by updatedAt; tiebreak: Owner wins; then lowest id. Reference implementation in code: - `src/utils/wiki.ts` provides `isAuthorized`, `canEdit`, and `selectCanonical` used across UI. - `src/utils/wikiSettingsCache.ts` caches per-blog (ownerName, settings) using `/arbitrary/resources?service=BLOG&identifier=...` and `/arbitrary/BLOG//`. - `src/hooks/useFetchPosts.tsx` groups search results by identifier and applies canonical selection in feed, favorites, and subscriptions. - `src/pages/BlogIndividualPost/BlogIndividualPost.tsx` resolves canonical author before fetching BLOG_POST JSON when wiki mode is enabled. ## UI - Blog Settings: toggle, Name pickers for whitelist/blacklist. - Implemented in `Edit Blog` modal (checkbox + comma-separated Name inputs). - Also available in `Create Blog` modal so new blogs can enable wiki from the start. - Post page: “Latest by Name on Date” subheader if revision not by Owner. - Edit: shown only if canEdit true. - Blog list: use resolver to show canonical per lineage. - Global feed, Subscriptions, and Favorites use a lightweight cache of per-blog settings to canonicalize duplicates by identifier. - Header blog switcher seeds blog context to ensure the posts list refreshes immediately on change. ## Backward Compatibility - Missing fields → defaults (wikiEnabled=false, lists empty, origin=id, lineage=blogId, updatedAt=QDN ts). ## Performance Notes - Settings Resolution: reads wiki settings from BLOG resource metadata when available; otherwise fetches BLOG JSON as fallback. - Prefetch: for each page of results, settings for blogs with duplicate identifiers are prefetched in parallel (singletons skip resolution). - Canonicalization happens only when necessary; otherwise owner or newest item is used. ## Edit Flow (Wiki) - **Editors do not need their own blog** to publish a revision of an existing post when the target blog has Wiki Mode enabled. - Edits publish a new `BLOG_POST` under the editor's **Name** using the **original BLOG_POST identifier**; the canonical resolver selects the visible revision. - Blog (`service: BLOG`) metadata is **not** republished during edits.