Guidelines and rules for developing in the codebase, including architecture principles, package structure, API spec conventions, and testing practices.
Installation
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Guidelines and rules for developing in the codebase, including architecture principles, package structure, API spec conventions, and testing practices.
Development Skill
When to Use
Invoke this skill whenever building, modifying, or reviewing code in this project. This includes adding features, creating new endpoints, adding MCP tools, writing domain logic, defining ports/adapters, or modifying API specs.
Project Overview
Tech stack: Go (backend, hexagonal architecture), SQLite (default storage), TypeSpec (API contract definitions), embedded frontend in single binary.
Architecture Rules (Hexagonal / Ports & Adapters)
Before writing any Go code, consult docs/hexagonal-architecture/ for the full guide. The critical rules are:
If you find yourself importing an adapter inside app/, or app/ inside an adapter — stop. Define a port interface, implement it in an adapter, inject through the composition root.
Package Import Reference
Package
Can import
Cannot import
domain/
standard library only
everything else
ports/
domain/
adapters/, app/, handlers/
app/
ports/, domain/
adapters/, handlers/
adapters/
ports/, domain/, clients/
app/, handlers/
handlers/
app/, domain/, common/
adapters/
services/
all internal packages
—
cmd/
services/, config/
—
Directory Structure
cmd/ → Entry points (main.go)
internal/
domain/ → Pure business entities, value objects, rules (NO external imports)
ports/ → Interface definitions with port-specific DTOs
<port_name>/
interface.go → Interface definition
types.go → Port-specific param/result DTOs
adapters/ → Concrete implementations of ports
<adapter_name>/
<impl>.go → Implementation
type_conversion.go → Mapping between port DTOs and infra types
app/ → Application layer (use cases)
commands/ → Write operations (each file = one command)
queries/ → Read operations (each file = one query)
decorators/ → Cross-cutting wrappers (logging, tracing, caching, errors)
executors/ → Generic Executor interfaces
<name>_app.go → Application struct grouping commands & queries
handlers/ → Primary adapters (HTTP/gRPC/CLI/event translation)
<handler_name>/
<service>.go
type_conversion.go
interceptors/ → Middleware (auth, logging, correlation ID)
clients/ → Low-level infrastructure client wrappers
common/ → Shared utilities (errors, logger, metrics)
config/ → Configuration structs, loaded from env vars
services/ → Composition root (dependency injection wiring)
resources/test/ → Test infrastructure (containers, seed, mocks)
Build & Generation Commands
Command
What it does
make generate
Full pipeline: TypeSpec → OpenAPI → Go stubs → TS client
make generate-spec
Compile TypeSpec to OpenAPI YAML
make generate-go
Generate Go server interface + types from OpenAPI
make generate-ts
Generate TypeScript API client from OpenAPI
make build
Build the Go server binary
Key Patterns
Executor pattern — All use cases implement a generic interface:
type Executor[Params any] interface {
Execute(ctx context.Context, params Params) error
}
type ExecutorWithReturn[Params, Result any] interface {
Execute(ctx context.Context, params Params) (Result, error)
}
Application struct — Groups commands and queries into a single injectable object:
type AdminApp struct {
Commands AdminCommands
Queries AdminQueries
}
Decorator pattern — Wrap executors for logging, tracing, caching, error handling. Applied in the composition root. Order matters (outermost executes first).
Compile-time interface checks — Every adapter must include:
var _ portpkg.SomeInterface = (*AdapterImpl)(nil)
Type conversion — Each adapter and handler has its own type_conversion.go. Never leak infrastructure types into ports or domain.
Manual dependency injection — No DI frameworks. The composition root (internal/services/) is the only place that knows all layers.
Error handling — Use AppError with error codes (NotFound, InvalidInput, Conflict, etc.) from internal/common/errors/. Handlers map codes to transport status codes. The error handler decorator wraps unexpected errors as Internal.
Configuration — All config from environment variables, loaded once at startup, injected through composition root. Adapters receive only what they need.
Testing
Unit tests: Mock port interfaces for app layer tests. Fast, no infra needed.
Integration tests: Test adapters against real infra via test containers.
Mocks: Live in resources/test/mock/. Use compile-time interface checks.
Database Migrations (Goose)
Migration files live in internal/adapters/sqlite_db/migrations/ and use goose format.
Every migration file MUST include -- +goose Up and -- +goose Down directives. Without these, goose cannot parse the file and the server will fail to start.
-- +goose UpCREATE TABLE example (
id TEXT PRIMARY KEY,
name TEXT NOT NULL
);
-- +goose DownDROPTABLE example;
Key rules:
Always start the file with -- +goose Up
Always include a -- +goose Down section for rollback
Multiple statements under a single -- +goose Up are fine (no need for StatementBegin/StatementEnd unless using procedural SQL)
Do NOT use CREATE TABLE IF NOT EXISTS — goose tracks applied migrations, so idempotent DDL is unnecessary
Every API change follows this strict sequence. Do NOT skip steps or implement code before the spec is updated and stubs are generated.
Update API spec — Define/update models in spec/models/<feature>.tsp and routes in spec/routes/<feature>.tsp. Import new route files in spec/main.tsp.
Generate OpenAPI from TypeSpec — Run make generate-spec (compiles TypeSpec to spec/tsp-output/schema/openapi.yaml).
Generate server/client stubs — Run make generate-go (generates internal/api/gen/server.gen.go and types.gen.go from OpenAPI) and make generate-ts (generates TypeScript client in ui/). Or run make generate to do all three steps at once.
Update implementations — Implement the corresponding Go handler, app commands/queries, ports, and adapters to satisfy the newly generated ServerInterface.
Key rules:
The generated ServerInterface in internal/api/gen/server.gen.go is the source of truth for HTTP handler signatures. Never hand-write route registrations.
Generated files (internal/api/gen/*.gen.go) must NEVER be manually edited. They are overwritten on each generation.
When modifying existing endpoints, always re-run the full generation pipeline (make generate) before updating Go code, so generated types stay in sync.
Handlers in internal/handlers/ implement gen.ServerInterface. The composition root registers them via gen.HandlerFromMux().
TypeSpec Conventions (this project)
Service namespace: Api
Models namespace: Api.Models
Routes namespace: Api.Routes
Group routes under @tag("<Feature>") namespaces
Use @summary() and JSDoc comments for documentation
Define response models explicitly in models/
Routes import models and use using Api.Models;
TypeSpec Quick Patterns
// Model with enum
enum Status { Active: "active", Inactive: "inactive" }
model Thing { id: string; name: string; status: Status; }
// CRUD routes
@tag("Things")
namespace Things {
@get @route("/things") @summary("List things")
op list(): Thing[];
@get @route("/things/{id}") @summary("Get thing")
op get(@path id: string): Thing | { @statusCode statusCode: 404; @body body: ErrorResponse; };
@post @route("/things") @summary("Create thing")
op create(@body body: CreateThingRequest): { @statusCode statusCode: 201; @body body: Thing; };
@delete @route("/things/{id}") @summary("Delete thing")
op delete(@path id: string): { @statusCode statusCode: 204; };
}
MCP Tools via github.com/modelcontextprotocol/go-sdk/mcp
In addition to the HTTP API, the system must expose command/query functionality as MCP (Model Context Protocol) tools. MCP tools are a separate primary adapter — they follow the same hexagonal architecture rules as HTTP handlers but are hand-written (no code generation).
MCP Tool Location
All MCP tools live in internal/handlers/mcp_handler/, organized by domain:
Handler struct: Add new app dependencies to the Handler struct in handler.go and the NewHandler() constructor
Server mounting: The MCP server is mounted at /mcp via mcp.NewStreamableHTTPHandler in internal/services/server.go
Auth: If AUTH_CREDENTIALS is configured, the MCP endpoint is wrapped with HTTP basic auth automatically
Workflow for Adding MCP Tools
Ensure app layer exists — The commands/queries your MCP tools will call must already exist (or be created first following hexagonal architecture rules)
Create or update the tools file — Add input/output DTOs, registration function, and handler methods in internal/handlers/mcp_handler/<domain>_tools.go
Register in handler.go — If it's a new file, add h.register<Domain>Tools(server) call in HTTPHandler()
Update Handler struct — If new app dependencies are needed, add them to the struct and NewHandler() in handler.go, then wire them in internal/services/server.go
Checklist for New Features
Phase 1: Spec-Driven Contract (do this FIRST, before any Go code)
Define API contract in TypeSpec (spec/models/<feature>.tsp + spec/routes/<feature>.tsp)
Import new route file in spec/main.tsp if it's a new file
Run make generate to compile spec → generate OpenAPI → generate Go server stubs + TS client
Verify the generated ServerInterface in internal/api/gen/server.gen.go has the new methods
Add domain entities/value objects in internal/domain/ (stdlib only, no external deps)
Define port interfaces and DTOs in internal/ports/<name>/ (imports domain only)
Implement adapters in internal/adapters/<name>/ with compile-time checks (imports ports + domain)
Create commands/queries in internal/app/commands/ or internal/app/queries/ (imports ports + domain)
Add decorators if needed in internal/app/decorators/ (imports app + executors)
Add handler with type_conversion.go in internal/handlers/<name>/ (imports app + gen + common)
Add MCP tools in internal/handlers/mcp_handler/<domain>_tools.go if the feature should be exposed via MCP (imports app + mcp SDK)
Wire everything in internal/services/ composition root (imports all layers)
Phase 3: Verification
Run go build ./... and go vet ./...
Write unit tests (mock port interfaces) and integration tests (test containers)
Verify dependency flow rules: no forbidden imports between layers
Phase 4: Documentation (website/docs/)
Update user-facing documentation in website/docs/ to reflect the feature change.
Rules:
Major features → Create a new page in the appropriate website/docs/<category>/ folder (e.g., guides/, api/, configuration/).
Minor feature updates → Update the existing relevant page, or add an info/details section within it.
Page too large → If an existing page has grown unwieldy, break it into multiple pages within a new or existing subfolder. Update _category_.json if adding a new folder.
Conventions:
Docusaurus auto-generates the sidebar from folder structure (sidebars.ts uses autogenerated). No manual sidebar edits needed.
Each new folder needs a _category_.json with label and position fields.
Use markdown frontmatter (sidebar_position, title) to control page ordering.
Link to related API endpoints or configuration options where relevant.
Checklist:
Determine scope: new page (major) vs. update existing page (minor)
If page is too large, split into subfolder with multiple pages + _category_.json
Add/update the relevant doc page in website/docs/<category>/