213 lines
7.9 KiB
Markdown
213 lines
7.9 KiB
Markdown
# 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`.
|
|
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
Browser → Next.js route → Library query use case → PostgreSQL projection → response DTO
|
|
```
|
|
|
|
### Prompt composition
|
|
|
|
```text
|
|
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.
|
|
|
|
```text
|
|
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
|
|
|
|
```text
|
|
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/playbooks`
|
|
- `GET /api/playbooks/{slug}/versions/{version}`
|
|
- `POST /api/compositions/preview`
|
|
- `POST /api/runs`
|
|
- `POST /api/runs/{id}/artifacts/run-pack`
|
|
- `POST /api/playbook-imports`
|
|
- `POST /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.
|