Spaces:
Running
Running
File size: 32,693 Bytes
7ba65c9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 | -- =============================================================================
-- CONTRAVAULT DATABASE SCHEMA
-- =============================================================================
-- This SQL file contains all table definitions for the Contravault platform.
-- Run this after enabling the pgvector extension in Neon:
-- CREATE EXTENSION IF NOT EXISTS vector;
-- CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =============================================================================
-- Enable extensions
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- =============================================================================
-- 1. USERS & AUTHENTICATION
-- =============================================================================
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email VARCHAR UNIQUE NOT NULL,
password_hash VARCHAR,
first_name VARCHAR,
last_name VARCHAR,
display_name VARCHAR,
avatar_url VARCHAR,
title VARCHAR,
department VARCHAR,
phone VARCHAR,
role VARCHAR DEFAULT 'user',
is_active BOOLEAN DEFAULT TRUE,
is_verified BOOLEAN DEFAULT FALSE,
preferences JSONB DEFAULT '{}',
timezone VARCHAR DEFAULT 'UTC',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
last_login TIMESTAMPTZ
);
CREATE INDEX idx_users_email ON users(email);
CREATE TABLE IF NOT EXISTS teams (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL,
description TEXT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS team_members (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
team_id UUID NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role VARCHAR DEFAULT 'member',
joined_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(team_id, user_id)
);
-- =============================================================================
-- 2. OPPORTUNITIES (SAM.gov Discovery)
-- =============================================================================
CREATE TABLE IF NOT EXISTS opportunities (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
solicitation_number VARCHAR UNIQUE NOT NULL,
notice_id VARCHAR,
title VARCHAR NOT NULL,
agency VARCHAR,
sub_agency VARCHAR,
office VARCHAR,
posted_date TIMESTAMPTZ,
response_deadline TIMESTAMPTZ,
archive_date TIMESTAMPTZ,
description TEXT,
description_plain TEXT,
naics_code VARCHAR,
naics_description VARCHAR,
psc_code VARCHAR,
set_aside VARCHAR,
place_of_performance VARCHAR,
contract_type VARCHAR,
estimated_value FLOAT,
pop_start TIMESTAMPTZ,
pop_end TIMESTAMPTZ,
link VARCHAR,
resource_links JSONB,
fit_score INTEGER DEFAULT 0,
fit_score_breakdown JSONB,
ai_summary TEXT,
ai_tags VARCHAR[],
status VARCHAR DEFAULT 'New',
ignore_reason VARCHAR,
notes TEXT,
discovered_at TIMESTAMPTZ DEFAULT NOW(),
last_checked TIMESTAMPTZ,
change_history JSONB,
project_id UUID
);
CREATE INDEX idx_opportunities_solicitation ON opportunities(solicitation_number);
CREATE INDEX idx_opportunities_notice ON opportunities(notice_id);
CREATE INDEX idx_opportunities_agency ON opportunities(agency);
CREATE INDEX idx_opportunities_deadline ON opportunities(response_deadline);
CREATE INDEX idx_opportunities_status ON opportunities(status);
CREATE INDEX idx_opportunities_naics ON opportunities(naics_code);
CREATE INDEX idx_opportunities_setaside ON opportunities(set_aside);
CREATE INDEX idx_opportunities_deadline_status ON opportunities(response_deadline, status);
CREATE INDEX idx_opportunities_naics_setaside ON opportunities(naics_code, set_aside);
-- =============================================================================
-- 3. PROJECTS
-- =============================================================================
CREATE TABLE IF NOT EXISTS projects (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
short_id VARCHAR UNIQUE,
opportunity_id UUID REFERENCES opportunities(id) ON DELETE SET NULL,
name VARCHAR NOT NULL,
client VARCHAR,
solicitation_number VARCHAR,
contract_number VARCHAR,
description TEXT,
executive_summary TEXT,
due_date TIMESTAMPTZ,
questions_due TIMESTAMPTZ,
award_date TIMESTAMPTZ,
pop_start TIMESTAMPTZ,
pop_end TIMESTAMPTZ,
estimated_value FLOAT,
bid_amount FLOAT,
budget_allocated FLOAT,
naics_code VARCHAR,
set_aside VARCHAR,
contract_type VARCHAR,
status VARCHAR DEFAULT 'Created',
stage VARCHAR DEFAULT 'discovery',
health_score INTEGER DEFAULT 100,
go_no_go_decision VARCHAR,
go_no_go_date TIMESTAMPTZ,
go_no_go_notes TEXT,
owner_id UUID REFERENCES users(id) ON DELETE SET NULL,
capture_manager VARCHAR,
proposal_manager VARCHAR,
tags VARCHAR[],
custom_fields JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
archived_at TIMESTAMPTZ
);
CREATE INDEX idx_projects_short_id ON projects(short_id);
CREATE INDEX idx_projects_solicitation ON projects(solicitation_number);
CREATE INDEX idx_projects_due_date ON projects(due_date);
CREATE INDEX idx_projects_status ON projects(status);
CREATE INDEX idx_projects_status_due ON projects(status, due_date);
-- Add FK from opportunities back to projects
ALTER TABLE opportunities ADD CONSTRAINT fk_opportunities_project
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE SET NULL;
-- Project team members (many-to-many)
CREATE TABLE IF NOT EXISTS project_team_members (
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role VARCHAR DEFAULT 'member',
added_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (project_id, user_id)
);
-- =============================================================================
-- 4. DOCUMENTS
-- =============================================================================
CREATE TABLE IF NOT EXISTS documents (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
filename VARCHAR NOT NULL,
original_filename VARCHAR,
path VARCHAR NOT NULL,
s3_key VARCHAR,
file_type VARCHAR,
mime_type VARCHAR,
size_bytes BIGINT,
page_count INTEGER,
word_count INTEGER,
category VARCHAR DEFAULT 'Other',
subcategory VARCHAR,
section_number VARCHAR,
is_ingested BOOLEAN DEFAULT FALSE,
is_shredded BOOLEAN DEFAULT FALSE,
is_indexed BOOLEAN DEFAULT FALSE,
ingestion_status VARCHAR DEFAULT 'pending',
ingestion_error TEXT,
ingestion_started_at TIMESTAMPTZ,
ingestion_completed_at TIMESTAMPTZ,
extracted_text TEXT,
extracted_metadata JSONB,
structure JSONB,
md5_hash VARCHAR,
sha256_hash VARCHAR,
uploaded_by UUID REFERENCES users(id) ON DELETE SET NULL,
uploaded_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_documents_project ON documents(project_id);
CREATE INDEX idx_documents_md5 ON documents(md5_hash);
CREATE INDEX idx_documents_project_category ON documents(project_id, category);
CREATE TABLE IF NOT EXISTS document_versions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
version_number INTEGER NOT NULL,
path VARCHAR NOT NULL,
s3_key VARCHAR,
size_bytes BIGINT,
md5_hash VARCHAR,
change_summary TEXT,
uploaded_by UUID REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(document_id, version_number)
);
-- =============================================================================
-- 5. DOCUMENT CHUNKS (Vector Store for RAG)
-- =============================================================================
CREATE TABLE IF NOT EXISTS doc_chunks (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
content TEXT NOT NULL,
content_tokens INTEGER,
chunk_index INTEGER,
page_number INTEGER,
section_ref VARCHAR,
parent_chunk_id UUID REFERENCES doc_chunks(id) ON DELETE SET NULL,
context_before TEXT,
context_after TEXT,
chunk_type VARCHAR,
metadata JSONB,
embedding vector(1536), -- pgvector for OpenAI embeddings
embedding_model VARCHAR DEFAULT 'text-embedding-3-small',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_chunks_document ON doc_chunks(document_id);
CREATE INDEX idx_chunks_document_page ON doc_chunks(document_id, page_number);
-- Vector similarity index (for semantic search)
CREATE INDEX idx_chunks_embedding ON doc_chunks
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
-- =============================================================================
-- 6. TAGS
-- =============================================================================
CREATE TABLE IF NOT EXISTS tags (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR UNIQUE NOT NULL,
color VARCHAR DEFAULT '#3b82f6',
category VARCHAR,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS requirement_tags (
requirement_id UUID NOT NULL,
tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (requirement_id, tag_id)
);
CREATE TABLE IF NOT EXISTS document_tags (
document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
tag_id UUID NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (document_id, tag_id)
);
-- =============================================================================
-- 7. REQUIREMENTS (Shredder Output / Compliance Matrix)
-- =============================================================================
CREATE TABLE IF NOT EXISTS requirements (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
document_id UUID REFERENCES documents(id) ON DELETE SET NULL,
short_id VARCHAR,
section_ref VARCHAR,
requirement_text TEXT NOT NULL,
source_text TEXT,
category VARCHAR,
subcategory VARCHAR,
type VARCHAR DEFAULT 'Mandatory',
volume VARCHAR,
page_number INTEGER,
line_number INTEGER,
risk_level VARCHAR DEFAULT 'Low',
risk_score INTEGER DEFAULT 0,
risk_factors JSONB,
status VARCHAR DEFAULT 'NotStarted',
compliance_response TEXT,
evidence TEXT,
exceptions TEXT,
assigned_to UUID REFERENCES users(id) ON DELETE SET NULL,
assigned_by UUID REFERENCES users(id) ON DELETE SET NULL,
assigned_at TIMESTAMPTZ,
due_date TIMESTAMPTZ,
priority VARCHAR DEFAULT 'medium',
reviewed_by UUID REFERENCES users(id) ON DELETE SET NULL,
reviewed_at TIMESTAMPTZ,
ai_suggestion TEXT,
ai_confidence FLOAT,
notes TEXT,
internal_notes TEXT,
parent_id UUID REFERENCES requirements(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_requirements_project ON requirements(project_id);
CREATE INDEX idx_requirements_short_id ON requirements(short_id);
CREATE INDEX idx_requirements_project_status ON requirements(project_id, status);
CREATE INDEX idx_requirements_assigned ON requirements(assigned_to, status);
-- Add FK for requirement_tags
ALTER TABLE requirement_tags ADD CONSTRAINT fk_requirement_tags_requirement
FOREIGN KEY (requirement_id) REFERENCES requirements(id) ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS requirement_responses (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
requirement_id UUID NOT NULL REFERENCES requirements(id) ON DELETE CASCADE,
version INTEGER DEFAULT 1,
response_text TEXT,
evidence TEXT,
status VARCHAR DEFAULT 'draft',
submitted_by UUID REFERENCES users(id) ON DELETE SET NULL,
submitted_at TIMESTAMPTZ,
reviewed_by UUID REFERENCES users(id) ON DELETE SET NULL,
reviewed_at TIMESTAMPTZ,
review_notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(requirement_id, version)
);
-- =============================================================================
-- 8. PROPOSAL SECTIONS
-- =============================================================================
CREATE TABLE IF NOT EXISTS proposal_sections (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
parent_id UUID REFERENCES proposal_sections(id) ON DELETE SET NULL,
order_index INTEGER DEFAULT 0,
title VARCHAR NOT NULL,
section_number VARCHAR,
volume VARCHAR,
content_sfdt JSONB,
content_html TEXT,
content_markdown TEXT,
content_plain TEXT,
word_count INTEGER DEFAULT 0,
page_estimate FLOAT,
status VARCHAR DEFAULT 'draft',
is_locked BOOLEAN DEFAULT FALSE,
locked_by UUID REFERENCES users(id) ON DELETE SET NULL,
locked_at TIMESTAMPTZ,
assigned_to UUID REFERENCES users(id) ON DELETE SET NULL,
due_date TIMESTAMPTZ,
page_limit INTEGER,
is_over_limit BOOLEAN DEFAULT FALSE,
ai_generated BOOLEAN DEFAULT FALSE,
ai_generation_prompt TEXT,
ai_model_used VARCHAR,
version INTEGER DEFAULT 1,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
last_edited_by UUID REFERENCES users(id) ON DELETE SET NULL
);
CREATE INDEX idx_sections_project ON proposal_sections(project_id);
CREATE INDEX idx_sections_project_volume ON proposal_sections(project_id, volume);
CREATE TABLE IF NOT EXISTS proposal_section_versions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
section_id UUID NOT NULL REFERENCES proposal_sections(id) ON DELETE CASCADE,
version_number INTEGER NOT NULL,
content_sfdt JSONB,
content_html TEXT,
word_count INTEGER,
change_summary TEXT,
edited_by UUID REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(section_id, version_number)
);
CREATE TABLE IF NOT EXISTS proposal_templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL,
description TEXT,
category VARCHAR,
content_sfdt JSONB,
content_html TEXT,
use_count INTEGER DEFAULT 0,
tags VARCHAR[],
is_public BOOLEAN DEFAULT FALSE,
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 9. PRICING
-- =============================================================================
CREATE TABLE IF NOT EXISTS pricing_items (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
clin_number VARCHAR,
clin_description TEXT,
parent_clin_id UUID REFERENCES pricing_items(id) ON DELETE SET NULL,
quantity FLOAT,
unit VARCHAR,
unit_price FLOAT,
extended_price FLOAT,
labor_cost FLOAT,
material_cost FLOAT,
odc_cost FLOAT,
indirect_cost FLOAT,
profit FLOAT,
labor_category VARCHAR,
labor_hours FLOAT,
labor_rate FLOAT,
period VARCHAR,
start_date TIMESTAMPTZ,
end_date TIMESTAMPTZ,
notes TEXT,
assumptions TEXT,
order_index INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS labor_categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL,
description TEXT,
hourly_rate FLOAT,
annual_salary FLOAT,
burden_rate FLOAT,
education_requirement VARCHAR,
experience_years INTEGER,
clearance_level VARCHAR,
gsa_rate FLOAT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 10. TASKS & WORKFLOW
-- =============================================================================
CREATE TABLE IF NOT EXISTS tasks (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
title VARCHAR NOT NULL,
description TEXT,
status VARCHAR DEFAULT 'todo',
priority VARCHAR DEFAULT 'medium',
assignee_id UUID REFERENCES users(id) ON DELETE SET NULL,
created_by UUID REFERENCES users(id) ON DELETE SET NULL,
due_date TIMESTAMPTZ,
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
requirement_id UUID REFERENCES requirements(id) ON DELETE SET NULL,
section_id UUID REFERENCES proposal_sections(id) ON DELETE SET NULL,
estimated_hours FLOAT,
actual_hours FLOAT,
tags VARCHAR[],
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS comments (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
requirement_id UUID REFERENCES requirements(id) ON DELETE CASCADE,
section_id UUID REFERENCES proposal_sections(id) ON DELETE CASCADE,
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
parent_id UUID REFERENCES comments(id) ON DELETE CASCADE,
content TEXT NOT NULL,
content_html TEXT,
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
mentions UUID[],
is_resolved BOOLEAN DEFAULT FALSE,
resolved_by UUID REFERENCES users(id) ON DELETE SET NULL,
resolved_at TIMESTAMPTZ,
is_edited BOOLEAN DEFAULT FALSE,
edited_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR DEFAULT 'info',
title VARCHAR NOT NULL,
message TEXT,
entity_type VARCHAR,
entity_id UUID,
action_url VARCHAR,
is_read BOOLEAN DEFAULT FALSE,
read_at TIMESTAMPTZ,
email_sent BOOLEAN DEFAULT FALSE,
email_sent_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
expires_at TIMESTAMPTZ
);
-- =============================================================================
-- 11. AI & KNOWLEDGE
-- =============================================================================
CREATE TABLE IF NOT EXISTS ai_conversations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
title VARCHAR,
context_type VARCHAR,
context_id UUID,
model VARCHAR DEFAULT 'gpt-4',
temperature FLOAT DEFAULT 0.7,
system_prompt TEXT,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS ai_messages (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
conversation_id UUID NOT NULL REFERENCES ai_conversations(id) ON DELETE CASCADE,
role VARCHAR NOT NULL,
content TEXT NOT NULL,
prompt_tokens INTEGER,
completion_tokens INTEGER,
total_tokens INTEGER,
retrieved_chunks JSONB,
rating INTEGER,
feedback TEXT,
model VARCHAR,
latency_ms INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS ai_generation_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
generation_type VARCHAR,
prompt TEXT,
output TEXT,
provider VARCHAR,
model VARCHAR,
temperature FLOAT,
prompt_tokens INTEGER,
completion_tokens INTEGER,
total_tokens INTEGER,
cost_usd FLOAT,
latency_ms INTEGER,
was_accepted BOOLEAN,
user_edits TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS company_knowledge (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
category VARCHAR NOT NULL,
subcategory VARCHAR,
title VARCHAR NOT NULL,
content TEXT NOT NULL,
metadata JSONB,
tags VARCHAR[],
embedding vector(1536),
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Vector index for company knowledge
CREATE INDEX idx_company_knowledge_embedding ON company_knowledge
USING ivfflat (embedding vector_cosine_ops) WITH (lists = 50);
-- =============================================================================
-- 12. ACTIVITY & AUDIT LOGS
-- =============================================================================
CREATE TABLE IF NOT EXISTS user_sessions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
session_token VARCHAR UNIQUE,
ip_address INET,
user_agent TEXT,
device_type VARCHAR,
browser VARCHAR,
os VARCHAR,
country VARCHAR,
city VARCHAR,
started_at TIMESTAMPTZ DEFAULT NOW(),
last_activity TIMESTAMPTZ DEFAULT NOW(),
ended_at TIMESTAMPTZ,
is_active BOOLEAN DEFAULT TRUE,
logout_reason VARCHAR
);
CREATE INDEX idx_sessions_token ON user_sessions(session_token);
CREATE INDEX idx_sessions_user ON user_sessions(user_id);
CREATE TABLE IF NOT EXISTS activity_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
session_id UUID REFERENCES user_sessions(id) ON DELETE SET NULL,
activity_type VARCHAR NOT NULL,
action VARCHAR,
entity_type VARCHAR,
entity_id UUID,
entity_name VARCHAR,
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
description TEXT,
details JSONB,
old_values JSONB,
new_values JSONB,
ip_address INET,
user_agent VARCHAR,
request_id VARCHAR,
status VARCHAR DEFAULT 'success',
error_message TEXT,
duration_ms INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_activity_type ON activity_logs(activity_type);
CREATE INDEX idx_activity_entity ON activity_logs(entity_type, entity_id);
CREATE INDEX idx_activity_project ON activity_logs(project_id);
CREATE INDEX idx_activity_user_time ON activity_logs(user_id, created_at);
CREATE INDEX idx_activity_project_time ON activity_logs(project_id, created_at);
CREATE INDEX idx_activity_type_time ON activity_logs(activity_type, created_at);
CREATE INDEX idx_activity_created ON activity_logs(created_at);
CREATE TABLE IF NOT EXISTS audit_trails (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID, -- No FK to preserve data if user deleted
user_email VARCHAR,
action VARCHAR NOT NULL,
table_name VARCHAR NOT NULL,
record_id UUID,
old_data JSONB,
new_data JSONB,
changed_fields VARCHAR[],
reason TEXT,
ip_address INET,
user_agent TEXT,
request_path VARCHAR,
request_method VARCHAR,
timestamp TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_audit_table ON audit_trails(table_name);
CREATE INDEX idx_audit_record ON audit_trails(record_id);
CREATE INDEX idx_audit_table_record ON audit_trails(table_name, record_id);
CREATE INDEX idx_audit_user_time ON audit_trails(user_id, timestamp);
CREATE INDEX idx_audit_timestamp ON audit_trails(timestamp);
CREATE TABLE IF NOT EXISTS error_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
error_type VARCHAR NOT NULL,
error_message TEXT NOT NULL,
stack_trace TEXT,
request_path VARCHAR,
request_method VARCHAR,
request_body JSONB,
environment VARCHAR,
server_hostname VARCHAR,
is_resolved BOOLEAN DEFAULT FALSE,
resolved_by UUID,
resolved_at TIMESTAMPTZ,
resolution_notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_errors_created ON error_logs(created_at);
-- =============================================================================
-- 13. ANALYTICS
-- =============================================================================
CREATE TABLE IF NOT EXISTS page_views (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
session_id UUID REFERENCES user_sessions(id) ON DELETE SET NULL,
page_path VARCHAR NOT NULL,
page_title VARCHAR,
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
referrer VARCHAR,
time_on_page_ms INTEGER,
viewport_width INTEGER,
viewport_height INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_pageview_path ON page_views(page_path);
CREATE INDEX idx_pageview_user_time ON page_views(user_id, created_at);
CREATE INDEX idx_pageview_page_time ON page_views(page_path, created_at);
CREATE INDEX idx_pageview_created ON page_views(created_at);
CREATE TABLE IF NOT EXISTS search_history (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
query VARCHAR NOT NULL,
search_type VARCHAR,
filters JSONB,
result_count INTEGER,
clicked_results JSONB,
latency_ms INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS feature_usage (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
project_id UUID REFERENCES projects(id) ON DELETE SET NULL,
feature_name VARCHAR NOT NULL,
action VARCHAR,
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_feature_name ON feature_usage(feature_name);
CREATE INDEX idx_feature_name_time ON feature_usage(feature_name, created_at);
-- =============================================================================
-- 14. SETTINGS
-- =============================================================================
CREATE TABLE IF NOT EXISTS system_settings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
key VARCHAR UNIQUE NOT NULL,
value JSONB,
value_type VARCHAR,
category VARCHAR,
description TEXT,
is_secret BOOLEAN DEFAULT FALSE,
is_editable BOOLEAN DEFAULT TRUE,
updated_by UUID REFERENCES users(id) ON DELETE SET NULL,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_settings_key ON system_settings(key);
CREATE TABLE IF NOT EXISTS user_settings (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
key VARCHAR NOT NULL,
value JSONB,
updated_at TIMESTAMPTZ DEFAULT NOW(),
UNIQUE(user_id, key)
);
CREATE TABLE IF NOT EXISTS pursuit_policies (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
parameter_name VARCHAR UNIQUE NOT NULL,
threshold_value VARCHAR NOT NULL,
comparison_operator VARCHAR,
weight FLOAT DEFAULT 1.0,
category VARCHAR,
description TEXT,
is_mandatory BOOLEAN DEFAULT FALSE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 15. SUBMISSION
-- =============================================================================
CREATE TABLE IF NOT EXISTS submission_packages (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
name VARCHAR NOT NULL,
version INTEGER DEFAULT 1,
status VARCHAR DEFAULT 'draft',
submission_method VARCHAR,
submitted_at TIMESTAMPTZ,
submitted_by UUID REFERENCES users(id) ON DELETE SET NULL,
confirmation_number VARCHAR,
is_validated BOOLEAN DEFAULT FALSE,
validation_errors JSONB,
is_sanitized BOOLEAN DEFAULT FALSE,
sanitization_report JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS submission_files (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
package_id UUID NOT NULL REFERENCES submission_packages(id) ON DELETE CASCADE,
filename VARCHAR NOT NULL,
path VARCHAR NOT NULL,
s3_key VARCHAR,
file_type VARCHAR,
size_bytes BIGINT,
volume VARCHAR,
order_index INTEGER DEFAULT 0,
page_count INTEGER,
word_count INTEGER,
is_compliant BOOLEAN,
md5_hash VARCHAR,
sha256_hash VARCHAR,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 16. ANALYSIS & INTELLIGENCE
-- =============================================================================
CREATE TABLE IF NOT EXISTS analysis_results (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
analysis_type VARCHAR NOT NULL,
result_json JSONB NOT NULL,
overall_score FLOAT,
confidence FLOAT,
model_used VARCHAR,
status VARCHAR DEFAULT 'complete',
error_message TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
created_by UUID REFERENCES users(id) ON DELETE SET NULL
);
CREATE INDEX idx_analysis_project ON analysis_results(project_id);
CREATE INDEX idx_analysis_type ON analysis_results(analysis_type);
CREATE TABLE IF NOT EXISTS competitors (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL,
duns_number VARCHAR,
cage_code VARCHAR,
website VARCHAR,
description TEXT,
capabilities JSONB,
proprietary_technologies JSONB,
certifications JSONB,
contract_vehicles JSONB,
past_performance_agencies JSONB,
incumbent_contracts JSONB,
strengths JSONB,
weaknesses JSONB,
annual_revenue FLOAT,
employee_count INTEGER,
size_standard VARCHAR,
socioeconomic_status JSONB,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_competitors_name ON competitors(name);
CREATE TABLE IF NOT EXISTS competitor_encounters (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
competitor_id UUID NOT NULL REFERENCES competitors(id) ON DELETE CASCADE,
project_id UUID REFERENCES projects(id) ON DELETE CASCADE,
opportunity_id UUID REFERENCES opportunities(id) ON DELETE CASCADE,
role VARCHAR,
confidence FLOAT,
source VARCHAR,
outcome VARCHAR,
notes TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- =============================================================================
-- 17. INTEGRATIONS
-- =============================================================================
CREATE TABLE IF NOT EXISTS integration_configs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR UNIQUE NOT NULL,
provider VARCHAR NOT NULL,
config JSONB,
credentials JSONB,
is_enabled BOOLEAN DEFAULT TRUE,
last_sync TIMESTAMPTZ,
last_error TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS webhook_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
direction VARCHAR NOT NULL,
provider VARCHAR,
event_type VARCHAR,
url VARCHAR,
method VARCHAR,
headers JSONB,
payload JSONB,
status_code INTEGER,
response_body JSONB,
is_success BOOLEAN,
error_message TEXT,
retry_count INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS scheduled_jobs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR NOT NULL,
job_type VARCHAR NOT NULL,
cron_expression VARCHAR,
interval_minutes INTEGER,
config JSONB,
is_enabled BOOLEAN DEFAULT TRUE,
last_run TIMESTAMPTZ,
last_status VARCHAR,
last_error TEXT,
next_run TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS job_executions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
job_id UUID REFERENCES scheduled_jobs(id) ON DELETE CASCADE,
job_name VARCHAR,
started_at TIMESTAMPTZ DEFAULT NOW(),
completed_at TIMESTAMPTZ,
duration_ms INTEGER,
status VARCHAR,
error_message TEXT,
result JSONB,
records_processed INTEGER
);
-- =============================================================================
-- END OF SCHEMA
-- =============================================================================
|