Security improvements, role in user creation, todo filters fix
- Remove better-auth dependency (unused) - Update JWT secrets to stronger values - Add ENCRYPTION_SALT env variable for password encryption - Add role field to createUserSchema validator - Accept role from body in admin.controller createUser - Fix todo filters: add priority filter, handle completed param - Remove .env.example (merged into .env) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,54 +0,0 @@
|
||||
import { db } from '../config/database.js';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
async function createProjectUsersTable() {
|
||||
console.log('⏳ Creating project_users table...');
|
||||
|
||||
try {
|
||||
// Check if table exists
|
||||
const result = await db.execute(sql`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'project_users'
|
||||
);
|
||||
`);
|
||||
|
||||
const tableExists = result.rows[0]?.exists;
|
||||
|
||||
if (tableExists) {
|
||||
console.log('✅ project_users table already exists');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Create the table
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS project_users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role TEXT,
|
||||
added_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
added_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT project_user_unique UNIQUE(project_id, user_id)
|
||||
);
|
||||
`);
|
||||
|
||||
// Create indexes
|
||||
await db.execute(sql`
|
||||
CREATE INDEX IF NOT EXISTS idx_project_users_project_id ON project_users(project_id);
|
||||
`);
|
||||
|
||||
await db.execute(sql`
|
||||
CREATE INDEX IF NOT EXISTS idx_project_users_user_id ON project_users(user_id);
|
||||
`);
|
||||
|
||||
console.log('✅ project_users table created successfully');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to create table:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
createProjectUsersTable();
|
||||
@@ -1,32 +0,0 @@
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
||||
import pkg from 'pg';
|
||||
const { Pool } = pkg;
|
||||
import dotenv from 'dotenv';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const pool = new Pool({
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '5432'),
|
||||
user: process.env.DB_USER || 'admin',
|
||||
password: process.env.DB_PASSWORD || 'heslo123',
|
||||
database: process.env.DB_NAME || 'crm',
|
||||
});
|
||||
|
||||
const db = drizzle(pool);
|
||||
|
||||
async function runMigrations() {
|
||||
console.log('⏳ Running migrations...');
|
||||
|
||||
try {
|
||||
await migrate(db, { migrationsFolder: './src/db/migrations' });
|
||||
console.log('✅ Migrations completed successfully');
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Migration failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
runMigrations();
|
||||
@@ -1,36 +0,0 @@
|
||||
CREATE TYPE "public"."role" AS ENUM('admin', 'member');--> statement-breakpoint
|
||||
CREATE TABLE "audit_logs" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid,
|
||||
"action" text NOT NULL,
|
||||
"resource" text NOT NULL,
|
||||
"resource_id" text,
|
||||
"old_value" text,
|
||||
"new_value" text,
|
||||
"ip_address" text,
|
||||
"user_agent" text,
|
||||
"success" boolean DEFAULT true NOT NULL,
|
||||
"error_message" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "users" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"username" text NOT NULL,
|
||||
"email" text,
|
||||
"email_password" text,
|
||||
"jmap_account_id" text,
|
||||
"first_name" text,
|
||||
"last_name" text,
|
||||
"password" text,
|
||||
"temp_password" text,
|
||||
"changed_password" boolean DEFAULT false,
|
||||
"role" "role" DEFAULT 'member' NOT NULL,
|
||||
"last_login" timestamp,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE set null ON UPDATE no action;
|
||||
@@ -1,34 +0,0 @@
|
||||
CREATE TABLE "contacts" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"name" text,
|
||||
"notes" text,
|
||||
"added_at" timestamp DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "emails" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"contact_id" uuid,
|
||||
"jmap_id" text,
|
||||
"message_id" text,
|
||||
"thread_id" text,
|
||||
"in_reply_to" text,
|
||||
"from" text,
|
||||
"to" text,
|
||||
"subject" text,
|
||||
"body" text,
|
||||
"is_read" boolean DEFAULT false NOT NULL,
|
||||
"date" timestamp,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
CONSTRAINT "emails_jmap_id_unique" UNIQUE("jmap_id"),
|
||||
CONSTRAINT "emails_message_id_unique" UNIQUE("message_id")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "contacts" ADD CONSTRAINT "contacts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "emails" ADD CONSTRAINT "emails_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "emails" ADD CONSTRAINT "emails_contact_id_contacts_id_fk" FOREIGN KEY ("contact_id") REFERENCES "public"."contacts"("id") ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,17 +0,0 @@
|
||||
CREATE TABLE "email_accounts" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"email_password" text NOT NULL,
|
||||
"jmap_account_id" text NOT NULL,
|
||||
"is_primary" boolean DEFAULT false NOT NULL,
|
||||
"is_active" boolean DEFAULT true NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "contacts" ADD COLUMN "email_account_id" uuid NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "emails" ADD COLUMN "email_account_id" uuid NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "email_accounts" ADD CONSTRAINT "email_accounts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "contacts" ADD CONSTRAINT "contacts_email_account_id_email_accounts_id_fk" FOREIGN KEY ("email_account_id") REFERENCES "public"."email_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "emails" ADD CONSTRAINT "emails_email_account_id_email_accounts_id_fk" FOREIGN KEY ("email_account_id") REFERENCES "public"."email_accounts"("id") ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,15 +0,0 @@
|
||||
CREATE TABLE "timesheets" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"file_name" text NOT NULL,
|
||||
"file_path" text NOT NULL,
|
||||
"file_type" text NOT NULL,
|
||||
"file_size" integer NOT NULL,
|
||||
"year" integer NOT NULL,
|
||||
"month" integer NOT NULL,
|
||||
"uploaded_at" timestamp DEFAULT now() NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "timesheets" ADD CONSTRAINT "timesheets_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
@@ -1,23 +0,0 @@
|
||||
CREATE TABLE "time_entries" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"project_id" uuid,
|
||||
"todo_id" uuid,
|
||||
"company_id" uuid,
|
||||
"start_time" timestamp NOT NULL,
|
||||
"end_time" timestamp,
|
||||
"duration" integer,
|
||||
"description" text,
|
||||
"is_running" boolean DEFAULT false NOT NULL,
|
||||
"is_edited" boolean DEFAULT false NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "time_entries" ADD CONSTRAINT "time_entries_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "time_entries" ADD CONSTRAINT "time_entries_project_id_projects_id_fk" FOREIGN KEY ("project_id") REFERENCES "public"."projects"("id") ON DELETE set null ON UPDATE no action;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "time_entries" ADD CONSTRAINT "time_entries_todo_id_todos_id_fk" FOREIGN KEY ("todo_id") REFERENCES "public"."todos"("id") ON DELETE set null ON UPDATE no action;
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "time_entries" ADD CONSTRAINT "time_entries_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE set null ON UPDATE no action;
|
||||
@@ -1,3 +0,0 @@
|
||||
-- Add flag to mark system-generated timesheets
|
||||
ALTER TABLE timesheets
|
||||
ADD COLUMN IF NOT EXISTS is_generated BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
@@ -1,29 +0,0 @@
|
||||
-- Migration: Add todo_users junction table and migrate from assignedTo
|
||||
-- Created: 2025-11-24
|
||||
-- Description: Allows many-to-many relationship between todos and users
|
||||
|
||||
-- Create todo_users junction table
|
||||
CREATE TABLE IF NOT EXISTS todo_users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
todo_id UUID NOT NULL REFERENCES todos(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
assigned_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
assigned_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT todo_user_unique UNIQUE(todo_id, user_id)
|
||||
);
|
||||
|
||||
-- Create indexes for better query performance
|
||||
CREATE INDEX IF NOT EXISTS idx_todo_users_todo_id ON todo_users(todo_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_todo_users_user_id ON todo_users(user_id);
|
||||
|
||||
-- Migrate existing assignedTo data to todo_users table
|
||||
INSERT INTO todo_users (todo_id, user_id, assigned_by, assigned_at)
|
||||
SELECT id, assigned_to, created_by, created_at
|
||||
FROM todos
|
||||
WHERE assigned_to IS NOT NULL;
|
||||
|
||||
-- Drop the old assigned_to column
|
||||
ALTER TABLE todos DROP COLUMN IF EXISTS assigned_to;
|
||||
|
||||
-- Add comment
|
||||
COMMENT ON TABLE todo_users IS 'Junction table for many-to-many relationship between todos and users (assigned users)';
|
||||
@@ -1,12 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS "company_remind" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"company_id" uuid NOT NULL,
|
||||
"description" text NOT NULL,
|
||||
"is_checked" boolean DEFAULT false NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "company_remind" ADD CONSTRAINT "company_remind_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX IF NOT EXISTS "company_remind_company_id_idx" ON "company_remind" ("company_id");
|
||||
@@ -1,20 +0,0 @@
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'emails' AND column_name = 'company_id'
|
||||
) THEN
|
||||
ALTER TABLE emails
|
||||
ADD COLUMN company_id UUID REFERENCES companies(id) ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_emails_company_id ON emails(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_emails_company_thread ON emails(company_id, thread_id);
|
||||
|
||||
UPDATE emails e
|
||||
SET company_id = c.company_id
|
||||
FROM contacts c
|
||||
WHERE e.contact_id = c.id
|
||||
AND c.company_id IS NOT NULL
|
||||
AND (e.company_id IS NULL OR e.company_id <> c.company_id);
|
||||
@@ -1,31 +0,0 @@
|
||||
-- Add company_id to contacts table
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name='contacts' AND column_name='company_id'
|
||||
) THEN
|
||||
ALTER TABLE contacts ADD COLUMN company_id UUID REFERENCES companies(id) ON DELETE SET NULL;
|
||||
CREATE INDEX idx_contacts_company_id ON contacts(company_id);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Add reminder fields to notes table
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name='notes' AND column_name='reminder_date'
|
||||
) THEN
|
||||
ALTER TABLE notes ADD COLUMN reminder_date TIMESTAMP;
|
||||
CREATE INDEX idx_notes_reminder_date ON notes(reminder_date) WHERE reminder_date IS NOT NULL;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name='notes' AND column_name='reminder_sent'
|
||||
) THEN
|
||||
ALTER TABLE notes ADD COLUMN reminder_sent BOOLEAN NOT NULL DEFAULT false;
|
||||
CREATE INDEX idx_notes_reminder_pending ON notes(reminder_date, reminder_sent) WHERE reminder_date IS NOT NULL AND reminder_sent = false;
|
||||
END IF;
|
||||
END $$;
|
||||
@@ -1,118 +0,0 @@
|
||||
-- Add new enum types
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE project_status AS ENUM('active', 'completed', 'on_hold', 'cancelled');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE todo_status AS ENUM('pending', 'in_progress', 'completed', 'cancelled');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE todo_priority AS ENUM('low', 'medium', 'high', 'urgent');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
|
||||
-- Create companies table
|
||||
CREATE TABLE IF NOT EXISTS companies (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
address TEXT,
|
||||
city TEXT,
|
||||
country TEXT,
|
||||
phone TEXT,
|
||||
email TEXT,
|
||||
website TEXT,
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create projects table
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
company_id UUID REFERENCES companies(id) ON DELETE CASCADE,
|
||||
status project_status NOT NULL DEFAULT 'active',
|
||||
start_date TIMESTAMP,
|
||||
end_date TIMESTAMP,
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create todos table
|
||||
CREATE TABLE IF NOT EXISTS todos (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
|
||||
company_id UUID REFERENCES companies(id) ON DELETE CASCADE,
|
||||
assigned_to UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
status todo_status NOT NULL DEFAULT 'pending',
|
||||
priority todo_priority NOT NULL DEFAULT 'medium',
|
||||
due_date TIMESTAMP,
|
||||
completed_at TIMESTAMP,
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Create notes table
|
||||
CREATE TABLE IF NOT EXISTS notes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
title TEXT,
|
||||
content TEXT NOT NULL,
|
||||
company_id UUID REFERENCES companies(id) ON DELETE CASCADE,
|
||||
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
|
||||
todo_id UUID REFERENCES todos(id) ON DELETE CASCADE,
|
||||
contact_id UUID REFERENCES contacts(id) ON DELETE CASCADE,
|
||||
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Add project_id to timesheets table if not exists
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name='timesheets' AND column_name='project_id'
|
||||
) THEN
|
||||
ALTER TABLE timesheets ADD COLUMN project_id UUID REFERENCES projects(id) ON DELETE SET NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Add is_generated flag to timesheets if not exists
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name='timesheets' AND column_name='is_generated'
|
||||
) THEN
|
||||
ALTER TABLE timesheets ADD COLUMN is_generated BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Create indexes for better query performance
|
||||
CREATE INDEX IF NOT EXISTS idx_companies_created_at ON companies(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_projects_company_id ON projects(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_projects_created_at ON projects(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_project_id ON todos(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_company_id ON todos(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_assigned_to ON todos(assigned_to);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_status ON todos(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_todos_created_at ON todos(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_company_id ON notes(company_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_project_id ON notes(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_todo_id ON notes(todo_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_contact_id ON notes(contact_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_notes_created_at ON notes(created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_timesheets_project_id ON timesheets(project_id);
|
||||
@@ -1,21 +0,0 @@
|
||||
-- Migration: Add project_users junction table for project team management
|
||||
-- Created: 2025-11-21
|
||||
-- Description: Allows many-to-many relationship between projects and users
|
||||
|
||||
-- Create project_users junction table
|
||||
CREATE TABLE IF NOT EXISTS project_users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role TEXT,
|
||||
added_by UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
added_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT project_user_unique UNIQUE(project_id, user_id)
|
||||
);
|
||||
|
||||
-- Create indexes for better query performance
|
||||
CREATE INDEX IF NOT EXISTS idx_project_users_project_id ON project_users(project_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_project_users_user_id ON project_users(user_id);
|
||||
|
||||
-- Add comment
|
||||
COMMENT ON TABLE project_users IS 'Junction table for many-to-many relationship between projects and users (project team members)';
|
||||
@@ -1,138 +0,0 @@
|
||||
import 'dotenv/config';
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pkg from 'pg';
|
||||
const { Pool } = pkg;
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
/**
|
||||
* Data-only migration script to move existing user emails to email_accounts
|
||||
* Assumes tables already exist from Drizzle migrations
|
||||
*/
|
||||
|
||||
const pool = new Pool({
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '5432'),
|
||||
user: process.env.DB_USER || 'admin',
|
||||
password: process.env.DB_PASSWORD || 'heslo123',
|
||||
database: process.env.DB_NAME || 'crm',
|
||||
});
|
||||
|
||||
const db = drizzle(pool);
|
||||
|
||||
async function migrateData() {
|
||||
console.log('🚀 Starting data migration to email accounts...\n');
|
||||
|
||||
try {
|
||||
// Step 1: Check if email_accounts table exists
|
||||
console.log('Step 1: Checking email_accounts table...');
|
||||
const tableExists = await db.execute(sql`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'email_accounts'
|
||||
)
|
||||
`);
|
||||
|
||||
if (!tableExists.rows[0].exists) {
|
||||
throw new Error('email_accounts table does not exist. Run Drizzle migrations first.');
|
||||
}
|
||||
console.log('✅ email_accounts table exists\n');
|
||||
|
||||
// Step 2: Migrate existing user emails to email_accounts
|
||||
console.log('Step 2: Migrating existing user emails to email_accounts...');
|
||||
const usersWithEmail = await db.execute(sql`
|
||||
SELECT id, email, email_password, jmap_account_id
|
||||
FROM users
|
||||
WHERE email IS NOT NULL
|
||||
AND email_password IS NOT NULL
|
||||
AND jmap_account_id IS NOT NULL
|
||||
`);
|
||||
|
||||
console.log(`Found ${usersWithEmail.rows.length} users with email accounts`);
|
||||
|
||||
for (const user of usersWithEmail.rows) {
|
||||
// Check if already migrated
|
||||
const existing = await db.execute(sql`
|
||||
SELECT id FROM email_accounts
|
||||
WHERE user_id = ${user.id} AND email = ${user.email}
|
||||
`);
|
||||
|
||||
if (existing.rows.length > 0) {
|
||||
console.log(` ⏩ Skipping user ${user.id}: ${user.email} (already migrated)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await db.execute(sql`
|
||||
INSERT INTO email_accounts (user_id, email, email_password, jmap_account_id, is_primary, is_active)
|
||||
VALUES (${user.id}, ${user.email}, ${user.email_password}, ${user.jmap_account_id}, true, true)
|
||||
`);
|
||||
console.log(` ✓ Migrated email account for user ${user.id}: ${user.email}`);
|
||||
}
|
||||
console.log('✅ User emails migrated\n');
|
||||
|
||||
// Step 3: Update existing contacts with email_account_id
|
||||
console.log('Step 3: Updating existing contacts with email_account_id...');
|
||||
const contactsNeedUpdate = await db.execute(sql`
|
||||
SELECT COUNT(*) as count FROM contacts WHERE email_account_id IS NULL
|
||||
`);
|
||||
|
||||
if (parseInt(contactsNeedUpdate.rows[0].count) > 0) {
|
||||
await db.execute(sql`
|
||||
UPDATE contacts
|
||||
SET email_account_id = (
|
||||
SELECT ea.id
|
||||
FROM email_accounts ea
|
||||
WHERE ea.user_id = contacts.user_id
|
||||
AND ea.is_primary = true
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE email_account_id IS NULL
|
||||
`);
|
||||
console.log(`✅ Updated ${contactsNeedUpdate.rows[0].count} contacts\n`);
|
||||
} else {
|
||||
console.log('✅ No contacts to update\n');
|
||||
}
|
||||
|
||||
// Step 4: Update existing emails with email_account_id
|
||||
console.log('Step 4: Updating existing emails with email_account_id...');
|
||||
const emailsNeedUpdate = await db.execute(sql`
|
||||
SELECT COUNT(*) as count FROM emails WHERE email_account_id IS NULL
|
||||
`);
|
||||
|
||||
if (parseInt(emailsNeedUpdate.rows[0].count) > 0) {
|
||||
await db.execute(sql`
|
||||
UPDATE emails
|
||||
SET email_account_id = (
|
||||
SELECT ea.id
|
||||
FROM email_accounts ea
|
||||
WHERE ea.user_id = emails.user_id
|
||||
AND ea.is_primary = true
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE email_account_id IS NULL
|
||||
`);
|
||||
console.log(`✅ Updated ${emailsNeedUpdate.rows[0].count} emails\n`);
|
||||
} else {
|
||||
console.log('✅ No emails to update\n');
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log('🎉 Data migration completed successfully!\n');
|
||||
console.log('Summary:');
|
||||
console.log(` - Email accounts migrated: ${usersWithEmail.rows.length}`);
|
||||
console.log(` - Contacts updated: ${contactsNeedUpdate.rows[0].count}`);
|
||||
console.log(` - Emails updated: ${emailsNeedUpdate.rows[0].count}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Migration failed:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Run migration
|
||||
migrateData().catch((error) => {
|
||||
console.error('Fatal error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,179 +0,0 @@
|
||||
import 'dotenv/config';
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pkg from 'pg';
|
||||
const { Pool } = pkg;
|
||||
import { users, emailAccounts, contacts, emails } from '../schema.js';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
/**
|
||||
* Migration script to move from single email per user to multiple email accounts
|
||||
*
|
||||
* Steps:
|
||||
* 1. Create email_accounts table
|
||||
* 2. Migrate existing user emails to email_accounts (as primary)
|
||||
* 3. Add email_account_id to contacts and emails tables
|
||||
* 4. Update existing contacts and emails to reference new email accounts
|
||||
*/
|
||||
|
||||
const pool = new Pool({
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: parseInt(process.env.DB_PORT || '5432'),
|
||||
user: process.env.DB_USER || 'admin',
|
||||
password: process.env.DB_PASSWORD || 'heslo123',
|
||||
database: process.env.DB_NAME || 'crm',
|
||||
});
|
||||
|
||||
const db = drizzle(pool);
|
||||
|
||||
async function migrateToEmailAccounts() {
|
||||
console.log('🚀 Starting migration to email accounts...\n');
|
||||
|
||||
try {
|
||||
// Step 1: Create email_accounts table
|
||||
console.log('Step 1: Creating email_accounts table...');
|
||||
await db.execute(sql`
|
||||
CREATE TABLE IF NOT EXISTS "email_accounts" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" uuid NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"email_password" text NOT NULL,
|
||||
"jmap_account_id" text NOT NULL,
|
||||
"is_primary" boolean DEFAULT false NOT NULL,
|
||||
"is_active" boolean DEFAULT true NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
)
|
||||
`);
|
||||
|
||||
await db.execute(sql`
|
||||
ALTER TABLE "email_accounts"
|
||||
ADD CONSTRAINT "email_accounts_user_id_users_id_fk"
|
||||
FOREIGN KEY ("user_id") REFERENCES "public"."users"("id")
|
||||
ON DELETE cascade ON UPDATE no action
|
||||
`);
|
||||
console.log('✅ email_accounts table created\n');
|
||||
|
||||
// Step 2: Migrate existing user emails to email_accounts
|
||||
console.log('Step 2: Migrating existing user emails to email_accounts...');
|
||||
const usersWithEmail = await db.execute(sql`
|
||||
SELECT id, email, email_password, jmap_account_id
|
||||
FROM users
|
||||
WHERE email IS NOT NULL
|
||||
AND email_password IS NOT NULL
|
||||
AND jmap_account_id IS NOT NULL
|
||||
`);
|
||||
|
||||
console.log(`Found ${usersWithEmail.rows.length} users with email accounts`);
|
||||
|
||||
for (const user of usersWithEmail.rows) {
|
||||
await db.execute(sql`
|
||||
INSERT INTO email_accounts (user_id, email, email_password, jmap_account_id, is_primary, is_active)
|
||||
VALUES (${user.id}, ${user.email}, ${user.email_password}, ${user.jmap_account_id}, true, true)
|
||||
`);
|
||||
console.log(` ✓ Migrated email account for user ${user.id}: ${user.email}`);
|
||||
}
|
||||
console.log('✅ User emails migrated\n');
|
||||
|
||||
// Step 3: Add email_account_id column to contacts (nullable first)
|
||||
console.log('Step 3: Adding email_account_id to contacts table...');
|
||||
await db.execute(sql`
|
||||
ALTER TABLE contacts
|
||||
ADD COLUMN IF NOT EXISTS email_account_id uuid
|
||||
`);
|
||||
console.log('✅ Column added to contacts\n');
|
||||
|
||||
// Step 4: Update existing contacts with email_account_id
|
||||
console.log('Step 4: Updating existing contacts with email_account_id...');
|
||||
await db.execute(sql`
|
||||
UPDATE contacts
|
||||
SET email_account_id = (
|
||||
SELECT ea.id
|
||||
FROM email_accounts ea
|
||||
WHERE ea.user_id = contacts.user_id
|
||||
AND ea.is_primary = true
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE email_account_id IS NULL
|
||||
`);
|
||||
|
||||
const contactsUpdated = await db.execute(sql`
|
||||
SELECT COUNT(*) as count FROM contacts WHERE email_account_id IS NOT NULL
|
||||
`);
|
||||
console.log(`✅ Updated ${contactsUpdated.rows[0].count} contacts\n`);
|
||||
|
||||
// Step 5: Make email_account_id NOT NULL and add foreign key
|
||||
console.log('Step 5: Adding constraints to contacts...');
|
||||
await db.execute(sql`
|
||||
ALTER TABLE contacts
|
||||
ALTER COLUMN email_account_id SET NOT NULL
|
||||
`);
|
||||
|
||||
await db.execute(sql`
|
||||
ALTER TABLE contacts
|
||||
ADD CONSTRAINT "contacts_email_account_id_email_accounts_id_fk"
|
||||
FOREIGN KEY ("email_account_id") REFERENCES "public"."email_accounts"("id")
|
||||
ON DELETE cascade ON UPDATE no action
|
||||
`);
|
||||
console.log('✅ Constraints added to contacts\n');
|
||||
|
||||
// Step 6: Add email_account_id column to emails (nullable first)
|
||||
console.log('Step 6: Adding email_account_id to emails table...');
|
||||
await db.execute(sql`
|
||||
ALTER TABLE emails
|
||||
ADD COLUMN IF NOT EXISTS email_account_id uuid
|
||||
`);
|
||||
console.log('✅ Column added to emails\n');
|
||||
|
||||
// Step 7: Update existing emails with email_account_id
|
||||
console.log('Step 7: Updating existing emails with email_account_id...');
|
||||
await db.execute(sql`
|
||||
UPDATE emails
|
||||
SET email_account_id = (
|
||||
SELECT ea.id
|
||||
FROM email_accounts ea
|
||||
WHERE ea.user_id = emails.user_id
|
||||
AND ea.is_primary = true
|
||||
LIMIT 1
|
||||
)
|
||||
WHERE email_account_id IS NULL
|
||||
`);
|
||||
|
||||
const emailsUpdated = await db.execute(sql`
|
||||
SELECT COUNT(*) as count FROM emails WHERE email_account_id IS NOT NULL
|
||||
`);
|
||||
console.log(`✅ Updated ${emailsUpdated.rows[0].count} emails\n`);
|
||||
|
||||
// Step 8: Make email_account_id NOT NULL and add foreign key
|
||||
console.log('Step 8: Adding constraints to emails...');
|
||||
await db.execute(sql`
|
||||
ALTER TABLE emails
|
||||
ALTER COLUMN email_account_id SET NOT NULL
|
||||
`);
|
||||
|
||||
await db.execute(sql`
|
||||
ALTER TABLE emails
|
||||
ADD CONSTRAINT "emails_email_account_id_email_accounts_id_fk"
|
||||
FOREIGN KEY ("email_account_id") REFERENCES "public"."email_accounts"("id")
|
||||
ON DELETE cascade ON UPDATE no action
|
||||
`);
|
||||
console.log('✅ Constraints added to emails\n');
|
||||
|
||||
console.log('🎉 Migration completed successfully!\n');
|
||||
console.log('Summary:');
|
||||
console.log(` - Email accounts created: ${usersWithEmail.rows.length}`);
|
||||
console.log(` - Contacts updated: ${contactsUpdated.rows[0].count}`);
|
||||
console.log(` - Emails updated: ${emailsUpdated.rows[0].count}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Migration failed:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Run migration
|
||||
migrateToEmailAccounts().catch((error) => {
|
||||
console.error('Fatal error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,248 +0,0 @@
|
||||
{
|
||||
"id": "d81153f7-e0c6-4843-bee9-21a7129f7d01",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.audit_logs": {
|
||||
"name": "audit_logs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"action": {
|
||||
"name": "action",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource": {
|
||||
"name": "resource",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource_id": {
|
||||
"name": "resource_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"old_value": {
|
||||
"name": "old_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"new_value": {
|
||||
"name": "new_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"ip_address": {
|
||||
"name": "ip_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"user_agent": {
|
||||
"name": "user_agent",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"success": {
|
||||
"name": "success",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"error_message": {
|
||||
"name": "error_message",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"audit_logs_user_id_users_id_fk": {
|
||||
"name": "audit_logs_user_id_users_id_fk",
|
||||
"tableFrom": "audit_logs",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email_password": {
|
||||
"name": "email_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"jmap_account_id": {
|
||||
"name": "jmap_account_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"first_name": {
|
||||
"name": "first_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_name": {
|
||||
"name": "last_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"temp_password": {
|
||||
"name": "temp_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"changed_password": {
|
||||
"name": "changed_password",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "role",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'member'"
|
||||
},
|
||||
"last_login": {
|
||||
"name": "last_login",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"username"
|
||||
]
|
||||
},
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"public.role": {
|
||||
"name": "role",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"admin",
|
||||
"member"
|
||||
]
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -1,476 +0,0 @@
|
||||
{
|
||||
"id": "1b8c1e0f-8476-470c-a641-b3c350a2c1a4",
|
||||
"prevId": "d81153f7-e0c6-4843-bee9-21a7129f7d01",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.audit_logs": {
|
||||
"name": "audit_logs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"action": {
|
||||
"name": "action",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource": {
|
||||
"name": "resource",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource_id": {
|
||||
"name": "resource_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"old_value": {
|
||||
"name": "old_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"new_value": {
|
||||
"name": "new_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"ip_address": {
|
||||
"name": "ip_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"user_agent": {
|
||||
"name": "user_agent",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"success": {
|
||||
"name": "success",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"error_message": {
|
||||
"name": "error_message",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"audit_logs_user_id_users_id_fk": {
|
||||
"name": "audit_logs_user_id_users_id_fk",
|
||||
"tableFrom": "audit_logs",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.contacts": {
|
||||
"name": "contacts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"notes": {
|
||||
"name": "notes",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"added_at": {
|
||||
"name": "added_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"contacts_user_id_users_id_fk": {
|
||||
"name": "contacts_user_id_users_id_fk",
|
||||
"tableFrom": "contacts",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.emails": {
|
||||
"name": "emails",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"contact_id": {
|
||||
"name": "contact_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"jmap_id": {
|
||||
"name": "jmap_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"message_id": {
|
||||
"name": "message_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"thread_id": {
|
||||
"name": "thread_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"in_reply_to": {
|
||||
"name": "in_reply_to",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"from": {
|
||||
"name": "from",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"to": {
|
||||
"name": "to",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"subject": {
|
||||
"name": "subject",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"body": {
|
||||
"name": "body",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"is_read": {
|
||||
"name": "is_read",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"emails_user_id_users_id_fk": {
|
||||
"name": "emails_user_id_users_id_fk",
|
||||
"tableFrom": "emails",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"emails_contact_id_contacts_id_fk": {
|
||||
"name": "emails_contact_id_contacts_id_fk",
|
||||
"tableFrom": "emails",
|
||||
"tableTo": "contacts",
|
||||
"columnsFrom": [
|
||||
"contact_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"emails_jmap_id_unique": {
|
||||
"name": "emails_jmap_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"jmap_id"
|
||||
]
|
||||
},
|
||||
"emails_message_id_unique": {
|
||||
"name": "emails_message_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"message_id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email_password": {
|
||||
"name": "email_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"jmap_account_id": {
|
||||
"name": "jmap_account_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"first_name": {
|
||||
"name": "first_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_name": {
|
||||
"name": "last_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"temp_password": {
|
||||
"name": "temp_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"changed_password": {
|
||||
"name": "changed_password",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "role",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'member'"
|
||||
},
|
||||
"last_login": {
|
||||
"name": "last_login",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"username"
|
||||
]
|
||||
},
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"public.role": {
|
||||
"name": "role",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"admin",
|
||||
"member"
|
||||
]
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -1,600 +0,0 @@
|
||||
{
|
||||
"id": "0a729a36-e7a3-488d-b9c5-26392e1cc67d",
|
||||
"prevId": "1b8c1e0f-8476-470c-a641-b3c350a2c1a4",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.audit_logs": {
|
||||
"name": "audit_logs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"action": {
|
||||
"name": "action",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource": {
|
||||
"name": "resource",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"resource_id": {
|
||||
"name": "resource_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"old_value": {
|
||||
"name": "old_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"new_value": {
|
||||
"name": "new_value",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"ip_address": {
|
||||
"name": "ip_address",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"user_agent": {
|
||||
"name": "user_agent",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"success": {
|
||||
"name": "success",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"error_message": {
|
||||
"name": "error_message",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"audit_logs_user_id_users_id_fk": {
|
||||
"name": "audit_logs_user_id_users_id_fk",
|
||||
"tableFrom": "audit_logs",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "set null",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.contacts": {
|
||||
"name": "contacts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email_account_id": {
|
||||
"name": "email_account_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"notes": {
|
||||
"name": "notes",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"added_at": {
|
||||
"name": "added_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"contacts_user_id_users_id_fk": {
|
||||
"name": "contacts_user_id_users_id_fk",
|
||||
"tableFrom": "contacts",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"contacts_email_account_id_email_accounts_id_fk": {
|
||||
"name": "contacts_email_account_id_email_accounts_id_fk",
|
||||
"tableFrom": "contacts",
|
||||
"tableTo": "email_accounts",
|
||||
"columnsFrom": [
|
||||
"email_account_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.email_accounts": {
|
||||
"name": "email_accounts",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email_password": {
|
||||
"name": "email_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"jmap_account_id": {
|
||||
"name": "jmap_account_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"is_primary": {
|
||||
"name": "is_primary",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"email_accounts_user_id_users_id_fk": {
|
||||
"name": "email_accounts_user_id_users_id_fk",
|
||||
"tableFrom": "email_accounts",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.emails": {
|
||||
"name": "emails",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email_account_id": {
|
||||
"name": "email_account_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"contact_id": {
|
||||
"name": "contact_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"jmap_id": {
|
||||
"name": "jmap_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"message_id": {
|
||||
"name": "message_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"thread_id": {
|
||||
"name": "thread_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"in_reply_to": {
|
||||
"name": "in_reply_to",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"from": {
|
||||
"name": "from",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"to": {
|
||||
"name": "to",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"subject": {
|
||||
"name": "subject",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"body": {
|
||||
"name": "body",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"is_read": {
|
||||
"name": "is_read",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"date": {
|
||||
"name": "date",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"emails_user_id_users_id_fk": {
|
||||
"name": "emails_user_id_users_id_fk",
|
||||
"tableFrom": "emails",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"emails_email_account_id_email_accounts_id_fk": {
|
||||
"name": "emails_email_account_id_email_accounts_id_fk",
|
||||
"tableFrom": "emails",
|
||||
"tableTo": "email_accounts",
|
||||
"columnsFrom": [
|
||||
"email_account_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
},
|
||||
"emails_contact_id_contacts_id_fk": {
|
||||
"name": "emails_contact_id_contacts_id_fk",
|
||||
"tableFrom": "emails",
|
||||
"tableTo": "contacts",
|
||||
"columnsFrom": [
|
||||
"contact_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"emails_jmap_id_unique": {
|
||||
"name": "emails_jmap_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"jmap_id"
|
||||
]
|
||||
},
|
||||
"emails_message_id_unique": {
|
||||
"name": "emails_message_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"message_id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"email_password": {
|
||||
"name": "email_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"jmap_account_id": {
|
||||
"name": "jmap_account_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"first_name": {
|
||||
"name": "first_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_name": {
|
||||
"name": "last_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"password": {
|
||||
"name": "password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"temp_password": {
|
||||
"name": "temp_password",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"changed_password": {
|
||||
"name": "changed_password",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": false
|
||||
},
|
||||
"role": {
|
||||
"name": "role",
|
||||
"type": "role",
|
||||
"typeSchema": "public",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'member'"
|
||||
},
|
||||
"last_login": {
|
||||
"name": "last_login",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_username_unique": {
|
||||
"name": "users_username_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"username"
|
||||
]
|
||||
},
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
"public.role": {
|
||||
"name": "role",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"admin",
|
||||
"member"
|
||||
]
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1763450484405,
|
||||
"tag": "0000_legal_karnak",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1763457837858,
|
||||
"tag": "0001_slow_drax",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1763547133084,
|
||||
"tag": "0002_parallel_guardian",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user