Wiki System
Overview#
The wiki is a community knowledge base embedded in the game. It serves two distinct purposes:
- Game guides and reference articles - authored by players or admins, covering mechanics, strategy, elections, and congress. These are stored as markdown documents in the
wikiPagesMongoDB collection. - Auto-generated entity pages - dynamically assembled from live game data at request time, covering politicians (player characters and NPPs), parties, congressional seats, and leadership roles. These do not have entries in
wikiPages; they are rendered from DB queries and flavor-text templates.
The wiki is accessible at /wiki/[slug]. All published pages are browsable via /wiki, and search is available site-wide via the navbar.
Page Types#
Manual Pages (stored in wikiPages)#
These are markdown pages that live in the database.
- Guide pages - player-written or admin-written articles on game mechanics, strategy, and lore. Examples:
getting-started,election-mechanics,campaign-strategy. - Election History - a special-cased slug (
elections) that renders a dynamic elections browser rather than a markdown page. - Admin-seeded reference pages - pages imported from
docs/design/*.mdduring migration. These haveisAutoGenerated: false.
Dynamic Entity Pages (not stored in wikiPages)#
These are served from dedicated app routes that query game data directly:
| Route pattern | Description |
|---|---|
/wiki/party/[id] |
Party profile: seat counts, member count, economic/social position, flavor text |
/wiki/seat/[slug] |
Office seat: current holder(s) for governor, US Senate class, or House delegation |
/wiki/leadership/[role] |
Congressional leadership role: Speaker, Majority/Minority Leaders and Whips |
/character/[id] |
Canonical public player profile with election history and game-facing context |
/politicians/npp/[id] |
Canonical public NPP profile with election history |
Seat slugs follow the pattern {state-lowercase}-{governor|senate-class-1|senate-class-2|senate-class-3|house} (e.g. fl-senate-class-1, ca-governor).
Edit Workflow#
Player-submitted pages go through a review cycle. Admin-created pages bypass review and publish immediately.
(player creates) (admin reviews) (admin rejects)
draft ──────────> pending_review ──────> draft
│
└──────────────> published
(admin approves)
published ──────────> archived
(admin deletes)
- draft - created when a player submission is rejected (returned for revision). Visible only to the submitting player and admins.
- pending_review - set automatically when any authenticated player submits a new page. Visible only to the submitting player and admins.
- published - publicly visible. Admins may approve with optional edits applied at approval time.
- archived - soft-deleted via the admin PATCH/DELETE endpoint. Treated as non-existent for public views.
Drafts and pending pages return 404 to users who are neither the page author nor an admin.
The editHistory array on each page records every state transition with the acting user's ObjectId, a timestamp, action name (created | edited | approved | rejected | archived), and an optional note (used to store the rejection reason).
Auto-generation#
Politician Election History#
When an election resolves (during turn processing), updatePoliticianPagesAfterElection() in runs for every non-NPP candidate. It writes or updates a document in the politicianOverrides collection with an electionHistory array entry per resolved election. Player characters only - NPPs are skipped.
Each history entry records: electionId, electionType, state, year, result (won/lost), raw vote count, vote percentage, party name, office label, and completion timestamp.
This data is then displayed on the canonical /character/[id] public profile page.
Flavor Text Generation#
For entity pages that have no user-authored content, the system generates templated flavor text at render time:
- Politicians - picks a bio template and "approach" phrase deterministically based on a hash of the politician's ID. Inputs are name, state, party, office status, and whether they are an NPP.
- Parties - returns hand-written blurbs for
democrat,republican, andindependent; generic template for all other parties. - Leadership roles - provides static blurbs and responsibility lists for all 10 congressional leadership roles.
Wikilink Resolution#
When page content is loaded via loadWikiContent() in , [[Page Title]] syntax is transformed into markdown links using a title-to-slug map built from all published wikiPages. Broken links render as italic markdown text (_Page Title_).
User Permissions#
| Action | Who can do it |
|---|---|
| Read published pages | Anyone (unauthenticated or authenticated) |
| Read draft/pending pages | Author or admin |
| Create a page | Any authenticated player (POST /api/wiki) |
| Edit own page | Author (PATCH /api/wiki/[slug]); published edits go to pending_review |
| Edit any field (incl. status) | Admin (PATCH /api/admin/wiki/[slug]) |
| Delete (archive) a page | Admin only (DELETE /api/admin/wiki/[slug]) |
| Approve a page | Admin only |
| Reject a page | Admin only |
| Create page bypassing review | Admin only (POST /api/admin/wiki) |
The canEdit flag returned by GET /api/wiki/[slug] is true for the page's author or any admin. Authors can edit their own pages via PATCH /api/wiki/[slug]; edits to a published page send it back to pending_review for re-approval. Admins use PATCH /api/admin/wiki/[slug] instead, which can update any field including status.
Database#
wikiPages collection#
| Field | Type | Description |
| -------------------- | --------------------- | ------------------------------------------------------------ | -------------- | --------- | ------------------------------------------- | --------- |
| _id | ObjectId | Standard document ID |
| slug | string | Unique URL identifier; lowercase alphanumeric + hyphens |
| title | string | Display title |
| description | string | Short summary (10-500 chars) |
| content | string | Markdown body (50-100,000 chars) |
| status | WikiPageStatus | draft | pending_review | published | archived |
| submittedBy | ObjectId? | User who created the page |
| reviewedBy | ObjectId? | Admin who approved the page |
| tags | string[]? | Freeform and system tags; first tag used as primary category |
| templateType | string? | References a wikiTemplates document slug |
| featured | boolean? | Shown in featured section on wiki home |
| difficulty | WikiPageDifficulty? | beginner | intermediate | advanced |
| estimatedReadTime | number? | Minutes |
| isAutoGenerated | boolean? | True for pages seeded by migration scripts |
| autoGenerateConfig | AutoGenerateConfig? | { type: "party | leadership | seat | politician", entityId, widgetComponents? } |
| createdAt | Date | |
| updatedAt | Date | |
| editHistory | EditHistoryEntry[]? | Append-only log of created | edited | approved | rejected | archived |
wikiTemplates collection#
| Field | Type | Description |
| ------------- | ----------------- | ---------------------------------------------------------------------------- | -------- | ----------------------------------- |
| _id | string | Template slug (used as identifier) |
| name | string | Display name |
| description | string | What this template is for |
| icon | string | Emoji or icon string |
| fields | TemplateField[] | Ordered list of form fields with id, label, placeholder, type (text | textarea | markdown), required, and order |
systemTags collection#
Curated tags with display metadata (name, description, icon, Tailwind color class, sort order). Player-created tags are plain strings on wikiPages.tags that do not have a systemTags document.
politicianOverrides collection#
Stores per-politician data that augments auto-generated profile pages. Key field: electionHistory - array of PoliticianElectionEntry objects written after each election resolution.
API Routes#
Public routes#
| Method | Path | Description |
|---|---|---|
GET |
/api/wiki |
List all wiki pages (no status filter - returns all) |
POST |
/api/wiki |
Submit a new page; requires auth; status set to pending_review |
GET |
/api/wiki/[slug] |
Fetch a single page by slug; enforces status visibility rules |
GET |
/api/wiki/search |
Full-text search over published pages; params: q, tags (comma-separated), limit |
GET |
/api/wiki/tags |
Returns system tags (with per-tag page counts) and player-defined tags |
GET |
/api/wiki/templates |
Returns all wikiTemplates documents |
GET |
/api/wiki/templates/[id] |
Returns a single template by slug |
GET |
/api/wiki/elections |
Completed election summaries, grouped by year+type and state+type; supports ?year=&type= and ?state=&type= filters |
GET |
/api/wiki/elections/[id] |
Full detail for a single completed election: primary results + general results from vote tallies |
GET |
/api/wiki/live-stats |
Current Congress seat counts by party and active/upcoming election counts; cached 2 min |
Admin routes (require admin auth)#
| Method | Path | Description |
|---|---|---|
POST |
/api/admin/wiki |
Create a page; published immediately (bypasses review) |
PATCH |
/api/admin/wiki/[slug] |
Update any field on an existing page including status |
DELETE |
/api/admin/wiki/[slug] |
Soft-delete: sets status to archived |
GET |
/api/admin/wiki/review-queue |
List all pending_review pages sorted by creation date |
POST |
/api/admin/wiki/review/[slug]/approve |
Approve a pending page; optionally apply edits to content, title, description, or tags |
POST |
/api/admin/wiki/review/[slug]/reject |
Reject a pending page (returns it to draft); requires a reason string |
Custom Markdown Components#
Wiki page content supports embedded interactive components via fenced code blocks with a custom language identifier. The registry lives in .
| Language identifier | Component | Description |
|---|---|---|
flowchart-turn |
TurnProcessingFlowchart |
Visual diagram of turn processing phases |
favorability-decay |
FavorabilityDecayDiagram |
Favorability decay curve visualization |
senate-classes |
SenateClassesDiagram |
Senate class rotation diagram |
congress-snapshot |
CongressSnapshot |
Live widget showing current House/Senate seat counts |
vote-share-calculator |
VoteShareCalculator |
Interactive calculator for vote share math |
Search Index#
getWikiSearchItems() in src/lib/wiki/searchIndex.ts builds a unified search index used by the navbar search. It merges:
- All
wikiPagesDB documents - Static config entries from
src/lib/wiki/config.ts(deprecated, kept for migration) - All player character profiles (excluding banned users)
- All active NPP profiles
- All seat pages derived from
getAllSeatSlugs() - All leadership role pages
- All party pages
Results are returned as WikiSearchItem objects with a slug, title, description, href, and optional searchText (heading extracts + content snippets).
Redirects#
maps legacy or shorthand slugs to their canonical paths:
| Slug | Redirects to |
|---|---|
democrat |
/wiki/party/1?country=us |
democrats |
/wiki/party/1?country=us |
republican |
/wiki/party/2?country=us |
republicans |
/wiki/party/2?country=us |
election-history |
/wiki/elections |
| Country aliases | The matching country overview |
| Feature aliases | The matching canonical wiki page |
The redirect helper preserves query strings in canonical targets, which is
required for country-scoped party pages. Country and feature aliases include
common names such as america, britain, ussr, campaign-presence, and
independence-referendums; consult WIKI_REDIRECTS for the complete current
map.