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)
- Log ind på platform-admin (
/admin) — kræver Platform Admin-rolle - Gå til Tenants → + Ny tenant
- 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. - Display name — det navn der vises i admin-headeren + på offentlige sider hvor det er relevant. Kan ændres senere.
- Site type — hvilken kategori af site er det:
artist_portfolio— kunstner/fotograf/skribent med gallerier + about + kontaktriding_club— forening med news + members + sponsors + tournamentsdocs— docs-style site (clean typography, prose-fokus — bruges af TesseraCMS selv)
- Layout package — hvilken visuel pakke skal site bruge. Forudfyldes med default for valgt site-type:
artsite-classicfor artist_portfolioriding-club-classicfor riding_clubdocs-classicfor docs
- 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:
- Opretter Tenants-row med slug, displayName, siteType, layoutPackage, status
- Aktiverer alle moduler som layout-package'en kræver (fx artsite-classic kræver
pages,media,images,forms,mail,branding,navigation,art) - Seeder default slot-fillers (fx brand i header, copyright-snippet i footer) — tomme placeholders som Tenant Owner senere fylder
- Seeder default-rollup-layouts (artist-portfolio sætter default gallery-layout som responsive grid)
- 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.
- Stadig på
/admin/tenants/<slug>(eller/admin/users→ tenant-tab) - + Inviter bruger → indtast email-adresse (kan være intern AAD-bruger eller ekstern B2B-gæst)
- Vælg Tenant Owner-rolle
- Send invitation
- 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:
/admin/tenants/<slug>→ Site config-fanen- Status:
draft→active - 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
- Azure Portal → Container App (
tesseracms) → Custom domains - Add custom domain → indtast domain-navn
- Følg Azure's verification-flow (CNAME-record eller TXT-record som DNS-provider skal sætte)
- Vælg/genkør certificate-binding (Azure leverer free managed cert via Let's Encrypt)
- Bekræft hostname er bound
Registrér domain i Tenants-row
/admin/tenants/<slug>→ Site config → Custom domains- Tilføj domain (
pallejacobsen.dk) - Gem
- 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