A web-based tool for digitizing, dating, and organizing a large collection of family photographs.
  • Python 63.8%
  • TypeScript 25.5%
  • CSS 10.2%
  • Mako 0.3%
  • HTML 0.2%
Find a file
Ryan 8eb89de3a7 Redirect to frontend after OAuth login; fix login button label
- Callback now issues a 302 to CIRCA_POST_LOGIN_REDIRECT_URL (default:
  http://localhost:5173) instead of returning raw JSON, completing the
  browser-based login flow correctly
- Login button label changed from "Sign in with Google" to "Sign in"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 17:37:22 -05:00
backend Redirect to frontend after OAuth login; fix login button label 2026-04-15 17:37:22 -05:00
docs Add Circa planning docs and Phase 1 scaffold 2026-04-14 02:30:39 -05:00
frontend Redirect to frontend after OAuth login; fix login button label 2026-04-15 17:37:22 -05:00
.gitignore Implement Phase 1 backend: schema, auth, ingest, full API 2026-04-15 17:03:09 -05:00
AGENTS.md Implement Phase 1 backend: schema, auth, ingest, full API 2026-04-15 17:03:09 -05:00
CHANGELOG.md Update README and CHANGELOG for Phase 1 v0.1.0 2026-04-15 17:14:20 -05:00
LICENSE Initial commit 2026-04-14 03:34:51 +00:00
README.md Update README and CHANGELOG for Phase 1 v0.1.0 2026-04-15 17:14:20 -05:00

Circa

A web-based tool for digitizing, dating, and organizing a large collection of family photographs.

Status

Phase 1 is implemented and running. Core review workflow is functional.

Stack

  • Backend: Python 3.11+ · FastAPI · SQLAlchemy 2 · Alembic · SQLite (WAL mode)
  • Frontend: React 19 · TypeScript · Vite · TanStack Query · React Router v7
  • Auth: OAuth/OIDC via Authlib (Google by default) · itsdangerous signed session cookies
  • Storage: Local filesystem (content-addressed by SHA-256)

Repo Layout

backend/
  app/
    api/routes/     — HTTP endpoints (auth, photos, jobs, ingest, health)
    auth/           — OAuth client, session helpers
    db/             — SQLAlchemy engine and session
    models/         — ORM models and enums
    repositories/   — DB access layer
    services/       — business logic (ingest, projections, storage, parsers)
    workers/        — background job scaffold
  alembic/versions/ — database migrations
frontend/
  src/
    api/            — typed fetch client
    components/     — AppShell
    hooks/          — useAuth
    pages/          — Dashboard, PhotoBrowser, ReviewWorkspace, Jobs, Login
    types/          — shared TypeScript types
docs/               — product, implementation, UI, wireframe, API, and planning docs

Running Locally

Backend

cd backend
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m alembic upgrade head
.venv/bin/uvicorn app.main:app --reload

The backend starts at http://localhost:8000.

Configuration — copy .env.example to .env or set environment variables with the CIRCA_ prefix:

Variable Default Description
CIRCA_DATABASE_URL sqlite:///./circa.db SQLAlchemy DB URL
CIRCA_SECRET_KEY change-me-in-production Session signing key
CIRCA_OAUTH_CLIENT_ID (empty) OAuth app client ID
CIRCA_OAUTH_CLIENT_SECRET (empty) OAuth app client secret
CIRCA_OAUTH_REDIRECT_URI http://localhost:8000/api/auth/callback OAuth callback URL
CIRCA_FIRST_ADMIN_EMAILS (empty) Comma-separated emails promoted to admin on first login
CIRCA_STORAGE_LOCAL_ROOT ./storage Directory for stored photo files

Without OAuth credentials configured the app starts but the login button won't complete (for development you can directly create a User in the DB or add a dev-login bypass later).

Frontend

cd frontend
npm install
npm run dev

The frontend starts at http://localhost:5173 and proxies /api to http://localhost:8000.

Phase 1 Capabilities

  • Ingest: Upload photos via POST /api/ingest; exact duplicate detection by SHA-256; filename and EXIF date evidence extracted automatically
  • Browse: Photo grid with status filters (pending / needs_review / approved / disputed)
  • Review workspace: Large image view with front/back toggle; evidence panel; decision form with optimistic concurrency (409 conflict detection); inline notes editing; comments; history tab; AI/OCR rerun job enqueueing; rescan flag
  • Jobs: Background job queue visible in the Jobs page (auto-refreshes)
  • Auth: Google OAuth login; first-admin bootstrap via env var

Phase 1 Explicit Non-Goals

  • Near-duplicate resolution UI
  • Album drag reorder
  • Backup/restore/export flows
  • Full admin console
  • Event anchor UI

Docs

  • docs/circa-spec.md — product spec
  • docs/circa-implementation-spec.md — implementation guidance
  • docs/circa-wireframes.md — UI wireframes
  • docs/circa-api-spec.md — API spec
  • docs/circa-phase1-plan.md — Phase 1 engineering plan
  • docs/circa-phase1-backlog.md — Phase 1 ticket backlog