managarten/services/mana-auth/src/spaces/index.ts
Till JS da1bb2d6e9 feat(spaces): auto-create personal space on signup via Better Auth hook
Wires databaseHooks.user.create.after to call createPersonalSpaceFor,
which provisions a Better Auth organization of type='personal' with the
user as owner. Every signup now produces a usable default space — no
UI code needed to bootstrap it.

Details:
- Slug derived from email local-part, lowercase, alphanumerics + hyphens,
  max 30 chars, random fallback if nothing usable remains.
- Reserved-slug list (me/admin/api/auth/…) blocks system-route clashes.
- Collision resolver appends -2, -3, … up to 999 before falling back to
  a random suffix. Tests cover both the DB-taken and reserved-slug cases
  via an injectable SlugTakenLookup (no DB needed for unit tests).
- Idempotent: if a personal space already exists for the user, returns
  it instead of creating a duplicate. Guards against retry double-signup.
- Failure propagates — an orphan user without a personal space is worse
  than a retry-able signup error.

Existing dev users will need a backfill or a re-provisioning of the dev
DB — new users are unaffected.

12 tests pass (23 total across the spaces module).

Plan: docs/plans/spaces-foundation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:10:26 +02:00

23 lines
586 B
TypeScript

/**
* Spaces — multi-tenancy helpers for mana-auth.
*
* The canonical SpaceType + allowlist lives in @mana/shared-types. This
* barrel adds auth-side concerns: Better Auth hook helpers for validating
* organization metadata, and (future) slug generation for personal spaces.
*
* See docs/plans/spaces-foundation.md.
*/
export {
assertValidSpaceMetadataForCreate,
assertSpaceIsDeletable,
buildSpaceMetadata,
} from './metadata';
export {
createPersonalSpaceFor,
candidateSlugFromEmail,
resolveUniqueSlug,
dbSlugTaken,
type SlugTakenLookup,
} from './personal-space';