Multi-stage build: node builds the SPA, dotnet publishes the API, the
runtime image serves the SPA from wwwroot/ and exposes /health. Frontend
Supabase URL + publishable key are baked in at build time; DB conn string
and Supabase JWKS metadata come from Coolify env vars. VITE_API_URL empty
means same-origin, so the browser hits /api/todos on the same host that
serves the SPA.
The scaffolded template shipped an opinionated marketing-page CSS
(fixed #root width, large h1 sizes, letter-spacing) that made the
TodoList header overlap. Replaced with a minimal reset so component
inline styles render as intended.
Port 5000 caused recurring collisions with stray processes across subagent
runs. 5057 is uncontested in this environment. CORS unaffected (Vite dev
origin is 5173).
Direct DB host is IPv6-only for new Supabase projects and unreachable from
IPv4-only environments. The session pooler (Supavisor, port 5432) is the
correct entry point and keeps prepared statements working with EF Core.
17 bite-sized tasks with manual verification (curl for backend,
browser for frontend) since the spec excludes automated tests
in the first pass. Uses marker-comment replacements in Program.cs
so JWT auth and CORS drop in cleanly without depending on the
exact template output.
Captures the approved brainstorming design: React SPA (Vite+TS) talks only
to the ASP.NET Core Web API; the API validates Supabase JWTs against the
JWKS URL and owns the Postgres connection. Minimal per-user todo CRUD,
local dev only.