Input: Design documents from specs/001-papi-control-plane/
Prerequisites: plan.md (required), spec.md (required), research.md, data-model.md, contracts/
Tests: Tests are included as the constitution mandates TDD (Principle III: Test-First Development NON-NEGOTIABLE).
Organization: Tasks are grouped by user story to enable independent implementation and testing of each story.
- [P]: Can run in parallel (different files, no dependencies)
- [Story]: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
- Go project:
cmd/papi/,internal/,pkg/rei/,tests/,api/openapi/ - Paths assume standard Go layout per plan.md
Purpose: Project initialization and basic structure
- T001 Initialize Go module with
go mod initand createcmd/papi/main.goentry point - T002 [P] Create project directory structure per plan.md (
internal/api/v1/handlers/,internal/api/v1/middleware/,internal/config/,internal/domain/namespace/,internal/domain/group/,internal/domain/operation/,internal/platform/,internal/rei/,internal/rei/cloudfoundry/,internal/queue/,internal/store/postgres/,internal/store/migrations/,pkg/rei/,tests/contract/,tests/integration/,tests/e2e/,api/openapi/) - T003 [P] Add core dependencies to go.mod: chi, pgx, sqlc, golang-jwt, coreos/go-oidc, oapi-codegen, testify, testcontainers-go, envconfig, prometheus client, OpenTelemetry SDK
- T004 [P] Copy OpenAPI v1 spec to
api/openapi/v1.yaml - T005 [P] Configure oapi-codegen to generate server interfaces and types from
api/openapi/v1.yamlintointernal/api/v1/generated.go - T006 [P] Setup linting (golangci-lint config) and formatting (gofumpt) in
.golangci.yml - T007 [P] Create
Makefilewith targets: build, test, lint, migrate, generate, run - T008 [P] Create
Dockerfilefor containerized builds
Purpose: Core infrastructure that MUST be complete before ANY user story can be implemented
- T009 Implement application configuration loading via envconfig in
internal/config/config.go(PAPI_DB_URL, PAPI_OIDC_ISSUER, PAPI_LISTEN_ADDR, PAPI_LOG_LEVEL, PAPI_METRICS_ADDR, PAPI_IDENTITY_CACHE_TTL) - T010 [P] Setup structured logging with slog in
internal/config/logging.go(JSON output, configurable level) - T011 [P] Setup PostgreSQL connection pool with pgx in
internal/store/postgres/connection.go - T012 Create database migration framework using golang-migrate in
internal/store/migrations/with initial schema migration000001_initial_schema.up.sqland000001_initial_schema.down.sql(all tables from data-model.md) - T013 Implement migration CLI command in
cmd/papi/main.go(migrate up/migrate downsubcommands) - T014 [P] Implement OIDC token validation middleware using coreos/go-oidc in
internal/api/v1/middleware/auth.go(JWKS discovery, token parsing, claims extraction) - T015 [P] Implement platform role authorization helper in
internal/platform/auth.go(check user roles from DB against required role) - T016 [P] Implement platform role store in
internal/store/postgres/platform_roles.go(GetRolesForUser, HasRole queries) - T017 [P] Setup chi router with API v1 route group, request logging middleware, and metrics middleware in
internal/api/v1/router.go - T018 [P] Implement error response helpers in
internal/api/v1/handlers/errors.go(ErrorResponse, ValidationErrorResponse JSON serialization) - T019 [P] Setup Prometheus metrics endpoint on separate port in
internal/config/metrics.go - T020 [P] Setup OpenTelemetry tracing initialization in
internal/config/tracing.go - T021 [P] Define REI interface package in
pkg/rei/rei.go(RuntimeEnvironment interface, request/result types, Status constants, Factory type, Registry) - T022 Wire up main.go: config loading → DB connection → migrations check → OIDC provider init → router setup → HTTP server start with graceful shutdown in
cmd/papi/main.go
Checkpoint: Foundation ready — user story implementation can now begin
Goal: Authenticated users can list namespaces they have access to
Independent Test: Authenticate and call GET /api/v1/namespaces; verify only accessible namespaces returned
NOTE: Write these tests FIRST, ensure they FAIL before implementation
- T023 [P] [US1] Contract test for GET /api/v1/namespaces in
tests/contract/namespaces_list_test.go(validates response matches OpenAPI schema, pagination, auth rejection) - T024 [P] [US1] Integration test for namespace listing in
tests/integration/namespace_list_test.go(testcontainers PostgreSQL, seed data, verify access control filtering)
- T025 [P] [US1] Create Namespace domain model in
internal/domain/namespace/model.go(Namespace struct, Member struct, enums for status/role/member_type) - T026 [P] [US1] Create IdentityGroupCache model in
internal/domain/namespace/identity_cache.go(cache struct, TTL logic) - T027 [US1] Implement namespace store in
internal/store/postgres/namespaces.go(ListByUser query — joins members table, filters by user identifier or cached group membership, pagination) - T028 [US1] Implement identity group cache store in
internal/store/postgres/identity_cache.go(GetCachedMembers, RefreshCache, IsUserInGroup queries) - T029 [US1] Implement namespace list service in
internal/domain/namespace/service.go(ListForUser method — combines direct membership + identity group cache lookup) - T030 [US1] Implement GET /api/v1/namespaces handler in
internal/api/v1/handlers/namespaces.go(auth required, calls service, returns paginated NamespaceListResponse) - T031 [US1] Register namespace list route in
internal/api/v1/router.go - T032 [US1] Add structured logging for namespace list operations (user, result count, duration) in handler
Checkpoint: User Story 1 fully functional — users can list their namespaces
Goal: Users with namespace-creator role can create namespaces with async provisioning
Independent Test: Authenticate as namespace-creator, POST namespace, verify 202 response and IN_PROGRESS status
NOTE: Write these tests FIRST, ensure they FAIL before implementation
- T033 [P] [US2] Contract test for POST /api/v1/namespaces in
tests/contract/namespaces_create_test.go(validates 202 response schema, 400 validation errors, 403 unauthorized, 409 conflict) - T034 [P] [US2] Contract test for GET /api/v1/namespaces/{id}/status in
tests/contract/namespaces_status_test.go(validates status response schema) - T035 [P] [US2] Integration test for namespace creation in
tests/integration/namespace_create_test.go(end-to-end: create namespace, verify DB state, verify operations queued)
- T036 [P] [US2] Implement namespace name template store in
internal/store/postgres/name_template.go(GetActiveTemplate, ValidateComponents) - T037 [P] [US2] Implement metadata rules store in
internal/store/postgres/metadata_rules.go(GetMandatoryRules, ValidateMetadata) - T038 [US2] Implement namespace name validation service in
internal/domain/namespace/naming.go(resolve template, validate each component against regex/allowed values, compose final name) - T039 [US2] Implement metadata validation service in
internal/domain/namespace/metadata.go(check mandatory fields present, validate against rules) - T040 [US2] Implement namespace creation service in
internal/domain/namespace/service.go(CreateNamespace method — validate name, validate metadata, check uniqueness, persist namespace + members, resolve default group, queue operations) - T041 [P] [US2] Implement Operation domain model in
internal/domain/operation/model.go(Operation struct, status enum, operation type enum) - T042 [US2] Implement operation store in
internal/store/postgres/operations.go(CreateOperation, ListByNamespace, UpdateStatus queries) - T043 [US2] Implement POST /api/v1/namespaces handler in
internal/api/v1/handlers/namespaces.go(namespace-creator role check, validation, calls service, returns 202 with NamespaceResponse) - T044 [US2] Implement GET /api/v1/namespaces/{id}/status handler in
internal/api/v1/handlers/namespaces.go(returns per-environment provisioning status) - T045 [US2] Register namespace create and status routes in
internal/api/v1/router.go - T046 [US2] Add structured logging for namespace creation (user, namespace name, group, member count, duration)
Checkpoint: User Story 2 fully functional — namespaces can be created with async provisioning queued
Goal: Unauthenticated users can check health and discover platform info
Independent Test: Call GET /api/v1/health and GET /api/v1/info without auth; verify correct responses
- T047 [P] [US3] Contract test for GET /api/v1/health in
tests/contract/health_test.go(validates schema, no auth required) - T048 [P] [US3] Contract test for GET /api/v1/info in
tests/contract/info_test.go(validates schema, version, OIDC endpoint)
- T049 [P] [US3] Implement health check handler in
internal/api/v1/handlers/system.go(aggregates runtime environment health from DB, returns overall status) - T050 [P] [US3] Implement info handler in
internal/api/v1/handlers/system.go(returns version, api_version, OIDC issuer URL) - T051 [US3] Register health and info routes (no auth middleware) in
internal/api/v1/router.go
Checkpoint: Platform discovery endpoints operational
Goal: Admins can CRUD groups; any authenticated user can list groups
Independent Test: Authenticate as admin, create/update/delete groups; authenticate as user, list groups
- T052 [P] [US4] Contract test for GET /api/v1/groups in
tests/contract/groups_list_test.go - T053 [P] [US4] Contract test for POST /api/v1/groups in
tests/contract/groups_create_test.go(201, 400, 403) - T054 [P] [US4] Contract test for PUT /api/v1/groups/{id} in
tests/contract/groups_update_test.go - T055 [P] [US4] Contract test for DELETE /api/v1/groups/{id} in
tests/contract/groups_delete_test.go(204, 403, 409) - T056 [P] [US4] Integration test for group CRUD in
tests/integration/groups_test.go
- T057 [P] [US4] Create RuntimeEnvironmentGroup domain model in
internal/domain/group/model.go(Group struct, Environment struct, orchestration strategy enum) - T058 [US4] Implement group store in
internal/store/postgres/groups.go(List, Create, Update, Delete, HasNamespaces queries) - T059 [US4] Implement group service in
internal/domain/group/service.go(ListAll, Create, Update, Delete with namespace dependency check) - T060 [US4] Implement GET /api/v1/groups handler in
internal/api/v1/handlers/groups.go(any authenticated user) - T061 [US4] Implement POST /api/v1/groups handler in
internal/api/v1/handlers/groups.go(admin role check) - T062 [US4] Implement PUT /api/v1/groups/{id} handler in
internal/api/v1/handlers/groups.go(admin role check) - T063 [US4] Implement DELETE /api/v1/groups/{id} handler in
internal/api/v1/handlers/groups.go(admin role check, 409 if namespaces assigned) - T064 [US4] Register group routes in
internal/api/v1/router.go
Checkpoint: Group management fully operational
Goal: Operations queued during namespace creation are executed against runtime environments
Independent Test: Create namespace for a group with multiple environments; verify provisioning executes on each
- T065 [P] [US5] Integration test for operation queue processing in
tests/integration/queue_test.go(queue operation, process it, verify REI called) - T066 [P] [US5] Integration test for Cloud Foundry REII in
tests/integration/cloudfoundry_test.go(mock CF API, verify org/space creation)
- T067 [P] [US5] Implement Cloud Foundry REII in
internal/rei/cloudfoundry/cloudfoundry.go(implements pkg/rei.RuntimeEnvironment — CreateNamespace creates org+space, HealthCheck calls /v3/info) - T068 [P] [US5] Implement CF namespace mapping store in
internal/store/postgres/cf_mapping.go(CreateMapping, GetMapping for CFNamespaceMapping table) - T069 [US5] Implement operation queue processor in
internal/queue/processor.go(polls pending operations, processes via REI, updates status, handles failures with retry) - T070 [US5] Implement PostgreSQL LISTEN/NOTIFY for new operations in
internal/queue/notifier.go(notify on insert, processor listens for immediate processing) - T071 [US5] Implement environment health checker in
internal/queue/health.go(periodic health check via REI.HealthCheck, updates environment status in DB) - T072 [US5] Register Cloud Foundry factory in REI Registry at application startup in
cmd/papi/main.go - T073 [US5] Start queue processor goroutine in
cmd/papi/main.go(graceful shutdown) - T074 [US5] Add structured logging and metrics for queue processing (operation type, environment, duration, success/failure counts)
Checkpoint: End-to-end provisioning operational — namespaces created in PAPI are provisioned in Cloud Foundry
Purpose: Improvements that affect multiple user stories
- T075 [P] Implement identity group cache background refresh worker in
internal/queue/identity_refresh.go(periodic TTL check, re-resolve from identity provider, update cache) - T076 [P] Add request ID / correlation ID middleware in
internal/api/v1/middleware/request_id.go(generate UUID, propagate via context, include in logs) - T077 [P] Add rate limiting middleware in
internal/api/v1/middleware/rate_limit.go - T078 [P] Add pagination helper in
internal/api/v1/handlers/pagination.go(parse page/page_size params, build Pagination response) - T079 Run quickstart.md validation (manual smoke test against running instance)
- T080 [P] Add OpenTelemetry trace spans to all handlers and queue processor
- T081 [P] Create
docker-compose.ymlfor local development (PostgreSQL, UAA mock)
- Setup (Phase 1): No dependencies — can start immediately
- Foundational (Phase 2): Depends on Setup completion — BLOCKS all user stories
- User Story 1 (Phase 3): Depends on Foundational
- User Story 2 (Phase 4): Depends on Foundational (can run in parallel with US1)
- User Story 3 (Phase 5): Depends on Foundational (can run in parallel with US1/US2)
- User Story 4 (Phase 6): Depends on Foundational (can run in parallel with US1/US2/US3)
- User Story 5 (Phase 7): Depends on US2 (needs operations queued) + US4 (needs groups created)
- Polish (Phase 8): Depends on all user stories complete
- US1 (List Namespaces): Independent after Foundational
- US2 (Create Namespace): Independent after Foundational (operations are queued but not processed until US5)
- US3 (Health/Info): Independent after Foundational
- US4 (Group CRUD): Independent after Foundational
- US5 (Provisioning): Depends on US2 + US4 (needs both operation queue and group/environment data)
- Tests MUST be written and FAIL before implementation
- Models before stores
- Stores before services
- Services before handlers
- Handlers before route registration
- All Setup tasks marked [P] can run in parallel
- All Foundational tasks marked [P] can run in parallel
- US1, US2, US3, US4 can all start in parallel after Foundational
- Within each story: tests [P], models [P] can run in parallel
- US5 must wait for US2 + US4
- Complete Phase 1: Setup
- Complete Phase 2: Foundational (CRITICAL — blocks all stories)
- Complete Phase 3: User Story 1 (List Namespaces)
- Complete Phase 4: User Story 2 (Create Namespace)
- STOP and VALIDATE: Both P1 stories independently functional
- Deploy/demo if ready (namespace CRUD works, provisioning is queued but not processed)
- Complete Phase 5: User Story 3 (Health/Info)
- Complete Phase 6: User Story 4 (Group CRUD)
- Complete Phase 7: User Story 5 (Provisioning — connects everything end-to-end)
- Complete Phase 8: Polish
- Run quickstart.md validation
- [P] tasks = different files, no dependencies
- [Story] label maps task to specific user story for traceability
- Each user story should be independently completable and testable
- Verify tests fail before implementing
- Commit after each task or logical group
- Stop at any checkpoint to validate story independently
- The REI interface (T021) is in Foundational because all stories eventually need it
- Operation queue processing (US5) is separate from creation (US2) — this is intentional for async decoupling