You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Vi behöver bygga en workflow som bygger färdiga containers i ett GitHub Actions workflow för detta projekt, sen startar upp de i podman compose och kör Playwright tester mot dem genom att använda en session cookie (som befintliga integrationstester gör).
Vi ska ha 4 separata containrar i en intern podman network, en för nginx, en för appen, en för sql server och en för keycloak. Vi ska terminera TLS på nginx reverse proxy och använda certifikat som genereras i workflow så att Playwright kan kommunicera säkert med appen. Nginx, Application, Keycloak och sql server ska ha konfiguration externt så att de inte behöver byggas om varje gång.
Alla containers ska byggas i workflow och pushas till GitHub Container Registry, och sedan användas i podman compose. Vi ska använda versioner i container taggarna så att vi kan ha kontroll över vilka versioner som används i testerna och som vi gör release på. Utvärdera om npm changeset är rätt verktyg för versionshantering och release notes eller det finns bättre verktyg för detta ändamål. Versionen vore också bra om den kan användas i Playwright testerna så att vi kan logga vilken version som testas, samt om vi kan få in den i appen så att den kan visas om man hovrar över titeln i header.
Det är också viktigt att använda minimum image, minimum konfiguration och low privilege när container byggs för att minimera attackytan. Vi ska också bara ha med produktionskod i containern och inte lint-verktyg, utvecklingsverktyg, dokumentation eller testkod och all konfiguration runt det.
Alla containrar ska ha konfiguration externt så att de inte behöver byggas om varje gång, och vi ska använda en intern podman network för att kommunicera mellan dem. Vi ska också terminera TLS på nginx reverse proxy och använda certifikat som genereras i workflow så att Playwright kan kommunicera säkert med appen. Konfigurationen ska vara minimal för det som behövs för respektive container en containers konfiguration ska inte innehålla konfiguration för andra containrar, så att de kan byggas om och startas om oberoende av varandra.
Databasen som används ska vara persistent och inte försvinna när containern startas om, så vi ska använda en extern databas som sql server som körs i en separat container.
Idag finns test seed data som används vid utveckling tillsamman med data som krävs för att köra appen (det måste finnas motsvarande även imorgon som stöd vid utveckling där utvecklare kan skapa test data för ny funktionalitet). Men vi behöver separera nödvändig databas data som kan laddas in separat från övrig test data, övrig test data som ska vara frivillig, t.ex. behövs kanske övrig test data för att köra integration testerna för produktionsflödet eller om en användare vill sätta upp en PoC av appen.
Vi ska också ha en separat container för keycloak som körs i samma interna nätverk så att vi kan testa autentisering och auktorisering i en miljö som liknar produktion, genom att använda en session cookie (som befintliga integrationstester gör).
Detta dokument beskriver den målbild vi arbetar fram för ett
produktionsbygg- och testflöde för Kravhantering. Dokumentet uppdateras
löpande när designbeslut blir tydliga.
Målbild
Vi ska bygga ett GitHub Actions-flöde som producerar färdiga
containerartefakter, startar en produktionslik miljö med Podman Compose
och kör Playwright-tester mot miljön med samma session-cookie-mönster som
befintliga integrationstester använder.
Körningsmiljön ska bestå av fyra separata containrar i ett internt
Podman-nätverk:
nginx som TLS-terminerande omvänd proxy
Next.js-applikationen
Microsoft SQL Server
Keycloak
Endast nginx ska exponeras mot Playwright via HTTPS. Certifikat ska
genereras i arbetsflödet och Playwright ska lita på den certifikatkedjan
så att testerna kör mot en säker URL utan att behöva sänka
säkerhetskraven i applikationen. Certifikat och privata nycklar ska bara
vara kortlivade körningsfiler och får inte sparas som artefakter.
Alla containrar ska ha sin konfiguration externt så att konfigurations-
ändringar inte kräver ombyggnad av avbildningar. Varje containers
konfiguration ska vara minimal och bara innehålla den konfiguration som
den containern behöver.
Beslut hittills
Releaseenhet
Releaseenheten är en versionerad applikations- och stackrelease, till
exempel v0.2.0.
Appavbildningen är den primära egenbyggda releaseartefakten. nginx-
konfiguration, Podman Compose-manifest, seed-/migreringskommandon och
testkonfiguration hör till samma release och ska versioneras tillsammans
med applikationen.
Microsoft SQL Server och Keycloak behandlas som externa
leverantörsavbildningar. De ska låsas till uttryckliga versionstaggar och
digest i den testade och släppta Compose-konfigurationen. Digest är det
som Compose ska använda för att starta containern, medan tagg och
ursprungligt avbildningsnamn dokumenteras som metadata. Om releaseflödet
måste kunna dra allt från GitHub Container Registry kan
leverantörsavbildningar speglas dit, men de ska inte byggas om med egna
containerrecept bara för att få en projektägd tagg.
nginx ska också behandlas som en extern leverantörsavbildning. Den ska
låsas till tagg och digest, och Compose ska starta nginx med en
avbildning som är låst till digest. Projektet äger nginx-konfigurationen
och TLS-materialet, inte en egen nginx-avbildning. nginx.conf,
site-konfiguration och certifikat ska monteras in skrivskyddat. En egen
nginx-avbildning ska bara byggas om vi senare behöver egna moduler eller
annan körningskod i nginx.
nginx-konfigurationen ska ligga statiskt i källträdet under
containers/nginx/ och granskas i pull requests. Arbetsflödet ska inte
generera hela nginx-konfigurationen dynamiskt i första versionen. Det ska
bara generera kortlivade certifikat och den slutliga Compose-fil som pekar
ut vilka filer som monteras in.
GitHub-projektet och applikationen är publika/open source. Det innebär att:
avbildningar, konfigurationsexempel och releaseartefakter inte får
innehålla hemligheter
GHCR-paket bör vara publikt läsbara där det är möjligt
OCI-etiketter, versionsanteckningar, avbildningsdigest och
versionsmetadata ska vara lätta att granska utifrån
releaseflödet ska vara robust mot pull requests från forks där
GitHub-token normalt inte ska ha paketpubliceringsrättigheter
Versionsexponering
Samma releaseversion ska kunna användas av flera ytor:
containeravbildningstaggar
Playwright-loggning och testartefakter
applikationens körningsmetadata
tooltip när användaren hovrar över titeln i headern
Första metadata-kontraktet ska vara en liten offentlig
public/build.json som skapas i arbetsflödet före next build och byggs
in i appavbildningen. Den ska inte innehålla hemligheter. Minsta innehåll
är version, commit-SHA, byggtid och avbildningstagg. Avbildningens digest
kan fyllas i när den är känd efter bygg och publicering eller sparas i
separat byggmetadata.
Appen ska kunna använda samma metadata för tooltipen i headern, och
Playwright ska kunna spara metadatafilen eller motsvarande innehåll som
testartefakt. Filen kan utökas med mer metadata senare utan att byta
grundmodell.
Öppna designfrågor
Teststrategi
Den befintliga fulla produktionslika sviten ska fortsätta köras som
CI-krav i befintligt flöde. Det nya containerflödet ska i stället köra
en separat röktestsvit för release mot den Podman Compose-startade
miljön.
Playwright ska alltid köras på GitHub Actions-runnern, inte som en
Compose-tjänst. Runnern ska nå miljön via nginx och
https://kravhantering.test. Playwright-rapporter, skärmdumpar,
spårningsfiler och byggmetadata ska sparas som GitHub Actions-artefakter.
Röktestsviten för release ska ladda upp skärmdumpar som bevis, men den
får inte enbart besöka sidor. Den ska ha kontroller som verifierar det
som är unikt eller särskilt riskfyllt i containerflödet:
HTTPS via kravhantering.test
OIDC-redirect via nginx /auth
lyckad Keycloak-inloggning och återanvänd sessionskaka
autentiserad /api/auth/me
minst en sida som läser från SQL Server
minst en muterande åtgärd eller API-kontroll så CSRF, session och
databasskrivning fungerar
statiska resurser laddas från containeravbildningen
appversion eller byggmetadata kan visas eller hämtas
Syftet är att containerflödet ska verifiera TLS, nginx, Keycloak via
publik utfärdar-URL, sessionskakor, avbildningsinnehåll,
miljökonfiguration och SQL Server-koppling utan att duplicera hela den
befintliga produktionslika sviten.
Röktestsviten för release ska använda fasta röktestdata från
db:seed:demo för sidor och skärmdumpsbevis. Själva testet får dessutom
göra en liten muterande åtgärd med ett unikt prefix för att verifiera
skrivvägen, men ska inte behöva skapa hela sin datagrund dynamiskt.
Den muterande åtgärden ska i första hand köras med release-smoke-user om
behörighetsmodellen tillåter det, så röktestet verifierar session, CSRF och
databasskrivning med en vanlig användare. release-smoke-admin ska bara
användas för sidor eller kontroller som faktiskt kräver förhöjd behörighet.
Första versionens muterande kontroll ska vara ett minimalt kravskapande via
API: GET /api/requirement-areas, POST /api/requirements med en unik
beskrivning som börjar med release-smoke-<run-id> och därefter
GET /api/requirements/:id för att verifiera att posten sparades. Det
återanvänder ett redan etablerat integrationsmönster och ger ett litet men
tydligt bevis på autentiserad skrivning mot SQL Server.
Röktestet ska inte städa bort den skapade kravposten i första versionen.
Posten ska ha unikt körningsprefix och får lämnas kvar som felsökningsspår i
den körningsspecifika testdatabasen. Testets resultat ska inte vara beroende av
att en efterföljande städning lyckas.
Bygg och publicering
Pull request-flöden ska inte publicera avbildningar till GitHub Container
Registry. De ska bygga appavbildningen lokalt i arbetsflödet, starta
Podman Compose med den lokala avbildningen och köra Playwright mot den
produktionslika miljön.
PR-flödet ska alltid spara följande GitHub Actions-artefakter:
Playwright-rapport
serverloggar
genererad Compose-fil
testad avbildningstagg och digest
byggmetadata
stacklåsningsfil med testade avbildningsnamn, taggar, digest-värden och
källor
hashes.sha256 med SHA256-kontrollsummor för sparade artefakter
Serverloggar och containerstatus ska samlas in i två steg. Om röktestet
misslyckas ska arbetsflödet först samla loggar medan Compose-stacken fortfarande
kör, så tillståndet inte tappas om felet beror på hängande tjänster,
startproblem eller sena containerfel. Därefter ska arbetsflödet försöka stänga
ned stacken och spara en slutlig logg- och statusdump efter
nedstängningsförsöket. Loggar och statusdump får inte innehålla hemligheter.
Statusdumpen ska ha en liten fast uppsättning uppgifter: resultat från
podman compose ps, avslutskoder för engångsjobben, senaste loggar per tjänst,
använda avbildningsreferenser med digest, monterade konfigurationsfiler som
sökvägar utan filinnehåll, nätverksnamn och volymnamn. Första versionen ska
inte spara fullständig rådata från podman inspect, eftersom den lätt blir
stor och kan innehålla miljövärden.
Statusdumpen ska sparas som artefakt i PR-, förhandsversions- och
releaseflöden, till exempel som läsbar container-status.txt och som liten
strukturerad container-status.json med samma uttryckligt tillåtna kärndata.
Arbetsflödet ska om möjligt ha ett eget steg för att samla och visa
containerstatus. Steget kan skriva en kort sammanfattning till GitHub Actions
jobbsammanfattning, men fullständiga loggar och statusfiler ska ligga i
artefakter.
PR-flödet ska också spara de containers som projektet bygger själv som
artefakter, så länge de inte innehåller hemligheter. Dessa artefakter ska
vara kortlivade och får inte ersätta GHCR-publicering i betrodda main-
och releaseflöden.
PR-flödet ska spara separata komprimerade OCI-arkiv per egenbyggd avbildning,
inte ett samlat arkiv för hela stacken. Första versionen ska minst skapa ett
arkiv för app-runtime och ett arkiv för db-job. Arkivnamn, digest-värden
och SHA256-kontrollsummor ska framgå i hashes.sha256 och
container-stack.lock.json, så det är tydligt vilken avbildning som användes
för appstart respektive migrering och seedning.
PR-röktestet ska starta från de lokala avbildningar som just byggts i
arbetsflödet, inte genom att packa upp de sparade OCI-arkiven i normalfallet.
Det håller testkörningen snabb och undviker onödiga extra laddningssteg. Efter
export ska arbetsflödet ändå göra en snabb kontroll av varje OCI-arkiv, till
exempel genom att läsa metadata eller ladda arkivet i en kontroll, och verifiera
att digest-värdet stämmer med container-stack.lock.json. Om arkivet inte går att
läsa eller digest-värdet avviker ska PR-flödet misslyckas, eftersom artefakten
då inte är användbar för felsökning.
Lokala PR-taggar ska vara tydliga körningstaggar som inte ska publiceras. De
ska inte använda latest eller semantiska versionstaggar. Exempel:
Taggen ska bara göra den lokala Compose-körningen läsbar. Digest-värdet och
container-stack.lock.json är spårbarhetskällan.
Artefakter ska ha olika lagringstid beroende på syfte och storlek. Självbyggda
OCI-arkiv i PR-flöden ska sparas kort, 1-3 dagar. Playwright-rapport,
serverloggar, statusfiler, genererad Compose-fil, stacklåsningsfil,
byggmetadata och hashes.sha256 från PR-flöden ska sparas längre, till
exempel 7 dagar, så att felsökning hinner göras utan att tunga arkiv blir
kvar i onödan. För förhandsversioner och stabila releases ska de publicerade
releaseartefakterna, kontrollsummorna och länkarna i GitHub
Release/GitHub-förhandsutgåva vara det permanenta revisionsspåret.
Avbildningsbyggen ska i första versionen göras med Docker Buildx i
GitHub Actions. Buildx ska användas för bygg, taggning, publicering till
GHCR och för att skapa den metadata som behövs för SBOM/provenance och
digest. Podman Compose ska däremot vara körmiljön för röktestet, både i
PR och i publicerade releaseflöden. Det ger starkt stöd för GitHub
Actions-attesteringar utan att flytta själva testmiljön från Podman.
Första målplattformen är linux/amd64. Fler arkitekturer ska inte vara
ett krav i första versionen, utan kan läggas till senare när appavbildning
och stack är stabila och reproducerbara.
PR-, förhandsversions- och releaseflöden ska använda samma Dockerfile,
Buildx-konfiguration och byggargument för appavbildningen. Skillnaden ska
vara exporter och behörigheter: PR-flöden exporterar till lokalt
OCI-arkiv och laddar avbildningen till testmiljön utan GHCR-publicering,
medan betrodda main- och releaseflöden publicerar till GHCR och skapar
signaturer, attesteringar och versionsanteckningar.
Produktionscontainrar ska ha en egen tydlig plats under containers/.
Appens Dockerfile ska ligga i containers/app/Dockerfile, inte i
repo-roten. Syftet är att inte blanda ihop produktionsavbildningen med
Dev Containers, lokala utvecklingsverktyg eller andra Dockerfile-varianter
som kan finnas för utvecklingsmiljöer.
Byggkontexten för appavbildningen ska vara repo-roten, eftersom Next.js-
bygget behöver filer från flera rotkataloger, till exempel package.json,
package-lock.json, next.config.ts, tsconfig.json, app/, lib/,
components/ och public/. För att ändå hålla produktionsbygget smalt
ska containers/app/Dockerfile.dockerignore användas som
Dockerfile-specifik .dockerignore-fil. Den ska exkludera dokumentation, tester,
lokala utvecklingsfiler, tidigare byggresultat och annat som inte behövs
för produktion. Rotens .dockerignore får finnas för andra lokala
byggflöden, men appens produktionsbygge ska styras av den
Dockerfile-specifika .dockerignore-filen.
Alla självbyggda containerarkiv ska sparas på varje PR-körning. För den
första versionen innebär det ett komprimerat OCI-arkiv för appavbildningen
med kort retention, till exempel 1-3 dagar.
Eftersom projektet är publikt får artefakter och dokumentation aldrig
innehålla riktiga hemligheter. Däremot får de innehålla samma publika
dev-only exempelvärden som används för lokal utveckling, till exempel
Keycloak-klienthemligheter, testlösenord och session-cookie-nycklar som
redan är uttryckligen markerade som icke-produktionsvärden.
PoC-dokumentationen ska beskriva hur en användare startar miljön med
dessa exempelvärden och hur de byts mot egna värden när miljön används
utanför lokal test eller demo.
PoC-dokumentationen ska ha demo som standardprofil: miljön ska kunna
startas med publika dev-only exempelvärden utan hemliga förberedelser.
Dokumentationen ska samtidigt vara tydlig med att demo-värdena inte är
säkra för en exponerad miljö. Den ska förklara exakt vilka värden som
måste ändras för att göra miljön säker, minst session-cookie-nyckel,
Keycloak-klienthemligheter, Keycloak-adminlösenord, SQL Server-lösenord,
TLS-certifikat och eventuella MCP-klienthemligheter.
Merge till main får bygga och publicera ögonblicksavbildningar till
GHCR, till exempel main-<sha> och sha-<sha>.
Taggade releases, till exempel v0.2.0, ska bygga, publicera och testa
exakta releaseavbildningar för både app-runtime och db-job. I
förhandsversions- och releaseflöden ska den testade Compose-konfigurationen
alltid referera till appavbildningen med digest, till exempel
ghcr.io/<owner>/<image>@sha256:<digest>, så att röktestet för release
bevisar exakt artefakt. Versionstaggen är metadata och söknyckel, men ska
inte vara det som avgör vilken avbildning Compose startar.
Compose-konfigurationen ska ha en källstyrd mall i källträdet.
Arbetsflödet ska generera en slutlig Compose-fil från mallen och den aktuella
stacklåsningsfilen. Den slutliga filen ska innehålla exakt de
avbildningsreferenser, digest-värden, monterade konfigurationsfiler och
testspecifika sökvägar som röktestet använder.
I PR-flöden ska den genererade Compose-filen referera till lokala
localhost/kravhantering/...:pr-<pr>-<run-id>-<sha>-taggar, eftersom
avbildningarna bara finns i runnerns lokala bildlager. PR-flödets
container-stack.lock.json, container-status.json och hashes.sha256 ska
däremot alltid innehålla digest-värden för de testade och exporterade
avbildningarna.
Regeln om lokala PR-taggar gäller bara projektets egenbyggda avbildningar,
först app-runtime och db-job. Leverantörsavbildningar för nginx,
SQL Server och Keycloak ska vara digest-låsta även i PR-Compose, enligt
stacklåsningsfilen. På så sätt är bara de avbildningar som byggs i PR lokala,
medan den omgivande stacken fortfarande är reproducerbar och skyddad mot
flyttade leverantörstaggar.
Den genererade Compose-filen ska sparas som artefakt i PR-,
förhandsversions- och releaseflöden. Release- och förhandsflöden ska också
kunna hänvisa till samma genererade fil från versionsanteckningarna. Det
gör basen granskningsbar i källträdet samtidigt som varje körning bevarar
bevis för exakt vilken stack som testades.
GitHub Actions-arbetsflödet ska styra startordningen uttryckligen i stället
för att bara förlita sig på Compose-beroenden. Det ska starta SQL Server och
Keycloak först, vänta in SQL Server, köra ett bootstrap-jobb som skapar
databasen och de SQL-principaler som stacken använder, köra db-migrate, köra
db-seed-required, vid behov köra db-seed-demo, starta app-runtime och
nginx, vänta på nginx, Keycloak discovery och appen via nginx och därefter
köra Playwright.
Compose-mallen får fortfarande ha hälsokontroller och beroenden för
tydlighet, lokal felsökning och bättre loggar. Release-röktestet ska
däremot använda arbetsflödets explicita steg som källa till ordningen. Det
gör fel lättare att förstå och undviker att migrering, seedning och appstart
glider ihop till en implicit Compose-effekt.
Första väntelogiken ska använda konkreta kontroller per tjänst:
SQL Server ska väntas in med TCP- och inloggningskontroll, motsvarande
dagens db:wait.
Keycloak ska väntas in via sin publika HTTPS-baserade utfärdar-URL genom
nginx, till exempel OIDC-konfigurationen för valt Keycloak-realm under
.well-known/openid-configuration.
nginx ska väntas in med TLS-verifierad HTTPS mot kravhantering.test.
appen ska först väntas in via nginx och befintliga GET /api/health,
som ska returnera HTTP 200 med { "status": "ok" }.
appens beroenden ska därefter väntas in via nginx och ett nytt
GET /api/ready, som ska returnera HTTP 200 när appen kan använda
de beroenden som krävs för att ta emot trafik.
Alla väntesteg i arbetsflödet ska ha flera försök med tydlig total
tidsgräns innan de misslyckas. Första versionen bör räkna med att SQL
Server, Keycloak, nginx eller appen kan behöva minst 30 sekunder innan de
svarar. Ett rimligt startvärde är 90-120 sekunders total väntan per
kritisk tjänst, med korta intervall mellan försöken och sista felsvaret
utskrivet i loggen.
Containerstackens hjälpkommandon ska ligga i scripts/containers/ och
anropas från GitHub Actions-arbetsflödet. Det omfattar till exempel
generering av slutlig Compose-fil, kontroller av container-stack.lock.json
och väntan på SQL Server, Keycloak, nginx, /api/health, /api/ready och
OIDC-discovery. YAML-filen ska hålla ihop stegens ordning, behörigheter och
artefakter, men inte innehålla större inbäddade kommandoblock för väntan,
tolkning av svar eller felrapportering. Samma skript ska kunna användas
lokalt för PoC/demo så att CI och lokal felsökning väntar på samma sätt.
scripts/release/ ska reserveras för hjälpkommandon som bara hör till
GitHub-utgåvor, till exempel versionsanteckningar, checksummor och
sammanställning av releaseartefakter.
Vänteskripten ska i första hand vara Node-baserade .mjs-skript. De ska
hantera HTTP-anrop, JSON-tolkning, tidsgränser, flera försök och tydliga
felmeddelanden. Det passar projektets befintliga skriptmiljö och gör
kontrollerna enklare att testa än om all logik ligger i YAML. Kommandoskal
ska bara användas för små systemnära steg där det behövs, till exempel
anrop till podman, openssl eller uppdatering av /etc/hosts.
/api/health är en liveness-kontroll för appens HTTP-process och ska inte
behöva verifiera databas, Keycloak eller användarsession. /api/ready
ska vara en readiness-kontroll för appens trafikberoenden. Den ska ha kort
tidsgräns, inte kräva autentisering, inte mutera databasen och inte läcka
hemligheter eller detaljerade interna fel i svaret.
Första versionen av /api/ready ska minst verifiera att appens
körningskonfiguration är tillräcklig och att SQL Server kan nås med en
enkel SQL-fråga som bara läser data. Den ska också verifiera att den
konfigurerade OIDC-utfärdaren kan nås via sin discovery-URL, med kort
tidsgräns per anrop. /api/ready ska inte själv göra lång väntan; det är
arbetsflödets väntesteg som gör flera försök. Röktestsviten ska
fortfarande vara den verifiering som bevisar Keycloak-inloggning, session,
autentiserad API-kontroll, databasläsning och en liten muterande åtgärd.
Det publika svaret från /api/ready ska vara snålt. Vid lyckad kontroll
ska svaret vara HTTP 200 med till exempel { "status": "ready" }. Vid
misslyckad kontroll ska svaret vara HTTP 503 med till exempel
{ "status": "not_ready" }. Svaret ska ha Cache-Control: no-store och
ska inte innehålla beroendenamn, anslutningssträngar, interna felmeddelanden
eller annan topologi. Detaljer om vilken kontroll som föll ska i stället
skrivas till serverloggen, som sparas som CI-artefakt.
Säkerhet i leveranskedjan
Betrodda GHCR-avbildningar från main, förhandsversioner och stabila
releaseflöden ska signeras och förses med verifierbar provenance och
SBOM. Detta gäller alla avbildningar projektet bygger själv, i första
versionen app-runtime och db-job.
Containeravbildningen ska signeras med Cosign och nyckelfri signering via
Sigstore och GitHub Actions OIDC, inte med långlivade privata
signeringsnycklar i GitHub Secrets. Signeringen ska göras mot
avbildningens digest, inte mot en flyttbar tagg. Arbetsflödena behöver
minst id-token: write och
packages: write när signering och attestering görs mot GHCR.
Provenance och SBOM ska skapas som GitHub Artifact Attestations och
kopplas till samma avbildningsdigest som signeras. För
containeravbildningar ska attestering använda fullständigt
avbildningsnamn och digest, utan att blanda in flyttbara taggar som
identitet. Användare ska kunna verifiera både Cosign-signaturen och
GitHub-attesteringarna från versionsanteckningarna.
PR-flöden ska inte publicera till GHCR och ska därför inte skapa publika
Cosign-signaturer eller permanenta attesteringar. PR-flöden ska i
stället bygga lokalt, skanna den lokala avbildningen och spara
kortlivade OCI-arkiv och rapporter som artefakter.
Röktestflödet för release ska verifiera publicerade avbildningar innan
Podman Compose startas. I main, förhandsversioner och stabila
releaseflöden ska verifieringen omfatta förväntad avbildningsdigest,
Cosign-signatur och GitHub Artifact Attestation för provenance för både
app-runtime och db-job. SBOM-attestering ska också verifieras när den
finns. PR-flöden verifierar inte publika signaturer eller permanenta
attesteringar eftersom de inte publicerar till GHCR. Efter verifieringen
ska Podman Compose starta samma avbildningar som verifierats och som är
låsta till digest, inte taggar som kan flyttas.
Även leverantörsavbildningar för nginx, SQL Server och Keycloak ska vara
låsta till digest i röktest och Compose-konfiguration för release.
Projektet signerar inte leverantörsavbildningar, men digest-låsning gör
testmiljön reproducerbar och förhindrar att en flyttad tagg i
källregistret ändrar vad röktestet för release faktiskt testar.
Låsta leverantörsavbildningar ska ha sin källa i respektive containerkatalog,
inte i en gemensam fil. Första versionen ska använda en liten incheckad
image.lock.json per leverantörscontainer, till exempel:
Varje image.lock.json ska använda samma fältnamn som en tjänstepost i
container-stack.lock.json: name, role, image, tag, digest och
source. Uppdateringar av leverantörsavbildningar ska därför göras som
vanliga PR-ändringar där tagg och digest granskas tillsammans i berörd
containerkatalog. Den genererade container-stack.lock.json ska kunna kopiera
leverantörsposterna utan fältöversättning och komplettera med aktuella
digest-värden för projektets egenbyggda avbildningar.
image.lock.json ska vara ren JSON utan kommentarer, så
scripts/containers/ kan läsa filerna utan specialparser. Instruktioner för
hur tagg och digest uppdateras ska i stället ligga i respektive
containers/<komponent>/README.md.
Varje leverantörscontainers README ska beskriva ett kort manuellt
uppdateringsflöde: uppdatera tagg och digest tillsammans i image.lock.json,
kör scripts/containers/generate-stack-lock.mjs för kontroll och kör
röktestet. Första versionen ska inte skapa automatiska uppdaterings-PR:er för
leverantörsavbildningar.
Första versionen ska inte kräva särskild text i PR-beskrivningen när
image.lock.json ändras. Spårbarheten ska komma från PR-diffen,
container-stack.lock.json, hashes.sha256 och röktestartefakterna.
scripts/containers/generate-stack-lock.mjs ska kunna köras både för att
skapa container-stack.lock.json och för att kontrollera en befintlig
stacklåsningsfil. När skriptet körs för kontroll ska det verifiera att varje
leverantörspost i container-stack.lock.json exakt motsvarar respektive
containers/<komponent>/image.lock.json. Kontrollen ska misslyckas om en
post saknas, om tagg eller digest avviker, eller om leverantörsposter har
redigerats direkt i den genererade stacklåsningsfilen.
Första versionen ska inte lägga till extra semantisk validering av
image.lock.json, till exempel särskild kontroll av digest-format, tom tagg,
avbildningsnamnets form eller en tillåten lista med roller. Sådana kontroller
kan läggas till senare om de ger tydligt värde. Första skyddet är att filerna
är ren JSON, att de kopieras konsekvent till stacklåsningsfilen och att den
faktiska körningen använder de låsta avbildningarna.
Varje PR-, förhandsversions- och releasekörning ska skapa en
stacklåsningsfil som artefakt. Den ska lista exakt avbildningsnamn,
versionstagg, digest, källa och roll i stacken för app-runtime,
db-job, nginx, SQL Server och Keycloak. För release- och förhandsflöden
ska samma information också användas för att skapa den digest-låsta
Compose-fil som testas. Eftersom appens slutliga digest inte är känd
förrän efter bygg och publicering är den fullständiga stacklåsningsfilen
en genererad artefakt, inte bara en statisk fil i källträdet.
Stacklåsningsfilen ska heta container-stack.lock.json och ha ett fast
JSON-format som kontrolleras i CI utan separat schema. Första
formatet ska minst innehålla
schemaVersion, releaseVersion, commitSha, generatedAt,
generatedBy, services[] och ett objekt för varje tjänst med name,
role, image, tag, digest och source. Filen behöver inte ha ett
verified-fält, eftersom CI ska kräva att verifieringen passerar innan
stacklåsningsfilen används som release- eller PR-artefakt. Formatet ska
vara enkelt att utöka med mer metadata utan att bryta befintliga verktyg.
Ett separat JSON Schema kan införas senare om formatet börjar användas av
flera oberoende verktyg, eller viktigt för CI, men behövs inte i första
versionen.
Versions- och releaseverktyg
GitVersion ska vara versionskälla för CI. Skälet är att GitVersion kan
räkna ut SemVer från git-historik, taggar och konfigurerade
commit-meddelanderegler, vilket passar flödet där betrodda merges till
main får förhandsversioner medan en stabil release skapas genom att
publicera en full versionstagg.
Huvudspåret är:
main får förhandsversioner med strikt SemVer-format, till exempel
1.0.0-preview.1 i stället för 1.0.0-preview1
förhandsversionstaggar skapas bara för betrodda main-merges som ändrar
applikationskod, körningskonfiguration eller beroendemanifest som kan
påverka applikationens säkerhet eller funktionalitet
förhandsversionen används för avbildningstaggar, public/build.json,
genererad Compose-fil, Playwright-loggning och artefakter
förhandsversionstaggar ska också skapa GitHub-förhandsutgåvor för
enhetlighet, men de ska markeras som pre-release och inte som latest
release
när en stabil tagg som v1.0.1 publiceras ska taggbygget producera exakt
version 1.0.1 och motsvarande releaseavbildning
git- och GitHub-taggar ska ha v-prefix, till exempel v1.0.1 och
v1.0.2-preview.1
versionsvärdet i appen, public/build.json, Compose, Playwright-
loggning och avbildningstaggar ska sakna v-prefix, till exempel 1.0.1
och 1.0.2-preview.1
GitHub Actions måste checka ut full git-historik och taggar, till
exempel med fetch-depth: 0, så att GitVersion kan räkna rätt
Conventional Commits-regler ska konfigureras så att feat höjer minor,
fix och perf höjer patch och breaking changes höjer major
Första versionen av filtret för förhandsversionstaggar ska utgå från
ändrade filer. Ändringar i till exempel app/**, components/**,
i18n/**, messages/**, public/**, middleware.ts, next.config.ts,
typeorm/migrations/**, relevanta seedfiler, container-/Compose-/
nginx-konfiguration samt package.json och package-lock.json ska kunna
skapa förhandsversion. Dokumentation, tester, lintkonfiguration och andra
utvecklingsytor ska inte skapa semantiska förhandsversionstaggar på egen
hand. Alla main-merges får däremot fortfarande kunna bygga
ögonblicksavbildningar med main-<sha> och sha-<sha> om kostnaden för
arbetsflödet är rimlig.
Första versionen ska inte använda en incheckad CHANGELOG.md.
Versionsanteckningar ska i stället vara taggbaserade och skapas i GitHub
Release. Förhandsversioner ska skapa GitHub-förhandsutgåvor och stabila
versionstaggar ska skapa vanliga GitHub Releases. Båda ska kompletteras
med den metadata som behövs för att kunna spåra den testade artefakten,
till exempel avbildningstagg, avbildningsdigest, commit-SHA och länk till
röktestartefakter för release.
Versionsanteckningar ska också innehålla SHA256-kontrollsummor för
publicerade releaseartefakter. Minst ska en hashes.sha256-fil skapas
som artefakt eller bifogad fil i GitHub Release, och GitHub
Release-texten ska återge eller länka till kontrollsummorna. Det ska
omfatta till exempel stacklåsningsfil, genererad Compose-fil,
byggmetadata, container-status.txt, container-status.json, SBOM,
testad avbildningsdigest och eventuella nedladdningsbara arkiv.
GitHub-förhandsutgåvor ska behållas permanent i GitHub. De är en del av
revisionsspåret för testade artefakter och ska inte tas bort när
motsvarande stabil release publiceras. Det är viktigare att kunna följa
vilken förhandsversion som testades än att hålla GitHub Releases-listan
helt kort. Bara stabila releases ska markeras som latest.
release-please ska inte ingå i första implementationen. Det kan
utvärderas senare om projektet behöver release-PR:er, kuraterad
ändringslogg eller mer kontrollerad releasekommunikation. Changesets är
fortsatt ett svagt alternativ för detta repo eftersom det främst löser
paketversionering.
Minimal appavbildning
Appavbildningen ska byggas med produktionsmål och bara innehålla
körningskod. Den ska inte innehålla lintverktyg, testkod, dokumentation,
utvecklingsverktyg, devDependencies eller konfigurationsfiler som bara
hör till utveckling, tester eller demo.
Next.js ska konfigureras med output: "standalone" för produktionsbygget.
Körningssteget i Dockerfile ska utgå från den genererade standalone-
utmatningen och bara kopiera in det som krävs för att starta appen:
.next/standalone, .next/static, public och nödvändiga
produktionsfiler. Det ska inte kopiera hela källträdet.
För första versionen ska appavbildningen bygga på Debian slim för Node
24, till exempel node:24-bookworm-slim, både i byggsteg och
körningssteg. Alpine väljs inte som första spår eftersom Next.js,
SQL Server-drivrutiner och native/transitiva beroenden typiskt ger mindre
friktion på en glibc-baserad avbildning.
Basavbildningar som projektet faktiskt bygger vidare på ska låsas direkt i
Dockerfile med tagg och digest, till exempel
FROM node:24-bookworm-slim@sha256:<digest>. Digest i Dockerfile ska inte
användas för nginx, SQL Server eller Keycloak, eftersom de är
leverantörsavbildningar som körs direkt i Compose utan projektägda
wrapper-avbildningar.
Körningssteget ska köra som icke-root användare. Miljöspecifik
konfiguration ska komma via miljövariabler eller monterade filer vid
start, inte genom att .env-filer, Compose-filer, certifikat,
Playwright-konfiguration eller annan icke-produktionskonfiguration byggs
in i avbildningen.
containers/app/Dockerfile ska ha minst två produktionsmål:
app-runtime är den minsta avbildningen för den körande appen. Den ska
bara innehålla standalone-utmatningen och filer som krävs vid appstart.
db-job är en separat avbildning för databasmigrering och
db:seed:required. Den får innehålla migreringsfiler och
produktionsrelevant seedningskod, men inte demo- eller testdata.
Båda målen ska byggas från samma Dockerfile och samma källrevision, men
de ska taggas och beskrivas separat i stacklåsningsfilen. I första
versionen är app-runtime den avbildning som nginx skickar trafik till,
medan db-job bara används av engångsjobb före appstart. db-job är
inte en femte långkörande container i runtime-stacken.
Eftersom db-job måste köras innan någon appcontainer startas ska den
följa samma release som app-runtime. Den ska publiceras till GHCR,
låsas till digest, signeras, attesteras, få SBOM/provenance och listas i
stacklåsningsfilen och versionsanteckningarna. Release-Compose ska köra
db-job som lyckade engångsjobb före app-runtime, och app-runtime
får inte starta förrän migrering och db:seed:required har slutförts.
Första Compose-modellen ska ha separata engångstjänster som använder samma
db-job-avbildning:
db-bootstrap skapar databasen och de SQL-principaler som app och
databasjobb använder.
db-migrate kör databasmigrering.
db-seed-required kör db:seed:required efter lyckad migrering.
Uppdelningen ger tydligare loggar, enklare felsökning och säkrare omkörning
än ett enda sammanslaget jobb.
CI-, röktest- och PoC-demo-profiler ska dessutom kunna lägga till
db-seed-demo som tredje engångstjänst med samma db-job-avbildning.
Den ska köras efter db-seed-required men före app-runtime.
Produktionsprofilen ska inte köra db-seed-demo.
Compose-konfigurationen ska använda profiler för att hålla standardflödet
rent:
demo lägger till db-seed-demo och eventuell demo-specifik extern
konfiguration
release-smoke lägger till db-seed-demo, röktest-specifik extern
konfiguration och runner-baserade Playwright-bevis
Standardprofilen ska motsvara en tom produktionslik miljö med nödvändig
referensdata, utan demo- eller testdata.
Extern konfiguration
nginx, applikationen, Keycloak och SQL Server ska kunna startas med
extern konfiguration. Det ska gå att ändra URL:er, certifikat,
OIDC-inställningar, databasanslutning och test-specifika värden utan att
bygga om respektive avbildning.
Varje container ska ha en egen katalog under containers/. Katalogen ska
innehålla all projektägd konfiguration, alla exempel på miljövariabler och ett
dokumenterat miljövariabelkontrakt i README.md för just den containern. Det
gäller även när själva avbildningen är en leverantörsavbildning, till exempel
SQL Server eller Keycloak. db-job får en egen katalog för sitt
miljökontrakt och sina engångskommandon även om avbildningen byggs från samma
Dockerfile som appen.
Det ska inte finnas gemensamma miljö- eller konfigurationsfiler som täcker två
eller flera containrar. Om samma värde behövs av flera containrar ska det
föras in i respektive containers egen konfiguration vid generering eller
start, i stället för att ägas av en gemensam .env-fil. Compose-mallen och
stacklåsningsfilen får beskriva sammansättning, monteringar, beroenden och
digest-låsta avbildningar, men ska inte vara källan för containrarnas egna
miljövärden.
Dokumentationen i varje containerkatalog ska beskriva vilka värden som krävs,
vilka som bara är för demo eller röktest, vilka som är känsliga och vilka
exempelvärden som är säkra att publicera i ett öppet källträd. Demo- och
testprofiler får ha publika exempelfiler med utvecklingsvärden i respektive
containerkatalog så att PoC-miljön kan startas utan hemliga förberedelser.
Dessa filer ska vara tydligt märkta som osäkra för exponerad drift.
GitHub Actions-arbetsflödena ska däremot mata in hemligheter och genererade
värden vid körning, till exempel certifikat, sessionsnycklar och lösenord.
Arbetsflödena ska inte vara beroende av underförstådda lokala .env-filer.
Publika exempelvärden ska namnges per container, till exempel
containers/app/.env.app.example och
containers/keycloak/.env.keycloak.demo.example. Arbetsflödet får generera
tillfälliga lokala filer med samma ägarskap, till exempel
containers/app/.env.app.local eller
containers/keycloak/.env.keycloak.local, när Compose behöver läsa
miljövariabler från fil. .local-filerna ska vara ignorerade av Git, får
innehålla hemligheter och ska aldrig sparas som artefakter. Artefakter ska i
stället innehålla publicerbara exempelvärden, redigerad Compose-fil utan
hemligheter, stacklåsningsfil, byggmetadata och checksummor.
nginx-konfigurationen ska vara en minimal, källstyrd konfiguration som
bara beskriver nginx ansvar: TLS-terminering, omvänd proxy till
applikationen och vidarebefordran till Keycloak under /auth. Certifikat
och privat nyckel ska monteras in som externa filer. Om fler värdnamn
eller sökvägar behövs senare kan en liten mall införas, men första
versionen ska vara statisk och enkel att granska.
nginx ska inte använda miljövariabler i första versionen. Dess
containerkatalog ska innehålla filbaserad konfiguration, till exempel
containers/nginx/nginx.conf och eventuell containers/nginx/conf.d/.
Certifikat, privat nyckel och tillfälliga CA-filer ska genereras av
arbetsflödet eller av lokal PoC-start och monteras in som filer. Om nginx
senare behöver miljöberoende värden ska det införas som ett separat beslut,
inte som en underförstådd .env-fil.
Databas och seed
SQL Server ska köras som separat container med beständig volym.
Databasen får inte försvinna vid containeromstart.
PR-, förhandsversions- och release-röktest ska däremot alltid starta med en
körningsspecifik SQL Server-volym. Arbetsflödet ska skapa volymen, köra
migrering, db:seed:required och db:seed:demo, spara loggar och artefakter
och därefter ta bort volymen. Röktestet ska därför vara reproducerbart från
avbildningar, låsfil och seeddata, inte från kvarvarande databasläge.
Lokal PoC/demo får använda en stabil namngiven SQL Server-volym för att data
ska finnas kvar mellan containeromstarter. Dokumentationen ska samtidigt ha ett
tydligt nollställningskommando som tar bort PoC/demo-volymen när användaren
vill börja om från migrering och seed.
SQL Server-containern ska inte ansvara för applikationens migreringar
eller seedning. Den ska vara en leverantörsavbildning för databasmotorn,
inte en specialbyggd avbildning med Node.js, TypeORM, applikationskod eller
seedningslogik. Det håller databascontainern minimal och gör att
Microsofts avbildning kan låsas till tagg och digest utan egen ombyggnad.
Databasmigrering och seedning ska köras som separata engångsjobb före
appstart, inte som en del av appcontainerns normala start. I CI/demo kan
det vara Compose-tjänster eller podman compose run --rm-kommandon som
använder db-job-avbildningen för att köra migrering och seedning.
Appcontainern ska därefter starta utan att mutera databasen.
Skälet är att appen på sikt kan köras med flera appcontainrar bakom
lastbalanserare. Om varje appinstans försöker migrera eller köra seedning
vid start finns risk för samtidiga schema- och dataändringar. Engångsjobb
ger tydligare ordning, enklare felsökning och bättre stöd för
horisontell skalning.
Seeddata behöver delas upp i minst två nivåer:
db:seed:required med nödvändig referensdata och systemdata som krävs
för att appen ska fungera
db:seed:demo med frivillig test-, demo-, PoC- och Playwright-data
som laddas när utvecklare, integrationstester eller PoC-miljöer behöver
realistiskt innehåll
Produktionsavbildningen får innehålla den kod och de filer som krävs för
migrering och db:seed:required, eftersom det är produktionsrelevant
driftsättning. db:seed:demo ska däremot inte bygga in demo- eller
testdata i produktionsavbildningen. Demo- och röktestdata ska tillföras
externt i CI/demo, till exempel som monterad fil, separat artefakt eller
separat Compose-konfiguration.
db:seed:demo ska köras som ett separat engångsjobb i PR-röktest,
release-röktest och PoC-demo. Jobbet ska använda samma db-job-
avbildning men läsa demo- och testdata från extern konfiguration eller
monterade filer. Det får inte vara en del av produktionsprofilen och får
inte krävas för en tom produktionslik miljö.
Utvecklare ska även fortsättningsvis kunna skapa och underhålla ny
testdata för ny funktionalitet.
Det befintliga db:seed-kommandot ska tas bort i stället för att leva
kvar som kompatibilitetsalias. Alla flöden ska välja seedprofil
uttryckligen. CI för integrationstester kör migrering, db:seed:required
och db:seed:demo. En tom produktionslik miljö kör migrering och
db:seed:required, men inte db:seed:demo.
Autentisering i produktionslik testmiljö
Keycloak ska köras i samma interna Podman-nätverk som övriga tjänster.
Playwright ska skapa sessioner genom det riktiga OIDC-flödet och sedan
återanvända storageState och sessionskaka på samma sätt som befintliga
integrationstester gör.
Keycloak ska exponeras via nginx under samma publika HTTPS-värd som
applikationen, till exempel under /auth. Applikationens
AUTH_OIDC_ISSUER_URL, Keycloaks annonserade värdnamn och Playwrights
inloggningsflöde ska därför använda samma HTTPS-baserade utfärdar-URL.
Det undviker specialfall där webbläsaren och appens serverkod ser olika
OIDC-utfärdare och gör demo-/testmiljön mer lik en riktig driftsättning.
CI- och demo-miljön ska använda kravhantering.test som fast
testvärdnamn. .test är en reserverad toppdomän för test och ska inte
användas via publik DNS. I GitHub Actions ska värdnamnet pekas mot
127.0.0.1, till exempel via /etc/hosts, och certifikatet som
genereras i arbetsflödet ska ha kravhantering.test i SAN. Playwright ska
köra mot https://kravhantering.test, och OIDC-utfärdare ska vara
https://kravhantering.test/auth/realms/kravhantering-test.
GitHub Actions-runnern ska generera en kortlivad lokal CA och ett
servercertifikat för kravhantering.test. Certifikat och privat nyckel
ska monteras skrivskyddat i nginx. Runnern ska lita på samma CA under
Playwright-körningen så att testerna kan använda vanlig HTTPS-verifiering.
Privata nycklar och CA-material ska inte laddas upp som artefakter.
Den produktionslika containerstacken ska ha en egen realm-fil under
containers/keycloak/, till exempel
containers/keycloak/realm-kravhantering-test.json. Den ska inte återanvända
dev/keycloak/realm-kravhantering-dev.json som källa vid release-röktest
eller PoC-demo. Utvecklingsrealmen kan fortsätta höra till befintliga lokala
utvecklingsflöden, medan containerstackens realm-fil ska följa
containerstackens publika HTTPS-adresser och konfigurationsstruktur.
Realm-filen i containers/keycloak/ ska innehålla de klienter, roller,
claim-mappningar och demo-/röktestanvändare som behövs för
containerbaserat röktest och PoC-demo. Den ska matcha
https://kravhantering.test/auth/realms/kravhantering-test,
AUTH_OIDC_CLIENT_ID, AUTH_OIDC_REDIRECT_URI,
AUTH_OIDC_POST_LOGOUT_REDIRECT_URI och eventuellt
AUTH_OIDC_API_AUDIENCE. Klienthemligheter och testlösenord i den incheckade
realm-filen får bara vara publika utvecklingsvärden. För exponerad drift ska
dokumentationen beskriva hur dessa värden byts ut.
Release-röktestet ska använda egna minimala testidentiteter i
realm-kravhantering-test.json, skilda från de konton och den data som dagens
integrationstester använder. Första versionen bör ha en administratör och en
vanlig användare med stabila tekniska användarnamn, till exempel
release-smoke-admin och release-smoke-user. Kontona ska bara ha de roller
som krävs för röktestets förutbestämda sidor och enkla skrivflöde. PoC-demo
får lägga till fler demoanvändare, men release-röktestets minsta konton ska
hållas små och stabila.
Appcontainern ska också använda samma publika utfärdar-URL via nginx, inte
en separat intern Keycloak-URL. OIDC-flödet skickar användarens webbläsare
till Keycloaks annonserade URL:er, så webbläsaren, appens serverkod och
Playwright måste se samma publika HTTPS-baserade utfärdare. Den interna
Podman-konfigurationen ska därför se till att appcontainern kan nå nginx på
kravhantering.test.
Detta dokument delar upp designen i prompt.md i mindre
implementationsfaser. Faserna ska göras i ordning, med fas 1 först. Syftet är
att en AI-agent ska kunna genomföra en fas i taget utan att behöva bära hela
lösningen i ett enda arbetspass.
Dokumentet ska inte ändra designen. Om en fas upptäcker att designen behöver
ändras ska prompt.md uppdateras först, och arbetet med fasen ska
fortsätta efter att beslutet är tydligt.
Gemensamma regler
En fas ska lämna källträdet i ett verifierbart läge.
Riktiga hemligheter får inte läggas i källkod, avbildningar eller
artefakter.
Gemensamma miljöfiler som styr flera containrar ska inte införas.
Varje container ska äga sin egen konfiguration i sin egen katalog.
PR-flöden får inte publicera till GHCR.
Leverantörsavbildningar ska inte byggas om som wrapper-avbildningar.
Relevanta tester och dokumentkontroller ska köras innan fasen avslutas.
Minsta dokumentkontroll efter ändringar i dessa dokument:
Mål: skapa den filstruktur och de kontrakt som senare faser bygger vidare på,
utan att ännu bygga hela stacken.
Gör:
Skapa containerkataloger för app, db-job, nginx, sqlserver och
keycloak.
Lägg till README.md i varje containerkatalog med respektive containers
miljövariabelkontrakt, känsliga värden, publika exempelvärden och
uppdateringsregler.
Lägg till image.lock.json för nginx, sqlserver och keycloak.
Säkerställ att varje image.lock.json är ren JSON med fälten name,
role, image, tag, digest och source.
Dokumentera i varje leverantörscontainers README hur tagg och digest
uppdateras manuellt.
Lägg till publika .env.<containernamn>.example-filer där de behövs.
Säkerställ att .env.<containernamn>.local-mönstret är ignorerat av Git.
Klart när:
Varje container har en tydlig egen katalog och inget nytt delat kontrakt för
miljöfiler har införts.
Leverantörsavbildningarnas låsning går att granska per container.
Dokumentkontrollerna är gröna.
Inte i fasen:
Ingen Compose-start.
Inga egna produktionsavbildningar.
Inga GitHub Actions-arbetsflöden.
Fas 2: Appens metadata och readiness
Mål: ge appen de körningskontroller och den versionsmetadata som
containerflödet behöver.
Gör:
Skapa eller anpassa generering av public/build.json före produktionsbygge.
Säkerställ att public/build.json innehåller minst version, commit-SHA,
byggtid och avbildningstagg.
Visa versionen i appen enligt designen, till exempel i tooltip på titeln i
headern.
Lägg till GET /api/ready med minimal publik respons.
Låt /api/ready kontrollera körningskonfiguration, SQL Server med en enkel
läsfråga och OIDC-discovery med kort tidsgräns.
Säkerställ att /api/ready inte kräver autentisering, inte muterar data och
inte läcker interna fel.
Klart när:
/api/health fortsätter vara enkel liveness-kontroll.
/api/ready kan användas av kommande vänteskript.
Appens metadata kan läsas av Playwright eller sparas som artefakt.
Relevanta enhets- eller integrationstester är uppdaterade.
Inte i fasen:
Ingen containerbyggnation.
Ingen Podman Compose-start.
Fas 3: Migrering och seedprofiler
Mål: dela databasseedning i produktionsrelevant data och frivillig demo- eller
röktestdata.
Gör:
Inför db:seed:required för nödvändig referensdata och systemdata.
Inför db:seed:demo för demo-, PoC- och röktestdata.
Ta bort befintligt db:seed utan kompatibilitetsalias.
Säkerställ att demo- och röktestdata kan läsas externt i senare
containerflöden.
Dokumentera hur utvecklare skapar och underhåller ny testdata för ny
funktionalitet.
Klart när:
Befintliga integrationstester kan köra migrering, db:seed:required och
db:seed:demo.
En tom produktionslik miljö kan beskrivas som migrering plus
db:seed:required.
Demo- och röktestdata är tydligt frivilliga.
Inte i fasen:
Ingen db-job-avbildning ännu.
Ingen release-röktestsvit.
Fas 4: App- och db-job-avbildningar
Mål: skapa projektets egenbyggda produktionsavbildningar med minimal
körningsyta.
Gör:
Säkerställ att utvecklingscontainern installerar Docker CLI, Docker
Compose-plugin och Buildx via Docker outside-of-Docker eller motsvarande
åtkomst till värdens Docker-socket.
Verifiera före avbildningsbyggen att docker --version,
docker buildx version, docker info och docker buildx ls fungerar, eller
dokumentera manuella installationskommandon om miljön blockerar installation.
Konfigurera Next.js med output: "standalone" om det inte redan är gjort.
Skapa containers/app/Dockerfile med målen app-runtime och db-job.
Lås basavbildningar i Dockerfile med tagg och digest.
Kör runtime-steget som icke-root användare.
Kopiera bara .next/standalone, .next/static, public och nödvändiga
produktionsfiler till app-runtime.
Låt db-job innehålla migrationsfiler och produktionsrelevant
seedningskod, men inte demo- eller testdata.
Skapa containers/app/Dockerfile.dockerignore.
Lägg till lokala byggkommandon för app-runtime och db-job.
Klart när:
Båda avbildningsmålen kan byggas lokalt.
Avbildningarna saknar testkod, dokumentation, lintverktyg och
utvecklingskonfiguration.
Basavbildningen är låst i Dockerfile.
Inte i fasen:
Ingen GHCR-publicering.
Ingen Cosign-signering.
Ingen full Compose-stack.
Fas 5: nginx, Keycloak och SQL Server-konfiguration
Mål: göra leverantörscontainrarna körbara i den produktionslika stacken utan
att bygga om dem.
Gör:
Lägg till statisk nginx-konfiguration under containers/nginx/.
Se till att nginx bara ansvarar för TLS-terminering, proxy till appen och
vidarebefordran till Keycloak under /auth.
Lägg till containers/keycloak/realm-kravhantering-test.json.
Säkerställ att realmen matchar
https://kravhantering.test/auth/realms/kravhantering-test.
Lägg till minimala röktestidentiteter, till exempel release-smoke-admin
och release-smoke-user.
Lägg till SQL Server-konfiguration och exempelvärden i
containers/sqlserver/.
Klart när:
nginx kan konfigureras helt med filer och monterade certifikat.
Keycloak-realmen är skild från dev/keycloak/.
Publika demo- och testvärden är tydligt markerade som osäkra för exponerad
drift.
Inte i fasen:
Ingen full Compose-generering.
Ingen Playwright-körning.
Fas 6: Stacklås, Compose-generering och vänteskript
Mål: skapa de återanvändbara skript som håller ihop containerstacken i lokal
felsökning och CI.
Röktestet är mycket mindre än den befintliga fulla produktionslika sviten.
Inte i fasen:
Ingen GHCR-publicering.
Ingen releasepublicering.
Fas 9: PR-arbetsflöde
Mål: köra containerbygg, Podman Compose och release-röktest i pull requests
utan att publicera till GHCR.
Gör:
Skapa GitHub Actions-arbetsflöde för PR.
Bygg app-runtime och db-job med Docker Buildx.
Använd lokala PR-taggar för egenbyggda avbildningar.
Exportera separata komprimerade OCI-arkiv för app-runtime och db-job.
Kontrollera att OCI-arkiven kan läsas och matchar stacklåsningsfilen.
Generera PR-Compose med lokala app- och db-job-taggar.
Håll nginx, SQL Server och Keycloak digest-låsta även i PR-Compose.
Kör Podman Compose och release-röktest.
Spara artefakter med rätt lagringstid.
Samla loggar och status både före och efter nedstängningsförsök vid fel.
Klart när:
PR från normalt repo kör hela röktestflödet utan GHCR-publicering.
PR-artefakter innehåller Playwright-rapport, loggar, statusfiler,
genererad Compose-fil, stacklåsningsfil, byggmetadata, OCI-arkiv och
hashes.sha256.
Fork-säkerheten är bevarad.
Inte i fasen:
Ingen publicering av förhandsversioner.
Ingen Cosign-signering.
Fas 10: Betrodd main- och releasepublicering
Mål: publicera, verifiera och dokumentera betrodda avbildningar från main
och stabila versionstaggar.
Gör:
Inför GitVersion som versionskälla.
Skapa förhandsversionstaggar för relevanta betrodda merges till main.
Skapa GitHub-förhandsutgåvor för förhandsversioner.
Publicera app-runtime och db-job till GHCR i betrodda flöden.
Starta release-Compose med GHCR-referenser låsta till digest.
Signera egenbyggda avbildningar med Cosign keyless signing.
Skapa och verifiera GitHub Artifact Attestations för provenance och SBOM.
Skapa versionsanteckningar med digest, checksummor och länkar till
röktestartefakter.
Behåll GitHub-förhandsutgåvor permanent och markera bara stabila releases
som latest.
Klart när:
Main kan skapa förhandsversioner enligt GitVersion-reglerna.
Stabil tagg kan skapa normal GitHub Release.
Releaseflödet verifierar signaturer, attesteringar och digest innan
Podman Compose startas.
Inte i fasen:
Ingen release-please-implementation.
Ingen automatisk uppdatering av leverantörsavbildningar.
Fas 11: PoC- och demodokumentation
Mål: göra stacken användbar för demo och PoC utan att ge intryck av att
publika utvecklingsvärden är säkra i exponerad drift.
Gör:
Dokumentera hur demo-profilen startas med publika exempelvärden.
Dokumentera vilka värden som måste bytas för en säker exponerad miljö:
sessionsnyckel, Keycloak-klienthemligheter, Keycloak-adminlösenord,
SQL Server-lösenord, TLS-certifikat och eventuella MCP-klienthemligheter.
Dokumentera nollställningskommandot för den lokala PoC/demo-volymen.
Dokumentera hur image.lock.json uppdateras per leverantörscontainer.
Dokumentera hur en användare hittar testad version, digest och
röktestbevis.
Klart när:
En användare kan starta demo utan hemliga förberedelser.
Samma dokumentation varnar tydligt för vad som måste ändras före exponerad
drift.
PoC/demodokumentationen pekar på de artefakter och låsfiler som faktiskt
skapas av arbetsflödena.
Inte i fasen:
Ingen ny produktionsdriftsättning utanför den containerbaserade
PoC/demo-modellen.
$grill-with-docs jag vill att vi jobbar och få fram den bästa lösningen som översiktligt beskrivs i docs/prompt.md, jag vill att vi ändrar i docs/prompt.md allt eftersom vi kommer fram till hur vi bäst gör ett produktions bygg/deploy flöde för detta project.
Jag tror vi behöver dela upp designen i implementationsfaser utan att förändra designen då det kan vara mycket att göra i ett svep för en AI. Kan du skapa en prompt-faser.md med lämpliga faser i ordning där fas 1 görs först