Files
reactbin/.specify/memory/constitution.md

289 lines
10 KiB
Markdown

<!--
SYNC IMPACT REPORT
==================
Version change: [TEMPLATE — no prior version] → 1.1.0
Ratified: 2026-05-01 | Last amended: 2026-05-02
Principles introduced (first population from docs/CONSTITUTION.md):
- §2 Architecture Principles (6 sub-principles)
- §3 API Design (4 sub-principles)
- §4 Data Model Principles (4 items — fixed duplicate §4.3 → §4.4)
- §5 Testing Discipline (4 sub-principles)
Sections introduced:
- §1 Project Identity
- §6 Tech Stack Constraints
- §7 Developer Experience
- §8 Scope Boundaries (v1)
- §9 Governance (new — derived from preamble + standard governance rules)
- §10 Revision Log
Templates updated:
✅ .specify/memory/constitution.md — this file
✅ .specify/templates/tasks-template.md — removed "Tests are OPTIONAL" language
that contradicted §5.1 TDD mandate
⚠ .specify/templates/plan-template.md — Constitution Check section references
"[Gates determined based on constitution file]";
no structural change needed, gates are
resolved at plan-generation time
⚠ .specify/templates/spec-template.md — no conflicts found; no update needed
Deferred TODOs:
- None. All placeholders resolved.
-->
# Reaction Image Board — Project Constitution
> This document is the authoritative source of project-wide principles.
> Every spec, plan, and task produced for this project MUST comply with it.
> Contradictions between a spec/plan/task and this constitution are resolved
> in favour of the constitution. Changes to the constitution require an
> explicit revision with a noted rationale.
---
## 1. Project Identity
A personal, self-hosted web application for uploading, tagging, and searching
reaction images. The system is split into two independently deployable units:
- **API** — Python / FastAPI
- **UI** — Angular (standalone SPA, communicates with the API over HTTP)
There is no server-side rendering. The UI is a pure client that consumes the
API. These two units may live in the same repository but are treated as
separate deployable artifacts with separate dependency manifests.
---
## 2. Architecture Principles
### 2.1 Strict separation of concerns
The API knows nothing about the UI framework. The UI knows nothing about
storage or database implementation details. All cross-unit communication is
through versioned HTTP contracts (OpenAPI spec is the source of truth).
### 2.2 Dependency direction
```
UI → API → Storage (S3-compatible)
→ Database (PostgreSQL)
```
No layer MAY import or directly call a layer above it in this diagram.
### 2.3 Storage abstraction
All file I/O goes through a `StorageBackend` interface. The initial
implementation is S3-compatible (MinIO locally, real S3 in production).
No code outside the storage module MAY reference bucket names, S3 URLs,
or SDK-specific types directly — only the interface contract.
### 2.4 Auth abstraction (progressive)
Authentication is treated as a pluggable backend from day one, even though
Phase 1 ships with no auth. The API MUST route all request-identity resolution
through a single `AuthProvider` interface. The no-op provider (Phase 1) returns
a static anonymous identity. Adding username/password or OIDC in a later phase
MUST be a new provider implementation, not a rewrite of business logic.
**Phase 1 implements: no-auth (localhost only).**
**Planned phases: username/password, then OIDC.**
The constitution acknowledges all three; the spec governs which is built.
### 2.5 Database abstraction
PostgreSQL is the Phase 1 database. All DB access MUST go through a repository
layer (one repository class per domain aggregate). Raw SQL or an ORM is
acceptable, but no query logic MAY live outside a repository. This makes the
planned PostgreSQL → SQLite refactor a repository-layer change only.
### 2.6 No speculative abstraction
Interfaces are introduced only when a second implementation either exists or
is explicitly planned in the constitution (StorageBackend, AuthProvider,
repositories). Everything else is concrete until a real second implementation
is needed. "Just in case" generics, base classes, or plugin systems are
prohibited.
---
## 3. API Design
### 3.1 Versioning
All API routes MUST be prefixed `/api/v1/`. Breaking changes require a new
version prefix. Adding fields to responses is non-breaking; removing or
renaming is breaking.
### 3.2 OpenAPI as contract
The FastAPI-generated OpenAPI schema is the binding contract between API and
UI. The UI MUST NOT depend on behaviour not described in the schema.
### 3.3 Error shape
All error responses MUST use a consistent envelope:
```json
{ "detail": "<human-readable message>", "code": "<machine-readable code>" }
```
The `code` field is required. Naked HTTP status codes with empty bodies are
prohibited.
### 3.4 Pagination
Any endpoint that returns a list MUST support cursor- or offset-based
pagination from the start. No endpoint MAY return an unbounded list.
---
## 4. Data Model Principles
### 4.1 Tags are lowercase, normalised strings
Tags are stored and matched case-insensitively. The API MUST normalise tag
input to lowercase and strip whitespace before persistence. The UI may display
tags in any case but MUST send them lowercase.
### 4.2 Images are immutable after upload
Once an image is stored, its file content is never replaced. The stored object
MUST NOT be mutated.
### 4.3 Deduplication by content hash
Every image MUST be hashed (SHA-256) on upload before storage. If a hash
already exists in the database, the upload is rejected or the existing record
is returned — the spec will decide the UX — but no duplicate object is written
to storage. The hash is stored on the image record and may also serve as the
storage object key.
### 4.4 Tag search is AND logic in v1
A search for tags `[cat, funny]` returns only images that have **both** tags.
OR/NOT logic is explicitly out of scope until the constitution is revised.
---
## 5. Testing Discipline
### 5.1 TDD is non-negotiable
No production code MAY be written before a failing test exists for it. This
applies to both API and UI. Tasks MUST include a "write failing test" step
before any implementation step.
### 5.2 Test pyramid
- **Unit tests** — pure logic, repository mocks, no I/O
- **Integration tests** — API routes tested against a real (test) database
and a real (test) S3-compatible bucket (e.g. MinIO in Docker)
- **E2E tests** — Angular + API, minimal set covering the core happy paths
Unit and integration tests are required. E2E tests are best-effort in v1.
### 5.3 Tests live next to the code they test
API tests in `api/tests/`, UI tests colocated with their components. No
separate top-level `tests/` directory that mirrors the source tree.
### 5.4 CI must pass before any task is considered done
"Done" means: all tests pass, linter passes, type checker passes. A task MUST
NOT be marked complete while CI is failing.
---
## 6. Tech Stack Constraints
| Concern | Choice | Rationale |
|---|---|---|
| API language | Python 3.12+ | Primary language, type hints required |
| API framework | FastAPI | Async, OpenAPI-native |
| ORM / query | SQLAlchemy 2.x (async) + asyncpg driver | Repository layer owns all queries |
| DB migrations | Alembic | Schema changes tracked in version control |
| Object storage | S3-compatible via `boto3` / `aiobotocore` | Swap MinIO ↔ S3 via env config |
| UI framework | Angular (latest stable) | Job-relevant, learning goal |
| UI language | TypeScript strict mode | No `any`, no implicit types |
| Containerisation | Docker + Docker Compose | Local dev must start with one command |
---
## 7. Developer Experience
### 7.1 One-command local start
`docker compose up` MUST start the full stack: PostgreSQL, MinIO, API, UI dev
server. No manual environment setup beyond copying `.env.example`.
### 7.2 Environment configuration
All environment-specific values (DB URL, S3 endpoint, bucket name, ports) MUST
come from environment variables. Hardcoded hostnames, credentials, or ports in
source code are prohibited. `.env.example` is committed; `.env` is gitignored.
### 7.3 Linting and formatting are not optional
API: `ruff` (lint + format). UI: `eslint` + `prettier`. Both are enforced in
CI. PRs/commits with lint failures MUST NOT be considered complete tasks.
---
## 8. Scope Boundaries (v1)
The following are **explicitly out of scope** for v1 and MUST NOT be designed
for, abstracted toward, or mentioned in specs unless the constitution is
revised:
- Multi-user support
- Public sharing or embeds
- Collections or albums beyond tag-based grouping
- Image editing or transformation
- OR/NOT tag logic
- Mobile-native app
- Username/password auth (planned Phase 2)
- OIDC auth (planned Phase 3)
---
## 9. Governance
This constitution supersedes all other project practices, conventions, and
prior documentation. Where a conflict exists between a spec, plan, or task and
this constitution, the constitution prevails.
**Amendment procedure**: Any change to this document MUST be accompanied by:
1. An explicit rationale entry in the Revision Log (§10).
2. A version bump following semantic versioning (see below).
3. A review of all active specs and plans for compliance with the change.
**Versioning policy**:
- MAJOR — backward-incompatible governance change: a principle removed,
redefined in a way that invalidates prior work, or a hard scope boundary
moved inward.
- MINOR — new principle or section added, or materially expanded guidance that
requires new compliance work.
- PATCH — clarifications, wording improvements, typo fixes, non-semantic
refinements that do not change what is required.
**Compliance review**: Every new spec MUST include a "Constitution Check" gate
(verified by the plan command) before Phase 0 research begins, and again after
Phase 1 design is complete.
---
## 10. Revision Log
| Version | Date | Change |
|---|---|---|
| 1.0.0 | 2026-05-01 | Initial constitution |
| 1.1.0 | 2026-05-01 | asyncpg driver explicit; SHA-256 deduplication added to data model; deduplication removed from out-of-scope |
| 1.1.0 | 2026-05-02 | Adopted into Spec Kit memory; fixed duplicate §4.3 → §4.4; strengthened "should" language to MUST/MUST NOT; added §9 Governance |
---
**Version**: 1.1.0 | **Ratified**: 2026-05-01 | **Last Amended**: 2026-05-02