# 9. Architecture Decisions Important, expensive, large scale or risky architecture decisions including rationales. With "decisions" we mean selecting one alternative based on given criteria. Refer to section 4 (Solution Strategy) where the most important decisions are already captured. Avoid redundancy. > Consider using [ADRs (Architecture Decision Records)](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions) for every important decision. ## ADR-001: Use DuckDB as the embedded database **Status:** accepted **Context:** The application needs persistent storage for user data. A full RDBMS (PostgreSQL, MySQL) would require a separate server process and adds operational complexity. **Decision:** Use DuckDB as an embedded, file-based database accessed in-process by the FastAPI backend. **Consequences:** No separate DB server needed. Limited to single-writer access patterns. Suitable for the expected load. --- ## ADR-002: Use FastAPI for the backend **Status:** accepted **Context:** The backend needs async performance for concurrent AI generation requests and automatic OpenAPI documentation. **Decision:** Use FastAPI with uvicorn as the ASGI server. **Consequences:** Async endpoints enable high concurrency. Auto-generated OpenAPI docs simplify frontend integration and testing. --- ## ADR-003: Use Flask for the frontend **Status:** accepted **Context:** A lightweight server-side rendering layer is needed for the UI with minimal frontend complexity. **Decision:** Use Flask with Jinja2 templates to serve HTML pages. **Consequences:** Simple, familiar framework. No JavaScript build toolchain required. Frontend calls FastAPI over HTTP. --- ## ADR-004: Serialize DuckDB writes with asyncio.Lock **Status:** accepted **Context:** FastAPI runs async coroutines concurrently in a single process. DuckDB's optimistic concurrency model raises errors when multiple coroutines issue writes simultaneously to the same connection. **Decision:** All write operations (`INSERT`, `UPDATE`, `DELETE`) acquire a single process-wide `asyncio.Lock` before executing. The lock is released immediately after the statement completes. **Consequences:** Writes are serialised within the process, eliminating concurrency errors. Read performance is unaffected. Throughput is acceptable for the expected user load. If write throughput becomes a bottleneck in future, migrating to PostgreSQL is the preferred path. --- ## ADR-005: Use OpenRouter as the unified AI provider gateway **Status:** accepted **Context:** The application needs access to multiple AI model providers (OpenAI, Anthropic, Stability AI, Runway, etc.) for text, image, and video generation. **Decision:** Route all AI generation requests through the [OpenRouter](https://openrouter.ai) API, which exposes an OpenAI-compatible REST interface for hundreds of models. **Consequences:** Single API key and base URL for all model providers. Model switching requires only a change to the `model` field in the request payload. If OpenRouter is unavailable, all generation endpoints return `502 Bad Gateway`. Pricing and rate limits are governed by OpenRouter's policies per model.