For Engineering

Database schema

Generated from laurelin/db.js initSchema() by scripts/generate-schema-docs.js. Do not edit by hand — your changes will be overwritten on the next deploy.

All primary keys are TEXT UUIDs via crypto.randomUUID() unless noted. JSON fields (email_domains, tags, source_metadata) are stored as TEXT. Soft-delete via deleted_at. Every UPDATE on companies/people/projects must call logChanges().

Total tables: 35

Core entities

people

Column Type Notes
id TEXT PK
name TEXT NOT NULL
email TEXT
role TEXT
phone TEXT
linkedin_url TEXT
telegram_handle TEXT
slack_handle TEXT
person_type TEXT NOT NULL; default 'external'; one of: internal, external
contact_type TEXT default 'working'
primary_flag INTEGER default 0
notes TEXT default ''
signature_parsed_at TEXT
signature_parse_attempts INTEGER default 0
created_at TEXT default (datetime('now'))

companies

Column Type Notes
id TEXT PK
name TEXT NOT NULL
email_domains TEXT default '[]'
company_types TEXT default '[]'
importance TEXT default 'medium'; one of: high, medium, low
stage TEXT default 'prospect'; one of: dormant, prospect, exploring, active, core, passed, in_market
ball_with TEXT default 'them'; one of: us, them
target_deal_type TEXT default ''
icp TEXT default ''
health TEXT default ''
owner_id TEXT
notes TEXT default ''
tags TEXT default '[]'
review_link TEXT
created_at TEXT default (datetime('now'))
updated_at TEXT default (datetime('now'))
deleted_at TEXT

projects

Column Type Notes
id TEXT PK
name TEXT NOT NULL
type TEXT default 'Other'; one of: Deal, Fund, Product, Infrastructure, Biz Dev, Campaign, Research, Legal, Automation, Finance, Diligence, Internal, Other
parent_id TEXT
next_step TEXT
blocker TEXT
notes TEXT default ''
strategy TEXT default ''
phase TEXT default ''
summary TEXT default ''
importance INTEGER default 5
deal_type TEXT default ''
coinvestors TEXT default ''
deal_stage TEXT
project_stage TEXT
intensity INTEGER default 0
deal_size_estimate REAL
status TEXT default 'active'; one of: sketch, hot, active, background, blocked, on-hold, completed, cancelled, deleted
health TEXT default ''
created_at TEXT default (datetime('now'))
updated_at TEXT default (datetime('now'))

interactions

Column Type Notes
id TEXT PK
date TEXT NOT NULL
company_id TEXT
type TEXT one of: email, call, meeting, note, telegram
source TEXT default 'manual'; one of: outlook, notion, telegram, manual, slack, calendar
direction TEXT one of: inbound, outbound, mutual, internal
subject TEXT
summary TEXT
logged_by_id TEXT
source_id TEXT
source_thread_id TEXT
source_metadata TEXT
project_id TEXT
created_at TEXT default (datetime('now'))

Joins

affiliations

Column Type Notes
person_id TEXT NOT NULL
company_id TEXT NOT NULL
role_at_company TEXT
started_at TEXT default (date('now'))
ended_at TEXT

interaction_companies

Column Type Notes
interaction_id TEXT NOT NULL
company_id TEXT NOT NULL

interaction_people

Column Type Notes
interaction_id TEXT NOT NULL
person_id TEXT NOT NULL
role TEXT default 'participant'; one of: participant, logged_by

project_companies

Column Type Notes
project_id TEXT NOT NULL
company_id TEXT NOT NULL

project_people

Column Type Notes
id TEXT PK
project_id TEXT NOT NULL
person_id TEXT NOT NULL
role TEXT default 'member'; one of: manager, member, watcher, contact
added_by TEXT default 'manual'; one of: manual, auto
source_interaction_id TEXT
created_at TEXT default (datetime('now'))

company_parents

Column Type Notes
child_id TEXT NOT NULL
parent_id TEXT NOT NULL
relation_type TEXT default 'parent_child'
note TEXT

Project tracking

project_milestones

Column Type Notes
id TEXT PK
project_id TEXT NOT NULL
label TEXT NOT NULL
date TEXT
notes TEXT default ''
created_at TEXT default (datetime('now'))

project_status_updates

Column Type Notes
id TEXT PK
project_id TEXT NOT NULL
week_of TEXT NOT NULL
body TEXT default ''
health TEXT default ''
no_change INTEGER default 0
submitted_by TEXT
submitted_at TEXT default (datetime('now'))

project_links

Column Type Notes
id TEXT PK
project_id TEXT NOT NULL
label TEXT NOT NULL
url TEXT NOT NULL
type TEXT default 'other'; one of: data-room, memo, legal, model, presentation, other
source TEXT default 'other'; one of: notion, sharepoint, google-drive, other
document_type TEXT default ''
link_status TEXT default 'working'; one of: working, final
created_at TEXT default (datetime('now'))

company_links

Column Type Notes
id TEXT PK
company_id TEXT NOT NULL
label TEXT NOT NULL
url TEXT NOT NULL
type TEXT default 'other'; one of: website, github, review, linkedin, crunchbase, data-room, other
created_at TEXT default (datetime('now'))

key_dates

Column Type Notes
id TEXT PK
entity_type TEXT NOT NULL; one of: company, project
entity_id TEXT NOT NULL
label TEXT NOT NULL
date TEXT
importance TEXT default 'medium'; one of: high, medium, low
flexible INTEGER default 1
notes TEXT default ''
created_at TEXT default (datetime('now'))

Sync pipeline

sync_inbox

