10 — Website Factory: delt applikation med D1 pr. kunde
Status: DISKUSSIONSOPLÆG — ingen beslutning truffet
Konsolideret 2026-09-07 fra arkitektur v1.4, udviklingsplan v1.0 og det reviewede v2.1-artifact. Dette er det nye samlede oplæg for produktlinje B. Dokumenternes egne betegnelser som »besluttet« er ikke overført til repoets ADR-log. Der er ikke bygget eller provisioneret en fabrik som del af denne dokumentationsopdatering.
Formål og afgrænsning
Første produkt er en website-service, som Allan og Danny administrerer for kunderne: én branche, én genanvendelig skabelon og et henvendelsesmodul. Frisører er en arbejdshypotese for første branche. Kunden får sit eget indhold, branding og domæne; applikationskoden deles.
Operatøren opretter kunden, redigerer indhold, viser preview, godkender en bestemt version og publicerer. Selvbetjeningseditor, bookingmotor, webshop, domænesalg og automatisk fakturering indgår ikke i det foreslåede første produkt. Se udviklingsplanen.
Fast ramme fra repoet: MobilePay til engangsbetaling og recurring er fortsat ufravigeligt. Manuel pilotfakturering ændrer ikke kravet; den konkrete betalingsgang skal afklares før salg. Modulpriser, abonnementspakker og leverandørvalg for betaling er fortsat åbne.
Foreslået teknisk grundlag
| Del | Forslag | Konsekvens |
|---|---|---|
| Applikation | Én Next.js/TypeScript-applikation på Cloudflare Workers | Offentlige websites og intern administration deler kode og runtime |
| Platformdata | Én D1-database pr. miljø | Kunder, medlemskaber, verificerede domæner, databaseoversigt og jobs |
| Kundedata | Én D1-database pr. kunde pr. miljø | Indhold, publicerede versioner, moduler og private henvendelser |
| Databaseadgang | Native D1-bindings med serverstyret register | Nye kunder kræver en fælles konfigurationsudgivelse |
| Medier | R2 med ejerskab og adgangskontrol | Private kladdebilleder må ikke udstilles som offentlige filer |
| Udgivelser | GitHub Actions og adskilte miljøer | Staging og produktion bruger forskellige databaser og credentials |
| AI | Afgrænsede kladdeoperationer efter manuel pilot | Samme validering som manuelle ændringer; menneskelig publiceringsgodkendelse |
Den aktuelle Next.js-integration skal bevises i staging. Artifactets påstande om en bestemt adapters status overføres ikke som et verificeret valg. D1-forslaget erstatter ikke Postgres som mulighed for produktlinje A.
C4: kontekst og containere
Diagrammerne viser forslaget, ikke en eksisterende deployment. En C4-container er en eksekverbar eller lagrende del, ikke nødvendigvis en Docker-container. Kilden er LikeC4-modellen.


