feat: db connection and migration
This commit is contained in:
23
server/db/migrate.ts
Normal file
23
server/db/migrate.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Idempotent migration runner. Run via `bun run migrate` / on container start.
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import postgres from "postgres";
|
||||||
|
|
||||||
|
const url = process.env.DATABASE_URL;
|
||||||
|
if (!url) {
|
||||||
|
console.error("DATABASE_URL not set");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const here = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const sql = postgres(url, { max: 1 });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ddl = readFileSync(join(here, "migrations", "0001_init.sql"), "utf8");
|
||||||
|
// Trusted local DDL file, not user input.
|
||||||
|
await sql.unsafe(ddl);
|
||||||
|
console.log("migration 0001_init applied");
|
||||||
|
} finally {
|
||||||
|
await sql.end();
|
||||||
|
}
|
||||||
22
server/db/migrations/0001_init.sql
Normal file
22
server/db/migrations/0001_init.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
-- ClaudeDo Online Inbox — initial schema.
|
||||||
|
-- Mirrors the desktop's Idle task backlog. Idempotent.
|
||||||
|
|
||||||
|
create table if not exists lists (
|
||||||
|
id text primary key, -- GUID supplied by the desktop, reused verbatim
|
||||||
|
name text not null,
|
||||||
|
updated_at timestamptz not null default now()
|
||||||
|
);
|
||||||
|
|
||||||
|
create table if not exists tasks (
|
||||||
|
id text primary key, -- GUID; shared id space (web + desktop)
|
||||||
|
list_id text not null references lists(id) on delete cascade,
|
||||||
|
title text not null,
|
||||||
|
description text,
|
||||||
|
source text not null, -- 'web' | 'desktop'
|
||||||
|
consumed boolean not null default false, -- web->desktop handoff flag
|
||||||
|
created_at timestamptz not null default now(),
|
||||||
|
updated_at timestamptz not null default now()
|
||||||
|
);
|
||||||
|
|
||||||
|
create index if not exists idx_tasks_list_id on tasks(list_id);
|
||||||
|
create index if not exists idx_tasks_unconsumed on tasks(consumed) where consumed = false;
|
||||||
13
server/utils/db.ts
Normal file
13
server/utils/db.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import postgres from "postgres";
|
||||||
|
|
||||||
|
let _sql: ReturnType<typeof postgres> | null = null;
|
||||||
|
|
||||||
|
/** Lazily-created shared postgres.js connection pool. */
|
||||||
|
export function getSql() {
|
||||||
|
if (!_sql) {
|
||||||
|
const url = process.env.DATABASE_URL;
|
||||||
|
if (!url) throw new Error("DATABASE_URL not set");
|
||||||
|
_sql = postgres(url, { max: 5, idle_timeout: 30 });
|
||||||
|
}
|
||||||
|
return _sql;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user