Sprint 4: security completion, observability, OpenAPI, publishing — MVP wrap - #12
Merged
Conversation
…ty, OpenAPI, publishing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add 'forbidden' error code to errorCodeSchema enum - Create eraseUserResponseSchema with counts breakdown - Add type EraseUserResponse for response inference Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds ErasureStore port (eraseUser: events/progress/unlocks/offerEvents counts) and its only implementation, PgErasureStore, which deletes the four scoped tables inside a single db.transaction so a mid-transaction failure rolls back cleanly. monthlyActiveUsers rows are deliberately left untouched (billing/usage history retained). Also widens AuthContext with allowedOrigins: string[] | null, per the established cross-sprint pattern (Tasks 3-4 wire it into verifyKey/CORS enforcement). This is an expected break for adapter-strapi and apps/api test fixtures, but pnpm turbo run typecheck stays fully green today: both packages scope tsc to src/ only, and adapter-strapi's verifyKey casts through `any`, so neither surfaces the missing field yet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…y user erasure - adapter-strapi: verifyKey now maps AuthContext field-by-field instead of blind-casting the response, so allowedOrigins is validated (array-of-strings or null) rather than silently passed through as whatever shape the config plane returns. - apps/api: origin enforcement in the auth middleware rejects publishable-key requests whose Origin header isn't in the key's allowedOrigins list; secret keys and requests without an Origin header are unaffected. - apps/api: new fixed-window (60s) rate limiter keyed by sha256(bearer token), wired before auth on /v1/*; 429 rate_limited with a retry-after header when exceeded. Single-instance MVP (in-memory Map); multi-instance limiting is backlog. - apps/api: DELETE /v1/users/:userId erasure route requires a secret key and delegates to the (already-implemented) PgErasureStore. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add pino logger with test-silent default, per-request x-request-id middleware that logs method/path/status/ms on completion, and route all apps/api console.* calls (events/placements catch blocks, app onError, index boot, webhooks dispatcher/scheduler) through it.
Serves GET /v1/openapi.json (no auth required, registered before the
rate-limit/auth middleware) with a document built once at module load
from @promocean/contracts schemas via zod v4's z.toJSONSchema(schema,
{ target: 'openapi-3.0' }).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add @promocean/sdk and @promocean/widgets READMEs (install, quickstart, error handling, SSR/security notes), an API surface table to the root README (method/path/auth/purpose plus rate-limit and origin-allowlist behavior), and replace the demo/cms boilerplate READMEs with pointers to the root README. Closes out the Sprint 4 / MVP docs task. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds GET /readyz (optional AppDeps.readiness, 3s-timeout Promise.allSettled checks for db and config plane, 503 naming failing checks) as the last missing MVP artifact from spec §5b. Also pre-serializes the OpenAPI document once at module scope and serves it with cache-control headers instead of re-stringifying it on every request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements the Sprint 4 plan (
docs/superpowers/plans/2026-07-07-sprint-4-polish.md) — the final MVP sprint, closing the spec's remaining §3.4/§4.4/§5b items:RATE_LIMIT_PER_MINUTE), origin allowlist enforcement for publishable keys (project-levelallowedOrigins, browser-defense documented), andDELETE /v1/users/:userIdGDPR erasure — transactional across all four runtime tables (MAU retained by design, test-locked) and the first secret-key-only endpointAuthContextfield-by-field with runtime validation onallowedOrigins(the blanketascast is gone)x-request-idon every response; zeroconsole.*left inapps/api/src), plus/readyzwith DB + config-plane checksz.toJSONSchema), served auth-free and cached atGET /v1/openapi.json— all six endpoints documented@promocean/sdkand@promocean/widgets, API-surface table in the root READMETest plan
Review notes
Eight tasks through the full gate cycle plus a final whole-branch review — verdict: ready to merge, with the MVP completeness checklist confirmed closed (the one silently-dropped spec artifact,
/readyz, was added in23197ed). Follow-ups filed: #10 (rate-limiter memory hardening), #11 (fast-follow polish), #2 cross-referenced with the erasure transaction as its implementation template. Deliberately deferred pending your decisions: hosting/deploy and Sentry (needs a DSN).🤖 Generated with Claude Code