diff --git a/.gitignore b/.gitignore index 3b462cb..603d0b0 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ Thumbs.db # Vite vite.config.js.timestamp-* vite.config.ts.timestamp-* + +# Database +/data/ diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..306904e --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'drizzle-kit'; + +export default defineConfig({ + schema: './src/lib/server/db/schema.ts', + out: './drizzle', + dialect: 'sqlite', + dbCredentials: { + url: process.env.DATABASE_PATH || './data/taskplaner.db' + } +}); diff --git a/package.json b/package.json index 84979f4..128098c 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,11 @@ "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch" + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio" }, "devDependencies": { "@sveltejs/adapter-auto": "^7.0.0", diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts new file mode 100644 index 0000000..96b86fe --- /dev/null +++ b/src/lib/server/db/index.ts @@ -0,0 +1,22 @@ +import Database from 'better-sqlite3'; +import { drizzle } from 'drizzle-orm/better-sqlite3'; +import * as schema from './schema'; +import { existsSync, mkdirSync } from 'fs'; +import { dirname } from 'path'; + +const DB_PATH = process.env.DATABASE_PATH || './data/taskplaner.db'; + +// Ensure data directory exists +const dbDir = dirname(DB_PATH); +if (!existsSync(dbDir)) { + mkdirSync(dbDir, { recursive: true }); +} + +const sqlite = new Database(DB_PATH); + +// Enable WAL mode for better concurrent read performance +sqlite.pragma('journal_mode = WAL'); + +export const db = drizzle(sqlite, { schema }); + +export { schema }; diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts new file mode 100644 index 0000000..6a7fa17 --- /dev/null +++ b/src/lib/server/db/schema.ts @@ -0,0 +1,22 @@ +import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; + +// Entry types: 'task' (actionable) or 'thought' (reference) +export const entries = sqliteTable('entries', { + id: text('id').primaryKey(), // nanoid + title: text('title'), + content: text('content').notNull(), + type: text('type', { enum: ['task', 'thought'] }).notNull().default('thought'), + status: text('status', { enum: ['open', 'done', 'archived'] }).default('open'), // for tasks + pinned: integer('pinned', { mode: 'boolean' }).default(false), + dueDate: text('due_date'), // ISO date string, nullable + createdAt: text('created_at') + .notNull() + .$defaultFn(() => new Date().toISOString()), + updatedAt: text('updated_at') + .notNull() + .$defaultFn(() => new Date().toISOString()) +}); + +// Type inference for TypeScript +export type Entry = typeof entries.$inferSelect; +export type NewEntry = typeof entries.$inferInsert;