Skip to content

Latest commit

 

History

History
292 lines (222 loc) · 12.7 KB

File metadata and controls

292 lines (222 loc) · 12.7 KB

Dataprint — Application Architecture

Architecture diagram: docs/architecture-diagram.png


What Dataprint Is

Dataprint is a multi-tenant SaaS platform for firms that pursue public sector contracts. This includes — but is not limited to — government contracting, education, municipal services, transportation, and other public-sector verticals. The platform is currently focused on firms operating in Texas, with plans for broader expansion.

It centralises the full pursuit lifecycle — from opportunity discovery through proposal development to export — within a single workspace. Each firm (organization) gets a fully isolated environment. Teams collaborate on bids, use AI to analyze RFQs/RFPs, and produce compliant proposal documents.


High-Level Architecture

┌─────────────────────────────────────────────────────────────────┐
│  FRONTEND (Next.js 16 / Vercel)                                 │
│  Dashboard  │  Pursuit Workspace  │  Admin / Settings           │
└────────────────────────┬────────────────────────────────────────┘
                         │ API Routes (Next.js Route Handlers)
┌────────────────────────▼────────────────────────────────────────┐
│  BACKEND SERVICES                                               │
│  Clerk Auth  │  Supabase (DB + RLS)  │  RFQ Analyzer (AI)      │
│  Export Engine (Word/PDF/InDesign)                              │
└────────────────────────┬────────────────────────────────────────┘
                         │
┌────────────────────────▼────────────────────────────────────────┐
│  EXTERNAL INTEGRATIONS                                          │
│  MS Graph API (SharePoint + Teams)  │  Claude API              │
│  Adobe InDesign  │  Public Procurement Sites                    │
└─────────────────────────────────────────────────────────────────┘

Frontend — Pages & Layout

The frontend is a Next.js 16 App Router application deployed on Vercel. All authenticated pages live under the /(dashboard) route group and are wrapped in a sidebar layout.

Route Map

Route Page Status
/ Main dashboard — KPI cards, pursuit trend chart, pursuit table Live
/dashboard Secondary dashboard view (static demo data) Live
/pursuits Pursuit list & management Empty state (in progress)
/opportunities Opportunity discovery from public procurement sites Empty state
/assets Digital assets (logos, boilerplate, past performance) Empty state
/database Org reference data (personnel, projects, clients) Empty state
/inbox Teams Chat integration / messaging Empty state
/templates Proposal section templates Empty state
/connections Partner firm connections Empty state
/settings Org admin settings (admin-only) In progress

Layout Structure

RootLayout (app/layout.tsx)
└── ClerkProvider (auth context + shadcn theme)
    └── ThemeProvider (light/dark mode)
        └── TooltipProvider
            ├── DashboardLayout (app/(dashboard)/layout.tsx)
            │   ├── AppSidebar (left navigation)
            │   ├── SiteHeader (top bar)
            │   └── ScrollArea (page body — only this section scrolls)
            └── Toaster (global toast notifications)

Sidebar Navigation

  • Inbox — pinned at top with primary action styling
  • Workspace section: Dashboard, Pursuits, Opportunities, Assets, Database, Templates, Connections
  • Settings — admin-only, conditionally rendered via membership?.role === "org:admin"
  • NavUser — bottom user menu (profile, logout via Clerk openUserProfile() / signOut())

Key Frontend Dependencies

