teecup/frontend/app/page.tsx
Erol Haagenrud 79c4406723 Update Todos
Skriv migrasjon 019 (app_user.country + bio)

Backend: profile_complete-felt, ProfileUpdate country/bio/HCP-cap

Frontend: onboarding-visning i /account, gate i page.tsx + dashboard.tsx

Scratch-verifiser hele flyten

Be om bekreftelse og rull ut live
Scratch-verifisert, alt grønt:

Migrasjon 019 kjørte rent (001→019), test_isolation.sql 12/12 uendret.
16/16 backend-sjekker: fersk konto starter profile_complete: false, delvis utfylling forblir ufullstendig, HCP >54 avvist (422), full utfylling (inkl. HCP=54) gir profile_complete: true, beskrivelse er reelt valgfri, å nullstille et obligatorisk felt i etterkant slår profile_complete tilbake til false, full isolasjon mellom to kontoer.
Ekte produksjonsbuild av frontend kompilerte rent, alle 16 ruter listet.
Ekte HTTP-nivå-bevis mot en kjørende produksjonscontainer: anonym mot / → 200 (innloggingsskjema), en ekte innlogget-men-ufullstendig sesjonscookie mot / → 307 → /account.
Klar for ekte teecup_db. Dette krever:

Kjøre 019_profile_country_bio.sql mot ekte teecup_db (kun to nye nullable kolonner på app_user — additivt, ingen eksisterende rader berørt).
docker compose up -d --build teecup_api teecup_frontend.
Verdt å merke: med dette rullet ut vil både hei@erol.no og erol.haagenrud@envide.no bli sendt til profil-fullføring ved neste innlogging — ingen av kontoene har disse feltene utfylt i dag (bekreftet med spørringen tidligere).
2026-07-22 07:53:29 +02:00

68 lines
2.8 KiB
TypeScript

import { cookies } from "next/headers"
import { redirect } from "next/navigation"
import { LoginForm } from "@/components/login-form"
import { Wordmark } from "@/components/wordmark"
// Server-side, IKKE nettleser-fetch -- går derfor IKKE gjennom
// next.config.mjs sin rewrites() (samme mønster som generateMetadata i
// app/t/[id]/page.tsx). Peker direkte på API-et.
const API_ORIGIN = process.env.TEECUP_API_ORIGIN || "http://localhost:8000"
// Må matche SESSION_COOKIE_NAME i app/auth.py -- ingen delt konstant på
// tvers av Python/TypeScript, samme mønster som andre API-kontrakt-felt
// som dupliseres bevisst i frontend-koden.
const SESSION_COOKIE_NAME = "teecup_session"
export default async function Page() {
// Reell bug funnet 2026-07-19: denne siden viste ALLTID innloggingsskjemaet,
// uansett om brukeren allerede hadde en helt gyldig sesjonscookie (30 dager,
// bekreftet riktig satt) -- Dashboard sjekker /auth/me og sender deg HIT ved
// manglende sesjon, men ingenting gjorde det motsatte. En bruker som besøkte
// teecup.teeoff.no direkte (i stedet for å navigere til /dashboard) så derfor
// alltid innloggingsskjemaet og ba unødvendig om en ny magic-link hver gang.
const cookieStore = await cookies()
const session = cookieStore.get(SESSION_COOKIE_NAME)
let authenticated = false
let profileComplete = true
if (session) {
try {
const res = await fetch(`${API_ORIGIN}/auth/me`, {
headers: { Cookie: `${SESSION_COOKIE_NAME}=${session.value}` },
cache: "no-store",
})
authenticated = res.ok
if (res.ok) {
const data = await res.json()
profileComplete = Boolean(data.profile_complete)
}
} catch {
// API utilgjengelig -- vis innloggingsskjemaet i stedet for å henge.
authenticated = false
}
}
if (authenticated) {
// Obligatorisk profil-fullføring (2026-07-22): en innlogget bruker som
// ennå ikke har fylt ut de obligatoriske profilfeltene sendes til
// /account (som selv viser en fokusert fullførings-visning) i stedet
// for dashbordet -- se AccountSettings sin profile_complete-gren.
redirect(profileComplete ? "/dashboard" : "/account")
}
return (
<main className="flex min-h-[100dvh] flex-col items-center justify-center bg-background px-5 py-10">
<div className="flex w-full max-w-sm flex-col gap-8">
<header className="flex flex-col items-center gap-3 text-center">
<Wordmark />
<p className="text-balance text-base leading-relaxed text-muted-foreground">
Logg inn for å følge turneringen din live.
</p>
</header>
<LoginForm />
<p className="text-center text-xs leading-relaxed text-muted-foreground text-pretty">
Ved å logge inn godtar du våre vilkår og personvernregler.
</p>
</div>
</main>
)
}