7.9 KiB
06 — Technical architecture
Architecture decision
Build the MVP as a modular monolith with two deployable process roles from one repository:
web: UI, API and synchronous domain operations;worker: imports, Gitea synchronization, artifact generation and maintenance jobs.
Both use PostgreSQL. Built-in playbook packages are mounted or copied into the application image and imported idempotently. No Redis, Elasticsearch or vector database is required for the MVP.
Required workspace
Routine implementation choices are fixed in docs/25-implementation-defaults.md.
apps/
web/ Next.js application and route adapters
worker/ background process entry point
packages/
domain/ entities, value objects, policies, domain errors
application/ use cases and ports
persistence/ PostgreSQL repositories and migrations
playbook-schema/ JSON Schema, semantic validation and canonicalization
prompt-engine/ composition, linting, provenance and rendering
repository-intel/ profile normalization, findings and adapters
integrations-gitea/ Gitea adapter
artifacts/ Markdown and ZIP generation
ui/ reusable design-system components
config/ environment parsing and feature flags
content/
playbooks/ canonical built-in packages
fixtures/ non-sensitive evaluation fixtures
schemas/ published interchange schemas
docs/
The bootstrap layout and canonical root commands in docs/40-bootstrap-repository-contract.md are normative. A materially different repository structure requires a blocker-level ADR before Milestone 1 and proof that package boundaries, deployment simplicity and every acceptance criterion remain equivalent. Do not bury domain logic in React components, server actions or HTTP handlers.
Main request flows
Library read
Browser → Next.js route → Library query use case → PostgreSQL projection → response DTO
Prompt composition
Browser → Composition API
→ load immutable playbook version
→ load selected profile revision
→ normalize and validate input
→ resolve policies and compatibility
→ compose prompt blocks
→ lint rendered prompt
→ return preview + provenance + findings
Preview is ephemeral. Final generation creates an immutable generated_run transactionally.
Built-in package import
The runtime imports the 28 P0 package directories under content/playbooks/; the 72-entry seed catalog remains a roadmap and is not silently exposed as executable content.
Worker startup/job
→ enumerate package directories
→ structural schema validation
→ semantic validation
→ canonicalize
→ compute digest
→ upsert playbook identity
→ insert missing immutable version
→ update search projection
→ report package-specific errors
One invalid package must not hide errors in other packages. The release build should fail if bundled packages are invalid.
Gitea synchronization
Scheduled/manual job
→ load encrypted credential
→ verify base URL and capability snapshot
→ bounded API collection
→ normalize evidence
→ store immutable snapshot
→ derive findings
→ optionally propose a new profile revision
The job must support cancellation, per-step timeouts, rate-limit handling and safe partial failure. A partially collected snapshot is never marked complete.
Technology guidance
Frontend
- Next.js App Router with TypeScript;
- server rendering for library and detail views where useful;
- client components only for interactive composer, editors and visualizations;
- Tailwind CSS and an accessible component foundation;
- Monaco or CodeMirror for schema-aware YAML/Markdown authoring;
- a small motion library for functional animation;
- URL-driven filter state;
- browser tests using Playwright.
Backend
- route handlers or a thin API layer;
- Zod or equivalent validation at transport boundaries;
- explicit use-case classes/functions;
- PostgreSQL with a typed migration/ORM layer;
- a PostgreSQL-backed job table and worker polling/notification mechanism;
- object artifacts on local disk in MVP, behind a storage port for future S3-compatible support.
During Milestone 0, Codex must verify current stable package compatibility before selecting exact versions. It may not replace the architecture or prohibited-technology boundaries merely because another starter template is familiar.
API style
Use REST-style JSON endpoints with generated OpenAPI documentation. Favor explicit resources and actions over mirroring database tables.
Examples:
GET /api/playbooksGET /api/playbooks/{slug}/versions/{version}POST /api/compositions/previewPOST /api/runsPOST /api/runs/{id}/artifacts/run-packPOST /api/playbook-importsPOST /api/repositories/{id}/snapshots
Background jobs
Initial job types:
- built-in playbook import;
- user playbook import;
- Gitea capability refresh;
- repository snapshot collection;
- Run Pack generation;
- artifact retention cleanup;
- stale integration health check;
- optional search projection rebuild.
Job records require state, attempt count, lease owner, lease expiry, progress, error code, redacted error detail and timestamps. Jobs must be idempotent or use idempotency keys.
Configuration
Environment values are parsed once into a typed configuration object. Invalid production configuration fails fast.
Required categories:
- database URL;
- public base URL;
- session/auth secrets;
- encryption master key and key version;
- content directory;
- artifact storage directory;
- maximum import/artifact sizes;
- allowed Gitea network ranges or host policy;
- log level;
- retention settings;
- feature flags.
Never expose server-only configuration through client bundles.
Storage model
PostgreSQL
Structured application data, canonical package JSON, prompt text, provenance and audit events.
Content directory
Read-only built-in playbook packages distributed with the application. Development mode can watch changes; production imports at startup or explicit migration job.
Artifact directory
Generated ZIP and Markdown files using opaque storage keys. Downloads require authorization; filenames are metadata, not direct filesystem paths.
Failure and degraded-mode design
- Database unavailable: readiness fails; liveness remains healthy while process is alive.
- Gitea unavailable: local app and last snapshots continue working.
- Package import failure: existing valid versions remain available; admin sees precise package errors.
- Artifact storage unavailable: prompt generation still succeeds, binary export shows a recoverable error.
- Worker unavailable: synchronous reads/composition work; jobs show queued/stalled state.
Identity and first run
Authentication, workspace authorization and setup lifecycle follow docs/26-authentication-authorization.md and docs/31-first-run-and-instance-lifecycle.md. Database relations follow database/reference-schema.sql.
Migration policy
- forward migrations are reviewed and idempotent where possible;
- destructive changes require a two-release expand/migrate/contract strategy;
- application startup must not silently apply irreversible migrations in production unless explicitly configured;
- backup guidance appears before migrations with destructive potential;
- migration version is exposed in admin health.
Architectural constraints
- no domain import from framework-specific code;
- adapters depend inward on ports, never the reverse;
- external API payloads are mapped to internal normalized models;
- generated prompt output is based only on immutable snapshots;
- direct forge writes require a separate future ADR and permission model;
- direct code execution requires a separate isolation architecture and is prohibited in MVP code paths.