# The road to cutover

2026-08-08. Written after Ernest moved the gate.

Yesterday's plan had the cutover happening "today or tomorrow", with everything
else additive and shipping afterwards. That is no longer the plan. The new
condition, in his words: **all official first-party modules built**, then a
**full development KB** covering the ins and outs of Convoro, then the **AI
Assistant ported from IPS and reading its answers out of that KB**. Only then do
we cut over.

This note records what that actually means, in what order, and the decisions it
forces — because "and Events, etc." is three months of work hiding inside an
"etc." and it should be counted rather than discovered.

---

## Why the gate moved, as I read it

The old gate was "can community.convoro.co run on convoro2?" — a migration
question. The new gate is "is Convoro a product?" — a completeness question.

They are different bars and the second is the right one here. Cutting over onto
three applications means the live site publicly *is* a forum with downloads and
a page builder, at the moment it is trying to be the thing that replaces a
platform with a dozen applications. Landing once, complete, with documentation
and something that can answer questions about it, is a better first impression
than landing early and visibly filling gaps in public.

The cost is honest and worth writing down: **the cutover slips by months, not
days.** Everything in the old queue that was "after go-live" is now before it.

## What counts as a first-party application

The content-type registry from
[2026-08-07-the-application-model.md](2026-08-07-the-application-model.md)
already answers this. An application owns content types, may be disabled, may
claim `/`, and declares `"application": true`. Services are not applications and
do not count towards this gate.

| Application | State |
|---|---|
| Forums | ✅ shipped |
| Downloads | ✅ shipped, and now sells |
| Pages | 🔨 **half** — blocks done, custom databases not built |
| Blog | ❌ does not exist |
| Events | ❌ does not exist |
| Gallery | ❌ does not exist |
| Clubs | ❌ does not exist |
| Knowledge Base | ❌ does not exist — new, and decided by this note |

Eight applications. Three of them exist. Pages counts as unfinished, not done:
the roadmap already says custom databases are "most of a CMS on its own", and a
Pages that cannot define a field is not a Pages anyone would migrate to.

🚨 **Clubs is not a peer of the others.** A club contains forums, galleries and
events, so it is a container that cross-cuts every application in the table. It
is built **last**, after the things it contains exist, or it gets built twice.

## Order, and the reasoning

1. **Pages custom databases.** Finishes the application that is already half
   there, and it is the piece the others learn from — fields, records, list and
   detail views, per-field permissions. Every application below is, structurally,
   a specialised version of this.
2. **Blog.** The lightest new application: entries, comments, categories, a
   per-member space, its own index. Almost entirely things the registry already
   knows how to do, which makes it the right first test of whether the registry
   earns its keep.
3. **Events.** A calendar: events, RSVPs, venues, month/week/day views. 🚨
   **Recurrence is the hard part and is where calendars go wrong** — an
   exception to a repeating event, a timezone that shifts under a series, "every
   third Tuesday". Its own note before any code.
4. **Gallery.** Images and albums. The application with real infrastructure
   underneath it: a thumbnailing pipeline, EXIF stripping (a privacy question,
   not a feature), storage limits, and a lightbox. Attachments already solve
   part of this and should not be solved twice.
5. **Knowledge Base.** Articles, categories, search, and "was this helpful".
   Built before the KB is written, obviously, and built before the assistant,
   because it is the assistant's corpus.
6. **Clubs.** Member-created spaces containing the above.

Then the KB content, then the assistant, then cutover.

### What this displaces

Stripe and the two polish items from 2026-08-08 — bigger forum grid cards, and
the widget editor's delete-X and grouped widget list — are **not** part of this
gate. They are small, they were asked for directly, and they stay at the front
because a week of application work is easier to face on a UI that is not
annoying. They are hours, not days.

## The Knowledge Base is an application, not a docs folder

Decided 2026-08-08: the KB is a **first-party Convoro application**, not a
markdown tree in `docs/`. Four reasons, in order of weight:

1. **The assistant needs a queryable corpus.** Files in git are not reachable
   from a running site without inventing a build step and a shipping format.
   Content in the database is reachable through the content-type registry, which
   already exists and already backs search.
2. **It dogfoods the platform.** A KB is exactly the kind of thing Convoro
   should be able to host. If our own documentation cannot live on it, that is
   information we want early.
