Implementation

Module Structure

src/domus_api/
├── main.py                  App factory, lifespan, 3 root endpoints, 25 router registrations
├── config.py                pydantic-settings with DOMUS_API_ prefix
├── exceptions.py            PageNotFound, InvalidPath
├── models/
│   ├── page.py              PageSummary, PageDetail, PageList
│   ├── project.py           ProjectCreate, ProjectResponse, ProjectStatusUpdate
│   ├── case_study.py        Severity, RiskLevel, IncidentCreate, CaseStudyResponse
│   └── search.py            SearchResult, SearchResponse
├── routes/                  25 routers, one per content domain
│   ├── pages.py             /pages, /pages/\{path}
│   ├── search.py            /search?q=
│   ├── projects.py          GET, POST, PATCH /\{slug}/status
│   ├── case_studies.py      POST incidents, changes, RCAs
│   ├── case_studies_read.py GET case studies by type
│   └── ...                  20 more domain routers
└── services/
    ├── filesystem.py        DocumentCache — in-memory metadata store
    ├── parser.py            AsciiDoc header extraction (title, attributes, includes)
    ├── scaffolder.py        File generation per STD-001/005/010/011
    ├── search.py            Regex full-text search with context windows
    ├── attributes.py        antora.yml attribute parser
    └── dependencies.py      FastAPI Depends(get_cache) injection

Dependency Injection

Route handlers receive the document cache via FastAPI’s Depends mechanism. The cache is stored on app.state during the lifespan context and retrieved by get_cache():

# services/dependencies.py
def get_cache(request: Request) -> DocumentCache:
    return request.app.state.cache

# routes/pages.py
@router.get("")
async def list_pages(
    cache: DocumentCache = Depends(get_cache),
    category: str | None = Query(None),
):
    pages = cache.list_pages(category=category)

This replaced the original module-level cache = None # type: ignore pattern across 20 route files. The Depends pattern is type-safe, testable, and does not require the lifespan to know about individual route modules.

DocumentCache Architecture

The cache is a Python dict loaded once at startup. It scans pages/ and partials/ for all .adoc files, parses each file’s first 30 lines for metadata (title, attributes, includes), and stores the results keyed by relative path.

Method Purpose

load()

Full filesystem scan — called once at startup

add_page(path)

Parse and cache a single page — called after POST writes

add_partial(path)

Parse and cache a single partial — called after project scaffold

get_page(path)

Lookup by relative path, returns metadata dict or None

list_pages(category, limit, offset)

Filtered listing with pagination

get_standards()

Filter pages where std-id attribute exists

get_projects()

Filter pages in projects/ category ending with index.adoc

Content is loaded on demand via Path.read_text() — only when a specific page is requested. List operations return metadata only. This keeps memory usage proportional to file count (~3,500 files × ~200 bytes metadata ≈ 700 KB), not total content size.

Service Layer

Service Responsibility

DocumentCache (filesystem.py)

In-memory metadata cache. Provides all read operations. Startup load + targeted invalidation on writes.

Parser (parser.py)

Extracts title, attributes, and include directives from AsciiDoc headers. First 30 lines only — fast.

Scaffolder (scaffolder.py)

Write engine. Creates incident reports (STD-011), change requests (STD-005), RCAs (STD-010), and projects (STD-001). Templates match the exact output of the CLI skills.

Search (search.py)

Regex full-text search across all cached pages. Returns ranked results with 80-char context windows around matches.

Attributes (attributes.py)

Parses antora.yml to extract all 127 AsciiDoc attributes. Loaded once at startup.

Dependencies (dependencies.py)

FastAPI Depends provider. Retrieves cache from app.state for injection into route handlers.

Configuration

All settings via pydantic-settings with DOMUS_API_ environment variable prefix:

Setting Default Override

docs_root

~/atelier/_bibliotheca/domus-captures/docs/modules/ROOT

DOMUS_API_DOCS_ROOT

antora_yml

~/atelier/_bibliotheca/domus-captures/docs/antora.yml

DOMUS_API_ANTORA_YML

skills_dir

~/.claude/skills

DOMUS_API_SKILLS_DIR

host

0.0.0.0

DOMUS_API_HOST

port

8080

DOMUS_API_PORT