feat: initialize Next.js project with database schema

- Set up Next.js with App Router, TypeScript, Tailwind CSS
- Configure shadcn/ui with dark theme
- Install dependencies: lightweight-charts, papaparse, lucide-react
- Set up Drizzle ORM with better-sqlite3
- Create database schema for candles and annotations tables
- Generate migration SQL
This commit is contained in:
Marko Djordjevic 2026-02-12 10:23:02 +01:00
parent 7d2fc42b73
commit d04b673cfa
25 changed files with 903 additions and 0 deletions

15
src/lib/db/index.ts Normal file
View file

@ -0,0 +1,15 @@
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import * as schema from './schema';
import path from 'path';
import fs from 'fs';
// Ensure data directory exists
const dataDir = path.join(process.cwd(), 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
const dbPath = path.join(dataDir, 'candles.db');
const sqlite = new Database(dbPath);
export const db = drizzle(sqlite, { schema });

23
src/lib/db/migrate.ts Normal file
View file

@ -0,0 +1,23 @@
import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
import path from 'path';
import fs from 'fs';
export function runMigrations() {
// Ensure data directory exists
const dataDir = path.join(process.cwd(), 'data');
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir, { recursive: true });
}
const dbPath = path.join(dataDir, 'candles.db');
const sqlite = new Database(dbPath);
const db = drizzle(sqlite);
// Run migrations
migrate(db, { migrationsFolder: './drizzle' });
sqlite.close();
console.log('✅ Migrations complete');
}

18
src/lib/db/schema.ts Normal file
View file

@ -0,0 +1,18 @@
import { sqliteTable, integer, real, text } from 'drizzle-orm/sqlite-core';
export const candles = sqliteTable('candles', {
id: integer('id').primaryKey({ autoIncrement: true }),
time: integer('time').notNull().unique(),
open: real('open').notNull(),
high: real('high').notNull(),
low: real('low').notNull(),
close: real('close').notNull(),
});
export const annotations = sqliteTable('annotations', {
id: integer('id').primaryKey({ autoIncrement: true }),
timestamp: integer('timestamp').notNull(),
label_type: text('label_type').notNull(),
geometry: text('geometry'), // JSON string for line coordinates
created_at: integer('created_at').notNull(),
});

6
src/lib/utils.ts Normal file
View file

@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}