diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e13ea76 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,36 @@ +# AGENTS.md — Containr + +Containr is a self-hosted Docker PaaS (Railway-style). Backend: Go + Gin + PostgreSQL (sqlc) + Redis-compatible cache (Dragonfly) + Docker API. Frontend: React + Vite + TypeScript + React Query. API contract: `docs/api/openapi.yaml` (generated types: `app/frontend/src/generated/api-types.ts`). + +This file is for **coding agents working on the repo**. For operating Containr as a deployed product, see `llms.txt`. + +## Layout + +- `app/backend` — Go monolith. Entrypoints: `cmd/server` (API), `cmd/cli` (`containr` CLI), `cmd/mcp` (`containr-mcp` MCP server). +- `app/backend/internal/api` — Gin handlers + route groups (`routes.go`: public / `read` OptionalAuth / `authed` / `admin`). +- `app/backend/internal/middleware` — `Auth` (JWT + Better Auth session + PAT), `RequireAdmin`, `Idempotency`. +- `app/backend/internal/cli/commands` — all CLI commands; shared `Client`, `Output`, `confirm` helpers live here. +- `app/backend/internal/mcpserver` — declarative MCP tool registry mirroring the API. +- `app/backend/sqlc` — `schema.sql` + `queries/*.sql`; generate via `sqlc generate` into `internal/database/sqlcdb`. +- `app/backend/migrations_goose` — goose migrations (`YYYYMMDDHHMMSS_name.sql`). +- `app/frontend` — React app. Pages under `src/features/`, API calls via `src/lib/api-client.ts`. + +## Build / test / verify + +```sh +cd app/backend && go build ./... && go vet ./... && go test ./... +cd app/frontend && npx tsc --noEmit && npm run lint && npm run build +cd app/frontend && npm run generate:api # after any openapi.yaml change +``` + +Dev stack: Postgres on `:15432` (`containr-postgres-1`), Dragonfly on `:16379` (`containr-dragonfly-1`). Server needs `DATABASE_URL`, `REDIS_URL`, `JWT_SECRET`, `PORT=8080`. + +## Conventions that matter + +- New endpoints go in the right route group; mutations on `authed`/`admin` get idempotency for free. +- New list endpoints use `pageWindow`/`paginationMeta` (`internal/api/pagination.go`) — cursor + page, `next_cursor` in the envelope. +- New errors use stable codes via `respondError(c, status, code, msg)` in `internal/api/errors.go`. +- New CLI command → also register an MCP tool in `internal/mcpserver/server.go` and document in OpenAPI. All three surfaces ship together. +- Destructive CLI commands must gate on `--yes`/`confirm` via `commands.confirm`; destructive MCP tools require `confirm: true`. +- sqlc: edit `schema.sql` + `queries/*.sql`, run `sqlc generate`, add the goose migration. +- Don't commit secrets. PATs (`cnp_…`) and agent tokens (`cagt_…`) are sha256-hashed at rest; raw values are shown once. diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..58406f7 --- /dev/null +++ b/llms.txt @@ -0,0 +1,30 @@ +# Containr + +> Self-hosted Docker PaaS — deploy and manage containerized apps, databases, cron jobs and preview environments. Operable by humans (web UI) and agents (API / CLI / MCP) through one contract. + +Base URL: `https:///api/v1`. OpenAPI: `docs/api/openapi.yaml`. + +## Access (pick one) + +- **API**: `Authorization: Bearer ` — create a PAT in Settings → Access Tokens or `containr tokens create`. Scopes: `read` (GET/HEAD/OPTIONS only), `write` (everything but admin routes), `admin` (requires platform-admin owner). +- **CLI**: `containr auth login --api-url ` (or `--token cnp_…`), then e.g. `containr projects list --json`, `containr up`. Global flags: `--json`, `--yes`, `--profile`, `--idempotency-key`. +- **MCP**: run `containr-mcp` over stdio with `CONTAINR_API_URL` + `CONTAINR_TOKEN` env (or CLI profile). ~60 tools mirroring the API; destructive tools require `confirm: true`. + +## Conventions + +- **Errors**: `{"error": "msg", "code": "MACHINE_CODE"}`. Codes: `UNAUTHENTICATED`, `INVALID_TOKEN`, `FORBIDDEN`, `ADMIN_REQUIRED`, `SCOPE_INSUFFICIENT`, `NOT_FOUND`, `VALIDATION`, `CONFLICT`, `INTERNAL`, `DEPENDENCY_UNAVAILABLE`, `IDEMPOTENCY_IN_PROGRESS`. +- **Idempotency**: send `Idempotency-Key: ` on POSTs — the first response replays for 24h; concurrent duplicates get 409. Always safe to send. +- **Pagination**: `?limit=` + `?cursor=` (pass `pagination.next_cursor` verbatim; legacy `?page=` also works). Invalid cursors fall back to page 1. +- **Identifiers**: all ids are UUIDs. Tokens: `cnp_` user PATs, `cagt_` agent onboarding tokens. + +## Core objects + +`projects` → `services` (git/app deploys) → `deployments`; plus `databases`, `templates`, `cron-jobs`, `variables`, `volumes`, `preview-environments`, `nodes`, `scaling`, `security`, `gateway`, `admin`, `notifications`, `user/tokens`. + +## Docs + +- `docs/guides/CLI.md` — full CLI reference +- `docs/guides/OPERATIONS.md` — PATs, agent tokens, ops +- `docs/api/openapi.yaml` — request/response contract +- `ROADMAP2.md` — product roadmap +- `AGENTS.md` — repo conventions for coding agents