ConusAI vendor v0.1.0-dev.20261027+9b1131fb
ci / gate (push) Waiting to run

This commit is contained in:
ConusAI vendor v0.1.0-dev.20261027+9b1131fb
2026-10-27 18:05:17 +00:00
commit 3102273ec7
538 changed files with 80203 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
<!-- SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0 -->
# The convex profile
**Status: selectable preview; not production-ready.** `kit template:prune --profile convex` now
selects this app composition, and the generated Next app builds. The BFF keeps the Convex admin
key server-side, domain queries and mutations execute within real Convex function transactions,
jobs use the Convex scheduler, and the one-shot deploy service installs the app's scoped platform
runtime variables before pushing functions. The local gate deploys generated functions to a local
backend and exercises a trusted identity, tenancy, notes, the outbox audit/usage sinks, and backup
restore. It does not yet prove browser login through the generated Next BFF or a native platform
deployment. File begin/complete/delete use server-side Convex actions around transactional
mutations; streamed parts stay on the Next BFF and go directly to Blob after a Convex authorization
query. The profile gate exercises an upload, streamed part, notes attachment, detach and delete
against a local backend and fake Blob; deleting rows also have a scheduled recovery action.
Documents OCR and proposal review run through a server-side Node action and the Convex scheduler;
the local gate exercises extraction, proposal approval, and the resulting document line. The
guides and support modules' effect procedures (each one call to a platform service, owning no app
row) are generated Convex actions: `convex/lib/effects.ts` runs the kernel in the action with the
module's platform port bound from the installed deployment variables, resolves the scope and checks
the permission in internal queries over `ctx.db` (`convex/effectScope.ts`), and runs a nested read
or write as its generated query or mutation. The account module's export and deletion are
generated actions too: they compose those modules' shares and reach the deletion ledger and the
person's rows through the account store bound in the action, whose every method is one internal
query or mutation of `convex/account.ts` (the Postgres profile's own store over `ctx.db`), so the
ledger records each step as it completes, a resumption runs only the steps left, and the five-minute
`account deletion sweep` cron finishes what a module held up. Better Auth's account events reach the
same flow (`account:providerEvent`). Branding logos remain unavailable; do not treat this preview as
a production deployment.
The table describes the current and intended profile architecture from spec §5.1 and §5.4.
| | postgres (default) | convex (this profile) |
|---|---|---|
| Primary store | Postgres 18 | Convex (self-hosted, managed link) |
| Data adapter | `@conusai-kit/data-kysely` | `@conusai-kit/data-convex` (`ctx.db` repositories) |
| Procedures reach handlers via | Hono HTTP mount + `callByName` | generated `convex/generated/<module>.ts` wrappers (`pnpm convex:gen`) |
| Jobs | pg-boss (Postgres) | Convex scheduler (`convex/conusaiJobs.ts` dispatcher; job rows and dispatch share a mutation) |
| Events | outbox → pg-boss relay | outbox table → scheduled internal mutation (`convex/relay.ts`, cron every minute); audit and usage use server-side platform adapters |
| Tenant wall | repository predicate + RLS | `convex-helpers` custom functions (`convex/lib/functions.ts`) + repository predicate |
| Migrations | numbered SQL, `migrate` job | `convex/schema.ts` generated from zod, pushed by `convex deploy`; data moves use the migrations component |
| Audit | outbox subscribers over HTTP | the same subscribers, audit written via `@conusai-sdk/convex-audit` (registered in `convex/convex.config.ts`) |
| Links | `postgres`, `identity` | `convex`, `identity` |
| Process env | `POSTGRES_URL`, `POSTGRES_READER_URL`, `POSTGRES_MIGRATE_URL` | `CONVEX_SELF_HOSTED_URL`, `CONVEX_SELF_HOSTED_ADMIN_KEY` (server only) |
## What this folder carries
- `convex-deploy` runs `profiles/convex/deploy.mjs`: it writes the app-scoped platform
variables to a mode-0600 temporary file, asks the Convex CLI to install them in the backend,
then deploys the app schema and functions before web and backup start. It uses the linked project
service credential, never a human owner credential.
- `convex/filesActions.ts` performs Blob begin/complete/delete calls; `convex/files.ts` keeps each
row transition in an internal mutation. A five-minute recovery cron reconciles abandoned uploads
and reschedules durable deletes.
Streamed part bodies stay in the Next BFF and are guarded before the server-side Blob client
sends them; no file bytes or platform token enter Convex arguments or browser bundles.
- The BFF uses the same filtered module registry as the generated functions. Its readiness check
compares the deployed module and procedure list plus the entity tables, columns, and indexes.
## Work required before this can be enabled
This remains a preview because browser login through the generated Next BFF, native platform
deployment, and external object-store workflows have not passed yet. The local file and OCR flows
use a fake Blob/platform API; production readiness still requires those flows against a project-
scoped test service credential and branding workflow composition.
## What the existing tests prove
- `@conusai-kit/data-convex` tests its adapter contracts and isolation behavior under
`convex-test` (`bun run --filter @conusai-kit/data-convex test:run`).
- `scripts/vendor/test-template.sh app --profile convex` validates `conusai.json`, checks
generated Convex files for deterministic regeneration, runs the adapter package suite, and tests
an app deploy and notes/outbox/file smoke plus backup export/restore against local Convex backend
containers. After deploying locally it also typechecks the functions against Convex's generated
contexts. The smoke calls Convex functions directly with a local test identity; it does not
prove browser login or the generated Next BFF route.
- The same smoke calls the guides actions (`guides.runtime.bootstrap`, `guides.runtime.record`) and
the support actions (`support.widget.config`, `support.widgetSession.mint`) for a member against the fake
platform, checks the subject, app tenant, `role` trait and display name the platform received, and
checks that a stranger to the organization and an identity pinned to another organization get the
kernel's not-found with no platform call. The guides deploy step (code guides and anchors) still
runs only in the Postgres profile's migrate job.
- The same smoke runs the account module against the real backend and the fake platform: the
export (complete, then a failed, named support section while support is down), the deletion
status, a mismatched confirmation (no ledger row), a deletion held by support with its steps
recorded, the session revoked and the identity detached, the `account:sweep` action failing while
it waits and finishing once support is back (widget sessions revoked before the contact is
erased), a repeated request, and a ban and a deletion as provider events. In a Better Auth app it
also starts a third backend for the Better Auth deployment: a person signs up there, and their
deletion ends that account (the password then signs nobody in).
- The derived-session revocation outbox (`account.sessions.revoke`) is still the Postgres
worker's: on this profile a sign-out asks the modules directly, bounded, once.
- This profile has no Postgres worker or migration process; supported module jobs run in Convex.
The local deployed-app smoke uploads, attaches, detaches and deletes a file through the real
Convex backend and fake Blob API, and verifies OCR proposals and approval. It does not prove
browser login or the generated Next BFF route.
## Backup implementation status
The platform does **not** back a Convex backend up (decision AT-D16). The backup runner, compose
schedule, Blob retention, and restore runbook are implemented and gated with a local round-trip.
Configure `CONVEX_SELF_HOSTED_ADMIN_KEY` only in server containers and use [the backup and restore
runbook](../../docs/backup.md). Backups run outside the Convex runtime because export is an admin
CLI operation.
## Runtime variables
The web and backup services receive `CONVEX_SELF_HOSTED_URL` and
`CONVEX_SELF_HOSTED_ADMIN_KEY` from the linked Convex service. The deploy service additionally
receives `CONUSAI_API_URL`, the project's scoped `CONUSAI_API_TOKEN`, `CONUSAI_PROJECT_ID`, and
`CONUSAI_ORG_SLUG`; it copies those values into the Convex backend so file, audit, and usage actions
can reach the platform. The web process also needs `AUTH_SESSION_SECRET`, `OIDC_ISSUER`,
`OIDC_WEB_CLIENT_ID`, and `OIDC_WEB_CLIENT_SECRET`; `OIDC_SCOPES`, `OIDC_AUDIENCE`,
`AUTH_COOKIE_NAME`, `AUTH_SESSION_IDLE_SECONDS`, and `AUTH_SESSION_ABSOLUTE_SECONDS` are optional
auth preferences. `CONVEX_BACKUP_INTERVAL_HOURS` defaults to 24 and
`CONVEX_BACKUP_RETENTION` defaults to 30. The platform-injected API token remains server-side and
is never sent to browser code.
With `AUTH_PROVIDER=convex-better-auth`, Better Auth runs in a second Convex deployment of the app,
beside this one, linked to the project under the `better-auth` role (`conusai.json`:
`{"type": "convex", "role": "better-auth"}`, which `kit template:prune --auth convex-better-auth`
writes in place of the Identity link). The data deployment's `default` link injects
`CONVEX_SELF_HOSTED_URL`, `CONVEX_SITE_URL` and `CONVEX_SELF_HOSTED_ADMIN_KEY`; the Better Auth
link injects `BETTER_AUTH_CONVEX_URL` (its cloud origin), `BETTER_AUTH_CONVEX_SITE_URL` (its site
origin) and `BETTER_AUTH_CONVEX_ADMIN_KEY`, as runtime-only variables. The operator sets only
`BETTER_AUTH_SECRET` (a secret) and `AUTH_IDENTITY_NAMESPACE` as project variables (the steps are in
docs/how-to/build-an-app-on-the-template.md of the platform repository). `web` receives the two URLs and the key; `convex-deploy` receives the
URL, the key, the namespace and the secret, deploys `better-auth/` to that deployment and installs
`AUTH_PROVIDER`, `AUTH_IDENTITY_NAMESPACE`, `BETTER_AUTH_CONVEX_URL` and
`BETTER_AUTH_CONVEX_ADMIN_KEY` in this backend, whose account actions end a deleted person's
Better Auth account. None of them reaches a browser or the image build.