# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project

Go backend for a Distributed Systems course (Year 3, Semester 2). The backend source lives in `backend-go/`.

## Architecture

```
Nginx LB (:80) → backend1/2/3 (Go/Chi, :8080) → PostgreSQL 18
                                                        ↑
                               migrations run on startup with pg_advisory_lock
```

## Commands

### Go backend (primary)

```sh
# Run locally (needs DATABASE_URL set)
cd backend-go
go run .

# Tidy dependencies
go mod tidy

# Build binary
go build -o forum-backend .
```

### Docker (recommended)

```sh
# Build and start everything
docker compose up --build

# Rebuild only the backends
docker compose up --build backend1 backend2 backend3

# Verify load balancing
for i in $(seq 1 9); do curl -s -D - http://localhost/api/health | grep X-Served-By; done
```

## Structure

```
backend-go/
  main.go                      Entry point: config → pool → migrations → router → ListenAndServe
  go.mod
  internal/
    api/
      app.go                   App struct + BuildRouter (Chi), writeJSON/writeError, X-Served-By
      health.go                GET /api/health
      users.go                 register, login, logout, me, getUser
      categories.go            listCategories, getCategory, listThreadsByCategory
      threads.go               createThread (DB transaction)
      posts.go                 listPosts, createPost, updatePost, deletePost
    auth/
      auth.go                  JWT HS256 encode/decode, __Secure-Fgp fingerprint cookie, RequireAuth middleware
    config/
      config.go                Env-driven Config; enforces 64-char JWT_SECRET
    db/
      db.go                    pgxpool + migration runner (pg_advisory_lock)

migrations/                    SQL migration files (shared, IF NOT EXISTS safe)
                               006_create_refresh_tokens.sql added the refresh-token
                               table — required for /api/auth/refresh rotation flow
  001_create_users.sql
  002_create_categories.sql
  003_create_threads.sql
  004_create_posts.sql
  005_seed_demo_data.sql       Seeds demo/admin/Lenny users + sample threads
docker/
  backend.Dockerfile           Multi-stage Go build (golang:1.26-alpine → alpine:3.23)
  nginx-lb/nginx.conf          Nginx upstream config + X-Served-By passthrough + passive failover
frontend/                      React 19 + Vite 8 SPA (TypeScript 6, Zustand, React Router 7)
docker-compose.yml             Full stack: db, backend1/2/3, loadbalancer, frontend
load-test/                     k6 load test script + results
```

## Environment Variables

| Variable       | Default                              | Description                              |
| -------------- | ------------------------------------ | ---------------------------------------- |
| `DATABASE_URL` | (required)                           | PostgreSQL connection URL                |
| `JWT_SECRET`   | 74-char dev default (warns if unset) | HS256 signing secret; must be ≥ 64 chars |
| `JWT_ISSUER`   | `forumz`                             | Expected `iss` claim                     |
| `INSTANCE_ID`  | `dev`                                | Replica identifier (returned as `X-Served-By`) |
| `PORT`         | `8080`                               | Listen port                              |