Package Purpose
next v16 Framework + App Router + Turbopack
@clerk/nextjs Authentication UI + session management
@tanstack/react-table Sortable/filterable data tables
recharts Pursuit trend charts
@dnd-kit/* Drag-and-drop (pursuit sections, kanban)
@xyflow/react Node/graph visualization
motion UI animations
sonner Toast notifications
tailwindcss v4 Utility-first styling
shadcn / radix-ui Accessible component primitives
@vercel/analytics Usage analytics

Backend Services

1. Authentication — Clerk

Clerk handles all identity: sign-in, sign-up, SSO, and multi-org membership.

  • Provider: ClerkProvider in root layout wraps the entire app
  • Appearance: shadcn theme from @clerk/themes applied for visual consistency
  • Auth pattern: Every protected API route calls auth() from @clerk/nextjs/server to get userId and orgId
  • Org roles: org:admin vs org:member — admins see Settings, control org configuration
  • Webhook sync: All Clerk user/org events (created, updated, deleted) are synced to Supabase via /api/webhooks/clerk — see Data Layer section
User signs in via Clerk
  → Clerk issues session JWT
  → orgId + userId available in all server components / API routes
  → Supabase queries filtered by organization_id

2. Database — Supabase

Supabase is the primary data store. All data is namespaced by organization_id for multi-tenant isolation.

Key Tables:

Table Contents
organizations Firm-level records synced from Clerk
users Member records synced from Clerk, linked to orgs
pursuits Active bid/proposal records
projects Past performance project records
personnel Staff records (bios, certs, roles)
assets Digital assets (images, files, logos)

Client Types:

  • lib/supabase/client.ts — Browser-safe client using anon key + RLS
  • lib/supabase/admin.ts — Server-only service role client (bypasses RLS, for trusted API routes)
  • lib/supabase/clerk-client.ts — Supabase client initialized with Clerk JWT for RLS-aware server requests

3. RFQ/RFP Analyzer — AI

The RFQ Analyzer reads uploaded solicitation documents and extracts structured data to pre-fill pursuit records and suggest relevant personnel, projects, and proposal sections.

  • Model: Claude (via @ai-sdk/anthropic + Vercel AI SDK)
  • API Route: /api/chat — streaming edge function
  • Runtime: Edge (low-latency streaming responses)
  • Features:
    • Streams responses in real-time to the frontend
    • System prompt context injection
    • Attachment/document support
    • Reasoning/chain-of-thought display in the chat UI
User uploads RFQ/RFP document
  → /api/chat receives document + prompt
  → Anthropic Claude analyzes content
  → Streams structured analysis back to UI
  → Suggestions populate pursuit workspace fields

4. Export Engine (planned — highest complexity)

The Export Engine converts a completed pursuit workspace into formatted proposal documents.

Target output formats:

  • Word (.docx) — standard proposal format
  • PDF — for final submission
  • InDesign (.indd) — for print-ready designed proposals via Adobe InDesign integration

Complexity factors:

  • Must maintain proposal section order, formatting, and compliance structure
  • InDesign export requires server-side scripting or Adobe APIs
  • Multi-section document assembly from disparate data sources (sections, personnel, projects, assets)
  • Page layout, headers/footers, table of contents generation

Pursuit Workspace

The Pursuit Workspace is the core product feature — a dedicated per-pursuit environment where proposal teams collaboratively build out a bid response. It is a child route of /pursuits/[id]/.

Workspace Modules

Module Function
RFQ/RFP Analysis Upload solicitation, AI extracts requirements, sets up workspace
Proposal Sections Section-by-section proposal writing with AI write-up suggestions
Personnel Assign team members; AI suggests best-fit staff from org database
Projects Attach relevant past performance; AI suggests matches from project database
Documents Store and manage supporting files for the pursuit
Export Generate final proposal in Word, PDF, or InDesign format

Data Flow in the Workspace

RFQ/RFP uploaded
  → Claude analyzes → extracts requirements, NAICS, due date, scope
  → Pursuit record pre-populated in Supabase
  → AI suggests: Personnel (from personnel table)
               + Projects (from projects table)
               + Section structure (from templates)
  → Team fills/refines each section
  → Export Engine compiles into final document

Data Layer — Multi-Tenant Isolation

Data security is enforced at two levels:

Row-Level Security (RLS) — Supabase

All tables have RLS policies that restrict reads/writes to rows where organization_id matches the authenticated user's org. No org can ever see another org's data — enforced at the database level.

Application-Level Filtering

All API routes additionally filter by organization_id derived from Clerk's orgId. This is a defense-in-depth measure on top of RLS.

Clerk ↔ Supabase Sync

/api/webhooks/clerk keeps Supabase in sync with Clerk as the source of truth for identity:

Clerk event fires (user.created / org.created / etc.)
  → Webhook validated via Svix signature
  → Supabase upsert to organizations / users tables
  → org metadata, member roles, avatars all synced

External Integrations

Microsoft Graph API

  • SharePoint Sync — sync assets and documents to/from SharePoint document libraries
  • Teams Chat — the Inbox surface; send/receive messages, @mention pursuit collaborators

Claude API (Anthropic)

  • Powers the AI Assistant chat interface
  • Powers the RFQ/RFP Analyzer
  • Accessed via Vercel AI SDK (@ai-sdk/anthropic) for streaming support
  • API key configured via ANTHROPIC_API_KEY env variable

Adobe InDesign

  • Target export format for print-ready designed proposals
  • Integration path: InDesign Server API or scripted file generation (.indd / IDML)
  • Highest complexity integration — requires layout engine and style mapping

Public Procurement Sites

  • Sources for opportunity discovery (SAM.gov, USASpending, state portals)
  • Data flows into the Opportunities page
  • Likely via scraping or official APIs (SAM.gov API)

API Routes Reference

Route Method Auth Purpose
/api/chat POST Clerk Streaming AI chat (Claude)
/api/pursuits GET Clerk + Org Fetch org's pursuit records
/api/projects GET Clerk + Org Fetch org's project records
/api/personnel GET Clerk + Org Fetch org's personnel records
/api/webhooks/clerk POST Svix sig Sync Clerk events to Supabase

Environment Variables

Variable Purpose
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY Clerk frontend key
CLERK_SECRET_KEY Clerk backend key
CLERK_WEBHOOK_SECRET Svix webhook signature validation
NEXT_PUBLIC_SUPABASE_URL Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase browser client key
SUPABASE_SERVICE_ROLE_KEY Supabase admin key (server only)
ANTHROPIC_API_KEY Claude AI API key
AZURE_CLIENT_ID / AZURE_TENANT_ID Microsoft Graph OAuth

Feature Build Priority

Based on the architecture, the logical build order is:

  1. Pursuits list page — real data from Supabase, create/edit pursuit records
  2. Pursuit Workspace — individual pursuit route with the module workflow
  3. Personnel & Projects database — org reference data management
  4. RFQ/RFP Analyzer — Claude integration within pursuit workspace
  5. Opportunities — procurement site data ingestion
  6. Assets — file/asset management with Supabase Storage
  7. Teams Chat / Inbox — MS Graph integration
  8. SharePoint Sync — MS Graph document sync
  9. Export Engine — Word/PDF first, InDesign last (highest complexity)

Last updated: 2026-02-25