mirror of
https://github.com/Dvorinka/Productier.git
synced 2026-06-04 20:43:02 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS workspaces (
|
||||
id text PRIMARY KEY,
|
||||
slug text NOT NULL UNIQUE,
|
||||
name text NOT NULL,
|
||||
role text NOT NULL,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS members (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
email text NOT NULL,
|
||||
role text NOT NULL,
|
||||
status text NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS members_workspace_email_idx ON members (workspace_slug, email);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invites (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
email text NOT NULL,
|
||||
role text NOT NULL,
|
||||
token text NOT NULL UNIQUE,
|
||||
created_at timestamptz NOT NULL,
|
||||
status text NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS activity_entries (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
title text NOT NULL,
|
||||
detail text NOT NULL,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS activity_entries_workspace_created_idx ON activity_entries (workspace_slug, created_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS board_groups (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
color text NOT NULL,
|
||||
sort_order integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS labels (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
color text NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
board_group_id text NOT NULL REFERENCES board_groups(id) ON DELETE CASCADE,
|
||||
title text NOT NULL,
|
||||
description text NOT NULL DEFAULT '',
|
||||
status text NOT NULL,
|
||||
color text NOT NULL,
|
||||
due_at timestamptz,
|
||||
scheduled_start timestamptz,
|
||||
scheduled_end timestamptz,
|
||||
assignee_id text,
|
||||
label_ids jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
attachments jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
comments jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS tasks_workspace_updated_idx ON tasks (workspace_slug, updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS calendar_events (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
title text NOT NULL,
|
||||
description text NOT NULL DEFAULT '',
|
||||
starts_at timestamptz NOT NULL,
|
||||
ends_at timestamptz NOT NULL,
|
||||
color text NOT NULL,
|
||||
linked_task_id text,
|
||||
attachments jsonb NOT NULL DEFAULT '[]'::jsonb
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS calendar_events_workspace_starts_idx ON calendar_events (workspace_slug, starts_at ASC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notes (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
title text NOT NULL,
|
||||
content text NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS focus_sessions (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
task_id text,
|
||||
mode text NOT NULL,
|
||||
started_at timestamptz NOT NULL,
|
||||
completed_at timestamptz,
|
||||
paused_at timestamptz,
|
||||
paused_total_seconds integer NOT NULL DEFAULT 0,
|
||||
duration_seconds integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS focus_sessions_workspace_started_idx ON focus_sessions (workspace_slug, started_at DESC);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS focus_sessions;
|
||||
DROP TABLE IF EXISTS notes;
|
||||
DROP TABLE IF EXISTS calendar_events;
|
||||
DROP TABLE IF EXISTS tasks;
|
||||
DROP TABLE IF EXISTS labels;
|
||||
DROP TABLE IF EXISTS board_groups;
|
||||
DROP TABLE IF EXISTS activity_entries;
|
||||
DROP TABLE IF EXISTS invites;
|
||||
DROP INDEX IF EXISTS members_workspace_email_idx;
|
||||
DROP TABLE IF EXISTS members;
|
||||
DROP TABLE IF EXISTS workspaces;
|
||||
@@ -0,0 +1,75 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS mailboxes (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
label text NOT NULL,
|
||||
email text NOT NULL,
|
||||
display_name text NOT NULL DEFAULT '',
|
||||
imap_host text NOT NULL,
|
||||
imap_port integer NOT NULL,
|
||||
imap_username text NOT NULL,
|
||||
imap_password_ciphertext text NOT NULL,
|
||||
imap_use_tls boolean NOT NULL DEFAULT true,
|
||||
smtp_host text NOT NULL,
|
||||
smtp_port integer NOT NULL,
|
||||
smtp_username text NOT NULL,
|
||||
smtp_password_ciphertext text NOT NULL,
|
||||
smtp_use_tls boolean NOT NULL DEFAULT true,
|
||||
sync_status text NOT NULL DEFAULT 'idle',
|
||||
sync_error text NOT NULL DEFAULT '',
|
||||
last_synced_at timestamptz,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS mailboxes_workspace_updated_idx ON mailboxes (workspace_slug, updated_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS mail_messages (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
mailbox_id text NOT NULL REFERENCES mailboxes(id) ON DELETE CASCADE,
|
||||
remote_uid bigint NOT NULL,
|
||||
message_id text NOT NULL DEFAULT '',
|
||||
folder text NOT NULL DEFAULT 'INBOX',
|
||||
from_address jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
to_recipients jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
cc_recipients jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
subject text NOT NULL DEFAULT '',
|
||||
snippet text NOT NULL DEFAULT '',
|
||||
text_body text NOT NULL DEFAULT '',
|
||||
html_body text NOT NULL DEFAULT '',
|
||||
received_at timestamptz NOT NULL,
|
||||
is_read boolean NOT NULL DEFAULT false,
|
||||
linked_task_id text,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS mail_messages_mailbox_folder_uid_idx ON mail_messages (mailbox_id, folder, remote_uid);
|
||||
CREATE INDEX IF NOT EXISTS mail_messages_workspace_received_idx ON mail_messages (workspace_slug, received_at DESC);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS outgoing_mails (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
mailbox_id text NOT NULL REFERENCES mailboxes(id) ON DELETE CASCADE,
|
||||
to_recipients jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
cc_recipients jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
bcc_recipients jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||
subject text NOT NULL DEFAULT '',
|
||||
text_body text NOT NULL DEFAULT '',
|
||||
html_body text NOT NULL DEFAULT '',
|
||||
status text NOT NULL,
|
||||
scheduled_for timestamptz,
|
||||
sent_at timestamptz,
|
||||
error_message text NOT NULL DEFAULT '',
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS outgoing_mails_workspace_created_idx ON outgoing_mails (workspace_slug, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS outgoing_mails_status_schedule_idx ON outgoing_mails (status, scheduled_for ASC);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS outgoing_mails;
|
||||
DROP TABLE IF EXISTS mail_messages;
|
||||
DROP TABLE IF EXISTS mailboxes;
|
||||
@@ -0,0 +1,79 @@
|
||||
-- +goose Up
|
||||
-- Contacts
|
||||
CREATE TABLE IF NOT EXISTS contacts (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
first_name text NOT NULL DEFAULT '',
|
||||
last_name text NOT NULL DEFAULT '',
|
||||
email text NOT NULL DEFAULT '',
|
||||
phone text NOT NULL DEFAULT '',
|
||||
company_id text,
|
||||
title text NOT NULL DEFAULT '',
|
||||
notes text NOT NULL DEFAULT '',
|
||||
avatar_url text NOT NULL DEFAULT '',
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS contacts_workspace_updated_idx ON contacts (workspace_slug, updated_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS contacts_workspace_email_idx ON contacts (workspace_slug, email);
|
||||
|
||||
-- Companies
|
||||
CREATE TABLE IF NOT EXISTS companies (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
domain text NOT NULL DEFAULT '',
|
||||
website text NOT NULL DEFAULT '',
|
||||
industry text NOT NULL DEFAULT '',
|
||||
size text NOT NULL DEFAULT '',
|
||||
notes text NOT NULL DEFAULT '',
|
||||
logo_url text NOT NULL DEFAULT '',
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS companies_workspace_updated_idx ON companies (workspace_slug, updated_at DESC);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS companies_workspace_name_idx ON companies (workspace_slug, name);
|
||||
|
||||
-- Add company foreign key to contacts
|
||||
ALTER TABLE contacts ADD CONSTRAINT contacts_company_fk FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE SET NULL;
|
||||
|
||||
-- Contact-Task links
|
||||
CREATE TABLE IF NOT EXISTS contact_tasks (
|
||||
id text PRIMARY KEY,
|
||||
contact_id text NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
||||
task_id text NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS contact_tasks_unique_idx ON contact_tasks (contact_id, task_id);
|
||||
|
||||
-- Contact-Event links
|
||||
CREATE TABLE IF NOT EXISTS contact_events (
|
||||
id text PRIMARY KEY,
|
||||
contact_id text NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
||||
event_id text NOT NULL REFERENCES calendar_events(id) ON DELETE CASCADE,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS contact_events_unique_idx ON contact_events (contact_id, event_id);
|
||||
|
||||
-- Contact-Email links (track which contacts are involved in emails)
|
||||
CREATE TABLE IF NOT EXISTS contact_emails (
|
||||
id text PRIMARY KEY,
|
||||
contact_id text NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
||||
mail_message_id text NOT NULL REFERENCES mail_messages(id) ON DELETE CASCADE,
|
||||
role text NOT NULL DEFAULT 'recipient', -- sender, recipient, cc
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS contact_emails_unique_idx ON contact_emails (contact_id, mail_message_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS contact_emails;
|
||||
DROP TABLE IF EXISTS contact_events;
|
||||
DROP TABLE IF EXISTS contact_tasks;
|
||||
ALTER TABLE contacts DROP CONSTRAINT IF EXISTS contacts_company_fk;
|
||||
DROP TABLE IF EXISTS contacts;
|
||||
DROP TABLE IF EXISTS companies;
|
||||
@@ -0,0 +1,71 @@
|
||||
-- +goose Up
|
||||
-- Recurring tasks
|
||||
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS recurrence_rule text NOT NULL DEFAULT '';
|
||||
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS recurrence_end timestamptz;
|
||||
|
||||
-- Recurring events
|
||||
ALTER TABLE calendar_events ADD COLUMN IF NOT EXISTS recurrence_rule text NOT NULL DEFAULT '';
|
||||
ALTER TABLE calendar_events ADD COLUMN IF NOT EXISTS recurrence_end timestamptz;
|
||||
|
||||
-- Quick capture inbox
|
||||
CREATE TABLE IF NOT EXISTS inbox_items (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
content text NOT NULL,
|
||||
source text NOT NULL DEFAULT 'manual', -- manual, email, api
|
||||
processed boolean NOT NULL DEFAULT false,
|
||||
processed_at timestamptz,
|
||||
processed_entity_type text, -- task, note, event
|
||||
processed_entity_id text,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS inbox_items_workspace_created_idx ON inbox_items (workspace_slug, created_at DESC);
|
||||
|
||||
-- Time tracking
|
||||
CREATE TABLE IF NOT EXISTS time_entries (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
task_id text REFERENCES tasks(id) ON DELETE CASCADE,
|
||||
description text NOT NULL DEFAULT '',
|
||||
started_at timestamptz NOT NULL,
|
||||
ended_at timestamptz,
|
||||
duration_seconds integer NOT NULL DEFAULT 0,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS time_entries_workspace_started_idx ON time_entries (workspace_slug, started_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS time_entries_task_idx ON time_entries (task_id);
|
||||
|
||||
-- Saved filters/views
|
||||
CREATE TABLE IF NOT EXISTS saved_views (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
entity_type text NOT NULL, -- tasks, contacts, companies
|
||||
filter_json jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
sort_json jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
is_default boolean NOT NULL DEFAULT false,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS saved_views_workspace_type_idx ON saved_views (workspace_slug, entity_type);
|
||||
|
||||
-- Archive support
|
||||
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS archived boolean NOT NULL DEFAULT false;
|
||||
ALTER TABLE calendar_events ADD COLUMN IF NOT EXISTS archived boolean NOT NULL DEFAULT false;
|
||||
ALTER TABLE notes ADD COLUMN IF NOT EXISTS archived boolean NOT NULL DEFAULT false;
|
||||
|
||||
-- +goose Down
|
||||
ALTER TABLE tasks DROP COLUMN IF EXISTS recurrence_rule;
|
||||
ALTER TABLE tasks DROP COLUMN IF EXISTS recurrence_end;
|
||||
ALTER TABLE calendar_events DROP COLUMN IF EXISTS recurrence_rule;
|
||||
ALTER TABLE calendar_events DROP COLUMN IF EXISTS recurrence_end;
|
||||
DROP TABLE IF EXISTS inbox_items;
|
||||
DROP TABLE IF EXISTS time_entries;
|
||||
DROP TABLE IF EXISTS saved_views;
|
||||
ALTER TABLE tasks DROP COLUMN IF EXISTS archived;
|
||||
ALTER TABLE calendar_events DROP COLUMN IF EXISTS archived;
|
||||
ALTER TABLE notes DROP COLUMN IF EXISTS archived;
|
||||
@@ -0,0 +1,70 @@
|
||||
-- +goose Up
|
||||
-- Integrations table for external service connections
|
||||
CREATE TABLE IF NOT EXISTS integrations (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
provider text NOT NULL, -- google_calendar, slack, etc.
|
||||
name text NOT NULL,
|
||||
config jsonb NOT NULL DEFAULT '{}'::jsonb,
|
||||
credentials_ciphertext text NOT NULL,
|
||||
status text NOT NULL DEFAULT 'active',
|
||||
last_sync_at timestamptz,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS integrations_workspace_provider_idx ON integrations (workspace_slug, provider);
|
||||
|
||||
-- Webhooks for external notifications
|
||||
CREATE TABLE IF NOT EXISTS webhooks (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
name text NOT NULL,
|
||||
url text NOT NULL,
|
||||
secret text NOT NULL,
|
||||
events jsonb NOT NULL DEFAULT '[]'::jsonb, -- ["task.created", "task.completed", etc.]
|
||||
active boolean NOT NULL DEFAULT true,
|
||||
last_triggered_at timestamptz,
|
||||
created_at timestamptz NOT NULL,
|
||||
updated_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS webhooks_workspace_idx ON webhooks (workspace_slug);
|
||||
|
||||
-- Notifications for users
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
user_email text NOT NULL,
|
||||
type text NOT NULL, -- task_assigned, mention, comment, etc.
|
||||
title text NOT NULL,
|
||||
body text NOT NULL DEFAULT '',
|
||||
entity_type text, -- task, event, note
|
||||
entity_id text,
|
||||
read boolean NOT NULL DEFAULT false,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS notifications_user_created_idx ON notifications (user_email, created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS notifications_unread_idx ON notifications (user_email, read) WHERE read = false;
|
||||
|
||||
-- Presence tracking for real-time collaboration
|
||||
CREATE TABLE IF NOT EXISTS presence (
|
||||
id text PRIMARY KEY,
|
||||
workspace_slug text NOT NULL REFERENCES workspaces(slug) ON DELETE CASCADE,
|
||||
user_email text NOT NULL,
|
||||
user_name text NOT NULL,
|
||||
entity_type text, -- board, task, note, etc.
|
||||
entity_id text,
|
||||
last_seen_at timestamptz NOT NULL,
|
||||
created_at timestamptz NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS presence_workspace_entity_idx ON presence (workspace_slug, entity_type, entity_id);
|
||||
CREATE INDEX IF NOT EXISTS presence_user_idx ON presence (user_email);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS presence;
|
||||
DROP TABLE IF EXISTS notifications;
|
||||
DROP TABLE IF EXISTS webhooks;
|
||||
DROP TABLE IF EXISTS integrations;
|
||||
Reference in New Issue
Block a user