ubiquitous-invention/plans/Plan-multitenant-saas-hardening/Plan-multitenant-saas-hardening.md
Randall Stillwell 778fe1d321 plans: scaffold daily-driver-finish, saas-hardening, agent-coordination
Three new plan trees that fill in the gaps surfaced during repo review.
Together they map out what remains between the current scaffold-with-stubs
state and a daily-usable, multitenant, agent-coordinated app.

* Plan-daily-driver-finish (P0): turn stubs into real data. Five tasks
  covering the lint/shared-types breakage, hardcoded dashboard mocks,
  AI-page setTimeout placeholder, post-signin landing decision, and a
  cross-browser collab smoke test against the deployed Hocuspocus
  instance.

* Plan-multitenant-saas-hardening (P1): everything multitenant needs
  beyond what Plan-multitenant-cursor-sync already covers. Invites and
  role management, soft-delete + append-only audit log, rate limits on
  the auth + mutation hot paths, and a Vitest + GitHub Actions test
  foundation so PRs can't ship red.

* Plan-agent-coordination (P2): the layer that makes a Task-*.md
  runnable, not just readable. Adds workflow_prompt with task -> epic
  -> plan inheritance, an agent_runs table for auditable sessions, and
  two new MCP tools (claim_task / complete_task) that replace the
  freeform update_object composition agents do today. Includes an
  intentionally-deferred Epic-optional-orchestrator that captures the
  Symphony-shaped runner as a decision point rather than an immediate
  build.

Each task is bead-scale (one focused Cursor session) with explicit
in-scope, out-of-scope, and anti-goal sections so a future agent can
pick up a single Task-*.md and start without scrollback context.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-01 23:52:22 -05:00

3.2 KiB

kind slug title status priority tenant_id cursor_plan_id updated_at
plan multitenant-saas-hardening Multitenant SaaS hardening — invites, audit, guardrails, test foundation ready P1 global null 2026-06-01

Plan overview

Plan-multitenant-cursor-sync covers the Cursor sync layer slice of multitenancy. This plan covers the rest: the operational hardening needed before Echodo can be safely used as a real multitenant SaaS rather than a homelab single-tenant app.

The unifying theme is tenant blast-radius — what's the worst thing a tenant (or a bug operating on behalf of a tenant) can do, and how do we cap it? Today the answer is "we don't really know," because there's no invite flow, no audit log, no rate limit, and no test runner.

Objectives and success criteria

  • A workspace owner can invite, role-change, and remove members from the app UI.
  • Every mutation against a tenant-scoped table is recorded in an append-only audit log with actor user id, action, and target.
  • Workspaces support soft-delete (archive) without losing data, and restore.
  • Public mutation endpoints have rate limits that survive a brute-force attempt against credentials sign-in.
  • pnpm test runs Vitest across the workspaces that have tests, and a minimal GitHub Actions CI runs lint + type-check + test on PRs.

Scope and boundaries

In scope

  • Invite + role management (DB + UI + tRPC).
  • Audit log table, write path, minimal read view.
  • Workspace soft-delete and restore.
  • Rate-limiting middleware on critical mutations.
  • Vitest bootstrap + GitHub Actions CI.

Out of scope (this plan)

  • Billing / Stripe (a separate plan when there's actual revenue to charge for).
  • SSO group-based role mapping (Authentik groups → workspace roles). Defer until manual invites are in.
  • Full SOC2 audit posture. The audit log here is a foundation, not a compliance artifact.

Cross-team collaborators

Name / group Role
Solo operator (you) Everything.

Epics

Epic Link
Tenant lifecycle ./Epic-tenant-lifecycle/Epic-tenant-lifecycle.md
Test foundation ./Epic-test-foundation/Epic-test-foundation.md

Metrics and milestones

Milestone Target Metric
Invites shipped M1 Owner can invite a new email and the recipient can accept and land in the workspace.
Audit visibility M2 Every mutation on objects / workspaces / workspace_members produces an audit row with actor_user_id.
Guardrails live M3 Brute-forcing credentials sign-in is rate-limited at the route handler.
CI green on PRs M4 A PR with pnpm lint && pnpm type-check && pnpm test failing cannot merge.

Risks and mitigations

Risk Mitigation
Soft-delete semantics get confused with hard-delete One column (archived_at timestamp); every workspace-scoped query adds archived_at IS NULL by default. No new "is_deleted" boolean.
Audit log becomes a write-amplification problem Single append-only table with a partial index on workspace_id, created_at. Don't denormalize until you measure.
Vitest adoption stalls Start with packages/database and packages/shared only. Don't try to test React components in v1.