3. **It is public.** Documentation nobody can read does not answer support
   questions or rank in a search engine.
4. **It is sellable.** Every mature platform has one. This one is on the list
   anyway.

`docs/design/` does not go away — design notes are provenance and stay in git.
What moves into the KB is the *reference* material: how the engine works, how to
write an extension, how to administer a site, how to use one.

### Written for all three audiences

Developers, administrators and end users — Ernest confirmed all three. They are
different documents and should not be blended into one voice:

- **Developer** — engine internals, the module system, `.cvr` templates,
  migrations, hooks and events, the extension API, the content-type registry,
  the payment `Provider` seam. This is the "full development KB" he asked for
  and it is the largest of the three.
- **Administrator** — installing, upgrading, permissions, moderation, themes,
  payments, backups, the task runner. What the assistant will actually be asked
  most often on a live site.
- **End user** — posting, following, notifications, account settings. Cheapest
  to write, highest question volume.

🚨 **The KB is being written to be retrieved from, not only read.** That changes
how it is written: one answer per article, each article self-contained enough to
stand alone when a retriever hands back three of them, titled as the question a
person would ask. An article that only makes sense after reading the four before
it is a bad KB article and a *useless* retrieval result. This is the same
standing rule as [[kb_standing_rule]] on the IPS side — anything a stranger
would want becomes an article — with a retrieval constraint on top.

## The AI Assistant

A port of **edaihelper**, the IPS app. 🚨 Worth being explicit, because the
licence rules in ROADMAP.md are strict and this is the one place they do not
bite: **edaihelper is Ernest's own code, not Invision's.** Porting his own
application across to his own platform is unrestricted. What stays off the table
is anything of Invision's it happened to sit next to — their APIs, their
templates, their copy. The port is of our behaviour and our interface, rewritten
against Convoro's seams.

It reads the KB and answers from it. Two things that must be decided before code:

**Retrieval.** Keyword search already exists and the KB will register with it.
Whether that is good enough, or whether this needs embeddings and a vector
store, is an open question — and it is not a small one, because embeddings mean
storing a vector per article, regenerating on edit, and a similarity query the
current search driver cannot express. Start on the existing search seam, measure
it against real questions, and only add vectors if it is actually failing.
Deciding otherwise now is deciding without evidence.

**🚨 The assistant breaks the outbound-call rule, and this is the conflict.**
The standing rule is: no outbound call inside a visitor's request, with one
deliberate exception — starting a checkout, which *is* the request. An assistant
answering a question is exactly the same shape: the model call *is* what the
visitor asked for, so it cannot be deferred to a queue without deferring the
answer. It becomes the **second** deliberate exception, and it carries the same
discipline as the first: a hard connect timeout, a hard read timeout, a visible
failure rather than a hung page, and a rate limit per member. Embedding, if it
happens, is the opposite case — it belongs to the task runner and must never
touch a visitor request.

## What the cutover still needs, unchanged

Moving the gate does not shrink this list; it only delays it. From the 08-08
handoff, all still true:

- Live PayPal credentials and a **webhook ID** — nothing settles without one.
- A production install through the web installer, **never yet run against a real
  server**.
- DNS, certificates and mail for convoro.co and community.convoro.co.
- The marketing home page. A *Page* still cannot claim `/`; only Forums and
  Downloads can. Small addition, and Pages custom databases is the natural
  moment to fix it.
- Redirects from old URLs, out of `cv_import_map`.

The content migration remains solved and re-runnable. It will need re-running
against fresh data on the day, and **re-verifying**, because months of new posts
will have landed on the old site by then.

## What this note does not decide

- **The field-type set for custom databases**, or how per-field permissions
  interact with search. That is the note that comes before item 1, and it is the
  part most likely to be got wrong.
- **Whether Blog entries are a content type of their own or a Pages database
  with a preset.** The second is tempting and probably wrong — a blog wants its
  own URLs, its own feed and its own per-member ownership model — but it should
  be argued in the Blog note rather than assumed here.
- **Which model the assistant runs against**, and who pays for the calls on a
  customer's install. That is a product question as much as a technical one.
- **Whether the KB ships enabled by default** on a fresh install, and whether
  our articles ship as seed content or the app starts empty.
