openvibers/openvibe.wiki AGENTS.md

AGENTS.md

main 6.1 KB · 101 lines · markdown

1# AGENTS.md — OpenVibe.Wiki
2
3## Project overview
4
5OpenVibe.Wiki (`https://openvibe.wiki`) is the network's knowledge product: wiki spaces (official
6editorial and community), page trees with canonical slugs, immutable revisions with diff and revert,
7typed infoboxes, `[[internal links]]`, citations bound to the revision that used them, Media
8attachments and Community discussion — server-rendered and useful without JavaScript.
9
10- **Entry:** `server/index.js`; app `server/app.js`; port `4800`, service id `wiki`.
11- **API/pages:** `server/http/api.js` (`/api/v1`), `pages.js`, `machine.js`, `openapi.js`,
12 `actor-limits.js`, `common.js`, `frame-groups.js`; rendering `server/render/` (`layout.js`,
13 `views.js`, `blocks.js`, `short.js`); public CSS/JS in `public/`.
14- **Wiki domain:** `server/wiki/` — `service.js`, `content.js`, `writer.js`, `access.js`,
15 `images.js`, `review-kind.js`, `import.js`, `seed.js`, `vibe.js`, `account-data.js`.
16- **Integrations:** `server/integrations/` — `platform.js` (Network/SSO), `image-fetch.js`,
17 `projects-module.js`, `vip.js` (gated spaces/pages).
18- **Docs:** `docs/threat-review.md`; seeds in `seeds/` and `scripts/seed.js`; `STATUS.json`.
19
20## Owns, does not own
21
22Owns the ten authority tables in `ov_wiki`: `wiki_spaces` (official/user, public/members/private),
23`wiki_pages` (canonical identity, slug, tree via `parent_id`, publication state, published revision),
24`wiki_page_revisions` (**immutable**; PL/pgSQL triggers refuse UPDATE/DELETE), plus the page
25content/blocks, citations, discussion refs, media refs, review queue, shares, proposals and outbox.
26
27Does not own: discussion (Community owns threads; Wiki stores only `wiki_discussion_refs` and
28renders/posts through Community); attachments (Media owns bytes; Wiki stores `med_…` ids and their
29last known state); source items (Sources; a citation stores the item id plus URL, title, retrieval
30time and licence read from its provenance); the network index (Search; Wiki sends
31`wiki.index_document.*`). It also does not own identity (Network), entitlements (VIP/Billing) or the
32projects module (Services).
33
34## Who calls it, what it calls
35
36People use their Network JWT (Bearer, or the `ov_token` cookie; cross-site cookie writes are refused);
37services use client-credentials tokens for audience `openvibe.wiki` with one capability per route, and
38content writes need the person in `X-OV-Subject` (whose space role applies). SDK `openvibe-sdk/wiki`
39is the read client; `openvibe-sdk/community` is used for discussion. Wiki calls Network (SSO, JWKS,
40names), Community (threads), Media (upload/read), Sources (citation provenance), Search (index events
41out), Events (outbox), AI (`wiki` proposals/drafts) and VIP (gated spaces/pages). AI proposals are
42drafts: a person reviews and publishes them.
43
44## Database and migrations
45
46PostgreSQL `ov_wiki` through `openvibe-sdk/db` (PgBouncer for the app, direct owner role for
47migrations); `migrations/0001..0009` cover spaces/pages/revisions, review kinds, shares, the outbox
48rejection index and defaults. Applied at boot; never edit one that has run. Revision immutability is
49enforced by database triggers, not only by code. Tests use PGlite or `WIKI_TEST_STORE=pg`; a migration
50that a rollback cannot tolerate is not allowed.
51
52## Auth and privacy
53
54Network RS256 JWTs (offline JWKS) and SSO. A person's space role decides writes; services act for a
55person only with `X-OV-Subject` and the capability. Visitors without SSO read public content only; a
56members/private space is gated through VIP and the entitlement check. Cross-site cookie writes are
57refused. AI generates proposals/drafts that need a person's approval before publication; every seed
58page is currently `noindex` because no person has reviewed it, and none is in Search. Public pages are
59cacheable; a signed-in page is `private, no-store`.
60
61## Deploy
62
63`sudo ovhost deploy wiki` (git-checkout: fast-forward `/opt/openvibe.wiki`, install on a lockfile
64change, restart, wait for `/api/ready`; rollback `sudo ovhost rollback wiki --to <sha>`). Unit
65`openvibe-wiki.service` on `127.0.0.1:4800`, env `/etc/openvibe/wiki.env`, database `ov_wiki`, nginx
66`deploy/nginx/openvibe.wiki.conf`; the release migrates at boot.
67
68## Commands and tests
69
70```bash
71npm ci
72npm run dev # http://127.0.0.1:4800
73npm test # every test/*.test.js, temp PGlite + stub upstreams
74npm test -- revisions seo # only matching files
75npm run test:pg # the same on PostgreSQL
76npm run seed # the official space's seed pages
77```
78
79`test/run.js` uses `openvibe-shared/test-runner` (60 s, serial): temporary PGlite, a generated RSA key
80and stub upstreams, never the network. Coverage includes page trees/slugs, immutable revisions and
81diff/revert, blocks/infoboxes/internal links, citations and the citation inspector, Media and
82Community integration, access/VIP/delegation, AI proposals/review, discovery/SEO, account data and the
83empty states.
84
85## Conventions and pitfalls
86
87- CommonJS, 4-space indent, single quotes, semicolons; RFC 9457 problem+json, escaped HTML and a safe
88 block renderer (user content never becomes raw markup).
89- **A revision is immutable.** Publish a new revision; never UPDATE/DELETE a `wiki_page_revisions` row
90 or bypass the trigger. Diff/revert and citations are computed from revisions.
91- **Citations are provenance, not decoration:** store the Sources item id, URL, title, retrieval time
92 and licence; a changed/removed source must be visible as such, never silently rewritten.
93- **Discussion and bytes live elsewhere:** store the Community thread id / Media `med_` id, verify the
94 access with the owning service, and never copy a thread or a file into Wiki.
95- **Seed/AI text is unreviewed until a person approves it:** keep `noindex` and out of Search until
96 reviewed; AI drafts are proposals, not publications.
97- **Slug and tree changes are redirects:** a moved page keeps its canonical identity and leaves a
98 redirect; `[[internal links]]` resolve through the canonical slug.
99- **Search is downstream:** publish/update/remove through `wiki.index_document.*` in the transaction
100 (or the outbox), never write Search's tables.
101