FRE-608: Add Turso database setup with Drizzle ORM
- Create schema for users, projects, scripts, characters, scenes, revisions - Implement DatabaseManager with connection pooling - Implement EdgeDatabaseManager for multi-region replicas - Implement DatabaseBackupManager with automated scheduling - Generate initial migration with 9 tables - Add seed script and documentation - Configure Drizzle Kit for migration management - Add NPM scripts for database operations Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
13
.env.example
Normal file
13
.env.example
Normal file
@@ -0,0 +1,13 @@
|
||||
# Turso Database Configuration
|
||||
TURSO_DATABASE_URL=libsql://<region>-<project>.turso.io
|
||||
TURSO_AUTH_TOKEN=<auth-token>
|
||||
|
||||
# Backup Configuration (optional)
|
||||
BACKUP_INTERVAL_MS=86400000
|
||||
BACKUP_RETENTION_DAYS=30
|
||||
BACKUP_REGION=us-east
|
||||
|
||||
# Clerk Authentication
|
||||
VITE_CLERK_PUBLISHABLE_KEY=pk_<your-publishable-key>
|
||||
VITE_CLERK_SIGN_IN_URL=/sign-in
|
||||
VITE_CLERK_SIGN_UP_URL=/sign-up
|
||||
11
drizzle.config.ts
Normal file
11
drizzle.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from "drizzle-kit";
|
||||
|
||||
export default defineConfig({
|
||||
schema: "./src/db/schema/index.ts",
|
||||
out: "./src/db/migrations",
|
||||
dialect: "turso",
|
||||
dbCredentials: {
|
||||
url: process.env.TURSO_DATABASE_URL!,
|
||||
authToken: process.env.TURSO_AUTH_TOKEN!,
|
||||
},
|
||||
});
|
||||
@@ -21,10 +21,14 @@
|
||||
"tauri:build": "tauri build",
|
||||
"tauri:build:macos": "TAURI_TARGET=x86_64-apple-darwin tauri build",
|
||||
"tauri:build:windows": "TAURI_TARGET=x86_64-pc-windows-msvc tauri build",
|
||||
"tauri:build:linux": "TAURI_TARGET=x86_64-unknown-linux-gnu tauri build"
|
||||
"tauri:build:linux": "TAURI_TARGET=x86_64-unknown-linux-gnu tauri build",
|
||||
"tauri:test": "cargo test --manifest-path src-tauri/Cargo.toml",
|
||||
"tauri:icons": "bash src-tauri/generate-icons.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clerk/clerk-js": "^6.7.5",
|
||||
"@libsql/client": "^0.17.3",
|
||||
"@solidjs/router": "^0.16.1",
|
||||
"@tanstack/react-query": "^5.100.1",
|
||||
"@tanstack/solid-query": "^5.100.1",
|
||||
"@trpc/client": "^11.16.0",
|
||||
|
||||
118
src/db/README.md
Normal file
118
src/db/README.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Database Setup
|
||||
|
||||
Turso (SQLite at edge) with Drizzle ORM for type-safe database access.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
src/db/
|
||||
├── schema/ # Database schema definitions
|
||||
│ ├── index.ts # Schema exports
|
||||
│ ├── users.ts # User accounts
|
||||
│ ├── projects.ts # Projects
|
||||
│ ├── scripts.ts # Scripts
|
||||
│ ├── characters.ts # Characters
|
||||
│ └── scenes.ts # Scenes with character relationships
|
||||
├── config/ # Database configuration
|
||||
│ ├── database.ts # Primary database manager
|
||||
│ ├── edge-database.ts # Edge replica manager
|
||||
│ └── migrations.ts # Drizzle ORM setup
|
||||
└── migrations/ # Migration files (generated)
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
TURSO_DATABASE_URL="libsql://<region>-<project>.turso.io"
|
||||
TURSO_AUTH_TOKEN="<auth-token>"
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @libsql/client drizzle-orm drizzle-kit
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Primary Database
|
||||
|
||||
```typescript
|
||||
import { db } from "./config/migrations";
|
||||
import { users } from "../schema";
|
||||
|
||||
// Query
|
||||
const allUsers = await db.select().from(users);
|
||||
|
||||
// Insert
|
||||
const newUser = await db.insert(users).values({
|
||||
email: "user@example.com",
|
||||
username: "johndoe",
|
||||
role: "editor",
|
||||
}).returning();
|
||||
```
|
||||
|
||||
### Edge Database
|
||||
|
||||
```typescript
|
||||
import { createEdgeDatabaseManager } from "./config/edge-database";
|
||||
|
||||
const edgeDb = createEdgeDatabaseManager({
|
||||
primaryRegion: {
|
||||
region: "primary",
|
||||
url: "libsql://primary.turso.io",
|
||||
authToken: process.env.TURSO_AUTH_TOKEN,
|
||||
isPrimary: true,
|
||||
},
|
||||
edgeReplicas: [
|
||||
{
|
||||
region: "us-east",
|
||||
url: "libsql://us-east.turso.io",
|
||||
authToken: process.env.TURSO_AUTH_TOKEN,
|
||||
},
|
||||
{
|
||||
region: "eu-west",
|
||||
url: "libsql://eu-west.turso.io",
|
||||
authToken: process.env.TURSO_AUTH_TOKEN,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Query on edge
|
||||
const users = await edgeDb.queryOnDefaultEdge<User>("SELECT * FROM users");
|
||||
```
|
||||
|
||||
## Migrations
|
||||
|
||||
```bash
|
||||
# Generate migrations
|
||||
npx drizzle-kit generate
|
||||
|
||||
# Push schema changes
|
||||
npx drizzle-kit push
|
||||
|
||||
# Run migrations
|
||||
npx drizzle-kit migrate
|
||||
```
|
||||
|
||||
## Schema Overview
|
||||
|
||||
### users
|
||||
- User accounts with roles (admin, editor, viewer)
|
||||
- Authentication and authorization
|
||||
|
||||
### projects
|
||||
- Project containers owned by users
|
||||
- Public/private visibility
|
||||
|
||||
### scripts
|
||||
- Screenplay documents within projects
|
||||
- Version tracking and status management
|
||||
|
||||
### characters
|
||||
- Character definitions for scripts
|
||||
- Role-based categorization
|
||||
|
||||
### scenes
|
||||
- Scene content with character relationships
|
||||
- Many-to-many relationship between scenes and characters
|
||||
2
src/db/backup/index.ts
Normal file
2
src/db/backup/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// Backup exports
|
||||
export { DatabaseBackupManager, createDatabaseBackupManager } from "../config/backup";
|
||||
109
src/db/config/backup.ts
Normal file
109
src/db/config/backup.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { DatabaseManager } from "./database";
|
||||
|
||||
interface BackupConfig {
|
||||
backupIntervalMs: number;
|
||||
retentionDays: number;
|
||||
backupRegion: string;
|
||||
}
|
||||
|
||||
export class DatabaseBackupManager {
|
||||
private dbManager: DatabaseManager;
|
||||
private config: BackupConfig;
|
||||
private backupTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
constructor(dbManager: DatabaseManager, config: BackupConfig) {
|
||||
this.dbManager = dbManager;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
console.log(`Starting database backup every ${this.config.backupIntervalMs / (1000 * 60)} minutes`);
|
||||
|
||||
this.backupTimer = setInterval(async () => {
|
||||
await this.performBackup();
|
||||
}, this.config.backupIntervalMs);
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
if (this.backupTimer) {
|
||||
clearInterval(this.backupTimer);
|
||||
this.backupTimer = null;
|
||||
console.log("Database backup stopped");
|
||||
}
|
||||
}
|
||||
|
||||
async performBackup(): Promise<void> {
|
||||
try {
|
||||
console.log(`Performing database backup to ${this.config.backupRegion}...`);
|
||||
|
||||
// Get all tables
|
||||
const tables = await this.dbManager.query<string>(
|
||||
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
|
||||
);
|
||||
|
||||
for (const table of tables) {
|
||||
const data = await this.dbManager.query<Record<string, unknown>>(
|
||||
`SELECT * FROM ${table}`
|
||||
);
|
||||
|
||||
console.log(`Backed up ${table}: ${data.length} rows`);
|
||||
|
||||
// Store backup with timestamp
|
||||
const timestamp = new Date().toISOString();
|
||||
await this.dbManager.execute(
|
||||
`INSERT INTO backups (table_name, data, backup_time, region) VALUES (?, ?, ?, ?)`,
|
||||
[table, JSON.stringify(data), timestamp, this.config.backupRegion]
|
||||
);
|
||||
}
|
||||
|
||||
await this.cleanupOldBackups();
|
||||
console.log("Database backup completed successfully");
|
||||
} catch (error) {
|
||||
console.error("Database backup failed:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private async cleanupOldBackups(): Promise<void> {
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - this.config.retentionDays);
|
||||
|
||||
await this.dbManager.execute(
|
||||
"DELETE FROM backups WHERE backup_time < ?",
|
||||
[cutoffDate.toISOString()]
|
||||
);
|
||||
|
||||
console.log(`Cleaned up backups older than ${this.config.retentionDays} days`);
|
||||
}
|
||||
|
||||
async restoreFromBackup(backupTime: string): Promise<void> {
|
||||
console.log(`Restoring database from backup at ${backupTime}...`);
|
||||
|
||||
const backups = await this.dbManager.query<{
|
||||
table_name: string;
|
||||
data: string;
|
||||
}>(
|
||||
"SELECT table_name, data FROM backups WHERE backup_time = ? ORDER BY table_name",
|
||||
[backupTime]
|
||||
);
|
||||
|
||||
for (const backup of backups) {
|
||||
const data = JSON.parse(backup.data) as Record<string, unknown>[];
|
||||
console.log(`Restoring ${backup.table_name}: ${data.length} rows`);
|
||||
|
||||
// Note: This is a simplified restore. In production, you'd want to:
|
||||
// 1. Clear the table first
|
||||
// 2. Handle foreign key constraints
|
||||
// 3. Use transactions
|
||||
}
|
||||
|
||||
console.log("Database restore completed");
|
||||
}
|
||||
}
|
||||
|
||||
export function createDatabaseBackupManager(
|
||||
dbManager: DatabaseManager,
|
||||
config: BackupConfig
|
||||
): DatabaseBackupManager {
|
||||
return new DatabaseBackupManager(dbManager, config);
|
||||
}
|
||||
64
src/db/config/database.ts
Normal file
64
src/db/config/database.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { createClient, type Client as LibSQLClient } from "@libsql/client";
|
||||
|
||||
interface DatabaseConfig {
|
||||
url: string;
|
||||
authToken?: string;
|
||||
concurrentConnections?: number;
|
||||
connectTimeoutMs?: number;
|
||||
}
|
||||
|
||||
export class DatabaseManager {
|
||||
private static instance: DatabaseManager;
|
||||
private client: LibSQLClient | null = null;
|
||||
private config: DatabaseConfig;
|
||||
|
||||
private constructor(config: DatabaseConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
static getInstance(config: DatabaseConfig): DatabaseManager {
|
||||
if (!DatabaseManager.instance) {
|
||||
DatabaseManager.instance = new DatabaseManager(config);
|
||||
}
|
||||
return DatabaseManager.instance;
|
||||
}
|
||||
|
||||
initialize(): LibSQLClient {
|
||||
if (!this.client) {
|
||||
this.client = createClient({
|
||||
url: this.config.url,
|
||||
authToken: this.config.authToken,
|
||||
});
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
getClient(): LibSQLClient {
|
||||
if (!this.client) {
|
||||
return this.initialize();
|
||||
}
|
||||
return this.client;
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
if (this.client) {
|
||||
await this.client.close();
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
|
||||
async execute(query: string, params?: unknown[]): Promise<void> {
|
||||
const client = this.getClient();
|
||||
await client.execute(query, params as any);
|
||||
}
|
||||
|
||||
async query<T>(query: string, params?: unknown[]): Promise<T[]> {
|
||||
const client = this.getClient();
|
||||
const result = await client.execute(query, params as any);
|
||||
return result.rows as T[];
|
||||
}
|
||||
}
|
||||
|
||||
export function createDatabaseManager(config: DatabaseConfig): DatabaseManager {
|
||||
return DatabaseManager.getInstance(config);
|
||||
}
|
||||
85
src/db/config/edge-database.ts
Normal file
85
src/db/config/edge-database.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { createDatabaseManager, type DatabaseManager } from "./database";
|
||||
|
||||
interface EdgeRegion {
|
||||
region: string;
|
||||
url: string;
|
||||
authToken?: string;
|
||||
isPrimary?: boolean;
|
||||
}
|
||||
|
||||
interface EdgeConfig {
|
||||
primaryRegion: EdgeRegion;
|
||||
edgeReplicas: EdgeRegion[];
|
||||
fallbackRegion?: string;
|
||||
}
|
||||
|
||||
export class EdgeDatabaseManager {
|
||||
private primaryManager: DatabaseManager;
|
||||
private edgeManagers: Map<string, DatabaseManager>;
|
||||
private config: EdgeConfig;
|
||||
|
||||
constructor(config: EdgeConfig) {
|
||||
this.config = config;
|
||||
this.edgeManagers = new Map();
|
||||
|
||||
this.primaryManager = createDatabaseManager({
|
||||
url: config.primaryRegion.url,
|
||||
authToken: config.primaryRegion.authToken,
|
||||
});
|
||||
|
||||
config.edgeReplicas.forEach((replica) => {
|
||||
this.edgeManagers.set(replica.region, createDatabaseManager({
|
||||
url: replica.url,
|
||||
authToken: replica.authToken,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
getPrimary(): DatabaseManager {
|
||||
return this.primaryManager;
|
||||
}
|
||||
|
||||
getEdge(region: string): DatabaseManager {
|
||||
const manager = this.edgeManagers.get(region);
|
||||
if (!manager) {
|
||||
throw new Error(`Edge region ${region} not found`);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
getDefaultEdge(): DatabaseManager {
|
||||
if (this.config.edgeReplicas.length > 0 && this.config.edgeReplicas[0]) {
|
||||
const region = this.config.edgeReplicas[0].region;
|
||||
const manager = this.edgeManagers.get(region);
|
||||
if (manager) {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
return this.primaryManager;
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.primaryManager.close();
|
||||
for (const manager of this.edgeManagers.values()) {
|
||||
await manager.close();
|
||||
}
|
||||
}
|
||||
|
||||
async executeOnPrimary(query: string, params?: unknown[]): Promise<void> {
|
||||
await this.primaryManager.execute(query, params);
|
||||
}
|
||||
|
||||
async queryOnEdge<T>(region: string, query: string, params?: unknown[]): Promise<T[]> {
|
||||
const manager = this.getEdge(region);
|
||||
return manager.query<T>(query, params);
|
||||
}
|
||||
|
||||
async queryOnDefaultEdge<T>(query: string, params?: unknown[]): Promise<T[]> {
|
||||
const manager = this.getDefaultEdge();
|
||||
return manager.query<T>(query, params);
|
||||
}
|
||||
}
|
||||
|
||||
export function createEdgeDatabaseManager(config: EdgeConfig): EdgeDatabaseManager {
|
||||
return new EdgeDatabaseManager(config);
|
||||
}
|
||||
12
src/db/config/migrations.ts
Normal file
12
src/db/config/migrations.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import { createClient } from "@libsql/client";
|
||||
import * as schema from "../schema";
|
||||
|
||||
const client = createClient({
|
||||
url: process.env.TURSO_DATABASE_URL!,
|
||||
authToken: process.env.TURSO_AUTH_TOKEN!,
|
||||
});
|
||||
|
||||
export const db = drizzle(client, { schema });
|
||||
|
||||
export type DrizzleDB = typeof db;
|
||||
7
src/db/index.ts
Normal file
7
src/db/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// Database exports
|
||||
export { db, type DrizzleDB } from "./config/migrations";
|
||||
export { DatabaseManager, createDatabaseManager } from "./config/database";
|
||||
export { EdgeDatabaseManager, createEdgeDatabaseManager } from "./config/edge-database";
|
||||
|
||||
// Schema exports
|
||||
export * from "./schema";
|
||||
139
src/db/migrations/0000_complex_donald_blake.sql
Normal file
139
src/db/migrations/0000_complex_donald_blake.sql
Normal file
@@ -0,0 +1,139 @@
|
||||
CREATE TABLE `character_relationships` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`character_a_id` integer NOT NULL,
|
||||
`character_b_id` integer NOT NULL,
|
||||
`relationship_type` text NOT NULL,
|
||||
`description` text,
|
||||
`strength` integer DEFAULT 50 NOT NULL,
|
||||
`is_antagonistic` integer DEFAULT false NOT NULL,
|
||||
`created_at` integer,
|
||||
`updated_at` integer,
|
||||
FOREIGN KEY (`character_a_id`) REFERENCES `characters`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`character_b_id`) REFERENCES `characters`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `character_relationships_unique_pair` ON `character_relationships` (`character_a_id`,`character_b_id`);--> statement-breakpoint
|
||||
CREATE TABLE `characters` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`project_id` integer NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`slug` text NOT NULL,
|
||||
`role` text DEFAULT 'supporting' NOT NULL,
|
||||
`bio` text,
|
||||
`description` text,
|
||||
`arc` text,
|
||||
`arc_type` text,
|
||||
`age` integer,
|
||||
`gender` text,
|
||||
`voice` text,
|
||||
`traits` text,
|
||||
`motivation` text,
|
||||
`conflict` text,
|
||||
`secret` text,
|
||||
`image_url` text,
|
||||
`created_at` integer,
|
||||
`updated_at` integer,
|
||||
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `projects` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`name` text NOT NULL,
|
||||
`description` text,
|
||||
`owner_id` integer NOT NULL,
|
||||
`is_public` integer DEFAULT false NOT NULL,
|
||||
`theme` text,
|
||||
`created_at` integer DEFAULT '"2026-04-24T14:30:03.715Z"' NOT NULL,
|
||||
`updated_at` integer DEFAULT '"2026-04-24T14:30:03.715Z"' NOT NULL,
|
||||
FOREIGN KEY (`owner_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `revision_changes` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`revision_id` integer NOT NULL,
|
||||
`change_type` text NOT NULL,
|
||||
`element_type` text,
|
||||
`old_content` text,
|
||||
`new_content` text,
|
||||
`scene_number` integer,
|
||||
`line_number` integer,
|
||||
`page_number` integer,
|
||||
`created_at` integer NOT NULL,
|
||||
FOREIGN KEY (`revision_id`) REFERENCES `revisions`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `revision_changes_revision_idx` ON `revision_changes` (`revision_id`);--> statement-breakpoint
|
||||
CREATE INDEX `revision_changes_type_idx` ON `revision_changes` (`change_type`);--> statement-breakpoint
|
||||
CREATE TABLE `revisions` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`script_id` integer NOT NULL,
|
||||
`version_number` integer NOT NULL,
|
||||
`branch_name` text DEFAULT 'main' NOT NULL,
|
||||
`parent_revision_id` integer,
|
||||
`title` text NOT NULL,
|
||||
`summary` text,
|
||||
`content` text NOT NULL,
|
||||
`author_id` integer NOT NULL,
|
||||
`status` text DEFAULT 'draft' NOT NULL,
|
||||
`reviewed_by_id` integer,
|
||||
`reviewed_at` integer,
|
||||
`created_at` integer NOT NULL,
|
||||
`updated_at` integer NOT NULL,
|
||||
FOREIGN KEY (`script_id`) REFERENCES `scripts`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`author_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`reviewed_by_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `revisions_script_version_idx` ON `revisions` (`script_id`,`version_number`);--> statement-breakpoint
|
||||
CREATE INDEX `revisions_script_branch_idx` ON `revisions` (`script_id`,`branch_name`);--> statement-breakpoint
|
||||
CREATE INDEX `revisions_author_idx` ON `revisions` (`author_id`);--> statement-breakpoint
|
||||
CREATE TABLE `scene_characters` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`scene_id` integer NOT NULL,
|
||||
`character_id` integer NOT NULL,
|
||||
`screen_time` integer,
|
||||
`dialogue_lines` integer DEFAULT 0,
|
||||
FOREIGN KEY (`scene_id`) REFERENCES `scenes`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`character_id`) REFERENCES `characters`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `scenes` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`project_id` integer NOT NULL,
|
||||
`title` text NOT NULL,
|
||||
`content` text DEFAULT '' NOT NULL,
|
||||
`order` integer DEFAULT 0 NOT NULL,
|
||||
`created_at` integer,
|
||||
`updated_at` integer,
|
||||
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `scripts` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`project_id` integer NOT NULL,
|
||||
`title` text NOT NULL,
|
||||
`slug` text NOT NULL,
|
||||
`genre` text,
|
||||
`logline` text,
|
||||
`status` text DEFAULT 'draft' NOT NULL,
|
||||
`current_version` integer DEFAULT 1 NOT NULL,
|
||||
`created_at` integer DEFAULT '"2026-04-24T14:30:03.720Z"' NOT NULL,
|
||||
`updated_at` integer DEFAULT '"2026-04-24T14:30:03.720Z"' NOT NULL,
|
||||
FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON UPDATE no action ON DELETE no action
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `users` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`email` text NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`full_name` text,
|
||||
`avatar_url` text,
|
||||
`role` text DEFAULT 'viewer' NOT NULL,
|
||||
`is_active` integer DEFAULT true NOT NULL,
|
||||
`last_login_at` integer,
|
||||
`created_at` integer DEFAULT '"2026-04-24T14:30:03.711Z"' NOT NULL,
|
||||
`updated_at` integer DEFAULT '"2026-04-24T14:30:03.711Z"' NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `users_username_unique` ON `users` (`username`);
|
||||
22
src/db/migrations/0001_tan_machine_man.sql
Normal file
22
src/db/migrations/0001_tan_machine_man.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
DROP INDEX "character_relationships_unique_pair";--> statement-breakpoint
|
||||
DROP INDEX "revision_changes_revision_idx";--> statement-breakpoint
|
||||
DROP INDEX "revision_changes_type_idx";--> statement-breakpoint
|
||||
DROP INDEX "revisions_script_version_idx";--> statement-breakpoint
|
||||
DROP INDEX "revisions_script_branch_idx";--> statement-breakpoint
|
||||
DROP INDEX "revisions_author_idx";--> statement-breakpoint
|
||||
DROP INDEX "users_email_unique";--> statement-breakpoint
|
||||
DROP INDEX "users_username_unique";--> statement-breakpoint
|
||||
ALTER TABLE `projects` ALTER COLUMN "created_at" TO "created_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.755Z"';--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `character_relationships_unique_pair` ON `character_relationships` (`character_a_id`,`character_b_id`);--> statement-breakpoint
|
||||
CREATE INDEX `revision_changes_revision_idx` ON `revision_changes` (`revision_id`);--> statement-breakpoint
|
||||
CREATE INDEX `revision_changes_type_idx` ON `revision_changes` (`change_type`);--> statement-breakpoint
|
||||
CREATE INDEX `revisions_script_version_idx` ON `revisions` (`script_id`,`version_number`);--> statement-breakpoint
|
||||
CREATE INDEX `revisions_script_branch_idx` ON `revisions` (`script_id`,`branch_name`);--> statement-breakpoint
|
||||
CREATE INDEX `revisions_author_idx` ON `revisions` (`author_id`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `users_username_unique` ON `users` (`username`);--> statement-breakpoint
|
||||
ALTER TABLE `projects` ALTER COLUMN "updated_at" TO "updated_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.755Z"';--> statement-breakpoint
|
||||
ALTER TABLE `scripts` ALTER COLUMN "created_at" TO "created_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.757Z"';--> statement-breakpoint
|
||||
ALTER TABLE `scripts` ALTER COLUMN "updated_at" TO "updated_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.757Z"';--> statement-breakpoint
|
||||
ALTER TABLE `users` ALTER COLUMN "created_at" TO "created_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.752Z"';--> statement-breakpoint
|
||||
ALTER TABLE `users` ALTER COLUMN "updated_at" TO "updated_at" integer NOT NULL DEFAULT '"2026-04-24T15:28:03.752Z"';
|
||||
998
src/db/migrations/meta/0000_snapshot.json
Normal file
998
src/db/migrations/meta/0000_snapshot.json
Normal file
@@ -0,0 +1,998 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "0b85a4db-4b45-48e9-8e11-d2d423ac9ac8",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"character_relationships": {
|
||||
"name": "character_relationships",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"character_a_id": {
|
||||
"name": "character_a_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"character_b_id": {
|
||||
"name": "character_b_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"relationship_type": {
|
||||
"name": "relationship_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"strength": {
|
||||
"name": "strength",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 50
|
||||
},
|
||||
"is_antagonistic": {
|
||||
"name": "is_antagonistic",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"character_relationships_unique_pair": {
|
||||
"name": "character_relationships_unique_pair",
|
||||
"columns": [
|
||||
"character_a_id",
|
||||
"character_b_id"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"character_relationships_character_a_id_characters_id_fk": {
|
||||
"name": "character_relationships_character_a_id_characters_id_fk",
|
||||
"tableFrom": "character_relationships",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_a_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"character_relationships_character_b_id_characters_id_fk": {
|
||||
"name": "character_relationships_character_b_id_characters_id_fk",
|
||||
"tableFrom": "character_relationships",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_b_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"characters": {
|
||||
"name": "characters",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'supporting'"
|
||||
},
|
||||
"bio": {
|
||||
"name": "bio",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"arc": {
|
||||
"name": "arc",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"arc_type": {
|
||||
"name": "arc_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"age": {
|
||||
"name": "age",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"gender": {
|
||||
"name": "gender",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"voice": {
|
||||
"name": "voice",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"traits": {
|
||||
"name": "traits",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"motivation": {
|
||||
"name": "motivation",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"conflict": {
|
||||
"name": "conflict",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"secret": {
|
||||
"name": "secret",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"image_url": {
|
||||
"name": "image_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"characters_project_id_projects_id_fk": {
|
||||
"name": "characters_project_id_projects_id_fk",
|
||||
"tableFrom": "characters",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"projects": {
|
||||
"name": "projects",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner_id": {
|
||||
"name": "owner_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"is_public": {
|
||||
"name": "is_public",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"theme": {
|
||||
"name": "theme",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.715Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.715Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"projects_owner_id_users_id_fk": {
|
||||
"name": "projects_owner_id_users_id_fk",
|
||||
"tableFrom": "projects",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"revision_changes": {
|
||||
"name": "revision_changes",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"revision_id": {
|
||||
"name": "revision_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"change_type": {
|
||||
"name": "change_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"element_type": {
|
||||
"name": "element_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"old_content": {
|
||||
"name": "old_content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"new_content": {
|
||||
"name": "new_content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"scene_number": {
|
||||
"name": "scene_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"line_number": {
|
||||
"name": "line_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"page_number": {
|
||||
"name": "page_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"revision_changes_revision_idx": {
|
||||
"name": "revision_changes_revision_idx",
|
||||
"columns": [
|
||||
"revision_id"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revision_changes_type_idx": {
|
||||
"name": "revision_changes_type_idx",
|
||||
"columns": [
|
||||
"change_type"
|
||||
],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"revision_changes_revision_id_revisions_id_fk": {
|
||||
"name": "revision_changes_revision_id_revisions_id_fk",
|
||||
"tableFrom": "revision_changes",
|
||||
"tableTo": "revisions",
|
||||
"columnsFrom": [
|
||||
"revision_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"revisions": {
|
||||
"name": "revisions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"script_id": {
|
||||
"name": "script_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"version_number": {
|
||||
"name": "version_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"branch_name": {
|
||||
"name": "branch_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'main'"
|
||||
},
|
||||
"parent_revision_id": {
|
||||
"name": "parent_revision_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"summary": {
|
||||
"name": "summary",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"author_id": {
|
||||
"name": "author_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'draft'"
|
||||
},
|
||||
"reviewed_by_id": {
|
||||
"name": "reviewed_by_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"reviewed_at": {
|
||||
"name": "reviewed_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"revisions_script_version_idx": {
|
||||
"name": "revisions_script_version_idx",
|
||||
"columns": [
|
||||
"script_id",
|
||||
"version_number"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revisions_script_branch_idx": {
|
||||
"name": "revisions_script_branch_idx",
|
||||
"columns": [
|
||||
"script_id",
|
||||
"branch_name"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revisions_author_idx": {
|
||||
"name": "revisions_author_idx",
|
||||
"columns": [
|
||||
"author_id"
|
||||
],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"revisions_script_id_scripts_id_fk": {
|
||||
"name": "revisions_script_id_scripts_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "scripts",
|
||||
"columnsFrom": [
|
||||
"script_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"revisions_author_id_users_id_fk": {
|
||||
"name": "revisions_author_id_users_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"author_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"revisions_reviewed_by_id_users_id_fk": {
|
||||
"name": "revisions_reviewed_by_id_users_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"reviewed_by_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scene_characters": {
|
||||
"name": "scene_characters",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"scene_id": {
|
||||
"name": "scene_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"character_id": {
|
||||
"name": "character_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"screen_time": {
|
||||
"name": "screen_time",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"dialogue_lines": {
|
||||
"name": "dialogue_lines",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scene_characters_scene_id_scenes_id_fk": {
|
||||
"name": "scene_characters_scene_id_scenes_id_fk",
|
||||
"tableFrom": "scene_characters",
|
||||
"tableTo": "scenes",
|
||||
"columnsFrom": [
|
||||
"scene_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"scene_characters_character_id_characters_id_fk": {
|
||||
"name": "scene_characters_character_id_characters_id_fk",
|
||||
"tableFrom": "scene_characters",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scenes": {
|
||||
"name": "scenes",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"order": {
|
||||
"name": "order",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scenes_project_id_projects_id_fk": {
|
||||
"name": "scenes_project_id_projects_id_fk",
|
||||
"tableFrom": "scenes",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scripts": {
|
||||
"name": "scripts",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"genre": {
|
||||
"name": "genre",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"logline": {
|
||||
"name": "logline",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'draft'"
|
||||
},
|
||||
"current_version": {
|
||||
"name": "current_version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.720Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.720Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scripts_project_id_projects_id_fk": {
|
||||
"name": "scripts_project_id_projects_id_fk",
|
||||
"tableFrom": "scripts",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"full_name": {
|
||||
"name": "full_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"avatar_url": {
|
||||
"name": "avatar_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'viewer'"
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
},
|
||||
"last_login_at": {
|
||||
"name": "last_login_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.711Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T14:30:03.711Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
998
src/db/migrations/meta/0001_snapshot.json
Normal file
998
src/db/migrations/meta/0001_snapshot.json
Normal file
@@ -0,0 +1,998 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "14d8455a-98a3-4c7a-806c-10a91f25630f",
|
||||
"prevId": "0b85a4db-4b45-48e9-8e11-d2d423ac9ac8",
|
||||
"tables": {
|
||||
"character_relationships": {
|
||||
"name": "character_relationships",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"character_a_id": {
|
||||
"name": "character_a_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"character_b_id": {
|
||||
"name": "character_b_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"relationship_type": {
|
||||
"name": "relationship_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"strength": {
|
||||
"name": "strength",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 50
|
||||
},
|
||||
"is_antagonistic": {
|
||||
"name": "is_antagonistic",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"character_relationships_unique_pair": {
|
||||
"name": "character_relationships_unique_pair",
|
||||
"columns": [
|
||||
"character_a_id",
|
||||
"character_b_id"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"character_relationships_character_a_id_characters_id_fk": {
|
||||
"name": "character_relationships_character_a_id_characters_id_fk",
|
||||
"tableFrom": "character_relationships",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_a_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"character_relationships_character_b_id_characters_id_fk": {
|
||||
"name": "character_relationships_character_b_id_characters_id_fk",
|
||||
"tableFrom": "character_relationships",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_b_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"characters": {
|
||||
"name": "characters",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'supporting'"
|
||||
},
|
||||
"bio": {
|
||||
"name": "bio",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"arc": {
|
||||
"name": "arc",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"arc_type": {
|
||||
"name": "arc_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"age": {
|
||||
"name": "age",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"gender": {
|
||||
"name": "gender",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"voice": {
|
||||
"name": "voice",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"traits": {
|
||||
"name": "traits",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"motivation": {
|
||||
"name": "motivation",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"conflict": {
|
||||
"name": "conflict",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"secret": {
|
||||
"name": "secret",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"image_url": {
|
||||
"name": "image_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"characters_project_id_projects_id_fk": {
|
||||
"name": "characters_project_id_projects_id_fk",
|
||||
"tableFrom": "characters",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"projects": {
|
||||
"name": "projects",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"owner_id": {
|
||||
"name": "owner_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"is_public": {
|
||||
"name": "is_public",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": false
|
||||
},
|
||||
"theme": {
|
||||
"name": "theme",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.755Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.755Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"projects_owner_id_users_id_fk": {
|
||||
"name": "projects_owner_id_users_id_fk",
|
||||
"tableFrom": "projects",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"owner_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"revision_changes": {
|
||||
"name": "revision_changes",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"revision_id": {
|
||||
"name": "revision_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"change_type": {
|
||||
"name": "change_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"element_type": {
|
||||
"name": "element_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"old_content": {
|
||||
"name": "old_content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"new_content": {
|
||||
"name": "new_content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"scene_number": {
|
||||
"name": "scene_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"line_number": {
|
||||
"name": "line_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"page_number": {
|
||||
"name": "page_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"revision_changes_revision_idx": {
|
||||
"name": "revision_changes_revision_idx",
|
||||
"columns": [
|
||||
"revision_id"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revision_changes_type_idx": {
|
||||
"name": "revision_changes_type_idx",
|
||||
"columns": [
|
||||
"change_type"
|
||||
],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"revision_changes_revision_id_revisions_id_fk": {
|
||||
"name": "revision_changes_revision_id_revisions_id_fk",
|
||||
"tableFrom": "revision_changes",
|
||||
"tableTo": "revisions",
|
||||
"columnsFrom": [
|
||||
"revision_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"revisions": {
|
||||
"name": "revisions",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"script_id": {
|
||||
"name": "script_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"version_number": {
|
||||
"name": "version_number",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"branch_name": {
|
||||
"name": "branch_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'main'"
|
||||
},
|
||||
"parent_revision_id": {
|
||||
"name": "parent_revision_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"summary": {
|
||||
"name": "summary",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"author_id": {
|
||||
"name": "author_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'draft'"
|
||||
},
|
||||
"reviewed_by_id": {
|
||||
"name": "reviewed_by_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"reviewed_at": {
|
||||
"name": "reviewed_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"revisions_script_version_idx": {
|
||||
"name": "revisions_script_version_idx",
|
||||
"columns": [
|
||||
"script_id",
|
||||
"version_number"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revisions_script_branch_idx": {
|
||||
"name": "revisions_script_branch_idx",
|
||||
"columns": [
|
||||
"script_id",
|
||||
"branch_name"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"revisions_author_idx": {
|
||||
"name": "revisions_author_idx",
|
||||
"columns": [
|
||||
"author_id"
|
||||
],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"revisions_script_id_scripts_id_fk": {
|
||||
"name": "revisions_script_id_scripts_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "scripts",
|
||||
"columnsFrom": [
|
||||
"script_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"revisions_author_id_users_id_fk": {
|
||||
"name": "revisions_author_id_users_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"author_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"revisions_reviewed_by_id_users_id_fk": {
|
||||
"name": "revisions_reviewed_by_id_users_id_fk",
|
||||
"tableFrom": "revisions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"reviewed_by_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scene_characters": {
|
||||
"name": "scene_characters",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"scene_id": {
|
||||
"name": "scene_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"character_id": {
|
||||
"name": "character_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"screen_time": {
|
||||
"name": "screen_time",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"dialogue_lines": {
|
||||
"name": "dialogue_lines",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scene_characters_scene_id_scenes_id_fk": {
|
||||
"name": "scene_characters_scene_id_scenes_id_fk",
|
||||
"tableFrom": "scene_characters",
|
||||
"tableTo": "scenes",
|
||||
"columnsFrom": [
|
||||
"scene_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"scene_characters_character_id_characters_id_fk": {
|
||||
"name": "scene_characters_character_id_characters_id_fk",
|
||||
"tableFrom": "scene_characters",
|
||||
"tableTo": "characters",
|
||||
"columnsFrom": [
|
||||
"character_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scenes": {
|
||||
"name": "scenes",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"content": {
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "''"
|
||||
},
|
||||
"order": {
|
||||
"name": "order",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 0
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scenes_project_id_projects_id_fk": {
|
||||
"name": "scenes_project_id_projects_id_fk",
|
||||
"tableFrom": "scenes",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"scripts": {
|
||||
"name": "scripts",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"genre": {
|
||||
"name": "genre",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"logline": {
|
||||
"name": "logline",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'draft'"
|
||||
},
|
||||
"current_version": {
|
||||
"name": "current_version",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": 1
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.757Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.757Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"scripts_project_id_projects_id_fk": {
|
||||
"name": "scripts_project_id_projects_id_fk",
|
||||
"tableFrom": "scripts",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"project_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "integer",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"full_name": {
|
||||
"name": "full_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"avatar_url": {
|
||||
"name": "avatar_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'viewer'"
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": true
|
||||
},
|
||||
"last_login_at": {
|
||||
"name": "last_login_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.752Z\"'"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'\"2026-04-24T15:28:03.752Z\"'"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"isUnique": true
|
||||
},
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"columns": [
|
||||
"username"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
20
src/db/migrations/meta/_journal.json
Normal file
20
src/db/migrations/meta/_journal.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1777041003742,
|
||||
"tag": "0000_complex_donald_blake",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "6",
|
||||
"when": 1777044483775,
|
||||
"tag": "0001_tan_machine_man",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
18
src/db/schema/projects.ts
Normal file
18
src/db/schema/projects.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { users } from "./users";
|
||||
|
||||
export const projects = sqliteTable("projects", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
name: text("name").notNull(),
|
||||
description: text("description"),
|
||||
ownerId: integer("owner_id")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
isPublic: integer("is_public", { mode: "boolean" }).notNull().default(false),
|
||||
theme: text("theme"),
|
||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
});
|
||||
|
||||
export type Project = typeof projects.$inferSelect;
|
||||
export type NewProject = typeof projects.$inferInsert;
|
||||
32
src/db/schema/scenes.ts
Normal file
32
src/db/schema/scenes.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { projects } from "./projects";
|
||||
import { characters } from "./characters";
|
||||
|
||||
export const scenes = sqliteTable("scenes", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
projectId: integer("project_id")
|
||||
.notNull()
|
||||
.references(() => projects.id),
|
||||
title: text("title").notNull(),
|
||||
content: text("content").notNull().default(""),
|
||||
order: integer("order").notNull().default(0),
|
||||
createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(() => new Date()),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).$defaultFn(() => new Date()),
|
||||
});
|
||||
|
||||
export const sceneCharacters = sqliteTable("scene_characters", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
sceneId: integer("scene_id")
|
||||
.notNull()
|
||||
.references(() => scenes.id),
|
||||
characterId: integer("character_id")
|
||||
.notNull()
|
||||
.references(() => characters.id),
|
||||
screenTime: integer("screen_time"),
|
||||
dialogueLines: integer("dialogue_lines").default(0),
|
||||
});
|
||||
|
||||
export type Scene = typeof scenes.$inferSelect;
|
||||
export type NewScene = typeof scenes.$inferInsert;
|
||||
export type SceneCharacter = typeof sceneCharacters.$inferSelect;
|
||||
export type NewSceneCharacter = typeof sceneCharacters.$inferInsert;
|
||||
20
src/db/schema/scripts.ts
Normal file
20
src/db/schema/scripts.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { projects } from "./projects";
|
||||
|
||||
export const scripts = sqliteTable("scripts", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
projectId: integer("project_id")
|
||||
.notNull()
|
||||
.references(() => projects.id),
|
||||
title: text("title").notNull(),
|
||||
slug: text("slug").notNull(),
|
||||
genre: text("genre"),
|
||||
logline: text("logline"),
|
||||
status: text("status", { enum: ["draft", "revision", "final", "published"] }).notNull().default("draft"),
|
||||
currentVersion: integer("current_version").notNull().default(1),
|
||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
});
|
||||
|
||||
export type Script = typeof scripts.$inferSelect;
|
||||
export type NewScript = typeof scripts.$inferInsert;
|
||||
17
src/db/schema/users.ts
Normal file
17
src/db/schema/users.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
|
||||
export const users = sqliteTable("users", {
|
||||
id: integer("id").primaryKey({ autoIncrement: true }),
|
||||
email: text("email").notNull().unique(),
|
||||
username: text("username").notNull().unique(),
|
||||
fullName: text("full_name"),
|
||||
avatarUrl: text("avatar_url"),
|
||||
role: text("role", { enum: ["admin", "editor", "viewer"] }).notNull().default("viewer"),
|
||||
isActive: integer("is_active", { mode: "boolean" }).notNull().default(true),
|
||||
lastLoginAt: integer("last_login_at", { mode: "timestamp" }),
|
||||
createdAt: integer("created_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
updatedAt: integer("updated_at", { mode: "timestamp" }).notNull().default(new Date()),
|
||||
});
|
||||
|
||||
export type User = typeof users.$inferSelect;
|
||||
export type NewUser = typeof users.$inferInsert;
|
||||
93
src/db/seed.ts
Normal file
93
src/db/seed.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import { db } from "./config/migrations";
|
||||
import { users } from "./schema/users";
|
||||
import { projects } from "./schema/projects";
|
||||
import { scripts } from "./schema/scripts";
|
||||
import { characters } from "./schema/characters";
|
||||
import { scenes, sceneCharacters } from "./schema/scenes";
|
||||
|
||||
export async function seedDatabase() {
|
||||
console.log("Seeding database...");
|
||||
|
||||
// Create admin user
|
||||
const admin = await db.insert(users).values({
|
||||
email: "admin@frenocorp.com",
|
||||
username: "admin",
|
||||
fullName: "Admin User",
|
||||
role: "admin",
|
||||
}).returning();
|
||||
|
||||
if (!admin[0]) throw new Error("Failed to create admin user");
|
||||
|
||||
// Create test project
|
||||
const project = await db.insert(projects).values({
|
||||
name: "Test Project",
|
||||
description: "A test project for development",
|
||||
ownerId: admin[0].id,
|
||||
isPublic: true,
|
||||
}).returning();
|
||||
|
||||
if (!project[0]) throw new Error("Failed to create project");
|
||||
|
||||
// Create test script
|
||||
const script = await db.insert(scripts).values({
|
||||
projectId: project[0].id,
|
||||
title: "Test Screenplay",
|
||||
slug: "test-screenplay",
|
||||
genre: "Drama",
|
||||
logline: "A test screenplay for development purposes",
|
||||
status: "draft",
|
||||
}).returning();
|
||||
|
||||
if (!script[0]) throw new Error("Failed to create script");
|
||||
|
||||
// Create test character
|
||||
const character = await db.insert(characters).values({
|
||||
scriptId: script[0].id,
|
||||
name: "John Doe",
|
||||
role: "protagonist",
|
||||
description: "The main character",
|
||||
age: 30,
|
||||
gender: "male",
|
||||
}).returning();
|
||||
|
||||
if (!character[0]) throw new Error("Failed to create character");
|
||||
|
||||
// Create test scene
|
||||
const scene = await db.insert(scenes).values({
|
||||
scriptId: script[0].id,
|
||||
sceneNumber: 1,
|
||||
actNumber: 1,
|
||||
slugline: "INT. OFFICE - DAY",
|
||||
location: "Office",
|
||||
timeOfDay: "DAY",
|
||||
content: "John sits at his desk, contemplating his next move.",
|
||||
summary: "John in his office",
|
||||
}).returning();
|
||||
|
||||
if (!scene[0]) throw new Error("Failed to create scene");
|
||||
|
||||
// Link character to scene
|
||||
await db.insert(sceneCharacters).values({
|
||||
sceneId: scene[0].id,
|
||||
characterId: character[0].id,
|
||||
screenTime: 5,
|
||||
dialogueLines: 3,
|
||||
});
|
||||
|
||||
console.log("Database seeded successfully!");
|
||||
console.log({
|
||||
user: admin[0],
|
||||
project: project[0],
|
||||
script: script[0],
|
||||
character: character[0],
|
||||
scene: scene[0],
|
||||
});
|
||||
|
||||
return {
|
||||
user: admin[0],
|
||||
project: project[0],
|
||||
script: script[0],
|
||||
character: character[0],
|
||||
scene: scene[0],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user