CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 4s
masterplan-lock / check (push) Successful in 5s
CI (SIAX Cloud) / security (pull_request) Successful in 16s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 16s
CI (SIAX Cloud) / integration (pull_request) Successful in 9m58s
CI (SIAX Cloud) / quality (pull_request) Successful in 10m25s
- Ledger accepts kind='grant' (a server-owned balance grant, not a payment). - OPT_TRIAL_CREDITS=N grants N credits once per tenant (idempotent key trial:<tenant>) on balance/structure, so reserve -> settle is exercised before any customer purchase. - sql/020 extends the kind constraint (re-runnable). - Tests for the grant helper; full suite 1345 passed.
4.8 KiB
4.8 KiB
Document workbench — upload → structure → validated export
The customer-facing slice that turns an uploaded file into evidence-bound data.
Routes
| Route | Purpose | Fails closed with |
|---|---|---|
POST /api/0pt/documents/upload |
multipart upload of the original bytes into DOC0, recorded in a durable attempt journal before dispatch | 503 DOC0_NOT_CONFIGURED, 503 PROJECT_AUTHORIZATION_NOT_CONFIGURED, 503 UPLOAD_JOURNAL_NOT_CONFIGURED |
POST /api/0pt/documents/structure |
re-reads the DOC0 segment index, calls INF0, validates every field against an exact source span, reserves/settles credits | 503 WORKBENCH_NOT_CONFIGURED, 503 MODEL_POLICY_NOT_CONFIGURED, 503 CREDITS_NOT_CONFIGURED, 402 INSUFFICIENT_CREDITS |
GET /api/0pt/documents/models |
the server-approved model routes and limits | 503 MODEL_POLICY_NOT_CONFIGURED |
GET /api/0pt/credits/balance |
tenant credit balance | 503 CREDITS_NOT_CONFIGURED |
GET /api/0pt/credits/packs |
sellable packs from the server-owned price book | 503 PRICE_BOOK_NOT_CONFIGURED |
POST /api/0pt/credits/checkout |
Stripe Checkout session + server price snapshot | 503 PRICE_BOOK_NOT_CONFIGURED, 503 STRIPE_NOT_CONFIGURED |
POST /api/webhooks/stripe |
re-reads the session and payment intent, then grants credits idempotently | non-2xx until processed |
UI: /portal/dokument (upload, structure, review, download) and /portal/krediter
(balance, packs, checkout). The portal signs in through Zitadel OIDC
(/api/auth/login → /api/auth/callback); the resulting signed session cookie
is accepted by middleware as a verified principal (Bearer still wins).
Invariants
- Tenant and actor come only from middleware's verified headers. A customer
route never trusts
tenant_id/actor_idfrom the body. - Project access is checked by OpenFGA (
@siax/access), the same primitive DOC0 uses. Until the central relationship store is deployed, an explicit server-owned grant list (OPT_PROJECT_GRANTS) can be used instead. Unconfigured or unavailable means denied, never allowed. - The model never sees unverified text.
Doc0SourceClientverifies version, tenant, checksum, segment hashes and that the index was not truncated before anything is sent to INF0. - Every returned value must point at an exact span in the source; otherwise
the result is
needs_reviewand nothing is exported. - Credits are reserved before the model runs and settled to measured usage. An unknown model outcome keeps the reservation for reconciliation instead of releasing it.
- No price is ever read from the client. The price book is a versioned,
server-owned JSON document (
OPT_CREDIT_PRICE_BOOK). - Trial credits are a grant, not a payment.
OPT_TRIAL_CREDITS=Ngrants N credits once per tenant (kind='grant', idempotency keytrial:<tenant>), so the ledger is fully exercised before any real purchase. It is never read from a client and never looks like a Stripe payment. - Pilot mode is explicit.
OPT_CREDITS_MODE=offskips reserve/settle and reportscredits: null. It is not a silent fallback and it does not enable purchases; unset/onrequires the price book and the ledger.
Reusable packages
packages/siax-access(@siax/access) — framework-neutral OpenFGA relationship checks and a fail-closedisProjectAccessAllowed. Intended for DOC0, N0D and every other SIAX product instead of per-repo copies ofproject-relationships.ts.src/document-workbench/*— upload coordination, DOC0 source reading, INF0 admission, structured-output validation, export and credit ledger. These modules have no Next.js imports and can be lifted into a published package unchanged.
Which AI path is used
Order:
- Decision server model (
DECISION_OLLAMA_URL+DECISION_OLLAMA_MODEL) — the self-hosted Ollama on server-decision-01, used while the external model API is on hold. Internal only, no provider key, no per-token cost. - Live LiteLLM gateway (
INF0_GATEWAY_LITELLM_KEY). - Native
INF0_URLsurface.
Admission — tenant/project scope, model allow-list, data class,
external-transfer policy and token limits — runs locally in every path before
the request leaves the process. Evidence spans are computed deterministically
from the returned values when a small local model omits offsets: a value must
occur exactly once in the source, otherwise the result is needs_review.
What is still deliberately not claimed
- The output is
mechanically_validated, not proven complete or semantically correct. OCR quality and coverage require review. - Refunds and chargebacks do not automatically revoke credits; no such handler is wired.
- Format breadth is limited by DOC0's parser. A file DOC0 cannot parse is reported, never guessed.