add architecture documentation and testing strategy
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
# 1. Introduction & Goals
|
||||||
|
|
||||||
|
Describes the relevant requirements and the driving forces that software architects and the development team must consider. These include underlying business goals, essential features, essential functional requirements, quality goals for the architecture, and relevant stakeholders and their expectations.
|
||||||
|
|
||||||
|
## Requirements Overview
|
||||||
|
|
||||||
|
**Project name**: AI Allucanget Biz
|
||||||
|
**Purpose**: Provide AI‑powered text, image, and video generation services via a web application.
|
||||||
|
|
||||||
|
Users can choose between different AI models for:
|
||||||
|
|
||||||
|
- Text generation
|
||||||
|
- Text‑to‑image generation
|
||||||
|
- Text‑to‑video generation
|
||||||
|
- Image‑to‑video generation
|
||||||
|
|
||||||
|
## Quality Goals
|
||||||
|
|
||||||
|
| Priority | Quality Goal | Scenario |
|
||||||
|
| -------- | ----------------- | --------------------------------------------- |
|
||||||
|
| 1 | High availability | Service is accessible 99.9% of the time |
|
||||||
|
| 2 | Low latency | Generation endpoints respond within 200 ms |
|
||||||
|
| 3 | Data privacy | User data is encrypted at rest and in transit |
|
||||||
|
|
||||||
|
## Stakeholders
|
||||||
|
|
||||||
|
| Role/Name | Contact | Expectations |
|
||||||
|
| ------------- | ---------- | --------------------------------------------- |
|
||||||
|
| Developer | Team | Clean APIs, testable code, good documentation |
|
||||||
|
| End User | Public | Fast, reliable AI generation features |
|
||||||
|
| Product Owner | Management | Feature completeness, uptime, cost control |
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# 10. Quality Requirements
|
||||||
|
|
||||||
|
This section contains all relevant quality requirements. The most important ones are already described in section 1.2 (Quality Goals), and should only be referenced here.
|
||||||
|
|
||||||
|
## Quality Requirements Overview
|
||||||
|
|
||||||
|
| Category | Quality Requirement |
|
||||||
|
| --------------- | ----------------------------------------------------------------------- |
|
||||||
|
| Availability | Service available ≥ 99.9% of the time |
|
||||||
|
| Performance | Generation endpoints respond within 200 ms (excluding AI model latency) |
|
||||||
|
| Security | All user data encrypted at rest and in transit; JWT-protected endpoints |
|
||||||
|
| Maintainability | Test coverage > 80% on `app/`; CI pipeline enforced |
|
||||||
|
| Portability | Runs on Windows and Linux without modification |
|
||||||
|
|
||||||
|
## Quality Scenarios
|
||||||
|
|
||||||
|
| Scenario ID | Source | Stimulus | Environment | Artifact | Response | Response Measure |
|
||||||
|
| ----------- | --------- | ------------------------------- | ----------- | ------------ | ------------------------------- | ----------------------------------------- |
|
||||||
|
| QS-01 | End user | Submits text generation request | Production | AI Service | Returns generated text | < 200 ms (excluding model latency) |
|
||||||
|
| QS-02 | Attacker | Sends request without valid JWT | Production | Auth Service | Returns 401 Unauthorized | 100% of unauthenticated requests rejected |
|
||||||
|
| QS-03 | Developer | Adds new API endpoint | Development | FastAPI app | Tests pass, coverage maintained | CI pipeline green |
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# 11. Risks and Technical Debt
|
||||||
|
|
||||||
|
A list of identified technical risks or technical debts, ordered by priority.
|
||||||
|
|
||||||
|
> "Risk management is project management for grown-ups." — Tim Lister, Atlantic Systems Guild.
|
||||||
|
|
||||||
|
| Priority | Risk / Technical Debt | Probability | Impact | Suggested Measures |
|
||||||
|
| -------- | ---------------------------------------------- | ----------- | ------ | ------------------------------------------------------------------------ |
|
||||||
|
| 1 | Dependency on openrouter.ai availability | medium | high | Add fallback models; implement retry logic with exponential backoff |
|
||||||
|
| 2 | DuckDB schema changes break existing data | low | high | Version migrations; backup strategy before upgrades |
|
||||||
|
| 3 | Single-process DuckDB limits write concurrency | low | medium | Monitor load; consider migration to PostgreSQL if needed |
|
||||||
|
| 4 | JWT secret leak | low | high | Rotate secrets via environment variables; never commit to source control |
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# 12. Glossary
|
||||||
|
|
||||||
|
The most important domain and technical terms that stakeholders use when discussing the system.
|
||||||
|
|
||||||
|
| Term | Definition |
|
||||||
|
| ------------- | --------------------------------------------------------------------------------------- |
|
||||||
|
| AI | Artificial Intelligence — machine learning models that generate text, images, or video |
|
||||||
|
| API | Application Programming Interface — HTTP endpoints exposed by the FastAPI backend |
|
||||||
|
| JWT | JSON Web Token — signed token used for stateless authentication |
|
||||||
|
| DuckDB | Embedded analytical database used for persistent storage |
|
||||||
|
| FastAPI | Python async web framework used for the backend |
|
||||||
|
| Flask | Python web framework used for the frontend |
|
||||||
|
| openrouter.ai | Third-party API aggregator providing access to multiple AI model providers |
|
||||||
|
| ADR | Architecture Decision Record — a document capturing an important architectural decision |
|
||||||
|
| HTTPS | Hypertext Transfer Protocol Secure — encrypted HTTP communication |
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# 2. Architecture Constraints
|
||||||
|
|
||||||
|
Any requirement that constrains software architects in their freedom of design and implementation decisions or decision about the development process. These constraints sometimes go beyond individual systems and are valid for whole organizations and companies.
|
||||||
|
|
||||||
|
## Technical Constraints
|
||||||
|
|
||||||
|
| Constraint | Background / Motivation |
|
||||||
|
| ----------------------------- | ------------------------------------------- |
|
||||||
|
| Must run on Windows and Linux | Cross-platform developer environments |
|
||||||
|
| FastAPI for backend | Async performance, OpenAPI support |
|
||||||
|
| Flask for frontend | Lightweight UI serving |
|
||||||
|
| DuckDB as embedded database | Lightweight, no separate DB server required |
|
||||||
|
| External AI via openrouter.ai | Unified access to multiple AI models |
|
||||||
|
|
||||||
|
## Organizational Constraints
|
||||||
|
|
||||||
|
| Constraint | Background / Motivation |
|
||||||
|
| ----------------- | --------------------------------- |
|
||||||
|
| Open source stack | Cost reduction, community support |
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
| Convention | Background / Motivation |
|
||||||
|
| -------------------- | --------------------------------------------------- |
|
||||||
|
| Python 3.11+ | Modern language features, type hints |
|
||||||
|
| pytest for all tests | Consistent test tooling across backend and frontend |
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# 3. Context and Scope
|
||||||
|
|
||||||
|
Delimits your system (i.e. your scope) from all its communication partners (neighboring systems and users, i.e. the context of your system). It thereby specifies the external interfaces.
|
||||||
|
|
||||||
|
## Business Context
|
||||||
|
|
||||||
|
Specification of **all** communication partners (users, IT-systems, …) with explanations of domain specific inputs and outputs or interfaces.
|
||||||
|
|
||||||
|
The system exposes REST APIs for authentication, user management, and AI generation. The Flask frontend consumes these APIs and serves pages at `http://ai.allucanget.biz`.
|
||||||
|
|
||||||
|
| Communication Partner | Input | Output |
|
||||||
|
| --------------------- | ------------------------------ | ------------------------------ |
|
||||||
|
| End User (browser) | Form submissions, API requests | Generated text, images, videos |
|
||||||
|
| openrouter.ai API | Prompt + model selection | AI-generated content |
|
||||||
|
| DuckDB | SQL queries | User data, session data |
|
||||||
|
|
||||||
|
## Technical Context
|
||||||
|
|
||||||
|
| Channel | Protocol | Description |
|
||||||
|
| -------------------------------- | ---------- | ------------------ |
|
||||||
|
| User ↔ Flask frontend | HTTPS | Browser-based UI |
|
||||||
|
| Flask frontend ↔ FastAPI backend | HTTP REST | Internal API calls |
|
||||||
|
| FastAPI backend ↔ openrouter.ai | HTTPS REST | AI model inference |
|
||||||
|
| FastAPI backend ↔ DuckDB | In-process | Embedded DB access |
|
||||||
|
|
||||||
|
**Mapping Input/Output to Channels:** All user-facing traffic flows through HTTPS. The backend communicates with openrouter.ai over HTTPS. DuckDB is accessed in-process with no network channel.
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# 4. Solution Strategy
|
||||||
|
|
||||||
|
A short summary and explanation of the fundamental decisions and solution strategies that shape system architecture. It includes:
|
||||||
|
|
||||||
|
- Technology decisions
|
||||||
|
- Decisions about the top-level decomposition of the system, e.g. usage of an architectural pattern or design pattern
|
||||||
|
- Decisions on how to achieve key quality goals
|
||||||
|
- Relevant organizational decisions, e.g. selecting a development process or delegating certain tasks to third parties
|
||||||
|
|
||||||
|
Micro‑service style: a single FastAPI process handles all API endpoints; a separate Flask process serves the UI.
|
||||||
|
|
||||||
|
| Quality Goal | Scenario | Solution Approach |
|
||||||
|
| ----------------- | ------------------------ | --------------------------------------------------------- |
|
||||||
|
| High availability | Service must be up 99.9% | Docker containers with health checks and restart policies |
|
||||||
|
| Low latency | Responses < 200 ms | FastAPI async endpoints; DuckDB in-process |
|
||||||
|
| Data privacy | Encrypted data | JWT auth, HTTPS everywhere, DuckDB file encryption |
|
||||||
|
|
||||||
|
**Key technology decisions:**
|
||||||
|
|
||||||
|
- **FastAPI** for async performance and automatic OpenAPI docs
|
||||||
|
- **DuckDB** for a lightweight embedded DB with no separate server
|
||||||
|
- **Flask** for a thin frontend layer with Jinja2 templates
|
||||||
|
- **openrouter.ai** for unified access to multiple AI model providers
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# 5. Building Block View
|
||||||
|
|
||||||
|
Static decomposition of the system into building blocks (modules, components, subsystems, classes, interfaces, packages, libraries, frameworks, layers, partitions, tiers, functions, macros, operations, data structures, …) as well as their dependencies (relationships, associations, …).
|
||||||
|
|
||||||
|
## Level 1 – Whitebox Overall System
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌───────────────────────┐
|
||||||
|
│ Frontend (Flask) │
|
||||||
|
└───────┬───────────────┘
|
||||||
|
│ REST API calls
|
||||||
|
┌───────▼───────────────┐
|
||||||
|
│ FastAPI Backend │
|
||||||
|
│ ├─ Auth Service │
|
||||||
|
│ ├─ User Service │
|
||||||
|
│ ├─ AI Service │
|
||||||
|
│ └─ DB Service (DuckDB)│
|
||||||
|
└───────┬───────────────┘
|
||||||
|
│ DB access
|
||||||
|
┌───────▼───────────────┐
|
||||||
|
│ DuckDB Database │
|
||||||
|
└───────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Motivation:** Separating the UI (Flask) from the API (FastAPI) allows independent scaling and testing of each layer.
|
||||||
|
|
||||||
|
**Contained Building Blocks:**
|
||||||
|
|
||||||
|
| Name | Responsibility |
|
||||||
|
| ---------------- | -------------------------------------------------- |
|
||||||
|
| Frontend (Flask) | Serves HTML/CSS/JS UI, proxies requests to FastAPI |
|
||||||
|
| FastAPI Backend | Handles auth, user management, AI generation API |
|
||||||
|
| Auth Service | JWT issuance and validation |
|
||||||
|
| User Service | CRUD operations for user accounts |
|
||||||
|
| AI Service | Sends prompts to openrouter.ai, returns results |
|
||||||
|
| DB Service | Reads/writes to DuckDB |
|
||||||
|
| DuckDB Database | Persistent storage for users and session data |
|
||||||
|
|
||||||
|
## Level 2 – FastAPI Backend internals
|
||||||
|
|
||||||
|
### White Box Auth Service (`/auth`)
|
||||||
|
|
||||||
|
Handles JWT issuance, validation, and refresh token lifecycle.
|
||||||
|
|
||||||
|
| Method | Path | Auth required | Description |
|
||||||
|
| ------ | ---------------- | :-----------: | ------------------------------------------------ |
|
||||||
|
| POST | `/auth/register` | — | Create a new user account |
|
||||||
|
| POST | `/auth/login` | — | Authenticate and receive access + refresh tokens |
|
||||||
|
| POST | `/auth/refresh` | — | Rotate refresh token, get a new access token |
|
||||||
|
| POST | `/auth/logout` | — | Revoke refresh token |
|
||||||
|
|
||||||
|
### White Box User Service (`/users`)
|
||||||
|
|
||||||
|
Self-service profile management and admin user CRUD.
|
||||||
|
|
||||||
|
| Method | Path | Auth required | Admin only | Description |
|
||||||
|
| ------ | ------------------ | ------------- | ---------- | ---------------------------------------- |
|
||||||
|
| GET | `/users/me` | ✓ | — | Get current user profile |
|
||||||
|
| PUT | `/users/me` | ✓ | — | Update own email or password |
|
||||||
|
| GET | `/users` | ✓ | ✓ | List all users |
|
||||||
|
| DELETE | `/users/{id}` | ✓ | ✓ | Delete a user (cannot self-delete) |
|
||||||
|
| PUT | `/users/{id}/role` | ✓ | ✓ | Change a user's role (`user` \| `admin`) |
|
||||||
|
|
||||||
|
### White Box Admin Service (`/admin`)
|
||||||
|
|
||||||
|
Operational endpoints for application management.
|
||||||
|
|
||||||
|
| Method | Path | Auth required | Admin only | Description |
|
||||||
|
| ------ | --------------------- | ------------- | ---------- | ------------------------------------- |
|
||||||
|
| GET | `/admin/stats` | ✓ | ✓ | User counts by role, token activity |
|
||||||
|
| GET | `/admin/health/db` | ✓ | ✓ | DuckDB connectivity check |
|
||||||
|
| POST | `/admin/tokens/purge` | ✓ | ✓ | Remove expired/revoked refresh tokens |
|
||||||
|
|
||||||
|
### White Box AI Service (`/ai`, `/generate`)
|
||||||
|
|
||||||
|
Model listing and multi-modal generation via openrouter.ai.
|
||||||
|
|
||||||
|
| Method | Path | Auth required | Description |
|
||||||
|
| ------ | ---------------------------- | ------------- | ------------------------------------------------------ |
|
||||||
|
| GET | `/ai/models` | ✓ | List available OpenRouter models |
|
||||||
|
| POST | `/ai/chat` | ✓ | Multi-turn chat completion |
|
||||||
|
| POST | `/generate/text` | ✓ | Single-prompt text generation (optional system prompt) |
|
||||||
|
| POST | `/generate/image` | ✓ | Text-to-image generation |
|
||||||
|
| POST | `/generate/video` | ✓ | Text-to-video generation |
|
||||||
|
| POST | `/generate/video/from-image` | ✓ | Image-to-video generation |
|
||||||
|
|
||||||
|
### White Box DB Service (`db.py`)
|
||||||
|
|
||||||
|
- Singleton DuckDB connection, opened on FastAPI startup via lifespan hook.
|
||||||
|
- `asyncio.Lock` serialises all write operations within the single process.
|
||||||
|
- Schema migration runs automatically on first startup.
|
||||||
|
- Tables: `users`, `refresh_tokens` (see Section 8 for schema details).
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# 6. Runtime View
|
||||||
|
|
||||||
|
Describes concrete behavior and interactions of the system's building blocks in form of scenarios from the following areas:
|
||||||
|
|
||||||
|
- Important use cases or features: how do building blocks execute them?
|
||||||
|
- Interactions at critical external interfaces: how do building blocks cooperate with users and neighboring systems?
|
||||||
|
- Operation and administration: launch, start-up, stop
|
||||||
|
- Error and exception scenarios
|
||||||
|
|
||||||
|
## Scenario 1: User Authentication
|
||||||
|
|
||||||
|
1. User submits login form in Flask frontend
|
||||||
|
2. Flask POSTs credentials to `POST /auth/login`
|
||||||
|
3. Auth Service validates credentials against DuckDB
|
||||||
|
4. Auth Service returns JWT token
|
||||||
|
5. Flask stores token in session cookie
|
||||||
|
6. User is redirected to dashboard
|
||||||
|
|
||||||
|
## Scenario 2: AI Text Generation
|
||||||
|
|
||||||
|
1. User fills in text generation form in Flask frontend
|
||||||
|
2. Flask POSTs prompt + model to `POST /generate/text` with JWT header
|
||||||
|
3. Auth Service validates JWT
|
||||||
|
4. AI Service sends prompt to openrouter.ai
|
||||||
|
5. openrouter.ai returns generated text
|
||||||
|
6. FastAPI returns result to Flask
|
||||||
|
7. Flask renders result page for user
|
||||||
|
|
||||||
|
## Scenario 3: Image Generation
|
||||||
|
|
||||||
|
1. User submits image generation form
|
||||||
|
2. Flask POSTs to `POST /generate/image`
|
||||||
|
3. AI Service calls openrouter.ai image model
|
||||||
|
4. Image URL returned to Flask
|
||||||
|
5. Flask renders page with generated image
|
||||||
|
|
||||||
|
## Scenario 4: Video Generation (Text-to-Video)
|
||||||
|
|
||||||
|
1. User submits video generation form with prompt and model selection
|
||||||
|
2. Flask POSTs to `POST /generate/video` with JWT header
|
||||||
|
3. Auth Service validates JWT
|
||||||
|
4. AI Service calls OpenRouter `/video/generations`
|
||||||
|
5. OpenRouter returns a job response (`status: "queued"` or `"completed"`)
|
||||||
|
6. FastAPI returns `VideoResponse` to Flask
|
||||||
|
7. Flask renders result page; if status is `queued`, the UI may poll or notify asynchronously
|
||||||
|
|
||||||
|
## Scenario 5: Image-to-Video Generation
|
||||||
|
|
||||||
|
1. User uploads or provides an image URL and a text prompt
|
||||||
|
2. Flask POSTs to `POST /generate/video/from-image` with JWT header
|
||||||
|
3. AI Service calls OpenRouter `/video/generations/from-image`
|
||||||
|
4. Returns `VideoResponse` with `video_url` when completed
|
||||||
|
|
||||||
|
## Scenario 6: Token Refresh
|
||||||
|
|
||||||
|
1. Access token expires (TTL 15 min)
|
||||||
|
2. Client POSTs current refresh token to `POST /auth/refresh`
|
||||||
|
3. Auth Service validates JTI against `refresh_tokens` table (not revoked, not expired)
|
||||||
|
4. Old JTI is revoked; new JTI inserted into `refresh_tokens`
|
||||||
|
5. New access token + new refresh token returned to client
|
||||||
|
|
||||||
|
## Scenario 7: Admin User Management
|
||||||
|
|
||||||
|
1. Admin logs in and receives access token with `role: admin`
|
||||||
|
2. Admin GETs `/admin/stats` to view user and token counts
|
||||||
|
3. Admin DELETEs `/users/{id}` to remove a user — refresh tokens for that user are cascade-deleted
|
||||||
|
4. Admin PUTs `/users/{id}/role` to promote a user to admin or demote to user
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# 7. Deployment View
|
||||||
|
|
||||||
|
Describes:
|
||||||
|
|
||||||
|
1. Technical infrastructure used to execute your system, with infrastructure elements like geographical locations, environments, computers, processors, channels and net topologies.
|
||||||
|
2. Mapping of (software) building blocks to that infrastructure elements.
|
||||||
|
|
||||||
|
## Infrastructure Level 1
|
||||||
|
|
||||||
|
```text
|
||||||
|
┌─────────────────────────────────────────────┐
|
||||||
|
│ Host / VM │
|
||||||
|
│ ┌─────────────┐ ┌─────────────────────┐ │
|
||||||
|
│ │ frontend │ │ backend │ │
|
||||||
|
│ │ (Flask) │ │ (FastAPI) │ │
|
||||||
|
│ │ :5000 │ │ :8000 │ │
|
||||||
|
│ └──────┬──────┘ └──────────┬──────────┘ │
|
||||||
|
│ │ │ │
|
||||||
|
│ └────────┬──────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────▼────────┐ │
|
||||||
|
│ │ db (DuckDB) │ │
|
||||||
|
│ │ data/app.db │ │
|
||||||
|
│ └────────────────┘ │
|
||||||
|
└─────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**Motivation:** All three components run on a single VM (or as Docker containers) for simplicity and low operational overhead.
|
||||||
|
|
||||||
|
**Quality and/or Performance Features:** The frontend and backend are stateless; DuckDB persists data on the host filesystem.
|
||||||
|
|
||||||
|
**Mapping of Building Blocks to Infrastructure:**
|
||||||
|
|
||||||
|
| Building Block | Container / Process | Port |
|
||||||
|
| --------------- | ---------------------------- | ---- |
|
||||||
|
| Flask frontend | `frontend` | 5000 |
|
||||||
|
| FastAPI backend | `backend` | 8000 |
|
||||||
|
| DuckDB | File on host (`data/app.db`) | — |
|
||||||
|
|
||||||
|
## Infrastructure Level 2
|
||||||
|
|
||||||
|
### Docker Compose (alternative)
|
||||||
|
|
||||||
|
All three services can be run with `docker compose up`. The `backend` mounts the `data/` volume for DuckDB persistence.
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# 8. Cross-cutting Concepts
|
||||||
|
|
||||||
|
Describes crosscutting concepts (practices, patterns, regulations or solution ideas). Such concepts are often related to multiple building blocks. They may include many different topics such as domain models, architecture patterns, rules for using specific technology, security, logging, and error handling.
|
||||||
|
|
||||||
|
> Pick **only** the most-needed topics for your system.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- All API endpoints (except `/auth/login`) require a valid JWT in the `Authorization: Bearer` header.
|
||||||
|
- HTTPS enforced in production via reverse proxy (nginx or Caddy).
|
||||||
|
- Passwords stored as bcrypt hashes.
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
- Structured JSON logs from FastAPI via Python `logging` + `structlog`.
|
||||||
|
- OpenTelemetry traces exported for observability.
|
||||||
|
- Log level configurable via environment variable `LOG_LEVEL`.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
- All API errors return a unified JSON shape: `{ "error": "<code>", "message": "<description>" }`.
|
||||||
|
- HTTP status codes follow REST conventions (400, 401, 403, 404, 422, 500).
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
- All secrets (API keys, DB path, JWT secret) loaded from environment variables or `.env` file.
|
||||||
|
- No secrets committed to source control.
|
||||||
|
|
||||||
|
## DuckDB Concurrency and Storage
|
||||||
|
|
||||||
|
### Single Writer Per Process
|
||||||
|
|
||||||
|
DuckDB allows only one process to open the database file in read-write mode at a time. The FastAPI backend must be run with a single worker (`uvicorn --workers 1`). Running multiple workers against the same DuckDB file will cause startup errors.
|
||||||
|
|
||||||
|
### asyncio.Lock for Writes
|
||||||
|
|
||||||
|
All database write operations (`INSERT`, `UPDATE`, `DELETE`) in the FastAPI async context are wrapped in a single `asyncio.Lock` (`get_write_lock()` from `backend/app/db.py`). This prevents concurrent coroutines from issuing overlapping writes within the single process, which would otherwise raise DuckDB optimistic concurrency errors.
|
||||||
|
|
||||||
|
Read operations (`SELECT`) do not require the lock — DuckDB's MVCC provides consistent read snapshots.
|
||||||
|
|
||||||
|
### Schema
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE users (
|
||||||
|
id UUID DEFAULT uuid() PRIMARY KEY,
|
||||||
|
email VARCHAR NOT NULL UNIQUE,
|
||||||
|
password_hash VARCHAR NOT NULL,
|
||||||
|
role VARCHAR DEFAULT 'user',
|
||||||
|
created_at TIMESTAMP DEFAULT now(),
|
||||||
|
updated_at TIMESTAMP DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE refresh_tokens (
|
||||||
|
jti UUID DEFAULT uuid() PRIMARY KEY,
|
||||||
|
user_id UUID NOT NULL, -- soft FK to users.id
|
||||||
|
issued_at TIMESTAMP DEFAULT now(),
|
||||||
|
expires_at TIMESTAMP NOT NULL,
|
||||||
|
revoked BOOLEAN DEFAULT false
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
> The `REFERENCES users(id)` foreign key is intentionally omitted from `refresh_tokens`. DuckDB fires FK checks on `UPDATE` of the parent table (including email changes), causing false constraint violations. Referential integrity is enforced manually: deleting a user also deletes their refresh tokens in the same write transaction.
|
||||||
|
|
||||||
|
### Access Tokens
|
||||||
|
|
||||||
|
Access tokens are **stateless** JWTs — not stored in the database. They are validated by signature and expiry claim only. The short TTL (15 minutes) limits the blast radius if a token is leaked.
|
||||||
|
|
||||||
|
### Refresh Tokens
|
||||||
|
|
||||||
|
Refresh tokens store a JTI (JWT ID) UUID in the `refresh_tokens` table. On each use the old JTI is revoked and a new one issued (rotation). On logout the JTI is immediately revoked. Expired and revoked tokens can be purged via `POST /admin/tokens/purge`.
|
||||||
|
|
||||||
|
### Future: AI Generation History
|
||||||
|
|
||||||
|
AI generation metadata (model, prompt, cost, result URLs) can be stored as JSON columns in a future `generation_history` table in DuckDB, enabling per-user analytics and usage dashboards at zero extra infrastructure cost.
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
# 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.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Architecture Documentation
|
||||||
|
|
||||||
|
This file is the entry point for the architecture documentation of **AI Allucanget Biz**.
|
||||||
|
|
||||||
|
The documentation follows the [arc42 template](https://arc42.org/overview) and is split into 12 section files, each covering a specific aspect of the architecture. Read the sections in order for a full picture, or jump directly to the section most relevant to you.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
| Section | File | Description |
|
||||||
|
| ------- | ---------------------------------------------------------------- | ----------------------------------------------------- |
|
||||||
|
| 1 | [1-introduction-and-goals.md](1-introduction-and-goals.md) | Requirements, quality goals, stakeholders |
|
||||||
|
| 2 | [2-constraints.md](2-constraints.md) | Technical, organizational, and convention constraints |
|
||||||
|
| 3 | [3-context-and-scope.md](3-context-and-scope.md) | System boundaries and external interfaces |
|
||||||
|
| 4 | [4-solution-strategy.md](4-solution-strategy.md) | Fundamental technology and design decisions |
|
||||||
|
| 5 | [5-building-block-view.md](5-building-block-view.md) | Static decomposition of the system |
|
||||||
|
| 6 | [6-runtime-view.md](6-runtime-view.md) | Key runtime scenarios and request flows |
|
||||||
|
| 7 | [7-deployment-view.md](7-deployment-view.md) | Infrastructure and deployment topology |
|
||||||
|
| 8 | [8-crosscutting-concepts.md](8-crosscutting-concepts.md) | Security, logging, error handling, configuration |
|
||||||
|
| 9 | [9-architectural-decisions.md](9-architectural-decisions.md) | Architecture Decision Records (ADRs) |
|
||||||
|
| 10 | [10-quality-requirements.md](10-quality-requirements.md) | Quality scenarios and acceptance criteria |
|
||||||
|
| 11 | [11-risks-and-technical-debt.md](11-risks-and-technical-debt.md) | Known risks and technical debt |
|
||||||
|
| 12 | [12-glossary.md](12-glossary.md) | Domain and technical terms |
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Testing Strategy
|
||||||
|
|
||||||
|
The FastAPI backend will be tested using a combination of unit and integration tests.
|
||||||
|
|
||||||
|
## Unit Tests
|
||||||
|
|
||||||
|
- Use `pytest` with `pytest-asyncio` for async endpoint handlers.
|
||||||
|
- Mock external dependencies such as the DuckDB connection and the openrouter.ai API.
|
||||||
|
|
||||||
|
## Integration Tests
|
||||||
|
|
||||||
|
- Use `pytest-flask` to spin up the FastAPI app in a test client.
|
||||||
|
- Test full request/response cycles for authentication, user CRUD, and AI generation endpoints.
|
||||||
|
- Use an in‑memory DuckDB instance for database tests.
|
||||||
|
|
||||||
|
## Test Coverage
|
||||||
|
|
||||||
|
- Aim for >80 % coverage on the `app/` package.
|
||||||
|
- Generate coverage reports with `pytest-cov`.
|
||||||
Reference in New Issue
Block a user