Files
ImageApi/.specify/memory/constitution.md
T
Cameron CordesandClaude Opus 5.5 fbe3d06ae5 docs: amend constitution to v1.1.0 (Observability for tracing migration)
Principle V now reflects the merged tracing migration (#148):
- tracing + tracing-opentelemetry spans in every build, with OTLP export
  gated on OTLP_OTLS_ENDPOINT;
- no manual Context threading;
- every spawn / fan-out carries its parent span;
- RUST_LOG gates span export (run at info/debug).
Layer and Tech Stack wording matches.

Also corrects stale "release builds only" telemetry notes in CLAUDE.md and
.env.example, updates the CLAUDE.md dependency list, and fixes the README's
RUST_LOG default. It also documents OTLP_OTLS_ENDPOINT in the README, as
Principle IV requires.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 18:03:44 -04:00

181 lines
7.8 KiB
Markdown

<!--
Sync Impact Report
==================
Version change: 1.0.0 -> 1.1.0
Bump rationale: MINOR. Principle V is materially expanded: the tracing
mechanism changed (tracing + tracing-opentelemetry in every build), and
it adds two new MUST rules: no manual Context threading, and carrying
the parent span across spawns. No principle is removed or redefined in
intent.
Modified principles:
- V. Observability: mechanism + rules updated for the tracing migration
(map #135, PR #148)
Also updated:
- I. Layered Architecture: Database Layer "traced" wording
- Technology Stack & Constraints: Tracing line
Added sections: N/A
Removed sections: N/A
Templates requiring updates:
- .specify/templates/plan-template.md — ✅ no changes needed (generic Constitution Check)
- .specify/templates/spec-template.md — ✅ no changes needed
- .specify/templates/tasks-template.md — ✅ no changes needed
- .specify/templates/checklist-template.md — ✅ no changes needed
- .specify/templates/agent-file-template.md — ✅ no changes needed
Runtime guidance:
- CLAUDE.md "Tracing" — ✅ already consistent (conventions landed with #148);
OTLP env line + dependency list updated alongside this amendment
- README.md — ✅ RUST_LOG default/gating corrected; OTLP_OTLS_ENDPOINT added
- .env.example — ✅ telemetry header corrected
Follow-up TODOs: None
-->
# ImageApi Constitution
## Core Principles
### I. Layered Architecture
All features MUST follow the established layered architecture:
- **HTTP Layer** (`main.rs`, feature modules): Route handlers, request
parsing, response formatting. No direct database access.
- **Service Layer** (`files.rs`, `exif.rs`, `memories.rs`, etc.): Business
logic. No HTTP-specific types.
- **DAO Layer** (`database/` trait definitions): Trait-based data access
contracts. Every DAO MUST be defined as a trait to enable mock
implementations for testing.
- **Database Layer** (Diesel ORM, `schema.rs`): Concrete `Sqlite*Dao`
implementations. Every query runs inside a `tracing` span via
`otel::trace_db_call`.
New features MUST NOT bypass layers (e.g., HTTP handlers MUST NOT
execute raw SQL). Actix actors are permitted for long-running async
work (video processing, file watching) but MUST interact with the
DAO layer through the established trait interfaces.
### II. Path Safety (NON-NEGOTIABLE)
All user-supplied file paths MUST be validated against `BASE_PATH`
using `is_valid_full_path()` before any filesystem operation. This
prevents directory traversal attacks.
- Paths stored in the database MUST be relative to `BASE_PATH`.
- Paths passed to external tools (ffmpeg, image processing) MUST be
fully resolved absolute paths.
- Extension detection MUST use the centralized helpers in
`file_types.rs` (case-insensitive). Manual string matching on
extensions is prohibited.
### III. Trait-Based Testability
All data access MUST go through trait-based DAOs so that every
handler and service can be tested with mock implementations.
- Each DAO trait MUST be defined in `src/database/` and require
`Sync + Send`.
- Mock DAOs for testing MUST live in `src/testhelpers.rs`.
- Integration tests against real SQLite MUST use in-memory databases
via `in_memory_db_connection()` from `database::test`.
- Handler tests MUST use `actix_web::test` utilities with JWT token
injection (using `Claims::valid_user()` and the `test_key` secret).
- New DAO implementations MUST include a `#[cfg(test)]` constructor
(e.g., `from_connection`) accepting an injected connection.
### IV. Environment-Driven Configuration
Server behavior MUST be controlled through environment variables
loaded from `.env` files. Hard-coded paths, URLs, or secrets are
prohibited.
- Required variables MUST call `.expect()` with a clear message at
startup so misconfiguration fails fast.
- Optional variables MUST use `.unwrap_or_else()` with sensible
defaults and be documented in `README.md`.
- Any new environment variable MUST be added to the README
environment section before the feature is considered complete.
### V. Observability
All database operations and HTTP handlers MUST be instrumented with
`tracing` spans, exported through `tracing-opentelemetry`: DAO bodies via
`otel::trace_db_call`, and handlers / feature functions via
`#[tracing::instrument]`. The per-request root span comes from the
`tracing-actix-web` middleware, which also honors an incoming W3C
`traceparent`.
- Spans are produced in debug and release builds alike. OTLP export is
enabled by `OTLP_OTLS_ENDPOINT`, not by build profile.
- Code MUST NOT thread an OpenTelemetry `Context` through call chains.
Spans parent on the ambient span.
- Every `tokio::spawn` or cross-thread fan-out (rayon, per-pass runtimes)
MUST carry its parent span: `.instrument(span)` or
`info_span!(parent: &span, ...)`. Tracing context is thread-local, and
an uncarried spawn orphans its spans onto a fresh trace.
- `RUST_LOG` gates span export as well as console output (one `EnvFilter`).
Deployments MUST run at `info` or `debug`.
- Logs are a separate pipeline: `env_logger` in debug, OTel log export in
release.
- Prometheus metrics (`imageserver_image_total`,
`imageserver_video_total`) MUST be maintained for key counters.
- Errors MUST be logged at `error!` level with sufficient context
for debugging without reproducing the issue.
**Rationale:** span parenting that relies on hand-threaded contexts drifted
into orphaned traces (the pre-migration baseline, #137). Ambient
parenting, plus an explicit carry at each spawn boundary, keeps a request or
job in one trace by construction.
## Technology Stack & Constraints
- **Language**: Rust (stable toolchain, Cargo build system)
- **HTTP Framework**: Actix-web 4
- **ORM**: Diesel 2.2 with SQLite backend
- **Auth**: JWT (HS256) via `jsonwebtoken` crate, bcrypt password
hashing
- **Video Processing**: ffmpeg/ffprobe (CLI, must be on PATH)
- **Image Processing**: `image` crate for thumbnails, `kamadak-exif`
for EXIF extraction
- **Tracing**: `tracing` + `tracing-opentelemetry` (every build), OTLP
export when `OTLP_OTLS_ENDPOINT` is set; logs via `env_logger` (debug) /
OTel log export (release)
- **Testing**: `cargo test`, `actix_web::test`, in-memory SQLite
External dependencies (ffmpeg, Ollama) are optional runtime
requirements. The server MUST start and serve core functionality
(images, thumbnails, tags) without them. Features that depend on
optional services MUST degrade gracefully with logged warnings,
not panics.
## Development Workflow
- `cargo fmt` MUST pass before committing.
- `cargo clippy` warnings MUST be resolved or explicitly suppressed
with a justification comment.
- `cargo test` MUST pass with all tests green before merging to
master.
- Database schema changes MUST use Diesel migrations
(`diesel migration generate`), with hand-written SQL in `up.sql`
and `down.sql`, followed by `diesel print-schema` to regenerate
`schema.rs`.
- Features MUST be developed on named branches
(`###-feature-name`) and merged to master via pull request.
- File uploads MUST preserve existing files (append timestamp on
conflict, never overwrite).
## Governance
This constitution defines the non-negotiable architectural and
development standards for the ImageApi project. All code changes
MUST comply with these principles.
- **Amendments**: Any change to this constitution MUST be documented
with a version bump, rationale, and updated Sync Impact Report.
- **Versioning**: MAJOR for principle removals/redefinitions, MINOR
for new principles or material expansions, PATCH for wording
clarifications.
- **Compliance**: Pull request reviews SHOULD verify adherence to
these principles. The CLAUDE.md file provides runtime development
guidance and MUST remain consistent with this constitution.
**Version**: 1.1.0 | **Ratified**: 2026-02-26 | **Last Amended**: 2026-09-29