feat(dm-dashboard): Wave 1 — auth fixes, DB schema, Open5e interfaces, AI clients
- Fix auth anti-patterns (JWT, OAuth, logout, middleware, url.origin) - Extend DB schema with tier, npcs, counters, translations, notes, initiative - Expand Open5e TypeScript interfaces (Monster, Spell) to full V2 - Build OpenRouter API client for FREE tier - Build Kimi API client for PRO tier - Add comprehensive tests for all modules
This commit is contained in:
+48
-8
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": 2,
|
||||
"active_work_id": "dm-dashboard-redesign-a1bfaddc",
|
||||
"active_work_id": "dm-dashboard-ai-c738b11e",
|
||||
"works": {
|
||||
"critical-refactor-f063daf0": {
|
||||
"work_id": "critical-refactor-f063daf0",
|
||||
@@ -387,19 +387,59 @@
|
||||
},
|
||||
"agent": "atlas",
|
||||
"task_sessions": {}
|
||||
},
|
||||
"dm-dashboard-ai-c738b11e": {
|
||||
"work_id": "dm-dashboard-ai-c738b11e",
|
||||
"active_plan": "/home/emil/Desktop/Coding/AI/Randify.pro/.sisyphus/plans/dm-dashboard-ai.md",
|
||||
"plan_name": "dm-dashboard-ai",
|
||||
"status": "active",
|
||||
"started_at": "2026-05-15T17:58:09.859Z",
|
||||
"updated_at": "2026-05-15T18:24:29.818Z",
|
||||
"session_ids": [
|
||||
"ses_1d3921469ffeQox08ZjNWWJq7u"
|
||||
],
|
||||
"session_origins": {
|
||||
"ses_1d3921469ffeQox08ZjNWWJq7u": "direct"
|
||||
},
|
||||
"agent": "atlas",
|
||||
"task_sessions": {
|
||||
"final-wave:f1": {
|
||||
"task_key": "final-wave:f1",
|
||||
"task_label": "F1",
|
||||
"task_title": "**Plan Compliance Audit** — `oracle`",
|
||||
"session_id": "ses_1d333a383ffeOqEVZptN3EbGAY",
|
||||
"agent": "Sisyphus-Junior",
|
||||
"category": "quick",
|
||||
"updated_at": "2026-05-15T18:24:29.818Z",
|
||||
"started_at": "2026-05-15T18:24:29.818Z",
|
||||
"status": "running"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"active_plan": "/home/emil/Desktop/Coding/AI/Randify.pro/.sisyphus/plans/dm-dashboard-redesign.md",
|
||||
"started_at": "2026-05-15T12:32:10.008Z",
|
||||
"active_plan": "/home/emil/Desktop/Coding/AI/Randify.pro/.sisyphus/plans/dm-dashboard-ai.md",
|
||||
"started_at": "2026-05-15T17:58:09.859Z",
|
||||
"status": "active",
|
||||
"updated_at": "2026-05-15T12:32:10.008Z",
|
||||
"updated_at": "2026-05-15T18:24:29.818Z",
|
||||
"session_ids": [
|
||||
"ses_1d6b615cbffe5pqd0AObdil6OK"
|
||||
"ses_1d3921469ffeQox08ZjNWWJq7u"
|
||||
],
|
||||
"session_origins": {
|
||||
"ses_1d6b615cbffe5pqd0AObdil6OK": "direct"
|
||||
"ses_1d3921469ffeQox08ZjNWWJq7u": "direct"
|
||||
},
|
||||
"plan_name": "dm-dashboard-ai",
|
||||
"task_sessions": {
|
||||
"final-wave:f1": {
|
||||
"task_key": "final-wave:f1",
|
||||
"task_label": "F1",
|
||||
"task_title": "**Plan Compliance Audit** — `oracle`",
|
||||
"session_id": "ses_1d333a383ffeOqEVZptN3EbGAY",
|
||||
"agent": "Sisyphus-Junior",
|
||||
"category": "quick",
|
||||
"updated_at": "2026-05-15T18:24:29.818Z",
|
||||
"started_at": "2026-05-15T18:24:29.818Z",
|
||||
"status": "running"
|
||||
}
|
||||
},
|
||||
"plan_name": "dm-dashboard-redesign",
|
||||
"task_sessions": {},
|
||||
"agent": "atlas"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# Auth Anti-Pattern Fixes — Learnings
|
||||
|
||||
## Date: 2026-05-15
|
||||
|
||||
### Patterns Applied
|
||||
|
||||
1. **Fail-fast env validation with Zod**
|
||||
- Created `src/lib/auth/env.ts` with a `z.object()` schema that validates `JWT_SECRET`, `VK_CLIENT_ID`, `VK_CLIENT_SECRET`, `YANDEX_CLIENT_ID`, `YANDEX_CLIENT_SECRET`, and `PUBLIC_APP_URL` at module load time.
|
||||
- `process.env.JWT_SECRET!` non-null assertion replaced with `authEnv.JWT_SECRET` which throws a descriptive error if the env var is missing.
|
||||
- `requireEnv()` helper provides typed access to validated env values.
|
||||
|
||||
2. **SameSite cookie fix**
|
||||
- Changed `sameSite: 'strict'` to `sameSite: 'lax'` in `setAuthCookie()` (`src/lib/auth/jwt.ts`).
|
||||
- `SameSite=Strict` breaks cross-site OAuth redirects because the browser doesn't send the cookie on the redirect back from the identity provider. `Lax` + `Secure` is the correct combination for OAuth session cookies.
|
||||
|
||||
3. **Removed all `|| ''` fallbacks**
|
||||
- `src/lib/auth/oauth.ts` had 5 instances of `process.env.XXX || ''`.
|
||||
- Replaced with `authEnv.XXX` references. Empty-string fallbacks silently produce invalid OAuth requests (e.g., `client_id: ''` causes 400 errors from VK/Yandex).
|
||||
|
||||
4. **Logout session cleanup**
|
||||
- `src/pages/api/auth/logout.ts` now reads the `auth_token` cookie and calls `deleteSession(token)` before clearing the cookie.
|
||||
- Previously the session row remained in the DB indefinitely.
|
||||
|
||||
5. **Middleware stale cookie cleanup**
|
||||
- `src/middleware/index.ts` now calls `context.cookies.delete('auth_token', { path: '/' })` in two places:
|
||||
- When `verifyToken()` throws (invalid/expired JWT)
|
||||
- When `getSession()` returns `null` (session expired or deleted from DB)
|
||||
- Previously the stale cookie stayed in the browser, causing repeated failed auth attempts on every request.
|
||||
|
||||
6. **PUBLIC_APP_URL exclusivity**
|
||||
- `src/pages/api/auth/callback/vk.ts`, `yandex.ts`, and the login handlers (`login/vk.ts`, `login/yandex.ts`) all used `process.env.PUBLIC_APP_URL || url.origin`.
|
||||
- Replaced with `authEnv.PUBLIC_APP_URL` exclusively.
|
||||
- `url.origin` breaks behind nginx reverse proxy because it returns `http://localhost:4321` instead of the public HTTPS URL.
|
||||
|
||||
### Testing Notes
|
||||
|
||||
- happy-dom strips `Set-Cookie` headers from `Response` objects (both via `Headers` instance and array entries). This is a known limitation — cookie clearing behavior must be tested via integration/Playwright instead of unit tests.
|
||||
- `vi.mock` with alias paths (`@/...`) does not reliably match dynamically imported modules after `vi.resetModules()` in vitest. Using `__mocks__` directories or avoiding deep DB mocking in unit tests is more stable.
|
||||
- `crypto.subtle` needs Node.js `webcrypto` for `jose` to work in vitest. Added `node:crypto` webcrypto to `tests/setup.ts`.
|
||||
- `astro:middleware` is a virtual module that doesn't resolve in vitest. Added an alias in `vitest.config.ts` pointing to `tests/mocks/astro-middleware.ts`.
|
||||
|
||||
### Verification
|
||||
|
||||
- `npx tsc --noEmit`: 0 errors
|
||||
- `npx vitest run src/lib/auth/`: 18/18 tests passed
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"sessionID": "ses_1d389e69bffedksVYoEM6rnr6t",
|
||||
"updatedAt": "2026-05-15T16:29:01.586Z",
|
||||
"sources": {
|
||||
"background-task": {
|
||||
"state": "idle",
|
||||
"updatedAt": "2026-05-15T16:29:01.586Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"sessionID": "ses_1d3921469ffeQox08ZjNWWJq7u",
|
||||
"updatedAt": "2026-05-15T16:20:30.027Z",
|
||||
"sources": {
|
||||
"background-task": {
|
||||
"state": "idle",
|
||||
"updatedAt": "2026-05-15T16:20:30.027Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user