Skip to content

Commit a8437e5

Browse files
gilcrestclaude
andcommitted
Add CLAUDE.md with project guidance for Claude Code
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f3ad161 commit a8437e5

9 files changed

Lines changed: 605 additions & 310 deletions

File tree

CLAUDE.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
DIY Go API is a RESTful API template backed by PostgreSQL. It demonstrates a multi-tenant B2B SaaS data model with CRUD operations for movies as the demo domain. The project favors the Go standard library, using third-party packages only when necessary.
8+
9+
## Build & Run Commands
10+
11+
**Build tool**: [Mage](https://magefile.org/) (Go-based make alternative), defined in `magefiles/magefile.go`.
12+
13+
| Command | Description |
14+
|---|---|
15+
| `mage -v run local` | Run the server locally |
16+
| `mage -v testall false local` | Run all tests (non-verbose) |
17+
| `mage -v testall true local` | Run all tests (verbose) |
18+
| `go test ./...` | Run tests directly (requires env vars set) |
19+
| `go test -v -run TestFunctionName ./path/to/package` | Run a single test |
20+
| `mage -v newkey` | Generate a new encryption key |
21+
| `mage -v cueGenerateGenesisConfig` | Generate genesis config from CUE schemas |
22+
| `task db-up` | Run database DDL migrations |
23+
| `mage -v gcp staging` | Build Docker image and deploy to GCP Cloud Run |
24+
25+
The `env` parameter for mage commands (e.g., `local`, `staging`) determines which config profile to load. Config is loaded from `config_profiles.json` or environment variables.
26+
27+
## Architecture
28+
29+
### Layer Structure
30+
31+
```
32+
HTTP Request → server (routes/middleware/handlers) → service (business logic) → sqldb/datastore (data access) → PostgreSQL
33+
```
34+
35+
- **Root package (`diygoapi.go`)**: Domain types, interfaces (`Datastorer`, service interfaces like `MovieServicer`, `OrgServicer`, `AppServicer`), and request/response structs.
36+
- **`server/`**: HTTP routing (`routes.go`), middleware chains (`middleware.go`), and handlers (`handlers.go`). Uses `justinas/alice` for composable middleware. Routes use Go 1.22+ method-pattern syntax (e.g., `"POST /api/v1/movies"`).
37+
- **`service/`**: Business logic implementations. Services are structs with a `Datastorer` field and optional `EncryptionKey`. Transactions managed here.
38+
- **`sqldb/datastore/`**: SQL queries generated by [sqlc](https://sqlc.dev/). Type-safe database access via `pgx/v5`.
39+
- **`cmd/`**: CLI wiring — flag parsing via `peterbourgon/ff/v3` (supports flags, env vars, config files), server initialization, dependency injection.
40+
41+
### Middleware Chain
42+
43+
Every route uses a middleware chain built with `alice`. Typical chain:
44+
```
45+
loggerChain → addRequestHandlerPattern → enforceJSONContentType → appHandler → authHandler → authorizeUserHandler → jsonContentTypeResponse → handler
46+
```
47+
48+
### Error Handling (errs package)
49+
50+
Based on the Upspin error pattern. Every function declares `const op errs.Op = "package/Function"` at the top and wraps errors with `errs.E(op, ...)`.
51+
52+
Key types: `Op` (operation trace), `Kind` (error classification: Validation, Unauthenticated, Unauthorized, etc.), `Code` (machine-readable), `Param` (related parameter), `Realm` (WWW-Authenticate).
53+
54+
Errors propagate up the call stack with op context. `errs.HTTPErrorResponse()` maps `Kind` to HTTP status codes. Internal/Database errors are not leaked to clients.
55+
56+
### Authentication & Authorization
57+
58+
- OAuth2 via Google (token validated against Google's OAuth2 v2 API)
59+
- Bearer token required in `Authorization` header on all requests
60+
- RBAC: Users have roles, roles have permissions, permissions map to resources
61+
- Context carries `App`, `User`, and `AuthParams` through the request lifecycle
62+
63+
### Database
64+
65+
- PostgreSQL with `pgx/v5` connection pooling
66+
- Migrations: SQL files in `scripts/db/migrations/up/` (numbered 000–014)
67+
- Uses PostgreSQL schemas for tenant isolation (search_path)
68+
- No ORM — raw SQL + sqlc code generation
69+
70+
### Configuration
71+
72+
Flags → environment variables → config file (precedence order). Key env vars:
73+
`DB_HOST`, `DB_PORT`, `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_SEARCH_PATH`, `ENCRYPT_KEY`, `PORT`, `LOG_LEVEL`, `LOG_LEVEL_MIN`, `LOG_ERROR_STACK`
74+
75+
### Logging
76+
77+
Structured JSON logging via `rs/zerolog`. Logger passed through request context. GCP-compatible log hooks in `logger/` package.
78+
79+
## Key Conventions
80+
81+
- **Testing**: Uses `frankban/quicktest` (`c := qt.New(t)`), table-driven subtests
82+
- **Error ops**: Always `const op errs.Op = "package/Function"` as first line, wrap with `errs.E(op, err)`
83+
- **External IDs**: API responses use external IDs (UUIDs), never internal database IDs
84+
- **Service constructors**: Services are struct literals with injected dependencies (no constructor functions)
85+
- **Domain interfaces**: Defined in root package, implemented in `service/`

Taskfile.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
version: '3'
2+
3+
tasks:
4+
db-up:
5+
desc: Run DDL up migration scripts found in the scripts/db/migrations/up directory
6+
cmds:
7+
- go run ./cmd/migrations/main.go

0 commit comments

Comments
 (0)