# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview ajet-chat is a Clojure monorepo for a team messaging platform (Slack-like). Early stage — module skeletons exist but most code is stubbed out. ## Repository Structure Monorepo with `:local/root` deps linking modules: - **shared/** — Common DB layer (next.jdbc + HoneySQL), EventBus (NATS via jnats), API client SDK, schemas, protocols - **auth-gw/** — Auth gateway: http-kit edge proxy, session/token validation, routing (has PG access) - **api/** — Stateless REST API: all data reads/writes to PG, publishes events to NATS - **web-sm/** — Web session manager: Hiccup + Datastar SSE for browsers (NATS + API, no PG) - **tui-sm/** — TUI session manager: SSE for terminal clients (NATS + API, no PG) - **cli/** — Terminal client: CLI (one-shot) + TUI (interactive via clojure-tui) - **mobile/** — Mobile client (deferred, placeholder only) **Dependency matrix:** ``` PG NATS API(HTTP) API yes pub — Auth GW yes — — Web SM — sub yes (internal) TUI SM — sub yes (internal) CLI — — yes (external, via Auth GW) ``` ## Common Commands ### Task Runner (Babashka) Preferred way to run tasks — `bb` wraps `clj` commands and manages Docker infra automatically. ```bash bb tasks # List all available tasks # Development bb dev # Start dev infra + nREPL (all modules) bb infra:dev # Start dev Docker infra only bb infra:dev:stop # Stop dev Docker infra # Testing bb test # All tests (starts test infra) bb test:unit # Unit tests only (no Docker needed) bb test:integration # Integration tests (starts test infra) bb test:e2e # E2E tests (starts test infra) # Per-module testing bb test:shared # All shared tests bb test:shared:unit # Shared unit tests only bb test:api # All API tests bb test:api:unit # API unit tests only bb test:auth-gw # All auth-gw tests # Per-module bb.edn (from module directory) cd shared && bb test:unit # Delegates to root bb.edn # Build & Deploy bb build api # Build uberjar for a module bb clean api # Clean module artifacts (or bb clean for all) bb prod # Start production stack (docker compose) bb prod:stop # Stop production stack bb prod:logs # Tail production logs # Database bb db:reset-test # Drop & recreate test DB schema ``` ### Running Services (REPL-driven) ```bash # Via bb (recommended) bb dev # nREPL with all modules + dev infra # Via clj directly clj -A:dev:api:web-sm:tui-sm:auth-gw # Single REPL with all modules clj -M:dev:api # Individual service REPL ``` Services expose `(start!)` / `(stop!)` / `(reset!)` in their REPL namespaces. ### Testing (Kaocha) ```bash # Via bb (recommended — manages Docker infra automatically) bb test:unit # Unit tests — no Docker needed bb test:integration # Integration — starts Docker automatically bb test # All tiers # Via clj directly (legacy — requires manual Docker management) clj -M:test/base:test/unit # Unit tests clj -M:test/base:test/integration # Integration tests clj -M:test -m kaocha.runner # All tests (using unified :test alias) ``` Docker infra for integration tests: `docker compose -f docker-compose.test.yml up -d` ### Architecture Diagram ```bash typst compile architecture.typst architecture.png ``` ## Architecture **Request flow:** Internet → nginx (TLS, prod only) → Auth Gateway → service (API / Web SM / TUI SM) **Key pattern — data vs events separation:** - All persistent data reads/writes go through the **API** (stateless REST, only service with PG access besides Auth GW) - Real-time events flow via **NATS** pub/sub (community-scoped subjects) - **Session managers** hold live client connections, subscribe to NATS for events, fetch full data from API via HTTP. No direct PG connection. - SMs publish ephemeral events (typing indicators) directly to NATS — bypasses API for latency **Auth Gateway** is a Clojure http-kit proxy that does its own DB reads/writes for session validation, then routes authenticated requests to internal services. ## Tech Stack - All server modules: Clojure 1.12, http-kit 2.8, reitit 0.7, Ring 1.13 - Data: PostgreSQL (next.jdbc + HoneySQL) — API + Auth GW only - Events: NATS (io.nats/jnats) — API publishes, SMs subscribe - Web: Hiccup 2.0 + Datastar SDK (web-sm) - CLI: shared API client SDK (babashka http-client) + clojure-tui (local dep at `../../clojure-tui`) - Files: MinIO (S3-compatible) ## Conventions - **PostgreSQL everywhere** — same DB in dev and prod, no SQLite. Dev infra runs in Docker. - **HoneySQL maps** for all queries — avoid raw SQL strings - **Migratus** for schema migrations - **NATS** for all event pub/sub — community-scoped subjects (`chat.events.{community-id}`), DM subjects (`chat.dm.{channel-id}`) - **MinIO** (S3-compatible) for file storage — same API as AWS S3 - **UUIDs** for all entity IDs (`java.util.UUID/randomUUID`) - **EventBus protocol**: `publish!`, `subscribe!`, `unsubscribe!` — backed by NATS - **SSE** for all server→client streaming (web + TUI), HTTP POSTs for client→server signals ## Namespace Conventions ``` ajet.chat.shared.* — shared/src/ ajet.chat.api.* — api/src/ ajet.chat.web.* — web-sm/src/ ajet.chat.tui-sm.* — tui-sm/src/ ajet.chat.auth-gw.* — auth-gw/src/ ajet.chat.cli.* — cli/src/ ```