Bygg PWA-installasjonsoppfordring (Android beforeinstallprompt + iOS instruksjonsbanner) Design og bygg flere flighter i én frittstående runde (løs gruppering, retning 1) Design og bygg scramble/greensome-statistikk (valgt utslag per spiller) Bygg push-varsler til telefonens OS (VAPID, push_subscription, service worker) Scratch-verifiser backend for alle fire (27/27 sjekker gjort) Browserverifiser alle fire i nettleser mot scratch-backend Rull ut mot ekte systemer (migrasjoner + containere), med bekreftelse Oppdater CLAUDE.md/FEATURE_BACKLOG.md/ARCHITECTURE_DECISIONS.md Alle fire er ferdigstilt, verifisert og live. Kort oppsummert: PWA-installasjonsoppfordring — ekte beforeinstallprompt-fanging, Android-knapp + iOS-instruksjonsbanner, vist på dashbordet. Bekreftet at Chrome faktisk fyrte eventet i testøkten. Flere flighter i én frittstående runde — løs gruppering av separate runder (delt UUID), "+ Legg til en flight til" gjenbruker hele opprett-flyten forhåndsutfylt, nytt kombinert leaderboard på tvers av flighter. Testet fra knappetrykk til ferdig runde, bekreftet i database. Scramble/greensome: valgt utslag per spiller — nytt felt i hull-registreringen (helt valgfritt), "Utslag brukt"-oppsummering på statistikksiden. Bygget for frittstående runder; org-turneringer bevisst utenfor omfang denne runden (notert i backloggen). Push-varsler til telefonens OS — Web Push/VAPID, ny av/på-bryter i kontoinnstillinger, dekker alle fire varseltyper automatisk. VAPID-nøkler generert og lagt i .env uten å vises i chatten. Én ærlig begrensning: ekte OS-varsel-levering med innvilget tillatelse kunne ikke testes i denne automatiserte nettleserøkten (tillatelsen var forhåndsblokkert av miljøet) — verdt å teste selv på en ekte enhet. 27/27 scratch-sjekker, full nettleser-gjennomgang uten konsollfeil, migrasjoner 035–037 kjørt mot ekte teecup_db, begge containere redeployet og verifisert, teeoff.no upåvirket. Alle tre .md-filene er oppdatert med full detalj.
63 lines
3.7 KiB
JavaScript
63 lines
3.7 KiB
JavaScript
// API-et proxyes server-side under samme opprinnelse (ingen CORS, cookien
|
|
// fungerer uendret) -- se ADR-009/015. TEECUP_API_ORIGIN peker mot en lokal
|
|
// backend i dev; i prod peker den mot teecup_api på det delte Docker-nettverket.
|
|
const API_ORIGIN = process.env.TEECUP_API_ORIGIN || "http://localhost:8000"
|
|
|
|
/** @type {import('next').NextConfig} */
|
|
const nextConfig = {
|
|
output: "standalone",
|
|
images: {
|
|
unoptimized: true,
|
|
},
|
|
// MERK (funnet 2026-07-19, se FEATURE_BACKLOG.md): en plain array her gir
|
|
// implisitt "afterFiles"-semantikk -- statiske filer/sider sjekkes FØR
|
|
// disse rewrites, men DYNAMISKE Next.js-sider (app/x/[id]/page.tsx)
|
|
// sjekkes ETTER. En frontend-SIDE må derfor ALDRI nestes direkte under
|
|
// et av prefiksene under (f.eks. /orgs/[id]/members) -- rewrite-regelen
|
|
// vinner presedens og siden blir uoppnåelig (rå API-404 i stedet).
|
|
// Legg nye frontend-sider et sted UTENFOR disse prefiksene (se
|
|
// app/organizations/[id]/members for eksempelet dette ble rettet på).
|
|
//
|
|
// SAMME FELLE, VERRE UTSLAG (funnet 2026-07-23, ADR-033): en EKSAKT
|
|
// kollisjon (ikke bare nøsting) mellom en frontend-side og et
|
|
// rewrite-prefiks slår begge veier. `/rounds` var opprinnelig BÅDE en
|
|
// frontend-liste-side OG rounds.py sitt API-prefiks -- statisk side vs.
|
|
// eksakt rewrite: SIDEN vant, så `fetch("/rounds")`/`POST /rounds` fra
|
|
// klienten traff aldri backend (fikk Next sin egen HTML tilbake, JSON-
|
|
// parsing feilet stille). `/rounds/[id]` (DYNAMISK side) vs.
|
|
// `/rounds/:path*`: REWRITEN vant, så selve rundedetalj-siden var
|
|
// fullstendig uoppnåelig (rå backend-JSON i stedet for UI-et). Løst ved
|
|
// å flytte frontend-sidene til et HELT ANNET toppnivå-prefiks
|
|
// (`/my-rounds/*`) som ikke overlapper `/rounds/*` i det hele tatt --
|
|
// API-et beholder `/rounds` uendret. Lærdom: et rewrite-prefiks og en
|
|
// frontend-sides toppnivå-segment må ALDRI være identisk streng, selv
|
|
// om det virker naturlig (f.eks. "runder" for begge).
|
|
async rewrites() {
|
|
return [
|
|
{ source: "/auth/:path*", destination: `${API_ORIGIN}/auth/:path*` },
|
|
{ source: "/orgs/:path*", destination: `${API_ORIGIN}/orgs/:path*` },
|
|
{ source: "/public/:path*", destination: `${API_ORIGIN}/public/:path*` },
|
|
{ source: "/superadmin/:path*", destination: `${API_ORIGIN}/superadmin/:path*` },
|
|
{ source: "/rounds/:path*", destination: `${API_ORIGIN}/rounds/:path*` },
|
|
{ source: "/rounds", destination: `${API_ORIGIN}/rounds` },
|
|
{ source: "/personal-courses/:path*", destination: `${API_ORIGIN}/personal-courses/:path*` },
|
|
{ source: "/personal-courses", destination: `${API_ORIGIN}/personal-courses` },
|
|
// Venner-kjernen (ADR-036, fase 1, 2026-07-25).
|
|
{ source: "/people/:path*", destination: `${API_ORIGIN}/people/:path*` },
|
|
{ source: "/friends/:path*", destination: `${API_ORIGIN}/friends/:path*` },
|
|
{ source: "/friends", destination: `${API_ORIGIN}/friends` },
|
|
// Merk (samme kollisjonsklasse som /rounds->/my-rounds og
|
|
// /friends->/my-friends): frontend-siden for dette heter derfor
|
|
// /my-notifications, ALDRI /notifications.
|
|
{ source: "/notifications/:path*", destination: `${API_ORIGIN}/notifications/:path*` },
|
|
{ source: "/notifications", destination: `${API_ORIGIN}/notifications` },
|
|
// Push-varsler til telefonens OS (Web Push/VAPID, 2026-07-28) -- ingen
|
|
// frontend-side bruker dette prefikset, kun fetch() fra /account.
|
|
{ source: "/push/:path*", destination: `${API_ORIGIN}/push/:path*` },
|
|
{ source: "/push", destination: `${API_ORIGIN}/push` },
|
|
{ source: "/health", destination: `${API_ORIGIN}/health` },
|
|
]
|
|
},
|
|
}
|
|
|
|
export default nextConfig
|