diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..e6a1228e --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,132 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What Is Pronghorn + +Pronghorn is an AI-powered software development platform (MIT license, Government of Alberta). It transforms unstructured requirements into production-ready code with traceability. Live at https://pronghorn.red. + +## Development Commands + +```bash +npm install # Install dependencies +npm run dev # Start Vite dev server on port 8080 +npm run build # Production build +npm run build:dev # Development build +npm run lint # ESLint +npm run preview # Preview production build +``` + +No `.env` file is needed for the frontend — Supabase config is embedded in `src/integrations/supabase/client.ts`. + +Edge functions are Deno TypeScript in `supabase/functions/` and deploy automatically on push. They require Supabase secrets (GEMINI_API_KEY, ANTHROPIC_API_KEY, GROK_API_KEY, GITHUB_PAT, RENDER_API_KEY, RESEND_API_KEY). + +## Architecture Overview + +**Frontend-only React SPA** backed by Supabase (PostgreSQL + Edge Functions + Realtime + Storage). + +### Provider Hierarchy (src/main.tsx) + +``` +ThemeProvider → QueryClientProvider → AuthProvider → AdminProvider → BrowserRouter → App +``` + +### Key Architectural Patterns + +1. **Token-Based RBAC**: All data access goes through `SECURITY DEFINER` RPC functions (e.g., `get_canvas_nodes_with_token`) that validate access via `authorize_project_access(p_project_id, p_token)`. Never query tables directly — always use `*_with_token` RPCs. + +2. **Share Token Flow**: Tokens appear in URL as `/project/:projectId/:page/t/:token`, get cached in memory + sessionStorage (`src/lib/tokenCache.ts`), then masked to `/t/masked` for security. The `useShareToken` hook (`src/hooks/useShareToken.ts`) manages this lifecycle and calls `set_share_token` RPC to configure the Postgres session. + +3. **Realtime Subscriptions**: Two-layer model: + - `postgres_changes`: RLS-protected database events (secure, filtered server-side) + - `broadcast`: Public refresh signals with empty payloads (data still requires valid token via RPC) + - Pattern: `useRef` for channel storage, cleanup on unmount. See `src/hooks/useRealtimeCanvas.ts` as reference. + +4. **Lazy Loading**: Heavy pages (Canvas, Build, Repository, etc.) use `React.lazy()` with `Suspense` + `PageLoader`. Lightweight pages (Landing, Auth, Terms) are eagerly loaded. + +5. **Agent Configuration as JSON**: All AI agent behaviors are defined in `public/data/*.json` files — not hardcoded. Key files: + - `agents.json` — 13 specification agents + - `buildAgents.json` — 10 canvas design agents + - `auditAgentInstructions.json` — audit orchestrator spec + - `codingAgentInstructions.json` — coding agent tools & patterns + - `presentAgentInstructions.json` — presentation blackboard spec + - `connectionLogic.json` — canvas edge validation rules + - `presentationLayouts.json` — 15 slide layouts + themes + +6. **Edge Function Pattern**: All edge functions follow the same structure — CORS headers, parse JSON body with `projectId` + `shareToken`, create Supabase client with auth header, validate access via `authorize_project_access` RPC, then perform operation. Streaming functions use SSE. + +### Role Hierarchy + +`owner` > `editor` > `viewer`. Owners can manage tokens and delete projects. Editors can create/update. Viewers are read-only. Role checked via `require_role(p_project_id, p_token, p_min_role)` in RPC functions. + +### Admin Roles + +Separate from project roles: `superadmin` > `admin` > `user`. Stored in `user_roles` table, exposed via `AdminContext`. + +## Tech Stack + +- **React 18** + TypeScript 5.8 + Vite 5.4 (SWC) +- **Tailwind CSS 3.4** + shadcn/ui (Radix primitives) — use `cn()` from `src/lib/utils.ts` +- **React Router DOM 6** — routes in `src/App.tsx` +- **TanStack React Query 5** — server state caching +- **React Flow 11** — interactive canvas diagrams +- **Monaco Editor** — code/SQL editing +- **Supabase JS v2** — client singleton at `src/integrations/supabase/client.ts` +- **LLM Providers**: Google Gemini, Anthropic Claude, xAI Grok + +## Project Structure + +``` +src/ + components/ # React components organized by feature domain + ui/ # shadcn/ui base components (do not edit manually — use shadcn CLI) + canvas/ # React Flow canvas editor + build/ # Coding agent interface + deploy/ # Database & deployment management + present/ # AI presentation generator + audit/ # Multi-agent audit system + collaboration/# Collaborative document editing + buildbook/ # Build Book management + gallery/ # Project gallery + artifacts/ # File/document management + repository/ # File tree, code editor, Git integration + requirements/ # Requirement tree management + specifications/# Spec generation + standards/ # Standards library UI + dashboard/ # Project cards & creation + layout/ # Navigation, sidebar, header + project/ # Project settings, token management + contexts/ # AuthContext (auth state), AdminContext (admin roles) + hooks/ # Custom hooks — realtime subscriptions, token management, data fetching + pages/ # Route pages (project/ subdirectory for project-scoped pages) + integrations/ # Supabase client & auto-generated types + lib/ # Utilities (tokenCache, connectionLogic, sqlParser, etc.) + styles/ # Global CSS + +supabase/ + functions/ # ~58 Deno edge functions + config.toml # Supabase project config (verify_jwt settings) + +public/data/ # JSON configuration files for AI agents and UI behavior +``` + +## Conventions + +- Path alias: `@/*` maps to `./src/*` +- TypeScript strict mode is OFF (`noImplicitAny: false`, `strictNullChecks: false`) +- ESLint: `@typescript-eslint/no-unused-vars` is disabled +- All edge functions set `verify_jwt = false` in `supabase/config.toml` (access validated via RPC instead) +- Dark mode: class-based (`tailwind.config.ts`) +- Colors use HSL CSS variables (e.g., `hsl(var(--primary))`) +- Vite splits vendor chunks: react, monaco, pdf, reactflow, charts, office, radix +- PWA support via `vite-plugin-pwa` with workbox caching strategies + +## URL Routing Pattern + +``` +/project/:projectId/:page # Authenticated users +/project/:projectId/:page/t/:token # Token-based shared access +/viewer/:artifactId # Public artifact viewer (no auth) +``` + +All project routes are duplicated for both patterns in `src/App.tsx`. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..7deaee29 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,22 @@ +# Pronghorn Documentation + +## Table of Contents + +| Document | Description | +|----------|-------------| +| [Architecture](./architecture.md) | System architecture, provider hierarchy, data flow, state management, security overview | +| [Authentication](./authentication.md) | Auth methods, token-based RBAC, role hierarchy, authorization functions, token caching | +| [AI Agents](./ai-agents.md) | Multi-agent systems, orchestration patterns, LLM providers, agent configuration files | +| [Edge Functions](./edge-functions.md) | All ~58 Deno edge functions, common patterns, streaming (SSE), secrets reference | +| [Realtime](./realtime.md) | WebSocket subscriptions, two-layer security model, hook pattern, available hooks | +| [Components](./components.md) | Component organization by feature domain, key components per domain, shared patterns | +| [Hooks](./hooks.md) | All custom hooks — token management, realtime, data fetching, state management | +| [Database Schema](./database-schema.md) | Key tables, access patterns, RPC conventions, authorization functions, custom types | +| [Development Guide](./development-guide.md) | Setup, scripts, configuration, working with Supabase/Realtime/Canvas, utility libraries | + +## Quick Links + +- **Live Application**: https://pronghorn.red +- **Repository**: https://github.com/pronghorn-red/pronghorn +- **CLAUDE.md** (Claude Code guidance): [../CLAUDE.md](../CLAUDE.md) +- **README.md** (Project README): [../README.md](../README.md) diff --git a/docs/ai-agents.md b/docs/ai-agents.md new file mode 100644 index 00000000..7ef821cc --- /dev/null +++ b/docs/ai-agents.md @@ -0,0 +1,160 @@ +# AI Agents & Orchestration + +Pronghorn uses multi-agent AI systems across several features. Agent behaviors are defined in JSON configuration files (`public/data/*.json`) rather than being hardcoded. + +## Agent Types + +### 1. Canvas Design Agents (Multi-Agent Orchestration) + +**Config**: `public/data/buildAgents.json` +**Edge Function**: `orchestrate-agents` + +10 specialized agents collaborate on canvas architecture design using a blackboard pattern: + +| Agent | Focus | +|-------|-------| +| Architect | System structure and component hierarchy | +| Developer | Implementation details and code patterns | +| DBA | Database schemas and data modeling | +| Security | Vulnerability assessment and secure patterns | +| QA | Test coverage and validation strategies | +| DevOps | Deployment and infrastructure | +| UX | User experience and interface design | +| API | API design and integration patterns | +| Performance | Optimization and scalability | +| Documentation | Technical documentation | + +**How it works**: +1. User configures which agents to include and how many iterations (epochs) +2. Each epoch, agents take turns reading the current canvas state and proposing changes +3. A critic agent reviews proposed changes after each epoch +4. Canvas nodes and edges are created/modified via the canvas RPC functions +5. Results are streamed back via SSE + +### 2. Specification Agents + +**Config**: `public/data/agents.json` +**Edge Function**: `generate-specification` + +13 agents generate comprehensive project documents: + +| Agent | Output | +|-------|--------| +| Overview | Executive summary and project scope | +| Technical Specification | Detailed technical documentation | +| Cloud Architecture | AWS/Azure/GCP infrastructure design | +| API Specification | OpenAPI/REST endpoint documentation | +| Security Analysis | Threat modeling and security controls | +| Data Requirements | Data models and storage requirements | +| Accessibility | WCAG compliance and accessibility audit | +| Internationalization | i18n/l10n requirements | +| DevOps | CI/CD and deployment strategies | +| Testing | Test strategy and coverage plans | +| Standards Compliance | Regulatory compliance mapping | +| Executive Summary | Business-focused project overview | +| Project Charter | Governance and stakeholder documentation | + +### 3. Audit Agents (Multi-Perspective Analysis) + +**Config**: `public/data/auditAgentInstructions.json` +**Edge Functions**: `audit-orchestrator`, `audit-extract-concepts`, `audit-merge-concepts`, `audit-merge-concepts-v2`, `audit-generate-venn`, `audit-build-tesseract`, `audit-enhanced-sort` + +5 agents provide multi-perspective cross-comparison: + +| Agent | Perspective | +|-------|-------------| +| Security Analyst | Vulnerability and risk assessment | +| Business Analyst | Business value and ROI analysis | +| Developer | Implementation feasibility | +| End User | Usability and user experience | +| Architect | System design and patterns | + +**Audit Pipeline** (runs locally until explicit save): + +``` +1. Extract Concepts (D1) → Extract concepts from dataset 1 elements +2. Extract Concepts (D2) → Extract concepts from dataset 2 elements +3. Merge Concepts → Find alignments between D1 and D2 concepts +4. Enhanced Sort → Smart sorting of merged results +5. Build Tesseract → Construct 3D evidence grid +6. Generate Venn → Synthesize Venn diagram (Unique to D1 | Aligned | Unique to D2) +``` + +**Key**: All audit processing runs locally in the browser (`useAuditPipeline` hook, `src/hooks/useAuditPipeline.ts`). No database writes occur until the user explicitly saves results. + +### 4. Coding Agent + +**Config**: `public/data/codingAgentInstructions.json`, `public/data/codingAgentToolsManifest.json`, `public/data/codingAgentPromptTemplate.json` +**Edge Function**: `coding-agent-orchestrator` + +Autonomous file operations with full Git workflow: +- Read, edit, create, delete, rename files +- Stage → Commit → Push workflow +- Real-time progress monitoring via SSE +- Pause/resume and abort operations +- Raw LLM logs viewer for debugging + +**Components**: `src/components/build/` (UnifiedAgentInterface, AgentProgressMonitor, StagingPanel, RawLLMLogsViewer) + +### 5. Presentation Agent + +**Config**: `public/data/presentAgentInstructions.json`, `public/data/presentationLayouts.json` +**Edge Function**: `presentation-agent` + +Uses the **Blackboard Memory Pattern**: +1. Agent reads project data sequentially (requirements, canvas, standards, etc.) +2. Accumulates insights on an append-only blackboard +3. Generates slides based on accumulated context +4. Supports 15+ slide layouts and multiple themes + +### 6. Collaboration Agent + +**Config**: `public/data/collaborationAgentInstructions.json` +**Edge Function**: `collaboration-agent-orchestrator` + +AI partner for document editing: +- Line-level `edit_lines` operations for surgical changes +- Respects human edits (never replaces entire documents) +- Change tracking with diff visualization +- Project context attachment (requirements, canvas, artifacts) + +### 7. Database Agent + +**Config**: `public/data/databaseAgentPromptTemplate.json`, `public/data/databaseAgentToolsManifest.json` +**Edge Function**: `database-agent-orchestrator` + +AI-powered database operations: +- Schema inference from imported data +- SQL generation and execution +- Data import wizard with type detection + +## LLM Providers + +| Provider | Models | Used For | +|----------|--------|----------| +| Google Gemini | gemini-2.5-flash, gemini-2.5-pro | Primary: chat, agents, image generation | +| Anthropic Claude | claude-opus-4-5 | Alternative chat provider | +| xAI Grok | grok-4-1-fast-reasoning, grok-4-1-fast-non-reasoning | Alternative chat provider | + +Image generation uses Gemini models: `gemini-2.5-flash-image`, `gemini-3-pro-image-preview`. + +## Agent Configuration Files + +All agent behaviors are defined in `public/data/`: + +| File | Purpose | +|------|---------| +| `agents.json` | 13 specification agent definitions (name, prompt, capabilities) | +| `buildAgents.json` | 10 canvas design agent definitions | +| `auditAgentInstructions.json` | Audit orchestrator and agent specifications | +| `codingAgentInstructions.json` | Coding agent system prompt and tool definitions | +| `codingAgentToolsManifest.json` | Available tools for the coding agent | +| `codingAgentPromptTemplate.json` | Prompt template for coding agent | +| `presentAgentInstructions.json` | Presentation agent blackboard specification | +| `presentationLayouts.json` | 15+ slide layout definitions with themes | +| `collaborationAgentInstructions.json` | Collaboration agent behavior specification | +| `databaseAgentPromptTemplate.json` | Database agent prompt template | +| `databaseAgentToolsManifest.json` | Database agent tool definitions | +| `graphicStyles.json` | 6 image generation style categories | +| `connectionLogic.json` | Canvas edge validation rules and flow hierarchy | +| `deploymentSettings.json` | Multi-runtime deployment configurations | diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 00000000..f80838e4 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,119 @@ +# Architecture Overview + +Pronghorn is a **frontend-only React SPA** backed entirely by **Supabase** (PostgreSQL, Edge Functions, Realtime WebSockets, and Storage). There is no custom backend server. + +## System Architecture + +``` +┌──────────────────────────────────────────────────────┐ +│ Browser (SPA) │ +│ React 18 + TypeScript + Vite + Tailwind + shadcn/ui │ +├──────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌────────────┐ ┌───────────────┐ │ +│ │ React Query │ │ Realtime │ │ Edge Func │ │ +│ │ (cache) │ │ WebSocket │ │ Invocations │ │ +│ └──────┬──────┘ └─────┬──────┘ └───────┬───────┘ │ +│ │ │ │ │ +└─────────┼───────────────┼──────────────────┼──────────┘ + │ │ │ + ▼ ▼ ▼ +┌──────────────────────────────────────────────────────┐ +│ Supabase │ +│ │ +│ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │ +│ │ PostgreSQL │ │ Realtime │ │ Edge Functions │ │ +│ │ + RLS │ │ (WS) │ │ (Deno) │ │ +│ │ + RPCs │ │ │ │ ~58 funcs │ │ +│ └────────────┘ └────────────┘ └───────┬────────┘ │ +│ │ │ +│ ┌────────────┐ ┌────────┴───────┐ │ +│ │ Storage │ │ External APIs │ │ +│ │ (files) │ │ Gemini/Claude/ │ │ +│ └────────────┘ │ Grok/GitHub/ │ │ +│ │ Render/Resend │ │ +│ └────────────────┘ │ +└──────────────────────────────────────────────────────┘ +``` + +## Provider Hierarchy + +The app wraps the component tree with providers in this exact order (see `src/main.tsx`): + +``` +StrictMode + └─ ThemeProvider (dark/light mode via next-themes) + └─ QueryClientProvider (TanStack React Query) + └─ AuthProvider (Supabase auth state) + └─ AdminProvider (admin role checking) + └─ BrowserRouter + └─ App (routes + Suspense) +``` + +## Data Flow + +All data flows through three channels: + +### 1. RPC Functions (Primary Data Access) +Client calls Supabase RPC functions (e.g., `get_canvas_nodes_with_token`) which are `SECURITY DEFINER` PostgreSQL functions. These validate the share token, check role permissions, and return data. The client **never queries tables directly**. + +### 2. Edge Functions (AI & External Services) +For operations that need external API calls (LLM providers, GitHub, Render.com), the client invokes Deno edge functions via `supabase.functions.invoke()`. These functions validate access using the same `authorize_project_access` RPC, then call external APIs. + +### 3. Realtime Subscriptions (Live Updates) +Supabase Realtime channels push database changes to connected clients via WebSockets. Two mechanisms: +- `postgres_changes` — RLS-protected, server-filtered events +- `broadcast` — lightweight refresh signals (empty payloads) + +## State Management + +| Layer | Technology | Purpose | +|-------|-----------|---------| +| Server State | TanStack React Query | Caching, deduplication, background refresh | +| Auth State | AuthContext | User session, sign-in/sign-out methods | +| Admin State | AdminContext | Admin role (superadmin/admin/user) | +| Token State | tokenCache.ts + useShareToken | In-memory + sessionStorage token caching | +| Realtime State | Custom useRealtime* hooks | Live collaboration via Supabase channels | +| UI State | Local component state | Form inputs, toggles, selections | + +## Routing Architecture + +Routes are defined in `src/App.tsx`. Every project page exists in two forms: + +``` +/project/:projectId/:page # Authenticated users +/project/:projectId/:page/t/:token # Token-based shared access +``` + +Pages are split into: +- **Eagerly loaded**: Landing, Auth, Terms, Privacy, License, NotFound +- **Lazy loaded**: All Dashboard/Gallery/Standards/BuildBooks/Settings and all project pages + +All protected routes are wrapped with `RequireSignupValidation`. + +## Code Splitting Strategy + +Vite produces manually-split vendor chunks to optimize loading: + +| Chunk | Contents | +|-------|----------| +| vendor-react | react, react-dom, react-router-dom, @tanstack/react-query | +| vendor-monaco | @monaco-editor/react | +| vendor-pdf | pdfjs-dist | +| vendor-reactflow | reactflow | +| vendor-charts | recharts | +| vendor-office | exceljs, mammoth, docx, jszip | +| vendor-radix | All @radix-ui/* components | + +PWA service worker uses `CacheFirst` for vendor chunks (30-day TTL) and `StaleWhileRevalidate` for page chunks (7-day TTL). + +## Security Architecture + +See [authentication.md](./authentication.md) for the full auth and RBAC system. + +Key security principles: +1. **No direct table access** — all data goes through `SECURITY DEFINER` RPCs +2. **Token validation at every layer** — RPCs, edge functions, and realtime all validate tokens +3. **URL masking** — share tokens are replaced with "masked" in the URL after caching +4. **Defense in depth** — broadcast channels carry no data; actual data requires RPC with valid token +5. **Edge function secrets** — API keys stored as Supabase secrets, never in client code diff --git a/docs/authentication.md b/docs/authentication.md new file mode 100644 index 00000000..f0204613 --- /dev/null +++ b/docs/authentication.md @@ -0,0 +1,131 @@ +# Authentication & Authorization + +## Authentication Methods + +| Method | Description | +|--------|-------------| +| Email/Password | Traditional signup via `send-auth-email` edge function | +| Google SSO | OAuth 2.0 redirect to Google, then back to `/dashboard` | +| Microsoft Azure SSO | OAuth 2.0 with Azure AD, scopes: `openid profile email` | +| Anonymous (Token) | No login — access via share token in URL | + +### Auth Flow + +1. `AuthProvider` (`src/contexts/AuthContext.tsx`) wraps the entire app +2. On mount, it subscribes to `supabase.auth.onAuthStateChange` and checks `getSession()` +3. Auth state (`user`, `session`, `loading`) is available via `useAuth()` hook +4. Signup goes through the `send-auth-email` edge function (not direct Supabase signup) for branded emails +5. Sign-out includes fallback to `scope: 'local'` if server signout fails + +### Signup Validation + +After signup, users may need to validate a signup code. The `RequireSignupValidation` component checks `user.user_metadata.signup_validated` and blocks access until validated via `validate-signup-code` edge function. + +## Multi-Token RBAC System + +### Role Hierarchy + +``` +owner (level 3) > editor (level 2) > viewer (level 1) +``` + +| Role | Permissions | +|------|-------------| +| **owner** | Full access: manage tokens, delete project, all CRUD | +| **editor** | Create, read, update (no token management or deletion) | +| **viewer** | Read-only access | + +### Token Storage + +```sql +project_tokens ( + id UUID PRIMARY KEY, + project_id UUID REFERENCES projects(id) ON DELETE CASCADE, + token UUID NOT NULL UNIQUE, + role project_token_role NOT NULL DEFAULT 'viewer', + label TEXT, + created_at TIMESTAMPTZ, + created_by UUID REFERENCES auth.users(id), + expires_at TIMESTAMPTZ, + last_used_at TIMESTAMPTZ +) +``` + +### URL Pattern + +``` +/project/{projectId}/{page}/t/{token} +``` + +When a user visits a URL with a token: +1. `useShareToken` hook extracts the token from URL params +2. Token is cached in memory (`Map`) and sessionStorage +3. `set_share_token` RPC is called to set the token in the Postgres session context +4. URL is rewritten to `/t/masked` to hide the real token +5. Subsequent navigations retrieve the token from cache + +### Authorization Functions (PostgreSQL) + +**`authorize_project_access(p_project_id, p_token)`** +- First checks if the authenticated user owns the project → returns `'owner'` +- Then checks if the token exists in `project_tokens`, is not expired → returns the token's role +- Otherwise raises "Access denied" + +**`require_role(p_project_id, p_token, p_min_role)`** +- Calls `authorize_project_access` to get the current role +- Compares `role_to_level(current)` against `role_to_level(min_required)` +- Raises "Insufficient permissions" if below threshold + +### RPC Function Pattern + +Every data operation uses this pattern: + +```typescript +// Client side +const { data, error } = await supabase.rpc('get_requirements_with_token', { + p_project_id: projectId, + p_token: shareToken || null // null for authenticated owners +}); +``` + +```sql +-- Server side +CREATE FUNCTION get_requirements_with_token( + p_project_id UUID, + p_token UUID DEFAULT NULL +) RETURNS SETOF requirements +LANGUAGE plpgsql SECURITY DEFINER +SET search_path TO 'public' +AS $$ +BEGIN + PERFORM require_role(p_project_id, p_token, 'viewer'); + RETURN QUERY SELECT * FROM requirements WHERE project_id = p_project_id; +END; +$$; +``` + +### Token Caching (src/lib/tokenCache.ts) + +Two-layer cache for synchronous access: +1. **Memory** (`Map`) — fastest, lost on page reload +2. **sessionStorage** — survives refresh within same tab, keyed as `pronghorn_token_{projectId}` + +```typescript +import { getProjectToken, setProjectToken, clearProjectToken } from "@/lib/tokenCache"; +``` + +## Admin Roles + +Separate from project token roles. Stored in `user_roles` table: + +| Role | Access | +|------|--------| +| superadmin | Full platform management (GitHub org, Render org) | +| admin | Build Book publishing, standards management | +| user | Default role | + +Exposed via `AdminContext` (`src/contexts/AdminContext.tsx`) and `useAdmin()` hook: + +```typescript +const { isAdmin, isSuperAdmin, role, loading } = useAdmin(); +``` diff --git a/docs/components.md b/docs/components.md new file mode 100644 index 00000000..83f25c09 --- /dev/null +++ b/docs/components.md @@ -0,0 +1,192 @@ +# Component Architecture + +## Organization + +Components are organized by **feature domain** under `src/components/`. Each subdirectory corresponds to a major feature area of the application. + +## Feature Domains + +### `ui/` — Base UI Components (shadcn/ui) + +Radix-based accessible primitives generated by the shadcn CLI. These should not be edited manually — use `npx shadcn@latest add ` to add new ones. + +Includes: Accordion, AlertDialog, Avatar, Button, Card, Checkbox, Command, Dialog, DropdownMenu, Form, Input, Label, Menubar, Popover, Progress, ScrollArea, Select, Separator, Sheet, Skeleton, Slider, Sonner (toast), Switch, Table, Tabs, Textarea, Toggle, Tooltip, etc. + +### `canvas/` — Visual Architecture Canvas + +Interactive React Flow-based system design editor. + +| Component | Purpose | +|-----------|---------| +| `CanvasNode.tsx` | Custom node renderer for all 24+ node types | +| `CanvasPalette.tsx` | Drag-and-drop node type selector | +| `AgentFlow.tsx` | Multi-agent orchestration UI | +| `AIArchitectDialog.tsx` | AI architect configuration dialog | +| `LayersManager.tsx` | Canvas layer management | +| `Lasso.tsx` | Freehand lasso selection tool | +| `CanvasToolbar.tsx` | Canvas action toolbar | +| `EdgeStyleSelector.tsx` | Edge styling options | +| `ConnectionLogicEnforcer.tsx` | Validates connections against rules from `connectionLogic.json` | + +### `build/` — Coding Agent Interface + +| Component | Purpose | +|-----------|---------| +| `UnifiedAgentInterface.tsx` | Main coding agent UI (chat + progress) | +| `AgentProgressMonitor.tsx` | Real-time operation progress tracking | +| `StagingPanel.tsx` | Git staging area (stage/unstage/commit) | +| `RawLLMLogsViewer.tsx` | Debug viewer for raw LLM request/response | +| `FileOperationTimeline.tsx` | Visual timeline of file operations | + +### `deploy/` — Database & Deployment + +| Component | Purpose | +|-----------|---------| +| `DatabaseExplorer.tsx` | Schema browser + SQL editor composite | +| `DatabaseImportWizard.tsx` | Multi-step data import wizard | +| `SqlQueryEditor.tsx` | Monaco-powered SQL editor | +| `ConnectDatabaseDialog.tsx` | External database connection dialog | +| `ExternalDatabaseCard.tsx` | External DB connection card | +| `import/FileUploader.tsx` | Drag-and-drop file upload | +| `import/ExcelDataGrid.tsx` | Excel/CSV data preview grid | +| `import/SchemaCreator.tsx` | AI-inferred or manual schema editor | +| `import/DatabaseErdView.tsx` | Entity-Relationship Diagram visualization | +| `import/JsonRelationshipFlow.tsx` | JSON relationship flow diagram | +| `import/SqlReviewPanel.tsx` | SQL preview before execution | + +### `present/` — AI Presentation Generator + +| Component | Purpose | +|-----------|---------| +| `SlideRenderer.tsx` | Renders individual slides | +| `SlideCanvas.tsx` | Main presentation canvas | +| `SlideThumbnails.tsx` | Slide thumbnail navigation | +| `LayoutSelector.tsx` | Choose from 15+ slide layouts | +| `FontScaleControl.tsx` | Per-slide font scaling | +| `SlideImageGenerator.tsx` | AI-generated slide images | +| `PdfExportRenderer.tsx` | High-quality PDF export | + +### `audit/` — Multi-Agent Audit System + +| Component | Purpose | +|-----------|---------| +| `AuditConfigurationDialog.tsx` | Configure audit parameters | +| `AuditBlackboard.tsx` | Shared agent reasoning board | +| `TesseractVisualizer.tsx` | 3D evidence grid visualization | +| `VennDiagramResults.tsx` | Unique D1 / Aligned / Unique D2 display | +| `KnowledgeGraph.tsx` | Force-directed concept graph | +| `KnowledgeGraphWebGL.tsx` | WebGL-accelerated knowledge graph | +| `PipelineActivityStream.tsx` | Live pipeline progress display | + +### `collaboration/` — Collaborative Document Editing + +| Component | Purpose | +|-----------|---------| +| `CollaborationEditor.tsx` | Main document editor | +| `CollaborationChat.tsx` | AI chat for document refinement | +| `CollaborationTimeline.tsx` | Change history timeline | +| `CollaborationHeatmap.tsx` | Edit activity heatmap | + +### `buildbook/` — Build Books + +| Component | Purpose | +|-----------|---------| +| `BuildBookCard.tsx` | Build Book display card | +| `BuildBookChat.tsx` | AI chat for Build Book content | +| `ApplyBuildBookDialog.tsx` | Apply standards/tech stack to project | + +### `gallery/` — Project Gallery + +| Component | Purpose | +|-----------|---------| +| `GalleryCard.tsx` | Project preview card | +| `GalleryPreviewDialog.tsx` | Detailed project preview | +| `GalleryCloneDialog.tsx` | Clone project dialog | + +### `artifacts/` — File & Document Management + +| Component | Purpose | +|-----------|---------| +| `ArtifactPdfViewer.tsx` | PDF viewer (pdfjs-dist) | +| `ArtifactDocxViewer.tsx` | DOCX viewer (mammoth) | +| `ArtifactExcelViewer.tsx` | Excel viewer (exceljs) | +| `VisualRecognitionDialog.tsx` | OCR/document text extraction | +| `EnhanceImageDialog.tsx` | AI image enhancement | + +### `repository/` — Git Integration & Code Editor + +| Component | Purpose | +|-----------|---------| +| `FileTree.tsx` | Repository file tree navigator | +| `CodeEditor.tsx` | Monaco-powered code editor | +| `IDEModal.tsx` | Full-screen IDE modal | +| `ContentSearchDialog.tsx` | Search across repository content | + +### `requirements/` — Requirement Tree Management + +Hierarchical requirement management: Epics → Features → User Stories → Acceptance Criteria. + +### `specifications/` — Specification Generation + +UI for triggering and displaying AI-generated specification documents. + +### `standards/` — Standards Library + +Global and project-level standards management with hierarchical trees. + +### `dashboard/` — Project Dashboard + +Project cards, creation dialogs, and dashboard layout. + +### `layout/` — Navigation & Layout + +Sidebar navigation, header, breadcrumbs. + +### `project/` — Project Settings + +| Component | Purpose | +|-----------|---------| +| `TokenManagement.tsx` | Token CRUD UI (create, copy, roll, revoke) | +| `AccessLevelBanner.tsx` | Shows current access level | + +## Shared Patterns + +### Lazy Loading +Heavy pages use `React.lazy()` in `src/App.tsx`: +```typescript +const Canvas = lazy(() => import("./pages/project/Canvas")); +``` +Wrapped in `}>`. + +### shadcn/ui Usage +Import from `@/components/ui/*`: +```typescript +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogHeader } from "@/components/ui/dialog"; +``` + +Use `cn()` for conditional Tailwind classes: +```typescript +import { cn } from "@/lib/utils"; +
+``` + +### React Query Integration +Components use TanStack React Query for server state: +```typescript +import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; +``` + +### Supabase Client +Single import path for the Supabase client: +```typescript +import { supabase } from "@/integrations/supabase/client"; +``` + +### Toast Notifications +Using Sonner (not shadcn toast): +```typescript +import { toast } from "sonner"; +toast.success("Saved"); +toast.error("Failed"); +``` diff --git a/docs/database-schema.md b/docs/database-schema.md new file mode 100644 index 00000000..b26525cf --- /dev/null +++ b/docs/database-schema.md @@ -0,0 +1,204 @@ +# Database Schema & Patterns + +Pronghorn uses PostgreSQL via Supabase with Row Level Security (RLS) and SECURITY DEFINER RPC functions. + +## Key Tables + +### Core Project Tables + +| Table | Purpose | +|-------|---------| +| `projects` | Root project entity (name, description, created_by, is_public, etc.) | +| `project_tokens` | Share tokens with role-based access (owner/editor/viewer) | +| `user_roles` | Platform-level admin roles (superadmin/admin/user) | + +### Requirements + +| Table | Purpose | +|-------|---------| +| `requirements` | Hierarchical requirements tree (Epic → Feature → Story → Criteria) | + +Type enum: `requirement_type` — `epic`, `feature`, `user_story`, `acceptance_criteria` + +### Canvas + +| Table | Purpose | +|-------|---------| +| `canvas_nodes` | React Flow nodes (position, data, type, canvas_id) | +| `canvas_edges` | React Flow edges (source_id, target_id, label, edge_type, style) | +| `canvas_layers` | Layer management for multi-layer canvases | +| `canvas_node_types` | Data-driven node type definitions (system_name, display_label, category, icon, color_class) | + +### Standards & Tech Stacks + +| Table | Purpose | +|-------|---------| +| `standards` | Global standards library (hierarchical) | +| `project_standards` | Standards linked to specific projects | +| `tech_stacks` | Technology stack definitions | + +### Build Books + +| Table | Purpose | +|-------|---------| +| `build_books` | Curated organizational templates | + +### Specifications + +| Table | Purpose | +|-------|---------| +| `specifications` | AI-generated specification documents | + +### Repository & Artifacts + +| Table | Purpose | +|-------|---------| +| `repositories` | GitHub repository links | +| `artifacts` | Uploaded files and documents | + +### Chat + +| Table | Purpose | +|-------|---------| +| `chat_sessions` | Chat session metadata | + +### Database Management + +| Table | Purpose | +|-------|---------| +| `project_databases` | Render.com hosted PostgreSQL instances | +| `project_database_connections` | External database connections | +| `project_database_sql` | Saved SQL queries per database | +| `project_migrations` | DDL migration history tracking | + +### Deployments + +| Table | Purpose | +|-------|---------| +| `deployments` | Render.com deployment tracking | + +### Audit + +| Table | Purpose | +|-------|---------| +| `audit_sessions` | Audit session metadata | +| `audit_knowledge_graph_nodes` | Knowledge graph concept nodes | +| `audit_knowledge_graph_edges` | Knowledge graph relationships | + +### Collaboration + +| Table | Purpose | +|-------|---------| +| `collaboration_sessions` | Document collaboration sessions | + +## Access Patterns + +### Never Query Tables Directly + +All data access goes through RPC functions: + +```typescript +// WRONG — bypasses security +const { data } = await supabase.from('requirements').select('*').eq('project_id', id); + +// CORRECT — validates token and role +const { data } = await supabase.rpc('get_requirements_with_token', { + p_project_id: id, + p_token: shareToken, +}); +``` + +### RPC Naming Convention + +| Pattern | Purpose | Min Role | +|---------|---------|----------| +| `get_*_with_token` | Read operations | viewer | +| `insert_*_with_token` | Create operations | editor | +| `update_*_with_token` | Update operations | editor | +| `upsert_*_with_token` | Create or update | editor | +| `delete_*_with_token` | Delete operations | editor/owner | + +### Authorization Functions + +```sql +-- Check access and return role +authorize_project_access(p_project_id UUID, p_token UUID) → project_token_role + +-- Enforce minimum role +require_role(p_project_id UUID, p_token UUID, p_min_role project_token_role) → project_token_role + +-- Set token in session context (for RLS) +set_share_token(token UUID) → void + +-- Convert role to numeric level +role_to_level(role project_token_role) → integer + -- owner=3, editor=2, viewer=1 +``` + +### Standard RPC Structure + +```sql +CREATE FUNCTION get_entity_with_token( + p_project_id UUID, + p_token UUID DEFAULT NULL +) RETURNS SETOF entity_table +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path TO 'public' +AS $$ +BEGIN + PERFORM require_role(p_project_id, p_token, 'viewer'); + RETURN QUERY + SELECT * FROM entity_table + WHERE project_id = p_project_id + ORDER BY created_at; +END; +$$; +``` + +### Write RPC Structure + +```sql +CREATE FUNCTION insert_entity_with_token( + p_project_id UUID, + p_token UUID, + p_title TEXT, + -- ... other fields +) RETURNS entity_table +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path TO 'public' +AS $$ +DECLARE + result entity_table; +BEGIN + PERFORM require_role(p_project_id, p_token, 'editor'); + INSERT INTO entity_table (project_id, title) + VALUES (p_project_id, p_title) + RETURNING * INTO result; + RETURN result; +END; +$$; +``` + +## Custom Types + +| Type | Values | +|------|--------| +| `project_token_role` | `owner`, `editor`, `viewer` | +| `requirement_type` | `epic`, `feature`, `user_story`, `acceptance_criteria` | + +## Node Types (Data-Driven) + +Canvas node types are stored in the `canvas_node_types` table with fields: +- `system_name` — machine identifier (e.g., `WEB_COMPONENT`, `API_ROUTER`, `DATABASE`) +- `display_label` — human-readable name +- `description` — tooltip/help text +- `category` — grouping for palette display +- `icon` — Lucide icon name +- `color_class` — Tailwind color class +- `order_score` — flow hierarchy position (100-1100, converted to levels 1-11) +- `is_active` — whether the type is available in the palette +- `is_legacy` — whether the type is deprecated + +New node types can be added via database without code changes. diff --git a/docs/development-guide.md b/docs/development-guide.md new file mode 100644 index 00000000..98a05184 --- /dev/null +++ b/docs/development-guide.md @@ -0,0 +1,226 @@ +# Development Guide + +## Prerequisites + +- Node.js 18+ +- npm (or bun) + +## Quick Start + +```bash +git clone https://github.com/pronghorn-red/pronghorn.git +cd pronghorn +npm install +npm run dev # Starts on http://localhost:8080 +``` + +No `.env` file is needed — the Supabase configuration is embedded in `src/integrations/supabase/client.ts`. + +## Available Scripts + +| Command | Purpose | +|---------|---------| +| `npm run dev` | Start Vite dev server on port 8080 | +| `npm run build` | Production build | +| `npm run build:dev` | Development build | +| `npm run lint` | Run ESLint | +| `npm run preview` | Preview production build | + +## Project Configuration + +### TypeScript + +- **Target**: ES2020 +- **Strict mode**: OFF (`noImplicitAny: false`, `strictNullChecks: false`) +- **Path alias**: `@/*` → `./src/*` +- **Config**: `tsconfig.json` → references `tsconfig.app.json` and `tsconfig.node.json` + +### ESLint + +- TypeScript-ESLint recommended rules +- React hooks rules +- React Refresh rules +- `@typescript-eslint/no-unused-vars`: disabled +- `react-refresh/only-export-components`: warn (allows constant exports) + +### Tailwind CSS + +- Dark mode: class-based +- Typography plugin: `@tailwindcss/typography` +- Animation plugin: `tailwindcss-animate` +- Colors: HSL CSS variables (e.g., `hsl(var(--primary))`) +- Custom animations: accordion, slide-in/out, float + +### Vite + +- Dev server: port 8080, host `::` +- SWC compiler via `@vitejs/plugin-react-swc` +- Lovable component tagger in development mode +- Brotli + Gzip compression for production +- PWA support via `vite-plugin-pwa` +- Manual chunk splitting for vendor libraries + +## Adding UI Components + +Use the shadcn CLI to add new base components: + +```bash +npx shadcn@latest add button +npx shadcn@latest add dialog +``` + +Config is in `components.json`: +- Style: default +- Base color: neutral +- CSS variables: enabled +- Aliases: `@/components`, `@/components/ui`, `@/hooks`, `@/lib` + +## Working with Supabase + +### Client Usage + +```typescript +import { supabase } from "@/integrations/supabase/client"; + +// RPC call (always use *_with_token functions) +const { data, error } = await supabase.rpc('get_requirements_with_token', { + p_project_id: projectId, + p_token: shareToken || null, +}); + +// Edge function invocation +const { data, error } = await supabase.functions.invoke('function-name', { + body: { projectId, shareToken, ...params } +}); +``` + +### Types + +Auto-generated types are at `src/integrations/supabase/types.ts`. These are generated by Supabase and should not be edited manually. + +### Share Token Pattern + +When building components that access project data: + +```typescript +import { useShareToken } from "@/hooks/useShareToken"; + +function MyComponent({ projectId }: { projectId: string }) { + const { token: shareToken, isTokenSet, tokenMissing } = useShareToken(projectId); + + // Wait for token to be ready + if (!isTokenSet) return ; + if (tokenMissing) return ; + + // Now safe to make RPC calls + const { data } = await supabase.rpc('get_data_with_token', { + p_project_id: projectId, + p_token: shareToken, + }); +} +``` + +## Working with Edge Functions + +Edge functions are Deno TypeScript files in `supabase/functions/*/index.ts`. + +### Local Development + +```bash +# Install Supabase CLI +npm install -g supabase + +# Start local Supabase +supabase start + +# Serve functions locally +supabase functions serve +``` + +### Creating a New Function + +1. Create `supabase/functions/my-function/index.ts` +2. Add `[functions.my-function]` config to `supabase/config.toml` if JWT verification should be disabled +3. Follow the standard pattern (CORS, auth, access validation) +4. Deploy: functions deploy automatically on push + +### Streaming Functions + +For AI/LLM functions that need streaming: + +```typescript +return new Response( + new ReadableStream({ + async start(controller) { + const encoder = new TextEncoder(); + controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`)); + controller.enqueue(encoder.encode('data: [DONE]\n\n')); + controller.close(); + }, + }), + { + headers: { + ...corsHeaders, + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + }, + } +); +``` + +## Working with Realtime + +See [realtime.md](./realtime.md) for the full pattern. Key points: + +1. Always wait for `isTokenSet` before subscribing +2. Use `useRef` for channel storage +3. Clean up channels on unmount +4. Handle connection failures by refreshing data + +## Working with the Canvas + +The canvas uses React Flow 11. Key files: +- `src/hooks/useRealtimeCanvas.ts` — data loading, realtime sync, save operations +- `src/components/canvas/CanvasNode.tsx` — custom node renderer +- `src/lib/connectionLogic.ts` — edge validation rules (loaded from `public/data/connectionLogic.json`) +- `src/hooks/useNodeTypes.ts` — dynamic node types from database + +Node types are data-driven (stored in database), not hardcoded. New types can be added without code changes. + +## Build & Deploy + +### Frontend +- Hosted on Lovable at https://pronghorn.red +- Push to the repository triggers automatic build and deploy + +### Edge Functions +- Deploy automatically when code is pushed to the Supabase project +- Secrets must be configured in the Supabase dashboard + +### Bundle Analysis +Vite produces these vendor chunks for optimal loading: +- `vendor-react` — React, React DOM, React Router, TanStack Query +- `vendor-monaco` — Monaco Editor +- `vendor-pdf` — PDF.js +- `vendor-reactflow` — React Flow +- `vendor-charts` — Recharts +- `vendor-office` — ExcelJS, Mammoth, DOCX, JSZip +- `vendor-radix` — All Radix UI primitives + +## Utility Libraries + +| File | Purpose | +|------|---------| +| `src/lib/utils.ts` | `cn()` — Tailwind class merging | +| `src/lib/tokenCache.ts` | In-memory + sessionStorage token caching | +| `src/lib/connectionLogic.ts` | Canvas edge validation rules | +| `src/lib/sqlParser.ts` | SQL parsing utilities | +| `src/lib/stagingOperations.ts` | Git staging utilities | +| `src/lib/presentationPdfExport.ts` | PDF export for presentations | +| `src/lib/lassoUtils.ts` | Lasso selection geometry | +| `src/lib/downloadUtils.ts` | File download helpers | +| `src/lib/buildBookDownloadUtils.ts` | Build Book export utilities | +| `src/lib/promptPreviewUtils.ts` | Prompt preview formatting | +| `src/lib/deploymentSecrets.ts` | Deployment secret management | +| `src/lib/databaseConnectionSecrets.ts` | Database connection secret management | +| `src/lib/react-query.ts` | React Query client configuration | diff --git a/docs/edge-functions.md b/docs/edge-functions.md new file mode 100644 index 00000000..20a19a1c --- /dev/null +++ b/docs/edge-functions.md @@ -0,0 +1,229 @@ +# Edge Functions Reference + +Pronghorn uses ~58 Deno edge functions hosted on Supabase for server-side operations. All functions are in `supabase/functions/`. + +## Common Pattern + +Every edge function follows this structure: + +```typescript +import "https://deno.land/x/xhr@0.1.0/mod.ts"; +import { serve } from "https://deno.land/std@0.168.0/http/server.ts"; +import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.81.1'; + +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', +}; + +serve(async (req) => { + // CORS preflight + if (req.method === 'OPTIONS') { + return new Response(null, { headers: corsHeaders }); + } + + try { + const { projectId, shareToken, ...params } = await req.json(); + + // Create Supabase client with caller's auth + const authHeader = req.headers.get('Authorization'); + const supabase = createClient( + Deno.env.get('SUPABASE_URL')!, + Deno.env.get('SUPABASE_ANON_KEY')!, + { global: { headers: authHeader ? { Authorization: authHeader } : {} } } + ); + + // Validate access + const { data: role, error: authError } = await supabase.rpc( + 'authorize_project_access', + { p_project_id: projectId, p_token: shareToken || null } + ); + if (authError || !role) { + return new Response(JSON.stringify({ error: 'Access denied' }), { + status: 403, + headers: { ...corsHeaders, 'Content-Type': 'application/json' } + }); + } + + // ... perform operation ... + + return new Response(JSON.stringify({ success: true }), { + headers: { ...corsHeaders, 'Content-Type': 'application/json' } + }); + } catch (error) { + return new Response(JSON.stringify({ error: error.message }), { + status: 500, + headers: { ...corsHeaders, 'Content-Type': 'application/json' } + }); + } +}); +``` + +### Key Implementation Notes + +- All functions have `verify_jwt = false` in `supabase/config.toml` (authorization is done via RPC instead) +- The Supabase client is created per-request using the caller's `Authorization` header +- Access is validated by calling `authorize_project_access` RPC, which checks both authenticated ownership and token-based access +- All responses include CORS headers + +## Streaming Functions (SSE) + +Chat and agent functions use Server-Sent Events for streaming: + +```typescript +// Return a ReadableStream for SSE +return new Response( + new ReadableStream({ + async start(controller) { + const encoder = new TextEncoder(); + // Stream chunks + controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`)); + // Signal completion + controller.enqueue(encoder.encode(`data: [DONE]\n\n`)); + controller.close(); + }, + }), + { + headers: { + ...corsHeaders, + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + }, + } +); +``` + +## Function Categories + +### Project Management + +| Function | Purpose | Role Required | +|----------|---------|---------------| +| `create-project` | Create project with initial token generation | None (creates new) | +| `delete-project` | Cascade delete project and all related data | owner | +| `clone-project` | Deep clone project with all children | viewer (source) | +| `project-activity` | Activity analytics by time period | viewer | +| `log-activity` | Log activity events | editor | + +### AI Agent Orchestration + +| Function | Purpose | Streaming | +|----------|---------|-----------| +| `orchestrate-agents` | Multi-agent canvas design with blackboard | Yes (SSE) | +| `ai-architect` | Generate architecture for canvas | Yes (SSE) | +| `ai-architect-critic` | Review and critique architecture | Yes (SSE) | +| `coding-agent-orchestrator` | Autonomous coding with file operations | Yes (SSE) | +| `presentation-agent` | Blackboard-based slide generation | Yes (SSE) | +| `collaboration-agent-orchestrator` | Collaborative document editing | Yes (SSE) | +| `database-agent-orchestrator` | AI-powered database operations | Yes (SSE) | + +### Audit Pipeline + +| Function | Purpose | +|----------|---------| +| `audit-orchestrator` | Coordinate multi-agent audit pipeline | +| `audit-extract-concepts` | Extract concepts from dataset elements | +| `audit-merge-concepts` | Merge concepts across two datasets | +| `audit-merge-concepts-v2` | Enhanced merging with knowledge graph linking | +| `audit-generate-venn` | Synthesize Venn diagram from knowledge graph | +| `audit-build-tesseract` | Build evidence grid (X: elements, Y: iterations, Z: polarity) | +| `audit-enhanced-sort` | Smart sorting for audit data | + +### Chat Streaming + +| Function | LLM Provider | Models | +|----------|-------------|--------| +| `chat-stream-gemini` | Google | gemini-2.5-flash, gemini-2.5-pro | +| `chat-stream-anthropic` | Anthropic | claude-opus-4-5 | +| `chat-stream-xai` | xAI | grok-4-1-fast-reasoning, grok-4-1-fast-non-reasoning | +| `summarize-chat` | Gemini | Chat session summarization | +| `summarize-artifact` | Gemini | Artifact content summarization | + +### Requirements & Standards + +| Function | Purpose | +|----------|---------| +| `decompose-requirements` | AI decomposition into Epics → Features → Stories → Criteria | +| `expand-requirement` | Expand single requirement into sub-items | +| `expand-standards` | Generate standards from descriptions | +| `ai-create-standards` | Bulk AI standards generation | +| `generate-specification` | Full specification document generation | + +### Image & Media + +| Function | Purpose | +|----------|---------| +| `generate-image` | AI image generation (Gemini) | +| `enhance-image` | Image editing/creation with Gemini image models | +| `upload-artifact-image` | Upload images to Supabase storage | +| `visual-recognition` | OCR and document text extraction | +| `ingest-artifacts` | Bulk artifact ingestion from files | + +### Repository & Git + +| Function | Purpose | +|----------|---------| +| `sync-repo-push` | Push commits to GitHub | +| `sync-repo-pull` | Pull changes from GitHub | +| `create-empty-repo` | Create empty GitHub repository | +| `create-repo-from-template` | Clone from GitHub template | +| `clone-public-repo` | Clone any public repository | +| `link-existing-repo` | Link existing GitHub repo | +| `staging-operations` | Stage/unstage/commit workflow | +| `sync-large-file` | Handle large file transfers | + +### Database Management + +| Function | Purpose | +|----------|---------| +| `manage-database` | Schema browsing, SQL execution, data export | +| `render-database` | Render.com PostgreSQL provisioning | +| `database-agent-import` | AI-powered schema inference for data imports | +| `database-agent-orchestrator` | AI-powered database operations | +| `database-connection-secrets` | Secure connection string encryption | + +### Deployment + +| Function | Purpose | +|----------|---------| +| `render-service` | Render.com web service management | +| `deployment-secrets` | Environment variable storage for deployments | +| `generate-local-package` | Generate downloadable development package | +| `report-local-issue` | Capture and report local testing logs | + +### Presentation + +| Function | Purpose | +|----------|---------| +| `presentation-agent` | Generate slides using blackboard memory pattern | +| `recast-slide-layout` | Restructure slide layout with AI | + +### Admin & Auth + +| Function | Purpose | +|----------|---------| +| `admin-management` | Admin role management | +| `send-auth-email` | Custom branded auth emails via Resend | +| `update-signup-validated` | Update signup validation status | +| `validate-signup-code` | Validate signup access codes | +| `superadmin-github-management` | GitHub organization management | +| `superadmin-render-management` | Render.com organization management | + +### Public Access + +| Function | Purpose | +|----------|---------| +| `serve-artifact` | Serve artifacts publicly (no auth required) | + +## Secrets Required + +| Secret | Purpose | +|--------|---------| +| `GEMINI_API_KEY` | Google Gemini API | +| `ANTHROPIC_API_KEY` | Anthropic Claude API | +| `GROK_API_KEY` | xAI Grok API | +| `GITHUB_PAT` | GitHub repository operations | +| `RENDER_API_KEY` | Render.com deployments & databases | +| `RENDER_OWNER_ID` | Render.com account ID | +| `RESEND_API_KEY` | Branded email delivery | diff --git a/docs/hooks.md b/docs/hooks.md new file mode 100644 index 00000000..64892387 --- /dev/null +++ b/docs/hooks.md @@ -0,0 +1,203 @@ +# Custom Hooks Reference + +All hooks are in `src/hooks/`. They manage realtime subscriptions, data fetching, token management, and shared state. + +## Token & Access + +### `useShareToken(projectId?: string)` + +**File**: `src/hooks/useShareToken.ts` + +Manages the share token lifecycle: extraction from URL, caching, Postgres session setup, and URL masking. + +```typescript +const { token, isTokenSet, tokenMissing } = useShareToken(projectId); +``` + +| Return | Type | Description | +|--------|------|-------------| +| `token` | `string \| null` | Current share token (from URL or cache) | +| `isTokenSet` | `boolean` | Whether token has been set in Postgres session (safe to make RPC calls) | +| `tokenMissing` | `boolean` | URL has `/t/masked` but no cached token (show recovery message) | + +**Always wait for `isTokenSet` before making RPC calls.** + +### `useProjectUrl()` + +**File**: `src/hooks/useProjectUrl.ts` + +Utility for constructing project URLs that preserve the current share token. + +## Realtime Subscriptions + +All realtime hooks follow the pattern described in [realtime.md](./realtime.md). + +### `useRealtimeCanvas(projectId, shareToken, isTokenSet, initialNodes, initialEdges, canvasId?)` + +**File**: `src/hooks/useRealtimeCanvas.ts` + +Most complex realtime hook. Manages React Flow nodes and edges with: +- Granular INSERT/UPDATE/DELETE handling +- Optimistic update deduplication +- Drag conflict avoidance (skips remote updates for actively-dragged nodes) +- Dynamic zone z-index calculation based on nesting depth +- Throttled save (200ms during drag) +- Broadcast refresh signals + +```typescript +const { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange, saveNode, saveEdge, loadCanvasData } = + useRealtimeCanvas(projectId, shareToken, isTokenSet, [], [], canvasId); +``` + +### `useRealtimeRequirements(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeRequirements.ts` + +Subscribes to the requirements table for live requirement tree updates. + +### `useRealtimeArtifacts(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeArtifacts.ts` + +Subscribes to artifact changes (file uploads, deletions, renames). + +### `useRealtimeLayers(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeLayers.ts` + +Canvas layer management with realtime sync. + +### `useRealtimeCollaboration(sessionId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeCollaboration.ts` + +Collaborative document editing realtime sync. + +### `useRealtimeBuildBooks()` + +**File**: `src/hooks/useRealtimeBuildBooks.ts` + +Build Book catalog changes. + +### `useRealtimeProject(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeProject.ts` + +Project metadata changes (name, description, settings). + +### `useRealtimeRepos(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeRepos.ts` + +Repository status and sync state changes. + +### `useRealtimeDatabases(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeDatabases.ts` + +Render.com database status changes. + +### `useRealtimeExternalDatabases(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeExternalDatabases.ts` + +External database connection changes. + +### `useRealtimeSpecifications(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeSpecifications.ts` + +Specification generation progress and results. + +### `useRealtimeProjectStandards(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeProjectStandards.ts` + +Project-level standards linking changes. + +### `useRealtimeDeployments(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeDeployments.ts` + +Deployment status changes. + +### `useRealtimeAudit(sessionId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeAudit.ts` + +Audit session and results changes. + +### `useRealtimeChatSessions(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useRealtimeChatSessions.ts` + +Chat session list changes. + +## Data Fetching + +### `useInfiniteAgentMessages(agentId, projectId, shareToken)` + +**File**: `src/hooks/useInfiniteAgentMessages.ts` + +Paginated fetching of coding agent messages with infinite scroll support. + +### `useInfiniteAgentOperations(agentId, projectId, shareToken)` + +**File**: `src/hooks/useInfiniteAgentOperations.ts` + +Paginated fetching of coding agent file operations. + +### `useProjectAgent(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useProjectAgent.ts` + +Manages the active coding agent session for a project. + +### `useProjectCanvases(projectId, shareToken, isTokenSet)` + +**File**: `src/hooks/useProjectCanvases.ts` + +Fetches and manages multiple canvases per project. + +### `useNodeTypes()` + +**File**: `src/hooks/useNodeTypes.ts` + +Fetches data-driven canvas node types from the database. + +### `useRequirementFiles(requirementId, projectId, shareToken)` + +**File**: `src/hooks/useRequirementFiles.ts` + +Fetches files attached to a specific requirement. + +## State Management + +### `useAuditPipeline()` + +**File**: `src/hooks/useAuditPipeline.ts` + +Orchestrates the full audit pipeline locally (no DB writes until save). Manages pipeline phases: +1. `creating_nodes` → `extracting_d1` → `extracting_d2` → `merging_concepts` → `enhanced_sort` → `building_tesseract` → `generating_venn` → `completed` + +Returns pipeline progress, step statuses, local graph data, and control functions. + +### `useFileBuffer()` + +**File**: `src/hooks/useFileBuffer.ts` + +Manages an in-memory buffer of file content for the coding agent's file operations. + +### `useAnonymousProjects()` + +**File**: `src/hooks/useAnonymousProjects.ts` + +Manages projects created by anonymous (non-authenticated) users with session persistence. + +## UI Utilities + +### `use-toast` + +**File**: `src/hooks/use-toast.ts` + +Toast notification state management (used with shadcn toast, though Sonner is the primary toast). diff --git a/docs/realtime.md b/docs/realtime.md new file mode 100644 index 00000000..97fbfb29 --- /dev/null +++ b/docs/realtime.md @@ -0,0 +1,153 @@ +# Real-Time Subscriptions + +Pronghorn uses Supabase Realtime WebSockets for live collaboration across all project features. + +## Two-Layer Security Model + +### Layer 1: postgres_changes (RLS-Protected) + +Database change events are secured by Row Level Security. The server only sends events the client is authorized to see. + +```typescript +// Before subscribing, set the token in the Postgres session +await supabase.rpc('set_share_token', { token: shareToken }); + +// Subscribe to changes — server enforces RLS +supabase + .channel(`canvas-nodes-${projectId}`) + .on('postgres_changes', { + event: '*', // INSERT, UPDATE, DELETE + schema: 'public', + table: 'canvas_nodes', + filter: `project_id=eq.${projectId}` + }, handleChange) + .subscribe(); +``` + +A client with only the `projectId` but no valid `share_token` cannot receive these events. + +### Layer 2: Broadcast (Public Refresh Signals) + +Broadcast channels are intentionally public but carry **no sensitive data**: + +```typescript +// Send refresh signal (empty payload) +channelRef.current?.send({ + type: 'broadcast', + event: 'canvas_refresh', + payload: {} // No data exposed +}); + +// Receive signal and refetch via RPC (which validates token) +.on('broadcast', { event: 'canvas_refresh' }, () => { + loadCanvasData(); // This calls RPC with token validation +}) +``` + +## Hook Pattern + +All realtime hooks follow this pattern (reference: `src/hooks/useRealtimeCanvas.ts`): + +```typescript +import { useEffect, useRef, useCallback } from "react"; +import { supabase } from "@/integrations/supabase/client"; + +export function useRealtimeEntity(projectId: string, shareToken: string | null, isTokenSet: boolean) { + const channelRef = useRef(null); + + const loadData = useCallback(async () => { + const { data, error } = await supabase.rpc('get_entity_with_token', { + p_project_id: projectId, + p_token: shareToken, + }); + // ... update state + }, [projectId, shareToken]); + + useEffect(() => { + if (!projectId || !isTokenSet) return; + + // Initial data load + loadData(); + + // Tab visibility refresh + const handleVisibility = () => { + if (!document.hidden) loadData(); + }; + document.addEventListener('visibilitychange', handleVisibility); + + // Realtime subscription + const channel = supabase + .channel(`entity-${projectId}`) + .on('postgres_changes', { + event: '*', + schema: 'public', + table: 'entity_table', + filter: `project_id=eq.${projectId}`, + }, (payload) => { + // Handle INSERT, UPDATE, DELETE granularly + if (payload.eventType === 'INSERT') { /* ... */ } + if (payload.eventType === 'UPDATE') { /* ... */ } + if (payload.eventType === 'DELETE') { /* ... */ } + }) + .on('broadcast', { event: 'entity_refresh' }, () => { + loadData(); + }) + .subscribe((status) => { + if (status === 'CHANNEL_ERROR' || status === 'TIMED_OUT') { + loadData(); // Fallback: refresh on connection failure + } + }); + + channelRef.current = channel; + + return () => { + document.removeEventListener('visibilitychange', handleVisibility); + supabase.removeChannel(channel); + channelRef.current = null; + }; + }, [projectId, isTokenSet, shareToken, loadData]); + + // Broadcast refresh to other clients + const broadcastRefresh = useCallback(() => { + channelRef.current?.send({ + type: 'broadcast', + event: 'entity_refresh', + payload: {}, + }); + }, []); + + return { /* state, broadcastRefresh */ }; +} +``` + +## Key Implementation Rules + +1. **Use `useRef` for channel storage** — prevents stale closures in event handlers +2. **Store channel reference during subscription** — needed for `send()` broadcasts +3. **Use `channelRef.current.send()`** — not `supabase.channel().send()` (which creates a new channel) +4. **Wait for `isTokenSet`** — never subscribe or fetch before token is ready +5. **Clean up on unmount** — call `supabase.removeChannel()` and null the ref +6. **Handle connection failures** — refresh data on `CHANNEL_ERROR` or `TIMED_OUT` +7. **Tab visibility refresh** — reload data when user returns to the tab +8. **Optimistic dedup** — skip INSERT events if entity already exists locally (from optimistic updates) +9. **Drag conflict avoidance** — canvas uses `draggedNodeRef` to skip UPDATE events for nodes currently being dragged + +## Available Realtime Hooks + +| Hook | Table(s) | File | +|------|----------|------| +| `useRealtimeCanvas` | canvas_nodes, canvas_edges | src/hooks/useRealtimeCanvas.ts | +| `useRealtimeRequirements` | requirements | src/hooks/useRealtimeRequirements.ts | +| `useRealtimeArtifacts` | artifacts | src/hooks/useRealtimeArtifacts.ts | +| `useRealtimeLayers` | canvas_layers | src/hooks/useRealtimeLayers.ts | +| `useRealtimeCollaboration` | collaboration_* | src/hooks/useRealtimeCollaboration.ts | +| `useRealtimeBuildBooks` | build_books | src/hooks/useRealtimeBuildBooks.ts | +| `useRealtimeProject` | projects | src/hooks/useRealtimeProject.ts | +| `useRealtimeRepos` | repositories | src/hooks/useRealtimeRepos.ts | +| `useRealtimeDatabases` | project_databases | src/hooks/useRealtimeDatabases.ts | +| `useRealtimeExternalDatabases` | project_database_connections | src/hooks/useRealtimeExternalDatabases.ts | +| `useRealtimeSpecifications` | specifications | src/hooks/useRealtimeSpecifications.ts | +| `useRealtimeProjectStandards` | project_standards | src/hooks/useRealtimeProjectStandards.ts | +| `useRealtimeDeployments` | deployments | src/hooks/useRealtimeDeployments.ts | +| `useRealtimeAudit` | audit_* | src/hooks/useRealtimeAudit.ts | +| `useRealtimeChatSessions` | chat_sessions | src/hooks/useRealtimeChatSessions.ts |