feat(15-01): add Logto service to Docker Compose and create init script
- Add Logto OIDC provider to docker-compose.yml and docker-compose.dev.yml - Create docker/init-logto-db.sql to initialize separate Logto database on Postgres - Add OIDC env vars (issuer, client ID/secret, auth secret) to app service - Document all required env vars in .env.example
This commit is contained in:
220
.planning/phases/15-external-authentication/15-01-PLAN.md
Normal file
220
.planning/phases/15-external-authentication/15-01-PLAN.md
Normal file
@@ -0,0 +1,220 @@
|
||||
---
|
||||
phase: 15-external-authentication
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- docker-compose.yml
|
||||
- docker-compose.dev.yml
|
||||
- docker/init-logto-db.sql
|
||||
- src/db/schema.ts
|
||||
- .env.example
|
||||
autonomous: true
|
||||
requirements: [AUTH-04]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Logto container starts alongside Postgres in docker-compose"
|
||||
- "Logto admin console is accessible at port 3002"
|
||||
- "Logto OIDC discovery endpoint responds at /oidc/.well-known/openid-configuration"
|
||||
- "GearBox schema no longer contains users or sessions tables"
|
||||
- "A separate logto database is created automatically on Postgres first boot"
|
||||
artifacts:
|
||||
- path: "docker-compose.yml"
|
||||
provides: "Production Logto service definition"
|
||||
contains: "svhd/logto"
|
||||
- path: "docker-compose.dev.yml"
|
||||
provides: "Dev Logto service definition"
|
||||
contains: "svhd/logto"
|
||||
- path: "docker/init-logto-db.sql"
|
||||
provides: "Postgres init script creating logto database"
|
||||
contains: "CREATE DATABASE logto"
|
||||
- path: "src/db/schema.ts"
|
||||
provides: "Schema without users/sessions tables"
|
||||
- path: ".env.example"
|
||||
provides: "Documentation of required OIDC env vars"
|
||||
contains: "OIDC_ISSUER"
|
||||
key_links:
|
||||
- from: "docker-compose.yml"
|
||||
to: "docker/init-logto-db.sql"
|
||||
via: "postgres volume mount to docker-entrypoint-initdb.d"
|
||||
pattern: "init-logto-db.sql:/docker-entrypoint-initdb.d"
|
||||
- from: "docker-compose.yml logto service"
|
||||
to: "docker-compose.yml postgres service"
|
||||
via: "depends_on with service_healthy"
|
||||
pattern: "condition: service_healthy"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Add Logto as a Docker Compose service and remove the users/sessions tables from the GearBox schema.
|
||||
|
||||
Purpose: Establishes the infrastructure foundation for OIDC authentication -- Logto must be running before server-side auth code can be integrated. Schema changes remove the old auth tables that will be replaced by Logto-managed identity.
|
||||
|
||||
Output: Updated docker-compose files with Logto, cleaned schema, env var documentation.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/15-external-authentication/15-CONTEXT.md
|
||||
@.planning/phases/15-external-authentication/15-RESEARCH.md
|
||||
@src/db/schema.ts
|
||||
@docker-compose.yml
|
||||
@docker-compose.dev.yml
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add Logto service to Docker Compose and create init script</name>
|
||||
<files>docker-compose.yml, docker-compose.dev.yml, docker/init-logto-db.sql, .env.example</files>
|
||||
<read_first>
|
||||
- docker-compose.yml (current production compose)
|
||||
- docker-compose.dev.yml (current dev compose)
|
||||
- .planning/phases/15-external-authentication/15-RESEARCH.md (Pattern 4: Logto Docker Compose Integration, Pitfall 1: OIDC Issuer URL Mismatch)
|
||||
</read_first>
|
||||
<action>
|
||||
**Per D-13 and D-14:** Add Logto as a service in both docker-compose files.
|
||||
|
||||
1. Create `docker/init-logto-db.sql` with content:
|
||||
```sql
|
||||
-- Creates a separate database for Logto on the shared Postgres instance
|
||||
CREATE DATABASE logto;
|
||||
```
|
||||
|
||||
2. Update `docker-compose.yml` (production):
|
||||
- Add volume mount on postgres service: `./docker/init-logto-db.sql:/docker-entrypoint-initdb.d/init-logto-db.sql`
|
||||
- Add `logto` service:
|
||||
```yaml
|
||||
logto:
|
||||
image: svhd/logto:latest
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
entrypoint: ["sh", "-c", "npm run cli db seed -- --swe && npm start"]
|
||||
ports:
|
||||
- "3001:3001"
|
||||
- "3002:3002"
|
||||
environment:
|
||||
TRUST_PROXY_HEADER: "1"
|
||||
DB_URL: postgres://gearbox:${POSTGRES_PASSWORD}@postgres:5432/logto
|
||||
ENDPOINT: ${LOGTO_ENDPOINT:-http://localhost:3001}
|
||||
ADMIN_ENDPOINT: ${LOGTO_ADMIN_ENDPOINT:-http://localhost:3002}
|
||||
```
|
||||
- Add to `app` service environment:
|
||||
```yaml
|
||||
OIDC_ISSUER: ${LOGTO_ENDPOINT:-http://localhost:3001}/oidc
|
||||
OIDC_CLIENT_ID: ${LOGTO_CLIENT_ID}
|
||||
OIDC_CLIENT_SECRET: ${LOGTO_CLIENT_SECRET}
|
||||
OIDC_AUTH_SECRET: ${OIDC_AUTH_SECRET}
|
||||
```
|
||||
- Add `depends_on` for app -> logto: `condition: service_started`
|
||||
|
||||
3. Update `docker-compose.dev.yml`:
|
||||
- Add the same postgres init volume mount
|
||||
- Add same `logto` service definition (ports 3001, 3002)
|
||||
- Logto environment uses hardcoded dev password: `DB_URL: postgres://gearbox:gearbox@postgres:5432/logto`
|
||||
|
||||
4. Create or update `.env.example` with all new OIDC env vars:
|
||||
```
|
||||
# PostgreSQL
|
||||
POSTGRES_PASSWORD=changeme
|
||||
|
||||
# Logto OIDC (get from Logto Admin Console at http://localhost:3002)
|
||||
LOGTO_ENDPOINT=http://localhost:3001
|
||||
LOGTO_ADMIN_ENDPOINT=http://localhost:3002
|
||||
LOGTO_CLIENT_ID=your-app-client-id
|
||||
LOGTO_CLIENT_SECRET=your-app-client-secret
|
||||
OIDC_AUTH_SECRET=generate-a-random-32-char-string-here
|
||||
|
||||
# GearBox
|
||||
GEARBOX_URL=http://localhost:3000
|
||||
```
|
||||
|
||||
**IMPORTANT (Pitfall 1):** The `ENDPOINT` on Logto and `OIDC_ISSUER` on the app must both use the *externally accessible* URL (e.g., `http://localhost:3001`), NOT Docker-internal hostnames. The browser redirect and server-side JWT validation must agree on the issuer string.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>grep -q "svhd/logto" docker-compose.yml && grep -q "svhd/logto" docker-compose.dev.yml && grep -q "CREATE DATABASE logto" docker/init-logto-db.sql && grep -q "OIDC_ISSUER" .env.example && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- docker-compose.yml contains `image: svhd/logto:latest`
|
||||
- docker-compose.yml logto service has `depends_on: postgres: condition: service_healthy`
|
||||
- docker-compose.yml logto service exposes ports 3001 and 3002
|
||||
- docker-compose.yml postgres service has volume mount containing `init-logto-db.sql:/docker-entrypoint-initdb.d/init-logto-db.sql`
|
||||
- docker-compose.yml app service has `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, `OIDC_AUTH_SECRET` env vars
|
||||
- docker-compose.dev.yml contains matching logto service definition
|
||||
- docker/init-logto-db.sql contains `CREATE DATABASE logto;`
|
||||
- .env.example contains `LOGTO_CLIENT_ID`, `LOGTO_CLIENT_SECRET`, `OIDC_AUTH_SECRET`, `LOGTO_ENDPOINT`
|
||||
</acceptance_criteria>
|
||||
<done>Both docker-compose files have Logto service, init SQL creates logto database, env vars documented</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Remove users and sessions tables from schema and generate migration</name>
|
||||
<files>src/db/schema.ts</files>
|
||||
<read_first>
|
||||
- src/db/schema.ts (current full schema with users, sessions, apiKeys, oauth* tables)
|
||||
- .planning/phases/15-external-authentication/15-CONTEXT.md (D-03: Remove users and sessions tables)
|
||||
</read_first>
|
||||
<action>
|
||||
**Per D-03:** Remove the `users` and `sessions` table definitions from `src/db/schema.ts`. Keep everything else: `categories`, `items`, `threads`, `threadCandidates`, `setups`, `setupItems`, `settings`, `apiKeys`, `oauthClients`, `oauthCodes`, `oauthTokens`.
|
||||
|
||||
Specifically:
|
||||
1. Delete the `users` table definition (lines defining `export const users = pgTable("users", { ... })`)
|
||||
2. Delete the `sessions` table definition (lines defining `export const sessions = pgTable("sessions", { ... })`)
|
||||
3. Remove the `boolean` import from `drizzle-orm/pg-core` if no longer used (check: `oauthCodes` uses `boolean` for `used` field, so keep it)
|
||||
4. Do NOT remove `apiKeys` table -- it stays per D-10
|
||||
|
||||
After editing schema, run migration generation:
|
||||
```bash
|
||||
bun run db:generate
|
||||
```
|
||||
|
||||
This creates a Drizzle migration SQL file in `drizzle/` that drops the `users` and `sessions` tables. Review the generated migration to confirm it only drops `users` and `sessions` -- no other tables.
|
||||
|
||||
**Do NOT run `bun run db:push` yet** -- that will be done when the full auth refactor is ready.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>! grep -q "export const users" src/db/schema.ts && ! grep -q "export const sessions" src/db/schema.ts && grep -q "export const apiKeys" src/db/schema.ts && echo "PASS" || echo "FAIL"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- src/db/schema.ts does NOT contain `export const users`
|
||||
- src/db/schema.ts does NOT contain `export const sessions`
|
||||
- src/db/schema.ts DOES contain `export const apiKeys`
|
||||
- src/db/schema.ts DOES contain `export const oauthClients`
|
||||
- src/db/schema.ts DOES contain `export const oauthCodes`
|
||||
- src/db/schema.ts DOES contain `export const oauthTokens`
|
||||
- A new migration file exists in drizzle/ directory
|
||||
</acceptance_criteria>
|
||||
<done>Users and sessions tables removed from schema, migration generated to drop them</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `grep -q "svhd/logto" docker-compose.yml` succeeds
|
||||
- `grep -q "svhd/logto" docker-compose.dev.yml` succeeds
|
||||
- `docker/init-logto-db.sql` exists with CREATE DATABASE logto
|
||||
- `src/db/schema.ts` has no `users` or `sessions` exports
|
||||
- `src/db/schema.ts` retains `apiKeys`, `oauthClients`, `oauthCodes`, `oauthTokens`
|
||||
- New Drizzle migration file exists in `drizzle/`
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Logto service defined in both docker-compose files with correct ports, env vars, and Postgres dependency
|
||||
- Postgres init script creates the logto database
|
||||
- GearBox schema has users and sessions tables removed
|
||||
- Drizzle migration generated for the table drops
|
||||
- All OIDC-related environment variables documented in .env.example
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/15-external-authentication/15-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user