Files
suaveplan/openspec/changes/enterprise-api-plugin-tenant/tasks.md
2026-05-27 23:29:53 +01:00

3.1 KiB

Tasks: enterprise-api-plugin-tenant

Change ID: enterprise-api-plugin-tenant Package: @suaveplan/api-plugin-tenant Target path: api/auth/api-plugin-tenant Prerequisite packages on Verdaccio: @suaveplan/api, @suaveplan/api-shared, @suaveplan/api-plugin-auth, @suaveplan/api-plugin-database, @suaveplan/feature-flags, @suaveplan/audit-logging, @suaveplan/events, @suaveplan/rate-limiter, @suaveplan/error


0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create directory with all subdirs; package.json v0.0.0, "sideEffects": ["src/events.ts"]; tsconfig.json + vitest.config.ts; standard scripts.

2. Types, errors, events

  • Types: Tenant, TenantMember, TenantInvite, TenantSettings, TenantPluginConfig (Zod).
  • Errors: 6-code TenantErrorCode union + metadata + registration. Test + doc.
  • Events: TenantEventMap module augmentation (tenant:created, tenant:suspended, tenant:deleted, tenant:member:invited, tenant:member:removed).

3. SurrealQL

  • surql/tenant.surql, tenant_member.surql, tenant_invite.surql, tenant_settings.surql.

4. TenantService

  • All 11 methods from proposal.
  • suspendTenant / deleteTenant: emit events + write audit entries.
  • inviteMember: generate signed token (expires 72 h); send email via plugin context service injection.
  • Per-tenant feature flag overrides: getSettings returns featureFlags map; FlagManager reads these on tenant context.
  • OTel span per method.
  • .test.ts (all methods, error cases) + .md.

5. Routes

  • POST /tenants, GET /tenants/:id, PATCH /tenants/:id, DELETE /tenants/:id, POST /tenants/:id/suspend.
  • /tenants/:id/members — list, invite, accept-invite, remove.
  • /tenants/:id/settings — get, update.
  • All behind requireAuth() + appropriate requireRole.
  • Rate limiting + idempotency on mutations.
  • Route .test.ts + .md.

6. Plugin factory + integration tests + publish

  • createTenantPlugin: definePlugin, dependencies: ["database", "auth"], migrationsPath: "./surql".
  • Integration: create tenant → invite member → accept invite → list members → remove (real SurrealDB).
  • bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-tenant — green; 100% coverage.
  • bun scripts/publish.ts --package @suaveplan/api-plugin-tenant.
  • Archive → openspec/archive/2026-04-24-enterprise-api-plugin-tenant/.