Commit Graph

6 Commits

Author SHA1 Message Date
saravanakumardb1
42c63dcc6e feat(platform): product ownership + owner-scoped "my projects" + tenant guard
Foundation for a generic, multi-tenant platform (any developer, not just the
built-in products).

- Products carry an optional ownerId (set on create + auto-register), so a
  product has a tenant. GET /products/mine returns the caller's owner-scoped
  list; admins/super_admins see all. productsForUser() is pure + unit-tested.
- requireProductAccess(): a flag-gated tenant authorization guard
  (FLEET_TENANT_ENFORCEMENT, default OFF). OFF = byte-for-byte current behavior;
  ON = a non-admin may only act on products they own (others -> 403; owner-less
  legacy products keep a grace allowance until migrated). Fleet routes now
  resolve productId through it in place of getRequestProductId.

ownerId is additive/optional; enforcement is off by default, so this is a
no-op for existing deployments until explicitly enabled.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-06-01 16:47:05 -07:00
saravanakumardb1
1fe1e75999 feat(platform-service): auto-registration on first request (Phase 4.1) — 8 tests
Zero-touch product provisioning: when a request arrives with an unknown
productId and a valid JWT, auto-create a minimal ProductDoc instead of
rejecting. Enables new products to use platform-service immediately.

- auto-register.ts: auto-create ProductDoc with sensible defaults
- Rate limited: max 10 auto-registrations per minute
- Requires valid JWT (unauthenticated requests still rejected)
- Audit logged as product.auto_registered
- request-context.ts: exported extractProductIdAsync with auto-register
- 8 tests: register, duplicate, format validation, rate limit
2026-03-19 22:00:57 -07:00
saravanakumardb1
18a5b342d9 fix(request-context): block sunset products in public productId resolver 2026-02-16 23:45:17 -08:00
saravanakumardb1
c7480661eb fix(waitlist): harden public endpoints and unsubscribe validation
- Block sunset products on public waitlist join/count/config endpoints
- Verify unsubscribe email matches unsubscribeToken before status change
- Keep idempotent join behavior explicit for existing entries (200 path)
- Escape CSV newline/carriage-return values to prevent malformed exports
- Refactor request productId extraction to shared helper in request-context
- Guard prelaunchConfig merge with safe default object in products update route
2026-02-16 23:28:32 -08:00
saravanakumardb1
66e657a646 feat(products): extend product status lifecycle + prelaunch config
- Add 6 product statuses: draft, pre_launch, beta, active, sunset, disabled
- Add PrelaunchConfig with customFields, CAPTCHA, tagline, maxSignups
- Add isValidStatusTransition() helper for safe status changes
- Update getRequestProductId() to block draft/sunset/disabled
- Add getRequestProductIdForPublic() for pre_launch waitlist routes
- Add status transition validation to product update route
- Add PRE_LAUNCH_SIGNUP_SYSTEM.md design doc with full roadmap
2026-02-16 22:36:53 -08:00
saravanakumardb1
365061566a feat(platform-service): add getRequestProductId() + getRequestProductConfig() helpers
- New lib/request-context.ts with product validation against cache
- Priority: JWT payload > X-Product-Id header > env var fallback
- Rejects unknown or disabled products with 400 Bad Request
- Augments FastifyRequest with jwtPayload type declaration
- getRequestProductConfig() for modules needing product-specific values
2026-02-15 14:14:17 -08:00