Adgangsgrænsen
En almindelig forespørgsel mod A's database læser ikke B's separate database. Men den fælles Worker har adgang til alle sine bindings og kan vælge forkert. Database pr. kunde beskytter derfor ikke alene mod fejl i routing eller kompromittering af den fælles runtime.
D1-bindings bruges fra Workerens miljø og tilbyder databaseoperationer. De er ikke PostgreSQL-roller med tabelrettigheder. Betegnelsen »INSERT-only« gælder kun en tilladt applikationsoperation, aldrig en garanti fra bindingen. D1 API.
| Adgang | Kontrol i applikationen |
|---|---|
| Besøgende | Verificeret aktivt hostname → tilladt binding → kun publiceret indhold |
| Henvendelsesformular | Kunde udledes fra websitet; validerede felter, parameteriseret SQL og misbrugsbegrænsning |
| Administration | Login og kundeadgang kontrolleres før valg af kundedatabase |
| Preview | Kræver adgangskontrol; noindex er kun en instruktion til søgemaskiner |
| Agent | Fast kunde, begrænsede kladdeoperationer; ingen SQL, betalingsadgang eller private henvendelser |
Ukendte domæner og manglende eller inkonsistente bindings afvises uden fallback til en anden kunde. Klienten må ikke angive et bindingsnavn eller database-id som autorisation. Individuelle konti, MFA og passende beskyttelse mod CSRF indgår i administrationsløsningen.
Datamodel og onboarding
| Placering | Centrale data |
|---|---|
| Platform | customers, memberships, domains, tenant_registry, provisioning_jobs, aftaleversioner og minimal audit |
| Kunde | tenant_identity, site_settings, content_versions, published_content, module_settings, form_submissions, outbox og migrationshistorik |
tenant_identity indeholder uforanderligt kunde- og miljø-id. tenant_registry forbinder kunden
med den forventede binding og skemaversion. Alle kundedatabaser bruger samme migrationsserie.
Rettighed til et modul, aktivering og gyldig konfiguration gemmes som tre adskilte forhold.
Foreslået onboarding:
- Opret en afventende kunde og et job med nøgle til sikker gentagelse.
- Opret kundedatabasen gennem den betroede provisioneringsproces.
- Kør migrationer og registrér kundeidentitet.
- Generér bindingskonfiguration fra betroede metadata.
- Udgiv konfigurationen med den godkendte applikationsversion.
- Kontrollér nye og eksisterende kunders identitet, schema og routing.
- Aktivér først kunden, når kontrollerne består.
Konfigurationsudgivelser køres i rækkefølge, så samtidige onboardinger ikke overskriver hinandens bindings. Rollback skal bevare aktive kunders bindings eller eksplicit suspendere de berørte kunder. Migrationer hører til provisionering/CI, ikke almindelige sidekald. Management-credentials ligger uden for den offentlige applikationsruntime.
Publicering og cache
Indhold følger kladde → validering → beskyttet preview → menneskelig godkendelse → publicering. Godkendelsen gælder et uforanderligt indholdssnapshot; en ændring opretter en ny version.
Publiceringskontrol, indhold, versionsreference og outbox-post skal gemmes sammen i kundens database.
D1 batch() samler SQL-operationer i en transaktion og ruller tilbage ved fejl i en sætning.
En betinget opdatering med nul ramte rækker er dog ikke automatisk en fejl: efterfølgende
publiceringsskrivninger skal også være beskyttet. D1 batch.
En transaktion på tværs af platformdatabase, kundedatabase og eksterne tjenester må ikke antages. Outbox-jobs får atomisk overtagelse, tidsbegrænset reservation, sikre gentagelser og synlige fejl. Platformens status afstemmes efterfølgende. Ved usikkert eksternt resultat undersøges leverandørens status før gentagelse; en lokal unik nøgle beviser ikke, at en ekstern faktura kun er oprettet én gang.
Cache-nøgler indeholder miljø, website, sti og indholdsversion. Kun godkendt offentligt indhold må cachelagres offentligt. Det kan omfatte godkendte navne og billeder; kladder, private henvendelser, kontodata og tokens må aldrig følge med. Backend kontrollerer aktuelle rettigheder og modulstatus, selv om en besøgende stadig ser en gammel cachet side.
Drift og datahensyn før pilot
EU-jurisdiktion for D1 vælges ved oprettelsen og kontrolleres i returnerede metadata. Et placeringsønske (location hint) er ikke det samme. Databaseplacering dokumenterer ikke EU-only behandling af hele tjenesten. D1 dataplacering.
Roller som dataansvarlig og databehandler vurderes pr. formål og relation; de afgøres ikke af, hvilken database oplysninger ligger i. Aftaler, leverandører og faktiske datastrømme skal gennemgås. Datatilsynet om rollefordeling.
Før rigtige henvendelser skal følgende demonstreres:
- Opbevaringsfrister pr. formål, automatisk udløb og fejlrapportering.
- Autoriseret eksport af relevante data og filer uden andre kunders oplysninger.
- Offboarding, der stopper trafik og jobs før bindings og ressourcer fjernes.
- Minimalt slettebevis uden for databasen, der slettes; årsag kan være udløb, anmodning eller offboarding.
- Restore på isolerede testdata med korrekt kundeidentitet og genanvendelse af sletteafgørelser.
- Overvågning, hændelsesansvar, begrænset supportadgang og dataminimering i logs.
Time Travel skal vurderes mod de aftalte mål for datatab og gendannelsestid. En restore-øvelse må ikke køres destruktivt mod produktion. Sletning af levende rækker betyder ikke øjeblikkelig sletning fra gendannelseshistorik. Time Travel.
Omkostninger og åbne valg
Budgettet omfatter Workers-trafik og CPU, D1-rækker og lagring, R2, domæner, AI, CI, kommunikation, betaling og arbejdstid. D1 er forbrugsafregnet; én database pr. kunde er ikke en separat serverleje. Cache kan reducere databasearbejde uden at fjerne prisen for requests, der kører Worker-kode. Artifactets platformsubtotal bruges derfor ikke som et samlet driftsbudget.
Åbne valg spores i de eksisterende temaer:
- Platform og hosting #17: Workers-integration, domæner og preview.
- Data og backend #18: D1, bindings, gendannelsesmål og isolationskrav.
- Moduler og CMS #19: første skabelon, redigering og modulrettigheder.
- Billing og betaling #20: MobilePay, pakker, domænesalg og senere fakturering.
- Overdragelse og jura #21: ejerskab, eksport, retention og leverandørforhold.
- AI og intern drift #22: agentleverandør og driftsansvar.
Kilder
Primærkilder for de overførte D1-, pris- og rolleoplysninger verificeret 2026-09-07. Ingen præcise priser, kapacitetsløfter eller registrarfrister er overført som gældende tal.
- Kildegrundlag og redaktionelle valg — de tre vedhæftede dokumenter og artifactet.
- Cloudflare: D1 API.
- Cloudflare: D1 dataplacering.
- Cloudflare: D1-priser.
- Cloudflare: Workers-priser.
- Cloudflare: Time Travel.
- Datatilsynet: rollefordeling.