# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **moments** is a personal activity timeline and portfolio site. It ingests developer activity from multiple forges (GitHub, Gitea, Mercurial, Bugzilla), stores raw JSON payloads in PostgreSQL, and serves a React frontend showing contribution graphs, a ranked project dashboard, and a filterable activity timeline. ## Architecture Hexagonal (ports & adapters) Rust backend with a React/TypeScript frontend. ### Crate Dependency Graph ``` moments-entities — pure types/DTOs, no DB or HTTP deps ^ moments-core — port traits (EventReader, EventWriter, EventSource, PollerStateStore) + presentation reshape + poller loop ^ moments-data — sole adapter: PgStore implements all core traits + EventSource impls (github, gitea, hg, bugzilla) + SQL migrations ^ moments-api — axum HTTP API binary (read-only, connects as moments_ro) moments-worker — ingestion daemon binary (runs migrations, connects as moments_rw) ``` ### Key Design Decisions - **Raw payload storage**: upstream JSON is stored verbatim in `events.payload` (JSONB). The `reshape()` function in `moments-core/src/presentation.rs` transforms payloads into `TimelineItem` at request time — no re-ingestion needed to change presentation. - **Public/private gate**: `events.public` boolean controls API visibility. Only `public = true` rows are served. - **Wire types are hand-maintained**: `ui/src/api/client.ts` mirrors Rust entity types manually. - **Migrations**: run automatically on worker startup via `sqlx::migrate!`. The API binary never runs migrations. ### Frontend React 19 + Vite 6 (SWC) + TypeScript + Bootstrap 5. State/data via `@tanstack/react-query`. Package manager is **pnpm**. Routes: `/` (dashboard), `/activity` (timeline), `/project/:source/*` (project detail), `/cv` (resume). ## Build & Dev Commands ### Rust ```sh cargo build --workspace # build all crates cargo build --workspace --release # release build cargo clippy --workspace # lint cargo fmt --check # format check cargo test --workspace # run tests # Run binaries (need DATABASE_URL) DATABASE_URL=postgres://localhost/moments cargo run -p moments-api DATABASE_URL=postgres://localhost/moments cargo run -p moments-worker ``` ### Frontend ```sh cd ui pnpm install # install deps pnpm dev # dev server on :5173 (proxies /api/* to localhost:8080) pnpm lint # tsc --noEmit type-check pnpm build # production build (tsc -b && vite build) ``` ## Database PostgreSQL with three migrations in `crates/moments-data/migrations/`. Two roles: `moments_rw` (worker, full access) and `moments_ro` (API, SELECT-only). ## API Endpoints All under `/v1/`: `healthz`, `events`, `sources`, `projects`, `activity/daily`, `forge/{source}/*`, `og/contributions.png`. ## Deployment Production uses `./script/deploy.sh`. Services run under systemd with hardened units. Secrets resolved from `pass` store via template substitution. Nginx reverse-proxies `/api/` to the API host.