openvibers/openvibe.wiki AGENTS.md
AGENTS.md
| 1 | # AGENTS.md — OpenVibe.Wiki |
| 2 | |
| 3 | ## Project overview |
| 4 | |
| 5 | OpenVibe.Wiki (`https://openvibe.wiki`) is the network's knowledge product: wiki spaces (official |
| 6 | editorial and community), page trees with canonical slugs, immutable revisions with diff and revert, |
| 7 | typed infoboxes, `[[internal links]]`, citations bound to the revision that used them, Media |
| 8 | attachments 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 | |
| 22 | Owns 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 |
| 25 | content/blocks, citations, discussion refs, media refs, review queue, shares, proposals and outbox. |
| 26 | |
| 27 | Does not own: discussion (Community owns threads; Wiki stores only `wiki_discussion_refs` and |
| 28 | renders/posts through Community); attachments (Media owns bytes; Wiki stores `med_…` ids and their |
| 29 | last known state); source items (Sources; a citation stores the item id plus URL, title, retrieval |
| 30 | time 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 |
| 32 | projects module (Services). |
| 33 | |
| 34 | ## Who calls it, what it calls |
| 35 | |
| 36 | People use their Network JWT (Bearer, or the `ov_token` cookie; cross-site cookie writes are refused); |
| 37 | services use client-credentials tokens for audience `openvibe.wiki` with one capability per route, and |
| 38 | content writes need the person in `X-OV-Subject` (whose space role applies). SDK `openvibe-sdk/wiki` |
| 39 | is the read client; `openvibe-sdk/community` is used for discussion. Wiki calls Network (SSO, JWKS, |
| 40 | names), Community (threads), Media (upload/read), Sources (citation provenance), Search (index events |
| 41 | out), Events (outbox), AI (`wiki` proposals/drafts) and VIP (gated spaces/pages). AI proposals are |
| 42 | drafts: a person reviews and publishes them. |
| 43 | |
| 44 | ## Database and migrations |
| 45 | |
| 46 | PostgreSQL `ov_wiki` through `openvibe-sdk/db` (PgBouncer for the app, direct owner role for |
| 47 | migrations); `migrations/0001..0009` cover spaces/pages/revisions, review kinds, shares, the outbox |
| 48 | rejection index and defaults. Applied at boot; never edit one that has run. Revision immutability is |
| 49 | enforced by database triggers, not only by code. Tests use PGlite or `WIKI_TEST_STORE=pg`; a migration |
| 50 | that a rollback cannot tolerate is not allowed. |
| 51 | |
| 52 | ## Auth and privacy |
| 53 | |
| 54 | Network RS256 JWTs (offline JWKS) and SSO. A person's space role decides writes; services act for a |
| 55 | person only with `X-OV-Subject` and the capability. Visitors without SSO read public content only; a |
| 56 | members/private space is gated through VIP and the entitlement check. Cross-site cookie writes are |
| 57 | refused. AI generates proposals/drafts that need a person's approval before publication; every seed |
| 58 | page is currently `noindex` because no person has reviewed it, and none is in Search. Public pages are |
| 59 | cacheable; 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 |
| 64 | change, 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 |
| 71 | npm ci |
| 72 | npm run dev # http://127.0.0.1:4800 |
| 73 | npm test # every test/*.test.js, temp PGlite + stub upstreams |
| 74 | npm test -- revisions seo # only matching files |
| 75 | npm run test:pg # the same on PostgreSQL |
| 76 | npm 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 |
| 80 | and stub upstreams, never the network. Coverage includes page trees/slugs, immutable revisions and |
| 81 | diff/revert, blocks/infoboxes/internal links, citations and the citation inspector, Media and |
| 82 | Community integration, access/VIP/delegation, AI proposals/review, discovery/SEO, account data and the |
| 83 | empty 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 |