Architecture
Technical overview of how Align works under the hood.
System Overview
┌─────────────────────────────────────────────────────────────────────┐
│ Your Tools │
│ Slack · Teams · Jira · GitHub · Linear │
└──────────────────────────────┬──────────────────────────────────────┘
│ webhooks / APIs
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Connectors (MCP) │
│ Each connector speaks one platform's API and normalizes data │
└──────────────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Gateway (Fastify) │
│ API server · Job orchestration · SSE streaming · Business logic │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────────────┐ │
│ │ Import │ │ Bulk Approval│ │ Relationship Candidate │ │
│ │ Worker │ │ Worker │ │ Detector │ │
│ └─────────────┘ └──────────────┘ └───────────────────────────┘ │
└──────────────────────────────┬──────────────────────────────────────┘
│
┌──────────┴──────────┐
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐
│ PostgreSQL (RLS) │ │ Brain (FastAPI) │
│ Decisions · Snapshots │ │ LLM analysis │
│ Relationships · Jobs │ │ Embeddings │
│ Candidates · Telemetry │ │ Relationship detection │
└──────────────────────────┘ └────────────┬─────────────┘
│
┌────────────┴────────────┐
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Local vLLM │ │ Cloud APIs │
│ (GPU node, opt) │ │ OpenAI/Anthropic│
│ Llama/Align │ │ (fallback or │
│ models │ │ primary) │
└──────────────────┘ └──────────────────┘
Services
| Service | Stack | Purpose |
|---|---|---|
| UI | SvelteKit 5 | Frontend application |
| Gateway | TypeScript / Fastify | API server, job orchestration, business logic |
| Brain | Python / FastAPI | LLM analysis, embeddings, relationship detection, tier classification, graph algorithms |
| Connectors | TypeScript / MCP | Platform-specific integrations (Slack, Teams, Jira, GitHub, Linear) |
| PostgreSQL | 15+ | Primary data store with Row-Level Security (RLS) |
| vLLM Server | Python / vLLM | Local GPU inference (optional, replaces cloud API calls) |
Data Flow
Real-time Capture
When someone mentions @align in Slack or Teams, the capture is instant but the intelligence is proactive:
User mentions @align → Connector receives webhook → Gateway creates Decision Snapshot
→ Auto-assigns to Decision Space (channel mapping)
→ Brain analyzes for relationships + conflicts
→ Tier classification runs (strategic/tactical/operational)
→ Links to related decisions created
→ Health scores updated across affected spaces
The @align mention is the only manual step. Everything after capture - relationship detection, conflict surfacing, tier classification, space assignment, and health scoring - runs automatically.
Discover (Historical Scan)
Discover is the pipeline for importing historical decisions from your existing tools. It runs in three stages:
Stage 1: Scan
UI starts scan → Gateway creates import job
→ Connector fetches items from platform API (paginated)
→ Brain analyzes each batch for decision-like content
→ Gateway stores suggestions in import_suggestions table
→ SSE streams progress to UI in real-time
The scan pipeline processes items in batches with adaptive chunking that limits both item count (30 per chunk) and payload size (500KB per chunk) to prevent timeouts.
Stage 2: Cross-Reference Detection
During the scan, the gateway automatically detects cross-platform references between suggestions:
┌──────────────────────────────────────────────────────────────┐
│ Suggestion A (Jira) Suggestion B (Slack) │
│ source_url: .../PROJ-123 text: "...see PROJ-123..." │
│ metadata: {issue_key: metadata: {issue_key: │
│ "PROJ-123"} "PROJ-123"} │
│ │
│ ──── deterministic match ──── │
│ Stored as relationship_candidate │
│ confidence: 1.0 │
└──────────────────────────────────────────────────────────────┘
Deterministic matchers (confidence = 1.0):
- Jira keys -
PROJ-123found in both a Jira ticket and a Slack message - GitHub PR/Issue references -
org/repo#42or full GitHub URLs - Slack thread timestamps - Same thread referenced from multiple sources
These precomputed candidates are stored in the relationship_candidates table, ready for instant promotion when the user approves.
Stage 3: Review & Approve
The user reviews AI-suggested decisions and approves them. Approval uses a two-phase flow for maximum speed:
User clicks "Approve All"
│
▼
┌─── Phase 1: Instant (< 1 second) ────────────────────────────┐
│ 1. Create all Decision Snapshots from approved suggestions │
│ 2. Look up precomputed relationship_candidates │
│ 3. Resolve suggestion IDs → decision IDs │
│ 4. Create decision_links for all precomputed matches │
│ 5. Stream "Linked: relates (N instant connections)" via SSE │
└──────────────────────────────────────────────────────────────┘
│
▼
┌─── Phase 2: Background (seconds to minutes) ─────────────────┐
│ 1. Filter out suggestions that already have precomputed links│
│ 2. Send ONLY unlinked decisions to Brain for LLM analysis │
│ 3. Brain discovers semantic/contextual relationships │
│ 4. Stream "Discovered: relates (N connections found)" via SSE│
└──────────────────────────────────────────────────────────────┘
Why two phases? Deterministic cross-references (same Jira key in two items) are facts, not opinions - they don't need LLM analysis. By promoting them instantly, the user sees connections appear within milliseconds of clicking approve. The LLM only runs for items where no obvious link exists, keeping bulk approval fast even for hundreds of decisions.
Database Schema (Key Tables)
| Table | Purpose |
|---|---|
decision_snapshots | Core decision records with title, summary, tier, status, embeddings |
decision_links | Relationships between decisions (relates, supersedes, conflicts, etc.) |
teams | Decision Spaces - hierarchical org structure (department, team, project) |
team_members | User-to-space membership with roles (owner, member) |
decision_space_memberships | Many-to-many mapping of decisions to spaces |
connector_team_mappings | Auto-assign decisions to spaces based on connector source patterns |
import_jobs | Discover scan job state and progress |
import_suggestions | AI-suggested decisions pending review |
relationship_candidates | Precomputed cross-platform links (pending promotion at approval time) |
connectors | Configured integrations |
tenants | Organizations / workspaces |
Row-Level Security (RLS)
All tenant data is isolated using PostgreSQL RLS. Every query runs within a withTenant() wrapper that sets app.current_tenant for the session:
-- Automatically applied to all queries
CREATE POLICY tenant_isolation ON decision_snapshots
USING (tenant_id = current_setting('app.current_tenant')::uuid);
Job Processing
Architecture Options
| Deployment | Queue | Worker | Use Case |
|---|---|---|---|
| Single-pod | In-memory | Embedded in gateway | Development, small teams |
| Multi-pod | AWS SQS | Embedded in gateway | Production, scaling |
The gateway includes an embedded worker that processes jobs directly when no external queue is configured. This means self-hosted single-pod deployments work out of the box with zero additional infrastructure.
Job Types
| Job | Trigger | What It Does |
|---|---|---|
| Import Job | User starts Discover scan | Fetches items from connector, sends to Brain for analysis, stores suggestions |
| Bulk Approval | User approves suggestions | Two-phase: instant link promotion + background LLM analysis |
SSE (Server-Sent Events)
Both scan and approval progress are streamed to the UI via SSE:
Gateway ──SSE──▶ UI
│
├─ scan_progress: items scanned, suggestions found
├─ scan_complete: scan finished
├─ approval_started: bulk approval begun
├─ relationship_found: links discovered (Phase 1 or Phase 2)
├─ analyzing: LLM analysis progress
└─ approval_complete: all done
For multi-pod deployments, Redis pub/sub ensures SSE events reach the correct pod regardless of which pod processes the job.
Decision Intelligence Engine
The Brain service includes a proprietary ML pipeline that powers Align's analytical features. These run alongside relationship detection and require no additional configuration.
Tier Classification
Decisions are auto-classified into strategic, tactical, or operational tiers:
Decision captured → Gateway gathers features → Brain GBM classifier → Tier assigned
(link count, platforms, (gradient boosting (stored on
participants, language) model) decision_snapshots)
Features are extracted from existing data - no additional LLM calls needed. Classification runs in the background and updates as new relationships are discovered.
Graph Algorithms
The Brain service runs graph algorithms on the decision graph:
| Algorithm | Purpose | Used By |
|---|---|---|
| PageRank | Identify most influential decisions | Centrality analysis |
| Louvain community detection | Find clusters of related decisions | Graph clustering |
| Shortest path | Measure distance between decisions | Relevance scoring |
| Recursive CTE traversal | Follow decision chains | Cascade view, impact simulation |
Sequence Model
A lightweight transformer model learns per-tenant decision patterns for:
- Drift scoring - How surprising is this decision given the team's history?
- Anomaly detection - Sudden changes in decision velocity or conflict rate
- Pattern recognition - Recurring decision anti-patterns
Self-Hosting Considerations
What Works Out of the Box
Self-hosted deployments get the full Discover and bulk approval pipeline with zero additional configuration:
- Embedded worker - No separate worker process needed
- In-memory job queue - No SQS/Redis required for single-pod
- Idempotent migrations - All migrations use
IF NOT EXISTS/CREATE OR REPLACEfor safe re-runs - Automatic fallbacks - No Redis? In-memory pub/sub. No SQS? Direct processing.
When to Add Infrastructure
| Scenario | Add | Why |
|---|---|---|
| Multiple gateway pods | Redis | SSE pub/sub across pods, shared job state |
| High-volume (1000s decisions/day) | SQS | Durable job queue, retry handling |
| Large scans (10k+ items) | PgBouncer | Connection pooling for parallel processing |
Performance Expectations
| Operation | Single-Pod | Multi-Pod |
|---|---|---|
| Scan (100 items) | ~30 seconds | ~30 seconds |
| Scan (1000 items) | ~3 minutes | ~3 minutes |
| Bulk approve (50 items, with precomputed links) | < 2 seconds (Phase 1) | < 2 seconds (Phase 1) |
| Bulk approve (50 items, LLM analysis) | ~30 seconds (Phase 2) | ~30 seconds (Phase 2) |
LLM Routing
The Brain service uses a unified LLM client that routes inference based on deployment configuration:
| Deployment | Primary | Fallback | Use Case |
|---|---|---|---|
| SaaS + GPU node | Local vLLM (Llama 8B) | Cloud APIs | Flat cost, data stays local |
| SaaS (no GPU) | Cloud APIs (Anthropic/OpenAI) | Other cloud provider | Pay-per-call |
| Self-hosted + GPU | Local vLLM (Align model or open-source) | Cloud APIs (if configured) | Full data sovereignty |
| Self-hosted (Your Keys) | Tenant's cloud API keys | Other provider if both configured | Customer manages costs |
| Self-hosted (CPU) | Ollama/llama.cpp | Cloud APIs (if configured) | No GPU required |
Key behaviors:
LOCAL_LLM_SERVER_URLenv var activates local GPU routing for allalign_managedtenants- Tenants with their own API keys always use those keys, never the local server
- Discover scans (bulk operations) bypass the local GPU and use cloud APIs for higher throughput
- Automatic fallback: if the primary provider fails (rate limit, auth error, server down), retries with the fallback
LLM Configuration
The Brain service requires an LLM for:
- Scan analysis - Identifying decisions in source content
- Relationship detection - Finding semantic connections (Phase 2 only)
- Summarization - Generating decision titles and descriptions
See LLM Setup for configuring OpenAI, Anthropic, or self-hosted models (Ollama, vLLM).
Cost optimization: Precomputed deterministic links (Phase 1) skip LLM entirely, reducing API costs. For teams with strong cross-referencing habits (linking Jira tickets in Slack, referencing PRs in issues), the majority of relationships are detected deterministically.
Relationship Detection
Align detects relationships between decisions using multiple strategies:
Deterministic (Phase 1 - Instant)
Cross-platform reference matching with 100% confidence:
| Pattern | Example | Detected From |
|---|---|---|
| Jira key | PROJ-123 | URLs, text content, metadata |
| GitHub PR | org/repo#42 or full URL | URLs, text content |
| GitHub Issue | org/repo#10 or full URL | URLs, text content |
| Slack thread | Thread timestamp | URLs |
LLM-Powered (Phase 2 - Background)
For decisions without deterministic links, the Brain service uses LLM analysis to find:
- Semantic similarity - Decisions about the same topic
- Supersession - Newer decisions replacing older ones
- Conflicts - Contradictory decisions
- Duplicates - Same decision captured from different sources
Relationship Types
| Type | Meaning |
|---|---|
relates | General relationship (most common) |
supersedes | This decision replaces an older one |
conflicts_with | These decisions contradict each other |
duplicates | Same decision captured from different sources |
refines | Adds detail or narrows scope of another decision |
clarifies | Resolves ambiguity in another decision |
questions | Raises concerns or open questions about a decision |