Add a resource
go run ./cmd/forge add resource Note
./bin/task generate
The generator adds internal/modules/note, a migration, SQL registration,
OpenAPI operations, tests, and composition wiring. List, create, get, update,
and delete use the same contract and pagination conventions as the API.
Add -dry-run to inspect the planned files before writing them.
Generated SQL identifiers must fit PostgreSQL’s 63-byte limit, including the
_list_idx suffix; shorten names rejected by preflight. SQL names are quoted,
so resource names such as Reference can use reserved words as table names.
Preflight also checks literal public table/index declarations in migration Up
sections, including drops and renames. It does not parse arbitrary SQL or infer
all database objects; generation and real-Postgres integration tests are still
required.
Concurrent generation in one checkout is locked. After an interrupted command,
inspect .forge-resource.lock and confirm its process has stopped before
removing the lock. Review the diff and restore unfinished generated source
before retrying. Separate worktrees avoid sharing that lock.
- Edit the module’s domain and service for its business rules.
- Update query SQL, migrations, and OpenAPI schemas for the data model.
- Choose access rules. Reads are public; writes require
notes:write. Issue that scope or grant it to selected roles ininternal/auth/principal.go. - Run
task generateafter SQL or contract edits. - Test successful requests, invalid input, and denied access.
- Run
go run ./cmd/dev check,task test:integration, andtask migrate.
task migrate requires FORGE_DB_URL. For local development, copy .env.example
to .env and set the database URL there; Task loads this file.
The logged development token has the admin role. For local Note writes, add
notes:write to that role’s existing grants in internal/auth/principal.go
(create the entry if absent), then rebuild/restart the API. New resources receive
no automatic role grants. See authorization for other policies.
Do not edit internal/gen. Module files outside that directory are ordinary
application code. The route must appear in /openapi.yaml and work through
the public router before the feature is complete.
For an operation on an existing resource, add its contract path and operation
ID, regenerate, implement the typed handler, and delegate it in
cmd/api/resources.go. Keep policy decisions in the service.
internal/modules/widget includes a complete persistence and HTTP example.