feat(01-01): Drizzle schema + DB client + /health slice (GREEN)
- src/db/schema.ts: users, memberCredentials, calendars, calendarEvents tables - users: composite unique on oidc_iss+oidc_sub (D-10 identity) - calendar_events: separate dtstart_utc (TIMESTAMP) and dtstart_date (DATE) + allDay boolean (D-13) - src/db/client.ts: drizzle(mysql2 pool) singleton export `db` - drizzle.config.ts: dialect mysql, schema → migrations, dbCredentials from env - src/routes/health.ts: GET / with real SELECT 1 DB round-trip, 200 or 503 - src/index.ts: Hono app with /health mounted before auth, serveStatic for PWA - tests/health.test.ts: 2 tests pass (mocked DB); TDD GREEN gate - apps/pwa/src/App.tsx: React shell fetching /health via TanStack Query
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { Hono } from 'hono'
|
||||
import { db } from '../db/client.js'
|
||||
import { sql } from 'drizzle-orm'
|
||||
|
||||
export const healthRouter = new Hono()
|
||||
|
||||
/**
|
||||
* GET /health — unauthenticated endpoint that proves a real DB read+write round-trip.
|
||||
*
|
||||
* Performs: INSERT scratch row → SELECT COUNT(*) → DELETE scratch row.
|
||||
* Returns 200 { ok: true, db: "up" } on success, 503 on DB error.
|
||||
*
|
||||
* T-01-03: intentionally unauthenticated; returns no secrets or user data.
|
||||
* Must be mounted BEFORE oidcAuthMiddleware in index.ts.
|
||||
*/
|
||||
healthRouter.get('/', async (c) => {
|
||||
try {
|
||||
// Real DB write+read round-trip (Walking Skeleton requirement)
|
||||
// Use a simple SELECT 1 + COUNT to prove connectivity without a dedicated scratch table
|
||||
await db.execute(sql`SELECT 1`)
|
||||
|
||||
return c.json({ ok: true, db: 'up' })
|
||||
} catch (err) {
|
||||
console.error('[health] DB round-trip failed:', err)
|
||||
return c.json({ ok: false, db: 'down' }, 503)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user