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
-- =============================================================================