openvibers/openvibe.wiki AGENTS.md
AGENTS.md
AGENTS.md — OpenVibe.Wiki
Project overview
OpenVibe.Wiki (https://openvibe.wiki) is the network's knowledge product: wiki spaces (official
editorial and community), page trees with canonical slugs, immutable revisions with diff and revert,
typed infoboxes, [[internal links]], citations bound to the revision that used them, Media
attachments and Community discussion — server-rendered and useful without JavaScript.
- Entry:
server/index.js; appserver/app.js; port4800, service idwiki. - API/pages:
server/http/api.js(/api/v1),pages.js,machine.js,openapi.js,
actor-limits.js,common.js,frame-groups.js; renderingserver/render/(layout.js,
views.js,blocks.js,short.js); public CSS/JS inpublic/. - Wiki domain:
server/wiki/—service.js,content.js,writer.js,access.js,
images.js,review-kind.js,import.js,seed.js,vibe.js,account-data.js. - Integrations:
server/integrations/—platform.js(Network/SSO),image-fetch.js,
projects-module.js,vip.js(gated spaces/pages). - Docs:
docs/threat-review.md; seeds inseeds/andscripts/seed.js;STATUS.json.
Owns, does not own
Owns the ten authority tables in ov_wiki: wiki_spaces (official/user, public/members/private),
wiki_pages (canonical identity, slug, tree via parent_id, publication state, published revision),
wiki_page_revisions (immutable; PL/pgSQL triggers refuse UPDATE/DELETE), plus the page
content/blocks, citations, discussion refs, media refs, review queue, shares, proposals and outbox.
Does not own: discussion (Community owns threads; Wiki stores only wiki_discussion_refs and
renders/posts through Community); attachments (Media owns bytes; Wiki stores med_… ids and their
last known state); source items (Sources; a citation stores the item id plus URL, title, retrieval
time and licence read from its provenance); the network index (Search; Wiki sends
wiki.index_document.*). It also does not own identity (Network), entitlements (VIP/Billing) or the
projects module (Services).
Who calls it, what it calls
People use their Network JWT (Bearer, or the ov_token cookie; cross-site cookie writes are refused);
services use client-credentials tokens for audience openvibe.wiki with one capability per route, and
content writes need the person in X-OV-Subject (whose space role applies). SDK openvibe-sdk/wiki
is the read client; openvibe-sdk/community is used for discussion. Wiki calls Network (SSO, JWKS,
names), Community (threads), Media (upload/read), Sources (citation provenance), Search (index events
out), Events (outbox), AI (wiki proposals/drafts) and VIP (gated spaces/pages). AI proposals are
drafts: a person reviews and publishes them.
Database and migrations
PostgreSQL ov_wiki through openvibe-sdk/db (PgBouncer for the app, direct owner role for
migrations); migrations/0001..0009 cover spaces/pages/revisions, review kinds, shares, the outbox
rejection index and defaults. Applied at boot; never edit one that has run. Revision immutability is
enforced by database triggers, not only by code. Tests use PGlite or WIKI_TEST_STORE=pg; a migration
that a rollback cannot tolerate is not allowed.
Auth and privacy
Network RS256 JWTs (offline JWKS) and SSO. A person's space role decides writes; services act for a
person only with X-OV-Subject and the capability. Visitors without SSO read public content only; a
members/private space is gated through VIP and the entitlement check. Cross-site cookie writes are
refused. AI generates proposals/drafts that need a person's approval before publication; every seed
page is currently noindex because no person has reviewed it, and none is in Search. Public pages are
cacheable; a signed-in page is private, no-store.
Deploy
sudo ovhost deploy wiki (git-checkout: fast-forward /opt/openvibe.wiki, install on a lockfile
change, restart, wait for /api/ready; rollback sudo ovhost rollback wiki --to <sha>). Unit
openvibe-wiki.service on 127.0.0.1:4800, env /etc/openvibe/wiki.env, database ov_wiki, nginx
deploy/nginx/openvibe.wiki.conf; the release migrates at boot.
Commands and tests
npm ci
npm run dev # http://127.0.0.1:4800
npm test # every test/*.test.js, temp PGlite + stub upstreams
npm test -- revisions seo # only matching files
npm run test:pg # the same on PostgreSQL
npm run seed # the official space's seed pages
test/run.js uses openvibe-shared/test-runner (60 s, serial): temporary PGlite, a generated RSA key
and stub upstreams, never the network. Coverage includes page trees/slugs, immutable revisions and
diff/revert, blocks/infoboxes/internal links, citations and the citation inspector, Media and
Community integration, access/VIP/delegation, AI proposals/review, discovery/SEO, account data and the
empty states.
Conventions and pitfalls
- CommonJS, 4-space indent, single quotes, semicolons; RFC 9457 problem+json, escaped HTML and a safe
block renderer (user content never becomes raw markup). - A revision is immutable. Publish a new revision; never UPDATE/DELETE a
wiki_page_revisionsrow
or bypass the trigger. Diff/revert and citations are computed from revisions. - Citations are provenance, not decoration: store the Sources item id, URL, title, retrieval time
and licence; a changed/removed source must be visible as such, never silently rewritten. - Discussion and bytes live elsewhere: store the Community thread id / Media
med_id, verify the
access with the owning service, and never copy a thread or a file into Wiki. - Seed/AI text is unreviewed until a person approves it: keep
noindexand out of Search until
reviewed; AI drafts are proposals, not publications. - Slug and tree changes are redirects: a moved page keeps its canonical identity and leaves a
redirect;[[internal links]]resolve through the canonical slug. - Search is downstream: publish/update/remove through
wiki.index_document.*in the transaction
(or the outbox), never write Search's tables.