managarten/packages/shared-branding/src/spaces.ts
Till JS 166d6c6ffb feat(spaces): validate space metadata on Better Auth organization hooks
Moves the canonical SpaceType + SPACE_MODULE_ALLOWLIST to @mana/shared-types
(framework-free) so the Bun services can consume them without pulling in
Svelte. shared-branding keeps only the UI-facing labels and descriptions
and re-exports the canonical types for frontend convenience.

Wires two Better Auth organization hooks in mana-auth:
- beforeCreateOrganization asserts metadata.type is a valid SpaceType,
  rejecting the create with a BAD_REQUEST otherwise.
- beforeDeleteOrganization rejects deletion of the personal space.

Covered by bun tests (11 assertions) for the helper module.

No migration and no schema change — type lives in the existing
organization.metadata jsonb column.

Plan: docs/plans/spaces-foundation.md

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

63 lines
2 KiB
TypeScript

/**
* Space — UI-facing labels and descriptions
*
* The canonical type/allowlist definitions live in `@mana/shared-types`
* (framework-free so Bun services can import them). This file adds only
* the i18n strings that belong to the UI branding layer.
*
* See docs/plans/spaces-foundation.md for the full RFC.
*/
import type { SpaceType } from '@mana/shared-types';
export const SPACE_TYPE_LABELS = {
de: {
personal: 'Persönlich',
brand: 'Marke',
club: 'Verein',
family: 'Familie',
team: 'Team',
practice: 'Praxis',
},
en: {
personal: 'Personal',
brand: 'Brand',
club: 'Club',
family: 'Family',
team: 'Team',
practice: 'Practice',
},
} as const satisfies Record<'de' | 'en', Record<SpaceType, string>>;
export const SPACE_TYPE_DESCRIPTIONS = {
de: {
personal: 'Dein eigener Bereich — wird beim Signup automatisch angelegt.',
brand: 'Externe Kommunikations-Identität (z.B. eine Marke, ein öffentlicher Account).',
club: 'Vereinsverwaltung mit Mitgliedern, Beiträgen und Events.',
family: 'Geteilter Bereich für Haushalt, Familie oder WG.',
team: 'Arbeitsteam oder Projekt mit mehreren Mitwirkenden.',
practice: 'Freelancer- oder Solo-Business mit Kunden und Rechnungen.',
},
en: {
personal: 'Your own space — created automatically at signup.',
brand: 'External communication identity (e.g. a brand, a public account).',
club: 'Club management with members, dues, and events.',
family: 'Shared space for household, family, or flatshare.',
team: 'Work team or project with multiple collaborators.',
practice: 'Freelancer or solo business with clients and invoices.',
},
} as const satisfies Record<'de' | 'en', Record<SpaceType, string>>;
// Re-export canonical types from shared-types so frontend consumers can
// import everything space-related from `@mana/shared-branding` for
// convenience.
export {
SPACE_TYPES,
SPACE_MODULE_ALLOWLIST,
isModuleAllowedInSpace,
isSpaceType,
parseSpaceMetadata,
type SpaceType,
type SpaceModuleId,
type SpaceMetadata,
} from '@mana/shared-types';