Column Type Notes
id TEXT PK
source TEXT NOT NULL; one of: outlook, calendar, slack, notion, telegram
source_id TEXT NOT NULL
source_thread_id TEXT
submitted_by TEXT
submitted_at TEXT default (datetime('now'))
entity_type TEXT NOT NULL; one of: interaction, project, company, person
entity_data TEXT NOT NULL; default '{}'
suggested_company_id TEXT
suggested_company_name TEXT
suggested_person_ids TEXT default '[]'
suggested_project_id TEXT
relevant_to TEXT default '[]'
status TEXT default 'pending'; one of: pending, approved, dismissed, merged
reviewed_by TEXT
reviewed_at TEXT
review_notes TEXT
target_domain TEXT NOT NULL; default ''

sync_watermarks

Column Type Notes
user_id TEXT NOT NULL
source TEXT NOT NULL
channel TEXT default ''
last_sync_at TEXT NOT NULL
last_source_id TEXT

sync_skip_rules

Column Type Notes
id TEXT PK
rule_type TEXT NOT NULL; one of: sender, domain, subject_pattern, source_id_prefix, contact_skip, slack_channel, telegram_handle
pattern TEXT NOT NULL
source TEXT default 'all'; one of: outlook, calendar, slack, telegram, all
created_by TEXT
created_at TEXT default (datetime('now'))
reason TEXT default ''

oauth_tokens

Column Type Notes
id TEXT PK
user_id TEXT NOT NULL
service TEXT NOT NULL; one of: outlook, slack, google
access_token TEXT NOT NULL
refresh_token TEXT
expires_at TEXT
scope TEXT
created_at TEXT default (datetime('now'))
updated_at TEXT default (datetime('now'))

email_do_not_track

Column Type Notes
email TEXT PK
added_by TEXT
reason TEXT default ''
added_at TEXT default (datetime('now'))

telegram_connections

Column Type Notes
business_connection_id TEXT PK
internal_person_id TEXT NOT NULL
user_chat_id INTEGER
is_enabled INTEGER default 1
can_reply INTEGER default 0
connected_at TEXT default (datetime('now'))
revoked_at TEXT

telegram_chat_scope

Column Type Notes
chat_id INTEGER NOT NULL
internal_person_id TEXT NOT NULL
chat_title TEXT
chat_type TEXT
enabled INTEGER default 1
company_id TEXT
tagged_by TEXT
tagged_at TEXT
first_seen_at TEXT default (datetime('now'))
last_message_at TEXT
last_changed_by TEXT
last_changed_at TEXT

telegram_shared_chat_overrides

Column Type Notes
chat_id INTEGER PK
team_scope TEXT NOT NULL; one of: enabled, disabled
set_by TEXT
set_at TEXT default (datetime('now'))

slack_channel_map

Column Type Notes
channel_id TEXT NOT NULL
team_id TEXT NOT NULL
company_id TEXT
channel_name TEXT
channel_type TEXT
is_external INTEGER default 0
first_seen_at TEXT default (datetime('now'))
last_message_at TEXT
last_changed_by TEXT
last_changed_at TEXT

Lost-thread detection

lost_thread_candidates

Column Type Notes
id TEXT PK
conversation_id TEXT NOT NULL
detected_for_user_id TEXT NOT NULL
subject TEXT
last_message_id TEXT
last_message_date TEXT NOT NULL
last_message_direction TEXT one of: inbound, outbound
last_sender_email TEXT
last_sender_name TEXT
snippet TEXT
days_stale INTEGER
urgency_tier TEXT default 'normal'; one of: normal, emergency
urgency_reason TEXT
detected_at TEXT default (datetime('now'))
resolved_at TEXT
resolved_interaction_id TEXT
status TEXT NOT NULL; default 'pending'; one of: pending, dismissed, resolved
dismissed_scope TEXT one of: once, forever
dismissed_until_message_id TEXT
draft_requested_at TEXT
draft_intent TEXT
draft_voice TEXT
draft_started_at TEXT
draft_completed_at TEXT
draft_body TEXT
draft_body_preview TEXT
content_hash TEXT

lost_thread_candidate_people

Column Type Notes
candidate_id TEXT NOT NULL
email TEXT NOT NULL
person_id TEXT

lost_thread_candidate_companies

Column Type Notes
candidate_id TEXT NOT NULL
company_id TEXT NOT NULL

System

changelog

Column Type Notes
id INTEGER PK
record_type TEXT NOT NULL
record_id TEXT NOT NULL
field TEXT
old_value TEXT
new_value TEXT
changed_by TEXT
changed_at TEXT default (datetime('now'))

settings

Column Type Notes
key TEXT PK
value TEXT

valinor_focus

Column Type Notes
kind TEXT NOT NULL; one of: week, month, annual
period_key TEXT NOT NULL
body TEXT NOT NULL; default ''
updated_at TEXT default (datetime('now'))
updated_by TEXT

Other

pipeline_checkpoints

Column Type Notes
id TEXT PK
label TEXT default ''
trigger TEXT default 'manual'; one of: manual, pre-pull, pre-push, pre-restore
created_by TEXT default ''
created_at TEXT default (datetime('now'))
snapshot TEXT NOT NULL

slack_channel_members

Column Type Notes
channel_id TEXT NOT NULL
team_id TEXT NOT NULL
slack_user_id TEXT NOT NULL
joined_at TEXT default (datetime('now'))

personal_blocks

Column Type Notes
id TEXT PK
user_id TEXT NOT NULL
rule_type TEXT NOT NULL; one of: email, domain, telegram_handle, slack_channel, slack_user, subject_pattern
pattern TEXT NOT NULL
source TEXT NOT NULL; default 'all'; one of: outlook, calendar, slack, telegram, notion, all
reason TEXT default ''
created_at TEXT default (datetime('now'))

project_relations

Column Type Notes
project_id TEXT NOT NULL
related_project_id TEXT NOT NULL