diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index b37a76a..b08c640 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -96,6 +96,7 @@ jobs: file: Dockerfile target: runner push: true + provenance: false tags: | git.farh.net/groombook/api:${{ steps.version.outputs.tag }} ${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/api:latest' || '' }} @@ -110,6 +111,7 @@ jobs: file: Dockerfile target: migrate push: true + provenance: false tags: | git.farh.net/groombook/migrate:${{ steps.version.outputs.tag }} ${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/migrate:latest' || '' }} @@ -124,6 +126,7 @@ jobs: file: Dockerfile target: seed push: true + provenance: false tags: | git.farh.net/groombook/seed:${{ steps.version.outputs.tag }} ${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/seed:latest' || '' }} @@ -138,6 +141,7 @@ jobs: file: Dockerfile target: reset push: true + provenance: false tags: | git.farh.net/groombook/reset:${{ steps.version.outputs.tag }} ${{ github.ref == 'refs/heads/main' && 'git.farh.net/groombook/reset:latest' || '' }} diff --git a/apps/api/src/routes/admin/seed.ts b/apps/api/src/routes/admin/seed.ts index 4458811..0f3dbe2 100644 --- a/apps/api/src/routes/admin/seed.ts +++ b/apps/api/src/routes/admin/seed.ts @@ -45,8 +45,8 @@ const UAT_CLIENT = { }; const UAT_PETS = [ - { name: "Bella", species: "Dog", breed: "Poodle", coatType: "curly", weightKg: "20.00" }, - { name: "Max", species: "Dog", breed: "Labrador Retriever", coatType: "short", weightKg: "30.00" }, + { name: "Bella", species: "Dog", breed: "Poodle", coatType: "curly" as const, weightKg: "20.00" }, + { name: "Max", species: "Dog", breed: "Labrador Retriever", coatType: "short" as const, weightKg: "30.00" }, ]; const DEMO_SERVICES = [ @@ -164,11 +164,11 @@ adminSeedRouter.post("/", async (c) => { .where(eq(pets.clientId, uatClientId)); for (const uatPet of UAT_PETS) { - const existing = existingUatPets.find( + const existingPet = existingUatPets.find( (p) => p.name === uatPet.name && p.species === uatPet.species ); - if (existing) { - results.push(`Pet '${uatPet.name}' already exists for UAT Customer (id: ${existing.id})`); + if (existingPet) { + results.push(`Pet '${uatPet.name}' already exists for UAT Customer (id: ${existingPet.id})`); } else { const [created] = await db .insert(pets) @@ -177,7 +177,7 @@ adminSeedRouter.post("/", async (c) => { name: uatPet.name, species: uatPet.species, breed: uatPet.breed, - coatType: uatPet.coatType as any, + coatType: uatPet.coatType, weightKg: uatPet.weightKg, dateOfBirth: new Date("2019-01-01T00:00:00Z"), }) @@ -194,4 +194,4 @@ adminSeedRouter.post("/", async (c) => { staffOidcSub: KNOWN_STAFF.oidcSub, }, }); -}); +}); \ No newline at end of file diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 8b3b01f..e3bc914 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -12,7 +12,7 @@ export function getDb() { if (_db) return _db; const url = process.env.DATABASE_URL; if (!url) throw new Error("DATABASE_URL is not set"); - const client = postgres(url, { max: 10 }); + const client = postgres(url, { max: 10, connect_timeout: 5 }); _db = drizzle(client, { schema }); return _db; } diff --git a/src/index.ts b/src/index.ts index 9ae50b8..3dd8921 100644 --- a/src/index.ts +++ b/src/index.ts @@ -59,6 +59,9 @@ app.use( ); // Health check — no auth required, registered on app at full path before auth middleware +// /health: used by Dockerfile HEALTHCHECK and K8s readinessProbe/livenessProbe (port 3000 direct) +app.get("/health", (c) => c.json({ status: "ok" })); +// /api/health: used by Gateway HTTPRoute (/api/* → API pod) app.get("/api/health", (c) => c.json({ status: "ok" })); // Public booking routes — no auth required, must be registered before auth middleware @@ -282,14 +285,16 @@ startReminderScheduler(); function shutdown() { console.log("Shutting down gracefully..."); + // SIGTERM/SIGINT → server.close() → callback → process.exit(0) + // If graceful close takes >8s, force-exit to avoid being killed undrained + setTimeout(() => { + console.error("Graceful close timeout — forcing exit"); + process.exit(1); + }, 8_000); server.close(() => { console.log("HTTP server closed"); process.exit(0); }); - setTimeout(() => { - console.error("Forced shutdown after timeout"); - process.exit(1); - }, 10_000); } process.on("SIGTERM", shutdown); diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 9e78740..da2b2d1 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -186,7 +186,9 @@ export async function initAuth(): Promise { const discoveryUrlStr = `${providerConfig.issuerUrl}/.well-known/openid-configuration`; let oidcConfig: Record = {}; try { - const discoveryRes = await fetch(discoveryUrlStr); + const discoveryRes = await fetch(discoveryUrlStr, { + signal: AbortSignal.timeout(5000), + }); if (discoveryRes.ok) { const discovery = await discoveryRes.json() as { authorization_endpoint?: string;