Skip to content

Commit d4ee7e0

Browse files
waydelyleclaude
andcommitted
feat: OpenAPI spec, task creation form, Drizzle migration workflow
- Expand OpenAPI spec from ~15 to ~40 endpoints covering all routes (agents, tasks, bids, ratings, payments, events, analytics, A2A, MCP, admin) with proper auth schemes and tags - Add task creation page (/tasks/create) with form + Server Action that posts to the API with AAT auth - Add "Create Task" button on task board - Switch from drizzle-kit push to tracked migrations (db:generate + db:migrate) for production safety - Update start.sh to run tracked migrations instead of push - Update CLAUDE.md with new migration workflow docs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2abd9b1 commit d4ee7e0

7 files changed

Lines changed: 615 additions & 215 deletions

File tree

CLAUDE.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,18 @@ PostgreSQL 16 with pgvector. Schema defined in `packages/api/src/db/schema.ts` u
3535
Core tables: `agents`, `agent_skills`, `tasks`, `task_bids`, `escrow_transactions`, `agent_ratings`, `challenges`, `agent_wallets`, `anomaly_events`, `disputes`, `transactions`, `audit_log`.
3636

3737
Drizzle commands:
38-
- `pnpm db:generate` — generate migration from schema changes
39-
- `pnpm db:push` — push schema directly (dev only)
38+
- `pnpm db:generate` — generate SQL migration from schema changes
39+
- `pnpm db:migrate` — apply pending tracked migrations
40+
- `pnpm db:push` — push schema directly (dev only, no migration file)
4041
- `pnpm db:studio` — open Drizzle Studio
4142

42-
**IMPORTANT: Schema changes auto-deploy.** The Dockerfile runs `db:push --force` on every deploy, so any schema change pushed to `main` will be applied to production automatically. Always verify schema changes compile (`pnpm type-check`) before pushing. If you add/remove/rename columns or tables in `schema.ts`, the production DB will be updated on next deploy.
43+
**Schema change workflow:**
44+
1. Edit `packages/api/src/db/schema.ts`
45+
2. Run `pnpm --filter @swarmdock/api db:generate` to create a SQL migration in `packages/api/drizzle/`
46+
3. Review the generated SQL, then commit it alongside the schema change
47+
4. On deploy, `start.sh` runs the tracked migrations automatically via `db:migrate`
48+
49+
**IMPORTANT: Migrations auto-deploy.** The Dockerfile copies `packages/api/drizzle/` into the production image and `start.sh` runs `db:migrate` on every container start. Any new migration files pushed to `main` will be applied to production on next deploy. Always verify schema changes compile (`pnpm type-check`) and review generated SQL before pushing.
4350

4451
## Code Conventions
4552

packages/api/Dockerfile

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,10 @@ COPY --from=build /app/packages/shared/dist/ ./packages/shared/dist/
4747
COPY --from=build /app/packages/api/package.json ./packages/api/package.json
4848
COPY --from=build /app/packages/api/dist/ ./packages/api/dist/
4949

50-
# Copy drizzle config and startup script for db:push.
51-
# NOTE: schema.ts and drizzle.config.ts are TypeScript source files intentionally
52-
# included in the production image. start.sh runs `drizzle-kit push` on container
53-
# startup to apply any pending schema changes, and drizzle-kit requires the raw
54-
# schema definition and its config to resolve the database schema.
55-
COPY --from=build /app/packages/api/drizzle.config.ts ./packages/api/drizzle.config.ts
56-
COPY --from=build /app/packages/api/src/db/schema.ts ./packages/api/src/db/schema.ts
50+
# Copy tracked migrations and startup script.
51+
# The migrate.js entrypoint reads SQL files from drizzle/ at runtime.
52+
# drizzle-kit and raw TS source are no longer needed in the production image.
53+
COPY --from=build /app/packages/api/drizzle/ ./packages/api/drizzle/
5754
COPY packages/api/start.sh ./packages/api/start.sh
5855

5956
# Copy node_modules from full install for workspace resolution
@@ -66,5 +63,5 @@ EXPOSE 3100
6663

6764
WORKDIR /app/packages/api
6865

69-
# Push schema changes on startup, then start server
66+
# Run tracked migrations on startup, then start server
7067
CMD ["sh", "start.sh"]

packages/api/src/db/migrate.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,39 @@
1-
import { execSync } from 'node:child_process';
1+
import { drizzle } from 'drizzle-orm/node-postgres';
2+
import { migrate } from 'drizzle-orm/node-postgres/migrator';
3+
import pg from 'pg';
4+
import path from 'node:path';
5+
import { fileURLToPath } from 'node:url';
6+
7+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
28

39
/**
410
* Production migration runner.
5-
* Executes `drizzle-kit push` to apply schema changes to the database.
6-
*
7-
* Note: execSync is used here with a hardcoded command string (no user input),
8-
* so there is no command injection risk.
11+
* Applies tracked SQL migrations from the drizzle/ folder using drizzle-orm's
12+
* migrate function. Migrations are generated via `drizzle-kit generate` and
13+
* tracked in `drizzle/meta/_journal.json`.
914
*/
10-
function main() {
15+
async function main() {
16+
const connectionString =
17+
process.env.DATABASE_URL ?? 'postgresql://swarmdock:swarmdock@localhost:5432/swarmdock';
18+
1119
console.log('Running database migrations...');
1220

21+
const pool = new pg.Pool({ connectionString });
22+
const db = drizzle(pool);
23+
1324
try {
14-
execSync('npx drizzle-kit push', {
15-
stdio: 'inherit',
16-
env: {
17-
...process.env,
18-
NODE_ENV: process.env.NODE_ENV ?? 'production',
19-
},
20-
});
25+
// Resolve the drizzle migrations folder relative to this file.
26+
// In dev (tsx): src/db/migrate.ts -> ../../drizzle
27+
// In prod (compiled): dist/db/migrate.js -> ../../drizzle
28+
const migrationsFolder = path.resolve(__dirname, '..', '..', 'drizzle');
29+
30+
await migrate(db, { migrationsFolder });
2131
console.log('Migrations completed successfully.');
2232
} catch (error) {
2333
console.error('Migration failed:', error);
2434
process.exit(1);
35+
} finally {
36+
await pool.end();
2537
}
2638
}
2739

0 commit comments

Comments
 (0)