disclosure-bureau/infra
guto 7d13f93393 ship: synthesize 158 entities, AG-UI artifacts, chat persistence, auth flow
Fase 3 onda 2 — entity synthesis at scale:
- scripts/synthesize/20_entity_summary.py: queries DB for entities with
  total_mentions ≥ threshold + top-K verbatim chunk snippets via
  entity_mentions JOIN, prompts Sonnet (Holmes-Watson voice, bilingual),
  writes narrative_summary EN+PT-BR + summary_status=synthesized.
  Ran on 187 candidates (mentions ≥ 20) → 158 OK · 1 err · 29 skipped (no
  snippets). Combined with anchor curation: 20 curated + 158 synthesized
  = 178 entities with real narrative (vs 0 a day ago).

Fase 4 — chat with typed artifacts + persistence:
- lib/chat/agui.ts: AG-UI v1 typed Artifact union (citation, crop_image,
  entity_card, evidence_card, hypothesis_card, case_card, navigation_offer)
  alongside the existing event types.
- lib/chat/tools.ts + openrouter.ts: hybrid_search emits up to 6
  citation + crop_image artifacts per query. Provider collects them and
  returns in done.artifacts so the route can persist.
- api/sessions/[id]/messages: persist artifacts to messages.citations.
- components/chat-bubble.tsx: ArtifactCard renders inline cards (citation,
  crop_image, entity_card, navigation_offer) for streamed and persisted
  messages. activeId now persisted in localStorage so navigation between
  pages keeps the same conversation. New sessions are lazy (only when user
  has zero). loadMessages hydrates tools + artifacts from server. CRUD UI:
  rename (✎) + archive (🗑) buttons per session in the list.

Home search:
- doc-list-filters: input now fires hybrid_search (rerank=0 for speed)
  in parallel with the local title filter; chunk hits render above the doc
  grid with snippet + score + classification.
- api/search/hybrid: accept ?rerank=0 to skip the cross-encoder (1.3s vs 60s).

Auth flow:
- infra: SMTP_HOST=mail.spacemail.com:587 + DMARC published; mail now lands
  in inbox. GOTRUE_MAILER_AUTOCONFIRM=false (real email verification).
- kong.yml: proxy /auth/callback on api.disclosure.top → web:3000 so PKCE
  email links don't 404 at the gateway.
- web/app/auth/callback: handle both ?code= (OAuth) and ?token=&type=
  (PKCE); redirect to the public site host before verifyOtp so the session
  cookie lands on the right domain.

Audit deliverables:
- .nirvana/outputs/disclosure-bureau/.../systems-atelier/: 5 docs (code
  analysis, tech debt, discovery brief, system arch, 5 ADRs) authored by
  sa-principal that produced this roadmap. Kept in-tree for traceability.
2026-05-18 03:52:59 -03:00
..
coolify baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00
disclosure-stack ship: synthesize 158 entities, AG-UI artifacts, chat persistence, auth flow 2026-05-18 03:52:59 -03:00
embed-service baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00
supabase baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00
DEPLOY-CHECKLIST.md baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00
README.md baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00
RETRIEVAL.md baseline: Disclosure Bureau pipeline + Next.js UI + Supabase stack 2026-05-17 22:44:36 -03:00

Infrastructure — Disclosure Bureau

Self-hosted stack on a single VPS (16 GB / 4 CPU / 200 GB NVMe) managed via Coolify.

                   Internet (443/80)
                          │
                ┌─────────▼─────────┐
                │  Caddy (Coolify)  │ ← auto-TLS Let's Encrypt
                └────┬──────────────┘
                     │
       ┌─────────────┼──────────────────────┬──────────────────┐
       ▼             ▼                      ▼                  ▼
  ┌─────────┐   ┌──────────┐         ┌──────────┐       ┌──────────┐
  │ Next.js │   │ Supabase │         │ Supabase │       │  shared  │
  │   web   │   │ disclosure│        │ project-B │       │ services │
  │ :3000   │   │ stack    │         │  stack    │       │ Meili··· │
  └─────────┘   │  ┌─────┐ │         │  ┌─────┐ │       │ Imgproxy │
                │  │PG/GT│ │         │  │PG/GT│ │       │ Dragonfly│
                │  └─────┘ │         │  └─────┘ │       └──────────┘
                └──────────┘         └──────────┘
                disclosure.top       projeto-b.com

Components

Layer Service Notes
Orchestration Coolify v4 Self-hosted PaaS — manages all containers, TLS, backups
Database + Auth + Storage Supabase self-hosted (one per project) Each project gets own Postgres + GoTrue + Storage
Frontend Next.js 15 (this repo's /web) Deployed via Coolify Git integration
Search Meilisearch (shared) Full-text search across pages + entities
Cache + Queue Dragonfly (shared) Redis-compatible, multi-threaded
Images Imgproxy (shared) On-the-fly resize / WebP conversion
Backups restic + Backblaze B2 Nightly Postgres + Storage dumps

Quick path

  1. coolify/INSTALL.md — install Coolify on the fresh VPS (~10 min)
  2. coolify/SUPABASE.md — create the disclosure Supabase project (~5 min)
  3. Run supabase/migrations/0001_chat_schema.sql via Supabase Studio SQL editor
  4. coolify/NEXTJS.md — deploy the /web app pointing at the Supabase URL
  5. coolify/SHARED.md — bring up Meilisearch, Dragonfly, Imgproxy

Adding more projects later

For each new project, repeat step 2 (new Supabase project in Coolify UI) and step 4 (new Next.js app). They get their own subdomain, own auth, own data. Total isolation.

Local development

For dev on macOS/Linux without the VPS, see ../web/README.md — uses the Supabase CLI to spin up a local stack on localhost:54321.