Skip to content

feat(exports): add GET /api/exports/health dependency probe - #1

Open
devcarole wants to merge 1184 commits into
mainfrom
feature/issue-728-exports-health-probe
Open

feat(exports): add GET /api/exports/health dependency probe#1
devcarole wants to merge 1184 commits into
mainfrom
feature/issue-728-exports-health-probe

Conversation

@devcarole

Copy link
Copy Markdown
Owner

greatest0fallt1me and others added 30 commits July 28, 2026 17:38
…en-rate-limit

Feat/930 refresh token rate limit
…meout

feat(forecast): add graceful timeout on /api/forecast (Closes CalloraOrg#935)
Add per-developer billing-concurrency stats admin endpoint (GrantFox FWC26).

- Export sharedDeveloperSemaphore singleton from developerSemaphore.ts so
  the middleware and admin route share the same in-memory state
- Add getActiveSlotCount(), isAtLimit(), and maxConcurrency getter to
  DeveloperSemaphore (mirrors KeySemaphore API)
- Update createPerDevConcurrencyMiddleware to accept injectable semaphore
  and default to sharedDeveloperSemaphore when no options are customised
- Add GET /api/admin/metrics/concurrency — snapshot of all developers
  with at least one in-flight billing request
- Add GET /api/admin/metrics/concurrency/:developerId — live count and
  atLimit flag for a single developer
- Mount new router at /metrics in the admin router
- 27 focused tests, all passing; lint clean; zero TS errors in changed files
- Add docs/per-dev-concurrency.md with API reference, config table,
  audit events, and operational notes

Closes CalloraOrg#608
…ue-913

feat: add prometheus latency histogram for GET /api/maintenance
…ook-retry-override

feat: add per-subscription webhook retry policy override
…lloraOrg#893)

- Register apis_request_duration_seconds histogram in src/metrics/registry.ts
  with explicit buckets (0.001-10s) tuned for marketplace listing latencies
  and labels: route, method, status_code
- Instrument all /api/apis handlers via middleware in src/routes/apis.ts
  to record request duration for ALL outcomes (success and error)
- Implement recordApisLatency() helper function for direct recording
- Add comprehensive test suite (src/__tests__/apisLatency.test.ts) covering:
  * Histogram registration and metadata
  * Direct recording with correct label values
  * Integration with route middleware
  * Error response capture (404, 4xx, 5xx)
  * Duration measurement accuracy (not hardcoded)
- Document metric design, buckets, labels, and usage in docs/apis-latency-metric.md
  with PromQL examples and alerting guidelines

Bucket rationale:
  Sub-millisecond granularity (1µs-50ms): cache hits + simple DB queries
  Tail visibility (100ms-10s): downstream service latency, slow clients

Labels breakdown:
  route: /api/apis (constant)
  method: GET or POST (identifies request type)
  status_code: HTTP response status (enables error-path analysis)

Closes CalloraOrg#893
 CalloraOrg#896)

Implement request deduplication for proxy POST/PATCH methods via the existing
idempotencyMiddleware, enabling safe retries without risking duplicate upstream
execution.

CHANGES:
- Applied idempotencyMiddleware to POST/PATCH routes in src/routes/proxyRoutes.ts
- Explicit per-method routing (POST, PATCH, GET, DELETE, etc.) instead of catch-all
- GET/DELETE bypass idempotency middleware (out of scope; naturally safe)
- Idempotency-Key header is optional but recommended for safe retries

FEATURES:
- True request deduplication: repeated requests with same key/payload do NOT
  call upstream a second time; cached response is replayed instead
- Payload mismatch detection: reusing a key with different payload returns
  409 IDEMPOTENCY_KEY_REUSE_MISMATCH (prevents silent bugs)
- Concurrent-duplicate handling: retries arriving while first is in-flight
  get 409 IDEMPOTENCY_IN_PROGRESS; upstream executes exactly once
- Actor-scoped idempotency: different API keys cannot access each other's
  cached responses (prevents cross-tenant leaks)
- PostgreSQL storage: safe for horizontal scaling; shared state across instances
- 24-hour retention window: configurable, automatic TTL cleanup

TESTS:
- Added 20+ integration tests covering first request, replay, mismatch,
  in-progress, GET/DELETE bypass, actor scoping, canonicalization
- All tests in src/__tests__/proxy.integration.test.ts

DOCUMENTATION:
- New: docs/api-proxy-idempotency.md (client-facing contract)
  - Header format, requirements, retention window
  - Response codes and behaviors (2xx, 409 scenarios)
  - Implementation examples (TypeScript retry loop)
  - Security and multi-tenancy notes
  - Troubleshooting guide
- New: IDEMPOTENCY_KEY_PROXY_IMPLEMENTATION.md (internal design doc)
  - Architecture decisions, design rationale
  - Multi-instance safety verification
  - Concurrent-duplicate race handling
  - Questions for human review

DEPLOYMENT:
- No new dependencies required
- No database migrations needed (idempotency_store table exists)
- Uses existing IDEMPOTENCY_RETENTION_WINDOW_SECONDS env var
- Backward compatible: Idempotency-Key is optional
- Clients opt-in by including the header

ISSUE: Closes CalloraOrg#896 (GrantFox FWC26 b#031)
- Implements true request deduplication (no double downstream execution)
- Handles concurrent retries correctly
- Actor-scoped storage prevents cross-tenant data leaks
- Multi-instance safe via PostgreSQL
Add SUBSCRIPTION_CORS_ALLOWED_ORIGINS env-driven CORS middleware to
/api/subscriptions, matching the pattern established by the maintenance
route CORS (MAINTENANCE_CORS_ALLOWED_ORIGINS).

- createSubscriptionCorsMiddleware() in src/middleware/cors.ts
  — exact-match allowlist, deny by default, 10-min preflight cache
- Applied as first middleware in createSubscriptionRouter()
- SUBSCRIPTION_CORS_ALLOWED_ORIGINS added to env schema & .env.example
- 5 new unit tests in cors.test.ts + Origin headers on all 56 existing
  subscription route tests

closes#900
- Mount correlationMiddleware on the refresh-token router
- Propagate X-Correlation-Id response header on every request
- Replace getRequestId() with req.correlationId from the middleware
- Add tests for correlation-id header propagation and structured logging

Closes CalloraOrg#957
…nfrastructure including app factory, middleware, metrics, and routing modules.
- Extract exportsQuerySchema from inline route to src/validators/export.ts
- Update src/routes/exports.ts to import from validator module
- Add focused test suite in src/validators/export.test.ts (11 tests)

Closes CalloraOrg#912
…-breaker-spike-884

feat(spike): add circuit breaker for audit service calls (closes CalloraOrg#884)
…loper-concurrency-stat-#608

feat: concurrency stat
…box-dispatcher

feat(outbox): add partition-aware sharded dispatcher for high-volume …
…-keys-integration-test

Feature/e2e api keys integration test
…gram-apis-latency

Feat/prom histogram apis latency
…port-security-headers

feat: security header sweep for /api/exports CalloraOrg#885
greatest0fallt1me and others added 29 commits July 29, 2026 16:09
…pike-examples

docs: add openapi examples for spike route
…743-health-probe

docs: Add /api/health/health dependency probe
…740-openapi-webhooks

docs: Add OpenAPI examples for /api/webhooks
…subscriptions-histogram

feat(metrics): add prometheus latency histogram for /api/subscription…
…738-proxy-test

Feature/issue 738 proxy test
…735-etag-apis

test: Add integration tests for ETag caching on /api/apis
- Pre-set strong ETag on GET /api/tenants from tenant data only,
  so the tag is stable across requests that return the same list
  regardless of volatile envelope fields (timestamp, requestId)
- Extend etagMiddleware to honour a pre-set ETag while still
  evaluating If-None-Match via strong comparison (RFC 7232 §3.2),
  preventing Express's built-in weak-comparison fresh module from
  firing incorrectly on W/"..." tags
- Add focused ETag/304 tests to src/routes/tenants.test.ts:
    - 200 with strong ETag header on first fetch
    - 304 Not Modified when If-None-Match matches
    - 200 when If-None-Match does not match
    - 200 (not 304) for weak ETag — strong comparison only
    - 401 for unauthenticated GET
    - 500 propagation for repository errors
- Document GET /api/tenants caching behaviour in docs/tenants-api.md

Closes CalloraOrg#946
Apply CSP, X-Content-Type-Options, and Referrer-Policy to every
/api/errors response via router.use(securityHeadersMiddleware).

The middleware fires before all route handlers so even 401 and 400
error responses carry the headers.

- src/routes/errors.ts: import securityHeadersMiddleware and mount
  it at the top of createErrorsRouter
- src/routes/errors.test.ts: add focused security-header describe
  block covering GET /, GET /:id (404), POST (201/401/400),
  PATCH (200/404), PUT (200), DELETE (204/404)
- docs/errors-security-headers.md: document the headers applied,
  rationale, implementation detail, and test coverage table

Closes CalloraOrg#945
Add request/response examples for all webhook management endpoints:
- DELETE /api/webhooks/{developerId} (remove webhook)
- POST /api/webhooks/{developerId}/rotate-secret (rotate signing secret)
- PATCH /api/webhooks/{developerId}/retry-policy (update retry config)
- POST /api/webhooks/deliver/{developerId} (deliver webhook event)

Also adds 400 error response examples for POST /api/webhooks (missing
fields, invalid events, invalid URL, invalid retry policy).

Updates companion test to verify all new endpoint examples are present.

Closes CalloraOrg#871

Co-authored-by: Cursor <cursoragent@cursor.com>
…sage-validate

feat: input validation usage
…red_json_access_logs

feat: add structured JSON access logs for /api/forecast
…ers-errors-945

feat: security header sweep for /api/errors (CalloraOrg#945)
…ok-openapi-examples

feat(openapi): add OpenAPI examples for /api/webhooks endpoints
…e-name

 Add graceful timeout on /api/plans [b#050]
Adds a public health probe endpoint at GET /api/subscriptions/health
that reports the operational status of the subscriptions subsystem's
external dependencies (database).

The endpoint follows the same pattern as other subsystem health probes
(e.g., /api/usage/health, /api/rate-limit/health):
- Probes the database with a bounded timeout
- Returns sanitised dependency status (ok/degraded/down)
- Returns 503 when the database is down
- Public (no auth required) for load-balancer health checks
- Supports x-request-id correlation for structured logging

Closes CalloraOrg#954

Co-authored-by: Cursor <cursoragent@cursor.com>
Adds a health probe for the /api/quotas route group, reporting the status
of its external dependencies (currently the shared PostgreSQL database,
which backs quota-request persistence and usage aggregation).

- src/routes/quotas/health.ts: GET / handler reusing the existing
  checkDatabase/sanitizeCheck infrastructure from
  src/services/healthCheck.ts and src/routes/health/dependencies.ts, so
  the response shape ({ status, timestamp, dependencies }) and error
  sanitization rules match the app's other dependency probes. Applies the
  same correlationMiddleware and quotasDrainTracker used by
  src/routes/quotas/counts.ts for structured logging and graceful
  shutdown.
- src/routes/quotas.ts: mount the new router at /api/quotas/health,
  after the shared per-user token-bucket rate limiter (same protection
  as every other /api/quotas route).
- docs/quotas-health-probe.md + README.md: document the endpoint,
  response shape, status codes, and correlation ID behavior.
- src/routes/quotas/health.test.ts: 8 tests covering healthy/down
  database status, error sanitization, dependency key set, correlation
  ID echo/generation, default pool wiring, and drain-tracker
  compatibility (93% line coverage on the new route file).

Closes CalloraOrg#773
…alth-probe

feat: add /api/quotas/health dependency probe
…-771-zod-forecast-validation

feat(forecast): add Zod input validation for /api/forecast endpoints
…ions-health-probe

feat(subscriptions): add /api/subscriptions/health dependency probe
…rg#728) - Implement health probe endpoint at GET /api/exports/health - Concurrently checks database, storage, queue, and notificationApi - Returns per-dependency status (ok/degraded/down) and aggregated overall - withTimeout() guard (5s) protects against hung probes - Structured JSON logging with correlation ID on every log line (x-correlation-id header or UUID v4 fallback) - ProbeRegistry DI pattern for easy test injection - 40 tests: all-healthy 200, partial/full failure 503, timeout 503, degraded 200, correlation ID echo/generation, log structure validation - health.ts coverage: 100% stmts, 100% funcs, 100% lines, 93.75% branches Build fixes (pre-existing issues resolved): - Rename jest.config.js -> jest.config.cjs (ESM package incompatibility) - Add tsconfig.test.json targeting CommonJS for Jest/ts-jest compatibility - Fix src/index.test.ts import extension (.js required for NodeNext) - Add isolatedModules: true to tsconfig.json - Upgrade ts-jest to 29.4.12 for Jest 30 support - Add --forceExit to test script
devcarole pushed a commit that referenced this pull request Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add /api/exports/health dependency probe