This repo was built by using Claude Code and agent skills which are harnessed around the Architecture Compiler, a deterministic compiler turning constraints into reviewable architectural decisions with clear trade-offs and cost impact, based on 180+ curated design patterns. Refer
SaferSkills independently audited arch-compiler-ai-harness-in-action (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Languages: English | 简体中文
Note: The English documentation is the canonical source of truth. If translations differ, follow the English version.
This repository was built with AI agents and agent skills harnessed around Architecture Compiler, a deterministic compiler that turns constraints into explicit, reviewable architectural decisions with clear trade-offs and cost impact, grounded in a curated registry of 180+ design patterns.
The work started with Claude Code using Superpowers skills to brainstorm with the user about the functional requirements and capture the initial concept in [[redacted]-bird-id-webapp-initial-draft.md]([redacted]-bird-id-webapp-initial-draft.md).
Claude Code then used the Architecture Compiler skills to generate the approved architecture artifacts under docs/architecture/ and the implementation plan in [docs/plans/[redacted]-bird-id-implementation.md](docs/plans/%5Bredacted%5D-bird-id-implementation.md). Adversarial review findings were addressed in the implementation plan before implementation began.
Implementation then proceeded against that approved architecture and plan, using both Architecture Compiler skills and Superpowers skills to keep the work aligned with the architectural contract.
For sensitivity reasons, certain dates, names, and related identifying details in the documentation have been redacted.
Everything below, and the rest of the documentation, was written by AI agents.
A SaaS web app where photographers upload bird photos and Claude AI identifies the species. Results are stored in a per-user history and species sighting log.
claude-sonnet-4-6 vision model identifies species, confidence, and count| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router, TypeScript, Tailwind) on Vercel |
| Backend | FastAPI (Python 3.12) on Railway |
| Database | PostgreSQL on Supabase |
| Cache / Rate limiting | Redis on Railway |
| Auth | Auth0 OIDC (PKCE, in-memory tokens) |
| Image storage | Cloudflare R2 (zero egress cost) |
| AI inference | Anthropic Claude via async background task |
| Observability | OpenTelemetry (OTLP traces + golden-signal metrics) |
| Pattern | Config |
|---|---|
arch-monolith | Horizontal scaling, stateless, rolling deploy |
db-managed-postgres | Supabase, connection pooling, SSL required |
cache-aside--redis | allkeys-lru, 256mb, sliding TTL |
idp-oidc--auth0 | Universal Login, PKCE, Google social connection |
resilience-circuit-breaker | failure_threshold=5, timeout=60s, half-open recovery |
resilience-timeouts-retries-backoff | exponential jitter, max 3 retries, 60s timeout for Claude |
hosting-managed-paas | Railway, health check, ON_FAILURE restart |
api-rest-resource-oriented | Offset pagination, UUID IDs, ETag caching |
release-feature-flags | Config file, simple boolean, kill switch enabled |
obs-open-telemetry-baseline | OTLP export, trace_sampling_rate=1.0, W3C TraceContext |
obs-golden-signals | identifications_total, identification_duration_ms, errors_total |
arch-egress-minimization | Cloudflare R2 ($0 egress), Vercel CDN for static assets |
finops-budget-guardrails | Alerts at $250 / $400 / $500 per month |
Full architecture specification: docs/architecture/architecture.yaml
arch-compiler-ai-harness-in-action/
├── backend/ # FastAPI application
│ ├── app/
│ │ ├── main.py # App entry point, CORS, API versioning middleware
│ │ ├── config.py # Pydantic settings (env vars)
│ │ ├── database.py # Async SQLAlchemy engine (asyncpg, SSL)
│ │ ├── auth.py # Auth0 JWKS validation, in-process cache, user provisioning
│ │ ├── schemas.py # Pydantic response models
│ │ ├── telemetry.py # OpenTelemetry setup + golden-signal meters
│ │ ├── feature_flags.py # Config-file feature flags (kill switch)
│ │ ├── redis_client.py # Async Redis singleton
│ │ ├── resilience.py # CircuitBreaker (3-state) + with_retry (exponential jitter)
│ │ ├── models/
│ │ │ ├── user.py # User (id, auth0_sub, email, plan)
│ │ │ ├── image.py # Image (storage_key, file_size_bytes)
│ │ │ └── identification.py # Identification + BirdDetected
│ │ ├── routers/
│ │ │ ├── identify.py # POST /identify — upload, rate-limit, background task
│ │ │ └── history.py # GET /history, /birds, /user/plan, /billing/upgrade
│ │ ├── services/
│ │ │ ├── claude.py # Claude vision inference (asyncio.to_thread)
│ │ │ └── storage.py # Cloudflare R2 via boto3 (asyncio.to_thread)
│ │ ├── middleware/
│ │ │ └── rate_limit.py # Redis sliding-TTL rate limiter
│ │ └── scripts/
│ │ └── cleanup_old_records.py # 365-day cascade delete
│ ├── tests/ # 34 tests (pytest-asyncio, savepoint rollback isolation)
│ ├── feature_flags.json # Runtime feature flag values
│ ├── Dockerfile # python:3.12-slim, uvicorn 2 workers
│ └── railway.toml # Railway deploy config
├── frontend/ # Next.js 16 application
│ ├── app/
│ │ ├── page.tsx # Upload page (drag-drop, 429 error handling)
│ │ ├── identify/[id]/ # Polling page (spinner → result, URL-based ID)
│ │ ├── history/ # History list (paginated) + detail
│ │ └── species/ # Species log + per-species sightings
│ ├── components/
│ │ ├── AuthGuard.tsx # Auth0 gate, wires getAccessTokenSilently to API client
│ │ ├── Providers.tsx # Auth0Provider (client component, SSR-safe)
│ │ ├── UploadZone.tsx # Drag-and-drop + keyboard accessible file picker
│ │ └── IdentificationResult.tsx # Bird list with confidence and count
│ ├── hooks/
│ │ └── usePolling.ts # 2s interval, 60s timeout ceiling, React 19 safe
│ ├── lib/
│ │ └── api.ts # Typed API client with 401 → token refresh → retry
│ └── vercel.json # Immutable CDN headers + security headers
├── docs/
│ ├── architecture/
│ │ ├── architecture.yaml # Approved architecture specification
│ │ └── patterns/ # 24 selected design pattern manifests
│ ├── adrs/ # Architecture Decision Records
│ ├── runbooks/ # Incident runbooks
│ └── plans/ # Implementation plan
└── docker-compose.yml # Local postgres + redis for development# 1. Start local postgres + redis
docker compose up -d
# 2. Set up Python virtualenv
cd backend
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
# 3. Copy and fill in env vars
cp ../.env.example .env
# Edit .env — see Environment Variables section below
# 4. Run database migrations
alembic upgrade head
# 5. Start the API server
uvicorn app.main:app --reload
# API available at http://localhost:8000cd frontend
npm install
# Copy and fill in env vars
cp .env.local.example .env.local
# Edit .env.local — see Environment Variables section below
npm run dev
# App available at http://localhost:3000Optional frontend verification:
npm run lint
npm run buildTests inject dummy credentials for all external services (Anthropic, Auth0, R2). The only real dependency is local Docker postgres + redis.
# Start local postgres + redis (if not already running)
docker compose up -d
cd backend
# Run all tests
.venv/bin/python -m pytest tests/ -v
# Silence OpenTelemetry export warnings (no local collector needed)
OTEL_SDK_DISABLED=true .venv/bin/python -m pytest tests/ -vExpected: 34 passed
The warnings Failed to export metrics to localhost:4317 are harmless — they appear when no OpenTelemetry collector is running locally and can be silenced with OTEL_SDK_DISABLED=true. The test fixture creates birdid_test automatically if it does not already exist.
backend/.env)| Variable | Description | Example |
|---|---|---|
DATABASE_URL | PostgreSQL connection string | postgresql://birdid:birdid@localhost:5432/birdid |
REDIS_URL | Redis URL | redis://localhost:6379 |
ANTHROPIC_API_KEY | From console.anthropic.com | sk-ant-... |
AUTH0_DOMAIN | Auth0 tenant domain | your-tenant.us.auth0.com |
AUTH0_AUDIENCE | Auth0 API identifier | https://api.bird-id.app |
R2_ACCOUNT_ID | Cloudflare account ID | |
R2_ACCESS_KEY_ID | R2 API token key ID | |
R2_SECRET_ACCESS_KEY | R2 API token secret | |
R2_BUCKET_NAME | R2 bucket name | bird-id-images |
R2_PUBLIC_URL | R2 public bucket URL | https://pub-xxx.r2.dev |
FRONTEND_URL | Frontend origin for CORS | http://localhost:3000 |
RATE_LIMIT_FREE_TIER | Monthly identification limit for free users | 10 |
OTEL_EXPORTER_OTLP_ENDPOINT | OpenTelemetry collector endpoint | http://localhost:4317 |
frontend/.env.local)| Variable | Description | Example |
|---|---|---|
NEXT_PUBLIC_API_URL | Backend API base URL | http://localhost:8000 |
NEXT_PUBLIC_AUTH0_DOMAIN | Auth0 tenant domain | your-tenant.us.auth0.com |
NEXT_PUBLIC_AUTH0_CLIENT_ID | Auth0 SPA application client ID | |
NEXT_PUBLIC_AUTH0_AUDIENCE | Auth0 API identifier | https://api.bird-id.app |
http://localhost:3000/http://localhost:3000/http://localhost:3000https://api.bird-id.app (or your own)Edit backend/feature_flags.json to toggle features without a deploy:
{
"claude_identification_enabled": true,
"pro_plan_enabled": false
}| Flag | Effect when false |
|---|---|
claude_identification_enabled | Kill switch — pending identifications fail immediately with a user-friendly message |
pro_plan_enabled | Pro plan upgrades are disabled |
backend/backend/Dockerfile automaticallyrailway.toml — Railway rolls back automatically on failed health checksfrontend/NEXT_PUBLIC_* environment variables in Vercel's dashboardvercel.json configures immutable CDN caching for /_next/static/* and security headers on all routesAll endpoints require Authorization: Bearer <token> except /health.
Response header API-Version: 2026-01-01 is included on every response.
| Method | Path | Description |
|---|---|---|
GET | /health | Health check |
GET | /api/v1/auth/me | Current user profile |
POST | /api/v1/identify | Upload image and start identification (returns identification_id) |
GET | /api/v1/identify/{id} | Poll identification status |
GET | /api/v1/history | Paginated identification history (?offset=0&limit=20) |
GET | /api/v1/history/{id} | Single identification with bird results |
GET | /api/v1/birds | Species sighting log (aggregated, complete identifications only) |
GET | /api/v1/birds/{scientific_name} | Per-species sighting history |
PATCH | /api/v1/user/plan | Update plan (free or pro) |
POST | /api/v1/billing/upgrade | Initiate Stripe checkout (stub — returns 202) |
Date: [redacted] | Status: Accepted
Context: Need user authentication. Options: self-hosted JWT, Auth0, Clerk.
Decision: Auth0 Universal Login with OIDC / PKCE authorization_code flow.
Consequences:
Date: [redacted] | Status: Accepted
Context: Claude vision calls take 3–15 seconds. Blocking HTTP causes timeouts on Vercel (10s limit).
Decision: POST /identify returns 202 immediately; client polls GET /identify/{id} every 2 seconds. identification_id stored in the URL so polling survives page reload.
Consequences:
identification_id in URL — user can bookmark or reopen a result after logging inDate: [redacted] | Status: Accepted
Context: Need object storage for uploaded bird images (image-heavy workload).
Decision: Cloudflare R2 with S3-compatible API.
Consequences:
Severity: 2 — degraded (identifications fail; app accessible)
Detection
"status": "failed" or error_messagecat backend/feature_flags.jsonDiagnosis
"Circuit open" → circuit breaker trippedgrep -c '"status":"failed"' railway_logs.txt for failure rateRecovery
claude_identification_enabled: false in feature_flags.json → redeployStuck pending records
Identifications stuck in pending > 10 minutes indicate a lost BackgroundTask (worker killed).
SELECT id FROM identifications WHERE status='pending' AND identified_at IS NULL;
UPDATE identifications SET status='failed', error_message='Worker lost — please retry' WHERE ...;Severity: 3 — minor (some users blocked; pro users unaffected)
Detection
429 responsesDiagnosis
rate:{user_id}:{YYYY-MM} in Redisredis-cli GET rate:<user_id>:<month>RATE_LIMIT_FREE_TIER env var)Recovery
redis-cli DEL rate:<user_id>:<month> to resetPATCH /api/v1/user/planBudget Alerts (finops-budget-guardrails: alert thresholds at 50%, 80%, 100% of $500 ceiling)
| Ceiling | Amount |
|---|---|
| Monthly operational | $500 |
| One-time setup | $40,000 |
All services use free tiers where possible (Supabase free, Railway free, Auth0 free up to 7,500 MAU, Vercel hobby).
| Gap | Impact | Mitigation |
|---|---|---|
BackgroundTasks reliability | If the Railway worker is killed mid-request, the background identification task is lost — record stays pending | Run the stuck-pending SQL query periodically (see runbook). For production reliability, replace with ARQ (Redis queue). |
time-series-storage for SLO alerting | obs-golden-signals requires a metrics backend for automated alerts | Railway built-in metrics dashboard used as best-effort substitute. Add Grafana Cloud (free tier) if automated SLO alerting is needed. |
| RPO 1440 minutes | Supabase free tier provides daily backups only | Acceptable for MVP. Upgrade Supabase to Pro for PITR if RPO tightens. |
log_correlation (OTel) | opentelemetry-instrumentation-logging not installed | Add package to inject trace_id/span_id into log records when needed. |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.