Files
ajet-chat/CLAUDE.md
2026-02-17 00:23:25 -05:00

4.1 KiB

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

Running Services (REPL-driven)

# Single REPL with all modules
clj -A:dev:api:web-sm:tui-sm:auth-gw

# Individual service REPLs
clj -M:dev:api        # API service
clj -M:dev:web-sm     # Web session manager
clj -M:dev:tui-sm     # TUI session manager
clj -M:dev:auth-gw    # Auth gateway

Services expose (start!) / (stop!) / (reset!) in their REPL namespaces.

Testing (Kaocha)

clj -M:test/unit          # Unit tests — no Docker needed
clj -M:test/integration   # Integration — requires Docker (Postgres + MinIO + NATS)
clj -M:test/e2e           # E2E — requires full stack in Docker
clj -M:test/all           # All tiers

Docker infra for integration tests: docker compose -f docker-compose.test.yml up -d

Architecture Diagram

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/