docs: update all documentation to reflect current codebase state

- CLAUDE.md: check off frontend tests (53 Vitest tests done), update test count to 220+, update endpoint count to 55, update CI description
- README.md: add missing API endpoints (PUT/DELETE for issuers, targets, teams, owners, policies; POST notifications/{id}/read; auth endpoints), update endpoint count from 40+ to 55, update test count to 220+
- architecture.md: add frontend test layer description, update CI section with Vitest step, update dashboard description with action buttons (create cert modal, deploy, archive, test issuer, enable/disable policy, delete)
- demo-guide.md: fix incorrect /api/v1/policies/violations endpoint to /api/v1/policies/{id}/violations, update "Demo Without Docker" section from stale web/index.html to Vite dev server
- quickstart.md: fix auto-generated ID format from UUID to name-timestamp format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
shankar0123
2026-03-16 00:12:58 -04:00
parent 73c6bd1416
commit 05443d5858
5 changed files with 41 additions and 20 deletions
+5 -5
View File
@@ -1,11 +1,11 @@
You are my long-term copilot for building certctl — a self-hosted certificate lifecycle platform. Help me design, document, and evolve the project across versions while preserving a small, understandable core, strong architecture, modular connectors, safe automation, good security, and excellent documentation for both beginners and experts. Be structured, opinionated, and practical. Challenge scope creep, separate core platform concerns from integrations, and recommend the smallest useful implementation before expanding. Always think in terms of maintainability, extensibility, observability, auditability, and clear product/engineering tradeoffs. You are my long-term copilot for building certctl — a self-hosted certificate lifecycle platform. Help me design, document, and evolve the project across versions while preserving a small, understandable core, strong architecture, modular connectors, safe automation, good security, and excellent documentation for both beginners and experts. Be structured, opinionated, and practical. Challenge scope creep, separate core platform concerns from integrations, and recommend the smallest useful implementation before expanding. Always think in terms of maintainability, extensibility, observability, auditability, and clear product/engineering tradeoffs.
## Project Status (Last Updated: March 15, 2026) ## Project Status (Last Updated: March 16, 2026)
### What's Built and Working ### What's Built and Working
- [x] Go 1.22 server with net/http stdlib routing, slog logging, handler->service->repository layering - [x] Go 1.22 server with net/http stdlib routing, slog logging, handler->service->repository layering
- [x] PostgreSQL 16 schema (14 tables, TEXT primary keys, idempotent migrations) - [x] PostgreSQL 16 schema (14 tables, TEXT primary keys, idempotent migrations)
- [x] REST API — 41 endpoints under /api/v1/ with pagination, filtering, async actions - [x] REST API — 55 endpoints under /api/v1/ with pagination, filtering, async actions
- [x] Web dashboard — Vite + React 18 + TypeScript + TanStack Query, 11 views wired to real API, dark theme - [x] Web dashboard — Vite + React 18 + TypeScript + TanStack Query, 11 views wired to real API, dark theme
- [x] Agent binary — heartbeat, work polling, cert fetch, CSR generation, job status reporting (real HTTP calls) - [x] Agent binary — heartbeat, work polling, cert fetch, CSR generation, job status reporting (real HTTP calls)
- [x] Local CA issuer connector — crypto/x509, in-memory CA, self-signed certs - [x] Local CA issuer connector — crypto/x509, in-memory CA, self-signed certs
@@ -28,9 +28,9 @@ You are my long-term copilot for building certctl — a self-hosted certificate
- [x] Demo mode — 14 certs, 5 agents, 5 targets, policies, audit events, notifications - [x] Demo mode — 14 certs, 5 agents, 5 targets, policies, audit events, notifications
- [x] Documentation — concepts guide, quickstart, advanced demo, architecture, connectors - [x] Documentation — concepts guide, quickstart, advanced demo, architecture, connectors
- [x] BSL 1.1 license — 7-year conversion to Apache 2.0 (March 2033) - [x] BSL 1.1 license — 7-year conversion to Apache 2.0 (March 2033)
- [x] Test suite — 170+ tests across service layer (63), handler layer (100+), integration (20+ subtests), connector (local CA) - [x] Test suite — 220+ tests: Go backend (170+ across service, handler, integration, connector layers) + frontend (53 Vitest tests for API client and utilities)
- [x] Input validation — centralized validators for common name, CSR PEM, policy type/severity, string length - [x] Input validation — centralized validators for common name, CSR PEM, policy type/severity, string length
- [x] GitHub Actions CI — parallel Go (build, vet, test+coverage+gates) and Frontend (tsc, vite build) jobs - [x] GitHub Actions CI — parallel Go (build, vet, test+coverage+gates) and Frontend (tsc, vitest, vite build) jobs
- [x] API key auth enforced by default — SHA-256 hashed keys, constant-time comparison, Bearer token middleware - [x] API key auth enforced by default — SHA-256 hashed keys, constant-time comparison, Bearer token middleware
- [x] Token bucket rate limiting — configurable RPS/burst, 429 responses with Retry-After header - [x] Token bucket rate limiting — configurable RPS/burst, 429 responses with Retry-After header
- [x] Configurable CORS — per-origin allowlist or wildcard, preflight caching - [x] Configurable CORS — per-origin allowlist or wildcard, preflight caching
@@ -43,7 +43,7 @@ You are my long-term copilot for building certctl — a self-hosted certificate
### What's NOT Wired Up Yet (Pre-v1.0 Gaps) ### What's NOT Wired Up Yet (Pre-v1.0 Gaps)
- [ ] **README screenshots**: Screenshots of actual dashboard in README - [ ] **README screenshots**: Screenshots of actual dashboard in README
- [ ] **Tagged Docker images**: Publish v1.0.0 images - [ ] **Tagged Docker images**: Publish v1.0.0 images
- [ ] **Frontend tests**: No React component or API integration tests - [x] **Frontend tests**: 53 Vitest tests (API client coverage, utility functions) with CI integration
--- ---
+21 -2
View File
@@ -8,7 +8,7 @@ A self-hosted certificate lifecycle platform. Track, renew, and deploy TLS certi
## What It Does ## What It Does
certctl gives you a single pane of glass for every TLS certificate in your organization. The **web dashboard** shows your full certificate inventory — what's healthy, what's expiring, what's already expired, and who owns each one. The **REST API** (40+ endpoints) lets you automate everything. **Agents** deployed on your infrastructure generate private keys locally and submit CSRs — private keys never leave your servers. certctl gives you a single pane of glass for every TLS certificate in your organization. The **web dashboard** shows your full certificate inventory — what's healthy, what's expiring, what's already expired, and who owns each one. The **REST API** (55 endpoints) lets you automate everything. **Agents** deployed on your infrastructure generate private keys locally and submit CSRs — private keys never leave your servers.
```mermaid ```mermaid
flowchart LR flowchart LR
@@ -202,19 +202,29 @@ POST /api/v1/agents/{id}/jobs/{jobId}/status Report job completion/failure
GET /api/v1/issuers List issuers GET /api/v1/issuers List issuers
POST /api/v1/issuers Create POST /api/v1/issuers Create
GET /api/v1/issuers/{id} Get GET /api/v1/issuers/{id} Get
PUT /api/v1/issuers/{id} Update
DELETE /api/v1/issuers/{id} Delete
POST /api/v1/issuers/{id}/test Test connectivity POST /api/v1/issuers/{id}/test Test connectivity
GET /api/v1/targets List deployment targets GET /api/v1/targets List deployment targets
POST /api/v1/targets Create POST /api/v1/targets Create
GET /api/v1/targets/{id} Get GET /api/v1/targets/{id} Get
PUT /api/v1/targets/{id} Update
DELETE /api/v1/targets/{id} Delete
``` ```
### Organization ### Organization
``` ```
GET /api/v1/teams List teams GET /api/v1/teams List teams
POST /api/v1/teams Create POST /api/v1/teams Create
GET /api/v1/teams/{id} Get
PUT /api/v1/teams/{id} Update
DELETE /api/v1/teams/{id} Delete
GET /api/v1/owners List owners GET /api/v1/owners List owners
POST /api/v1/owners Create POST /api/v1/owners Create
GET /api/v1/owners/{id} Get
PUT /api/v1/owners/{id} Update
DELETE /api/v1/owners/{id} Delete
``` ```
### Operations ### Operations
@@ -225,10 +235,19 @@ POST /api/v1/jobs/{id}/cancel Cancel
GET /api/v1/policies List policy rules GET /api/v1/policies List policy rules
POST /api/v1/policies Create POST /api/v1/policies Create
PUT /api/v1/policies/{id} Update (enable/disable)
DELETE /api/v1/policies/{id} Delete
GET /api/v1/policies/{id}/violations List violations for rule GET /api/v1/policies/{id}/violations List violations for rule
GET /api/v1/audit Query audit trail GET /api/v1/audit Query audit trail
GET /api/v1/notifications List notifications GET /api/v1/notifications List notifications
POST /api/v1/notifications/{id}/read Mark as read
```
### Auth
```
GET /api/v1/auth/info Auth mode info (no auth required)
GET /api/v1/auth/check Validate credentials
``` ```
### Health ### Health
@@ -310,7 +329,7 @@ make docker-clean # Stop + remove volumes
## Roadmap ## Roadmap
### V1 (feature-complete → v1.0.0 tag pending) ### V1 (feature-complete → v1.0.0 tag pending)
All nine development milestones (M1M9) are complete. The backend covers the full certificate lifecycle: Local CA and ACME v2 issuers, NGINX/F5/IIS target connectors, threshold-based expiration alerting, agent-side ECDSA P-256 key generation, API auth with rate limiting, and a React dashboard with 11 views wired to the real API. The CI pipeline runs build, vet, lint, test with coverage gates (service layer 30%+, handler layer 50%+), and frontend checks on every push. 170+ tests across service, handler, integration, and connector layers. All nine development milestones (M1M9) are complete. The backend covers the full certificate lifecycle: Local CA and ACME v2 issuers, NGINX/F5/IIS target connectors, threshold-based expiration alerting, agent-side ECDSA P-256 key generation, API auth with rate limiting, and a React dashboard with 11 views wired to the real API. The CI pipeline runs build, vet, test with coverage gates (service layer 30%+, handler layer 50%+), frontend type checking, Vitest test suite, and Vite production build on every push. 220+ tests total: 170+ Go tests across service, handler, integration, and connector layers, plus 53 frontend Vitest tests covering API client functions and utility helpers.
Remaining before the v1.0.0 tag: dashboard screenshots in README, tagged Docker images published, final error-handling audit to confirm no panics or unhandled error paths. Remaining before the v1.0.0 tag: dashboard screenshots in README, tagged Docker images published, final error-handling audit to confirm no panics or unhandled error paths.
+5 -3
View File
@@ -82,7 +82,7 @@ The agent runs two background loops: a heartbeat (every 60 seconds) to signal it
The web dashboard is the primary operational interface for certctl. It is built with Vite + React + TypeScript and uses TanStack Query for server state management (caching, background refetching, optimistic updates). The web dashboard is the primary operational interface for certctl. It is built with Vite + React + TypeScript and uses TanStack Query for server state management (caching, background refetching, optimistic updates).
**Current views**: certificate inventory (list + detail with version history), agent fleet (health indicators from heartbeat), job queue (status, retry, cancel), notification inbox (threshold alert grouping), audit trail (time range and actor/action filters), policy management (rules + violations), and a summary dashboard. **Current views**: certificate inventory (list with "New Certificate" creation modal + detail with version history, deploy, archive, and trigger renewal actions), agent fleet (health indicators from heartbeat), job queue (status, retry, cancel), notification inbox (threshold alert grouping, mark-as-read), audit trail (time range and actor/action filters), policy management (rules with enable/disable toggle + delete + violations), issuers (list with test connection + delete), targets (list with delete), and a summary dashboard.
The dashboard includes a **demo mode** that activates when the API is unreachable — it renders realistic mock data for screenshots and offline presentations. The dashboard includes a **demo mode** that activates when the API is unreachable — it renders realistic mock data for screenshots and offline presentations.
@@ -560,7 +560,7 @@ For production, you would also add an ingress controller, TLS termination for th
## Testing Strategy ## Testing Strategy
certctl uses a layered testing approach aligned with the handler → service → repository architecture, with 170+ tests across four layers. The goal is high-confidence regression prevention at the service and handler layers, where the most complex business logic lives, combined with integration tests that exercise the full request path from HTTP to database. certctl uses a layered testing approach aligned with the handler → service → repository architecture, with 220+ tests across five layers (service, handler, integration, connector, and frontend). The goal is high-confidence regression prevention at the service and handler layers, where the most complex business logic lives, combined with integration tests that exercise the full request path from HTTP to database.
**Service layer unit tests** (`internal/service/*_test.go`) — 74 test functions across 7 files with mock repositories. These test all business logic in isolation: certificate CRUD with validation, agent lifecycle (registration, heartbeat, CSR submission with both keygen modes), job state machine (creation, processing, cancellation, retry logic), policy evaluation (all 4 rule types, violation creation), renewal and issuance flow (server-side and agent-side keygen paths), and notification deduplication (threshold tag matching, channel routing). Mock repositories are simple structs with function fields, avoiding heavy mocking frameworks — this keeps tests readable and avoids coupling to mock library APIs. **Service layer unit tests** (`internal/service/*_test.go`) — 74 test functions across 7 files with mock repositories. These test all business logic in isolation: certificate CRUD with validation, agent lifecycle (registration, heartbeat, CSR submission with both keygen modes), job state machine (creation, processing, cancellation, retry logic), policy evaluation (all 4 rule types, violation creation), renewal and issuance flow (server-side and agent-side keygen paths), and notification deduplication (threshold tag matching, channel routing). Mock repositories are simple structs with function fields, avoiding heavy mocking frameworks — this keeps tests readable and avoids coupling to mock library APIs.
@@ -568,7 +568,9 @@ certctl uses a layered testing approach aligned with the handler → service →
**Integration tests** (`internal/integration/`) — Two test files exercising the full stack from HTTP request through router, handler, service, and postgres repository layers. `lifecycle_test.go` has 11 subtests covering the complete certificate lifecycle: team/owner creation, certificate creation, issuer verification, renewal trigger, job verification, agent registration, CSR submission, deployment, and status reporting. `negative_test.go` has 12 subtests covering error paths: nonexistent resource lookups (404s), invalid request bodies (malformed JSON, missing required fields), invalid CSR submission, heartbeat for nonexistent agents, wrong HTTP methods on list endpoints, empty list responses, renewal on nonexistent certificates, and expired certificate lifecycle. Both use a shared `setupTestServer()` that builds a fully-wired server with real postgres repositories and the Local CA issuer connector. **Integration tests** (`internal/integration/`) — Two test files exercising the full stack from HTTP request through router, handler, service, and postgres repository layers. `lifecycle_test.go` has 11 subtests covering the complete certificate lifecycle: team/owner creation, certificate creation, issuer verification, renewal trigger, job verification, agent registration, CSR submission, deployment, and status reporting. `negative_test.go` has 12 subtests covering error paths: nonexistent resource lookups (404s), invalid request bodies (malformed JSON, missing required fields), invalid CSR submission, heartbeat for nonexistent agents, wrong HTTP methods on list endpoints, empty list responses, renewal on nonexistent certificates, and expired certificate lifecycle. Both use a shared `setupTestServer()` that builds a fully-wired server with real postgres repositories and the Local CA issuer connector.
**CI pipeline** (`.github/workflows/ci.yml`) — Two parallel jobs: Go (build, vet, test with `-race` and coverage, coverage threshold enforcement) and Frontend (TypeScript type check, Vite production build). The Go job runs all tests with `-coverprofile`, then enforces coverage thresholds: service layer must be at least 30% (current: ~34%) and handler layer must be at least 50% (current: ~61%). These thresholds act as regression floors — they can only go up. The service layer threshold is deliberately lower because much of the service code depends on postgres repositories and external connectors that require real infrastructure to test meaningfully. Connector tests are included via `./internal/connector/issuer/local/...` (the Local CA package, which has unit tests for certificate signing logic). **Frontend tests** (`web/src/api/client.test.ts`, `web/src/api/utils.test.ts`) — 53 Vitest tests covering the API client and utility functions. The API client tests mock `globalThis.fetch` and verify all endpoint functions (certificates, agents, jobs, policies, issuers, targets, notifications, audit, health) send correct HTTP methods, URLs, headers, and request bodies. They also test API key management (store/retrieve/clear), auth header propagation, 401 event dispatching, and error handling (server messages, error fields, status text fallback). The utility tests use `vi.useFakeTimers()` for deterministic date testing and cover `formatDate`, `formatDateTime`, `timeAgo`, `daysUntil`, and `expiryColor`. The test environment uses jsdom with `@testing-library/jest-dom` matchers.
**CI pipeline** (`.github/workflows/ci.yml`) — Two parallel jobs: Go (build, vet, test with coverage, coverage threshold enforcement) and Frontend (TypeScript type check, Vitest test suite, Vite production build). The Go job runs all tests with `-coverprofile`, then enforces coverage thresholds: service layer must be at least 30% (current: ~34%) and handler layer must be at least 50% (current: ~61%). These thresholds act as regression floors — they can only go up. The service layer threshold is deliberately lower because much of the service code depends on postgres repositories and external connectors that require real infrastructure to test meaningfully. Connector tests are included via `./internal/connector/issuer/local/...` (the Local CA package, which has unit tests for certificate signing logic). The Frontend job runs `npx vitest run` between the TypeScript check and production build steps.
**What's not tested and why:** Postgres repository implementations (`internal/repository/postgres/`) require a real database and are tested only through integration tests, not unit tests. Target connectors (NGINX, F5, IIS) depend on real infrastructure or complex mocks. Scheduler loops are time-dependent and tested manually during development. The ACME connector requires a real ACME server (tested manually against Let's Encrypt staging). These are all candidates for future expansion as the test infrastructure matures. **What's not tested and why:** Postgres repository implementations (`internal/repository/postgres/`) require a real database and are tested only through integration tests, not unit tests. Target connectors (NGINX, F5, IIS) depend on real infrastructure or complex mocks. Scheduler loops are time-dependent and tested manually during development. The ACME connector requires a real ACME server (tested manually against Let's Encrypt staging). These are all candidates for future expansion as the test infrastructure matures.
+7 -7
View File
@@ -77,8 +77,8 @@ curl -s http://localhost:8443/api/v1/agents | jq .
# View audit trail # View audit trail
curl -s http://localhost:8443/api/v1/audit | jq . curl -s http://localhost:8443/api/v1/audit | jq .
# View policy violations # View policy violations (replace POLICY_ID with a real policy ID, e.g. pr-require-owner)
curl -s http://localhost:8443/api/v1/policies/violations | jq . curl -s http://localhost:8443/api/v1/policies/pr-require-owner/violations | jq .
# Check system health # Check system health
curl -s http://localhost:8443/health | jq . curl -s http://localhost:8443/health | jq .
@@ -86,13 +86,13 @@ curl -s http://localhost:8443/health | jq .
## Demo Without Docker ## Demo Without Docker
The dashboard includes a **Demo Mode** that works without any backend. Just open the HTML file directly: The dashboard includes a **Demo Mode** that works without any backend. Build and serve the frontend with Vite:
```bash ```bash
open web/index.html cd web
# or npm install
python3 -m http.server 3000 -d web/ npm run dev
# then visit http://localhost:3000 # Dashboard available at http://localhost:5173
``` ```
When the API is unreachable, the dashboard automatically loads realistic mock data and shows a subtle "Demo Mode" badge. This is perfect for screenshots, presentations, or quick demos without any infrastructure. When the API is unreachable, the dashboard automatically loads realistic mock data and shows a subtle "Demo Mode" badge. This is perfect for screenshots, presentations, or quick demos without any infrastructure.
+3 -3
View File
@@ -159,10 +159,10 @@ curl -s -X POST http://localhost:8443/api/v1/certificates \
}' | jq . }' | jq .
``` ```
The server returns the created certificate with an auto-generated ID: The server returns the created certificate. Since we didn't include an `id` field, the server auto-generates one using the name and a timestamp:
```json ```json
{ {
"id": "a1b2c3d4-...", "id": "My First Certificate-1710403200000000000",
"name": "My First Certificate", "name": "My First Certificate",
"common_name": "myapp.example.com", "common_name": "myapp.example.com",
"status": "Pending", "status": "Pending",
@@ -170,7 +170,7 @@ The server returns the created certificate with an auto-generated ID:
} }
``` ```
Save the certificate ID: Save the certificate ID (or provide your own `id` in the request body, e.g. `"id": "mc-my-first"`):
```bash ```bash
CERT_ID="<paste the id from the response>" CERT_ID="<paste the id from the response>"
``` ```