Engineering contract¶
These are Scribe's durable architecture and engineering invariants. A change that intentionally replaces one must update this page, the narrower concept or operations page, and the executable acceptance contract in the same review.
Settled architecture¶
- Connect and protobuf are the application API contract. Do not add REST-only business operations.
- A complete IIIF Presentation 3 AnnotationPage using the IIIF Text Granularity Extension is canonical OCR correction state.
- Canonical pages have Scribe HTTP(S) IDs, workspace/item-image ownership, and monotonic revisions. Imported Canvas IDs are targets and provenance, not tenant keys.
- hOCR, PAGE XML, ALTO XML, plain text, metrics, search rows, and public resources are derived from a committed canonical revision.
- Structural annotation mutations and model-driven processing live behind backend operations reusable by the bundled app and external editors.
- Browser-only state is limited to the local draft, selection, viewport, history, and conflict/rebase presentation.
- Authorization is enforced at route middleware and policy boundaries and is side-effect free. Import and processing are explicit authorized operations.
- Providers and segmentors are registered capabilities. Workspaces cannot choose an authenticated URL or audience pair.
- Keep a modular monolith plus worker until an independently scalable or isolated service boundary is demonstrated.
- Pull-request code never executes Terraform or repository scripts with cloud credentials. Preview and production CI applies use protected environments.
Canonical IIIF and persistence¶
- One
internal/iiifboundary owns IDs, parsing/building, extension semantics, raw-property preservation, andiiif-specvalidation. - Complete workspace-scoped pages and revisions are stored transactionally.
- Annotation/search rows and legacy export formats are rebuildable views.
- Versioned database migrations own schema changes once the greenfield schema stabilizes; processes do not replay a monolithic schema at startup.
- Item deletion is transactional and cleans relational, blob, Triplet, job, audit, and outbox state through explicit child-first application deletes. The schema has no foreign keys, so repository transactions own consistency and cleanup acceptance tests.
- Webhook subscription creation, deletion, and event delivery expansion serialize on the owning workspace row. Subscription and event deletion are child-first, and the recovery audit independently detects missing delivery parents or a parent workspace mismatch. Do not add a one-off database relationship mechanism that bypasses this repository-wide lifecycle model.
Editor¶
- A typed editor-session reducer owns the base page/revision, local draft, history, pending remote changes, conflict, and save states.
- OpenSeadragon coordinate conversion lives in one tested geometry module.
- Edits preserve unknown IIIF page, body, target, selector, service, and extension properties.
- One documented event bridge connects Mirador and the application shell.
Processing and extensibility¶
- Ingest, reprocess, delete, and publish orchestration lives in application use cases with transactions, idempotency, and outbox events.
- Provider and segmentor descriptors contain models, defaults, capabilities, limits, secret schema, and endpoint policy.
- Configuration fields are consumed by runtime behavior; unused fields are removed.
- Unicode is preserved and language/model filtering is explicit and testable.
Security and operations¶
- API keys stay hashed, sessions stay secure, body capture stays disabled, and audit retention stays bounded.
- Request, upload-byte, decoded-pixel, rate, workspace, provider, and stream limits apply before expensive work.
/livezreports process liveness;/readyzreports persistence readiness.- Long-running Compose services are restartable with readiness-aware ordering and graceful termination.
- Cloud deployments contain no VM: Cloud Run hosts stateless processes, Cloud SQL MySQL 8.4 stores application and Triplet Presentation state, GCS stores uploads, and Secret Manager owns cloud secrets through keyless ADC.
- Cloud workers scale to zero using authenticated Pub/Sub pushes and scheduled, bounded maintenance requests. Work completes within the request lifetime; local workers poll. Both use bounded shutdown and revision-fenced work.
- Actions, module commits, tools, downloads, and container digests are pinned; Renovate updates related references together.
- Protected
previewandproductionenvironments are required. GCP Workload Identity Federation claims are restricted to the repository, workflow, ref, and environment. - Each preview has isolated Cloud SQL, storage, queue, and secret resources; its runtime cannot read dev/prod secrets. Destruction has no shared Vault namespace dependency.
Developer experience and documentation¶
.go-version,.nvmrc,.tool-versions, Make targets, Docker images, and CI remain aligned.- Missing Buf, sqlc, or security tools fail with an installation command; generation and lint never silently skip.
- Shell automation may invoke reviewed packaged Python tools required by Kraken
or Zensical, but does not embed Python with
-c, standard input, or a heredoc. Repository helpers are Go or Bash; Node is limited to frontend packages. - Do not add or expand lifecycle state machines in Bash. New stateful deployment orchestration belongs in typed Go; shell entrypoints for those components remain thin binary launchers without lifecycle or policy logic.
make generate-checkcovers Go, Connect, TypeScript, sqlc, and OpenAPI output.- Zensical source under
docs/owns quickstart, architecture, extension, API, configuration, deployment, observability, backup, and recovery guidance. - The README and
AGENTS.mdremain concise entry points. Detailed and durable claims belong in tested, published documentation.
Use the release criteria to decide whether implementation evidence is complete.