Onboard ny tenant

1. Onboard ny tenant

Når en ny kunde eller intern entitet skal have sit eget TesseraCMS-site, opretter du en ny tenant. En tenant er fuldt isoleret: egen data, egen brugere, egne uploads, egne menus. Tenants deler kode-base og Azure-infrastruktur men ser hinanden aldrig.

Der er to provisioning-flows: wizard-flowet (anbefalet, UI-baseret) og CLI-flowet (når wizarden ikke kan, eller for bulk-onboarding).

Wizard-flowet (/admin/tenants/ny)

  1. Log ind på platform-admin (/admin) — kræver Platform Admin-rolle
  2. Gå til Tenants+ Ny tenant
  3. Tenant slug — kort, lowercase, snake_case eller hyphen-case. Bruges i URL'er (/<slug>) og PartitionKey i storage. Eksempler: palle_jacobsen, nyborg_rideklub, acme_corp. Kan ikke ændres senere uden migration.
  4. Display name — det navn der vises i admin-headeren + på offentlige sider hvor det er relevant. Kan ændres senere.
  5. Site type — hvilken kategori af site er det:
    • artist_portfolio — kunstner/fotograf/skribent med gallerier + about + kontakt
    • riding_club — forening med news + members + sponsors + tournaments
    • docs — docs-style site (clean typography, prose-fokus — bruges af TesseraCMS selv)
  6. Layout package — hvilken visuel pakke skal site bruge. Forudfyldes med default for valgt site-type:
    • artsite-classic for artist_portfolio
    • riding-club-classic for riding_club
    • docs-classic for docs
  7. Status: draft (default) — tenanten oprettes men er ikke synligt offentligt. Du kan slå om til active når content + Tenant Owner er klar.

Hvad sker der under hood

Wizarden kalder seedTenantFromPackage(slug, packageId) der atomart:

  1. Opretter Tenants-row med slug, displayName, siteType, layoutPackage, status
  2. Aktiverer alle moduler som layout-package'en kræver (fx artsite-classic kræver pages, media, images, forms, mail, branding, navigation, art)
  3. Seeder default slot-fillers (fx brand i header, copyright-snippet i footer) — tomme placeholders som Tenant Owner senere fylder
  4. Seeder default-rollup-layouts (artist-portfolio sætter default gallery-layout som responsive grid)
  5. Seeder default-page-blocks (artist-portfolio sætter default forside-blocks som Hero + AboutRollup + ContactSection)

Resultatet: en tenant der er rendrebar fra start uden manuel konfig. Du kan straks besøge /<slug> og se en placeholder-version.

Tildel første Tenant Owner

Når tenanten er oprettet, skal mindst én Tenant Owner tildeles — ellers kan ingen administrere den.

  1. Stadig på /admin/tenants/<slug> (eller /admin/users → tenant-tab)
  2. + Inviter bruger → indtast email-adresse (kan være intern AAD-bruger eller ekstern B2B-gæst)
  3. Vælg Tenant Owner-rolle
  4. Send invitation
  5. Brugeren modtager invite-mail og accepterer (eller logger ind hvis de allerede er i AAD)

Vigtig regel: når der ER mindst én Tenant Owner, kan du fjerne dig selv som Platform Admin fra deres dag-til-dag admin-flows. Du kan altid genvinde adgang via /admin-niveauet — det er det smukke ved separation-of-roles.

Aktivér tenanten

Når Tenant Owner har bekræftet adgang og lavet basale content-ændringer (logo, forside-tekst, navigation), kan du flippe status:

  1. /admin/tenants/<slug>Site config-fanen
  2. Status: draftactive
  3. Gem

Nu er /<slug>-URL'en offentligt tilgængelig. Hvis du ikke har custom domain, er det https://<platform-host>/<slug>. Søgemaskiner indekserer aktive tenants.

Custom domain

De fleste kunder vil have deres eget domain (pallejacobsen.dk i stedet for tesseracms.bravemeadow-XXX.azurecontainerapps.io/palle_jacobsen).

Tilføj domain til Container App

  1. Azure Portal → Container App (tesseracms) → Custom domains
  2. Add custom domain → indtast domain-navn
  3. Følg Azure's verification-flow (CNAME-record eller TXT-record som DNS-provider skal sætte)
  4. Vælg/genkør certificate-binding (Azure leverer free managed cert via Let's Encrypt)
  5. Bekræft hostname er bound

Registrér domain i Tenants-row

  1. /admin/tenants/<slug>Site configCustom domains
  2. Tilføj domain (pallejacobsen.dk)
  3. Gem
  4. Når en request kommer ind på det domain, slår middleware'n PartitionKey'en op via customDomains-feltet og router til den korrekte tenant

Gotcha: domain skal være tilføjet både Azure Container App og Tenants-rowen. Hvis kun den ene er sat, får du enten 502 (ACA mangler binding) eller default-redirect til /tesseracms (Tenants-table mangler entry).

CLI-flowet (alternativ)

Når wizarden ikke duer (bulk-onboarding, scripted demo-environments, restore fra backup), kør CLI'en:

npx tsx scripts/seed-tenant-from-package.ts <slug> <package-id> [--local] [--dry-run] [--force]

Eksempler:

# Dry-run mod Azurite — vis hvad der ville ske
npx tsx scripts/seed-tenant-from-package.ts margit_jacobsen artsite-classic --local --dry-run

# Apply mod prod
npx tsx scripts/seed-tenant-from-package.ts margit_jacobsen artsite-classic

# Reset eksisterende tenant til package-defaults (overskriver slot-fillers!)
npx tsx scripts/seed-tenant-from-package.ts nyborg_rideklub riding-club-classic --force

CLI'en bruger samme seedTenantFromPackage()-funktion som wizarden, så outcome er identisk.

Common pitfalls

  • Glemt at oprette Tenant Owner — sitet er aktivt men ingen kan administrere det. Wizarden burde påminde om dette i v2.
  • Custom domain sat i kun ét sted — se gotcha ovenfor; tjek altid begge places
  • Forkert site-type valgt — kan ikke trivielt ændres. Hvis du har forkert, opret en ny tenant og restore content fra backup
  • Brugte slug der allerede findes — wizarden vil afvise; vælg en anden slug eller delete den eksisterende først (/admin/tenants/<slug> → Danger zone)
  • Tenant aktiveret før Tenant Owner har testet — public site er live men measure-tools (analytics, Search Console) reportere indtryk på ufærdig content; planlæg aktivering til efter Tenant Owner har testet basal flow