AGENTS.md and README.md were stale since ~2026-04-11 (4 weeks). Updated to reflect magic-link + OIDC auth (ADR-0028), pkg/auth, pkg/email, pkg/user/api packages, and 30-ADR index. Endpoints listing decision : keep curated short list + pointer to swagger as source of truth (see body of changes). Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
203 lines
6.7 KiB
Markdown
203 lines
6.7 KiB
Markdown
# dance-lessons-coach — Agent Documentation
|
|
|
|
AI agent reference for developing, testing, and operating the dance-lessons-coach service.
|
|
|
|
## Tech Stack
|
|
|
|
| Component | Technology | Version |
|
|
|-----------|------------|---------|
|
|
| Language | Go | 1.26.1 |
|
|
| Router | Chi | v5.2.5 |
|
|
| Logging | Zerolog | v1.35.0 |
|
|
| Configuration | Viper | v1.21.0 |
|
|
| Telemetry | OpenTelemetry | v1.43.0 |
|
|
| Database | PostgreSQL + GORM | (optional, for user persistence) |
|
|
| Auth | JWT + bcrypt | with rotating secrets |
|
|
| Email | SMTP (Mailpit dev) | for magic-link delivery |
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
dance-lessons-coach/
|
|
├── adr/ # Architecture Decision Records
|
|
├── cmd/
|
|
│ ├── greet/ # CLI application
|
|
│ └── server/ # Web server entry point
|
|
├── pkg/
|
|
│ ├── auth/ # Auth context keys, OIDC client, helpers
|
|
│ ├── config/ # Viper-based configuration
|
|
│ ├── email/ # SMTP sender abstraction
|
|
│ ├── greet/ # Core domain logic + API handlers
|
|
│ ├── server/ # HTTP server, routing, graceful shutdown
|
|
│ ├── telemetry/ # OpenTelemetry instrumentation
|
|
│ ├── user/ # User domain (auth, JWT, repository)
|
|
│ ├── user/api/ # Auth + admin HTTP handlers
|
|
│ └── validation/ # Request validation
|
|
├── scripts/ # Server lifecycle, build, test scripts
|
|
├── config.yaml # Configuration file
|
|
└── config.example.yaml # Configuration template
|
|
```
|
|
|
|
## Server Management
|
|
|
|
```bash
|
|
# Start / stop / restart
|
|
./scripts/start-server.sh start
|
|
./scripts/start-server.sh stop
|
|
./scripts/start-server.sh restart
|
|
|
|
# Status and logs
|
|
./scripts/start-server.sh status
|
|
./scripts/start-server.sh logs
|
|
|
|
# Test all API endpoints
|
|
./scripts/start-server.sh test
|
|
```
|
|
|
|
## Configuration
|
|
|
|
All settings can be provided via `config.yaml` or environment variables (`DLC_` prefix).
|
|
|
|
| Option | Env var | Default | Description |
|
|
|--------|---------|---------|-------------|
|
|
| Host | `DLC_SERVER_HOST` | `0.0.0.0` | Bind address |
|
|
| Port | `DLC_SERVER_PORT` | `8080` | Listening port |
|
|
| Shutdown timeout | `DLC_SHUTDOWN_TIMEOUT` | `30s` | Graceful shutdown window |
|
|
| JSON logging | `DLC_LOGGING_JSON` | `false` | Structured JSON output |
|
|
| Log output | `DLC_LOGGING_OUTPUT` | `""` | File path (empty = stderr) |
|
|
| API v2 | `DLC_API_V2_ENABLED` | `false` | Enable `/api/v2` routes |
|
|
| Config file | `DLC_CONFIG_FILE` | `./config.yaml` | Override config path |
|
|
|
|
Minimal `config.yaml`:
|
|
```yaml
|
|
server:
|
|
host: "0.0.0.0"
|
|
port: 8080
|
|
shutdown:
|
|
timeout: 30s
|
|
logging:
|
|
json: false
|
|
```
|
|
|
|
**Priority**: env var > config file > default.
|
|
|
|
## API Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/api/health` | Liveness — always `{"status":"healthy"}` |
|
|
| GET | `/api/healthz` | Alternative liveness probe (k8s convention) |
|
|
| GET | `/api/ready` | Readiness — 200 when ready, 503 during shutdown |
|
|
| GET | `/api/info` | Composite info endpoint (cf. ADR-0026) |
|
|
| GET | `/api/version` | Version info (`?format=plain\|full\|json`) |
|
|
| GET | `/api/v1/greet/` | Default greeting |
|
|
| GET | `/api/v1/greet/{name}` | Personalized greeting |
|
|
| POST | `/api/v1/auth/login` | Username + password login (JWT) |
|
|
| POST | `/api/v1/auth/register` | Account creation |
|
|
| POST | `/api/v1/auth/validate` | JWT validation |
|
|
| POST | `/api/v1/auth/password-reset/request` | Request a password reset |
|
|
| POST | `/api/v1/auth/password-reset/complete` | Complete a password reset |
|
|
| POST | `/api/v1/auth/magic-link/request` | Passwordless : request a magic link by email |
|
|
| GET | `/api/v1/auth/magic-link/consume` | Passwordless : consume a magic-link token |
|
|
| GET | `/api/v1/auth/oidc/{provider}/start` | OIDC : begin authorization (PKCE) |
|
|
| GET | `/api/v1/auth/oidc/{provider}/callback` | OIDC : authorization code → JWT |
|
|
| GET | `/api/v1/admin/jwt/secrets` | Admin : list JWT signing secrets |
|
|
| POST | `/api/v1/admin/jwt/secrets` | Admin : add a JWT signing secret |
|
|
| POST | `/api/v1/admin/jwt/secrets/rotate` | Admin : rotate the active JWT secret |
|
|
| POST | `/api/v2/greet` | V2 greeting with validation (feature-flagged) |
|
|
| POST | `/api/admin/cache/flush` | Admin : flush in-memory caches |
|
|
| GET | `/swagger/` | Swagger UI |
|
|
| GET | `/swagger/doc.json` | OpenAPI spec (source of truth) |
|
|
|
|
```bash
|
|
curl http://localhost:8080/api/health
|
|
curl http://localhost:8080/api/v1/greet/Alice
|
|
|
|
# See `/swagger/` for the full interactive list of endpoints.
|
|
# The OpenAPI spec at `/swagger/doc.json` is the source of truth.
|
|
```
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
# Unit + integration tests
|
|
go test ./...
|
|
go test -v ./...
|
|
|
|
# Graceful shutdown + JSON logging validation
|
|
./scripts/test-graceful-shutdown.sh
|
|
|
|
# OpenTelemetry end-to-end
|
|
./scripts/test-opentelemetry.sh
|
|
```
|
|
|
|
**Note:** Do not call `go generate` unless editing API endpoint annotations.
|
|
When needed: `go generate ./pkg/server/`
|
|
|
|
## Build
|
|
|
|
```bash
|
|
./scripts/build.sh
|
|
# Produces: ./bin/server ./bin/greet
|
|
./bin/server --version
|
|
```
|
|
|
|
Build injects version, commit, and date via `-ldflags`.
|
|
|
|
## Graceful Shutdown
|
|
|
|
On `SIGTERM` / `SIGINT`:
|
|
1. Readiness context is cancelled → `/api/ready` returns 503.
|
|
2. 1-second propagation window (load balancer drains).
|
|
3. `srv.Shutdown()` waits up to `shutdown.timeout` for active requests.
|
|
4. Process exits cleanly.
|
|
|
|
Health endpoint stays 200 throughout; readiness endpoint goes 503 immediately on signal.
|
|
|
|
## OpenTelemetry / Jaeger
|
|
|
|
Enable in config or via env:
|
|
```bash
|
|
export DLC_TELEMETRY_ENABLED=true
|
|
export DLC_TELEMETRY_OTLP_ENDPOINT="localhost:4317"
|
|
```
|
|
|
|
Quick Jaeger setup:
|
|
```bash
|
|
docker run -d --name jaeger \
|
|
-e COLLECTOR_OTLP_ENABLED=true \
|
|
-p 16686:16686 -p 4317:4317 \
|
|
jaegertracing/all-in-one:latest
|
|
```
|
|
|
|
## Architecture Decision Records
|
|
|
|
The full index is at [adr/README.md](adr/README.md) — 30 ADRs covering Go version, Chi router, Zerolog, OpenTelemetry, BDD testing, JWT auth, PostgreSQL, OIDC migration, email infrastructure, etc.
|
|
|
|
Add a new ADR : copy an existing file in `adr/`, edit it, update `adr/README.md`.
|
|
|
|
## Commit Conventions
|
|
|
|
[Conventional Commits](https://www.conventionalcommits.org) with optional [gitmoji](https://gitmoji.dev):
|
|
|
|
| Emoji | Type | When |
|
|
|-------|------|------|
|
|
| ✨ | `feat` | New feature |
|
|
| 🐛 | `fix` | Bug fix |
|
|
| 📝 | `docs` | Documentation |
|
|
| 🎨 | `style` | Formatting only |
|
|
| ♻️ | `refactor` | Structural change |
|
|
| 🚀 | `perf` | Performance |
|
|
| 🔒 | `security` | Security fix |
|
|
| 📦 | `chore` | Dependencies / build |
|
|
| 🧪 | `test` | Tests |
|
|
| 🤖 | `ci` | CI/CD |
|
|
| 🔥 | `remove` | Delete code/files |
|
|
|
|
Examples:
|
|
```
|
|
feat: add JWT authentication middleware
|
|
fix: ensure first log line is JSON when json logging is enabled
|
|
docs: rewrite AGENTS.md for clarity
|
|
```
|