- **Per-organization seed-data clone for new signups** (`@objectstack/plugin-security`) — In multi-tenant mode, when a user signs up after the very first user (whose org gets the seed via `claimOrphanTenantRows`), SecurityPlugin now copies the platform-first organization's user-defined data into the new user's personal workspace via `cloneTenantSeedData()`. Without this, every user-after-the-first landed on an empty dashboard — multi-tenant isolation is correctly enforced, so seed rows owned by the first org are filtered out by RLS for everyone else. Implementation: two-pass strategy — pass A inserts shallow row copies (lookup field values left as donor's old IDs) under the new `organization_id` and records `oldId → newId` per object; pass B walks each cloned record's lookup fields and rewrites values via the per-object remap so intra-clone foreign keys (e.g. `opportunity.account → account.id`) stay intact without needing topological insert ordering. Skips computed/virtual field types (`formula`, `summary`, `autonumber`) that have no underlying SQL column. Disambiguates `unique: true` columns with a per-tenant `clone-<orgsuffix>-` prefix so global UNIQUE indexes (e.g. `lead.email`) don't collide. Idempotent per-object — if the target org already has any row in an object, that object is skipped. Donor org is the oldest `sys_organization`. Best-effort: a per-object failure is logged at `warn` and never blocks signup. Wired via DI hook in `ensureUserHasOrganization` so the security plugin owns the policy and the helper stays unit-testable. Verified end-to-end with `pnpm dev:crm`: 2nd registered user gets 3 leads, 5 accounts, 4 opportunities, 5 campaigns, 4 products, 5 tasks, 2 cases, 1 contract cloned into their personal workspace.
0 commit comments