docs: add Federation Architecture design document
Captures: - Peer-to-peer federation model (master/spoke) - Agent Federation Protocol (CONNECT, QUERY, COMMAND, EVENT, DISCONNECT) - Authentik integration for enterprise SSO and RBAC - Data sovereignty principles (query, don't replicate) - RBAC model with workspace/team hierarchy - Implementation phases targeting 0.1.0 MVP - Versioning policy (0.0.x dev, 0.1.0 MVP, 1.0.0 stable)
This commit is contained in:
@@ -70,4 +70,44 @@ When creating a new design document:
|
||||
|
||||
---
|
||||
|
||||
### [Federation Architecture](./federation-architecture.md)
|
||||
|
||||
**Status:** Design Phase
|
||||
**Version:** 0.0.1
|
||||
**Date:** 2025-01-29
|
||||
|
||||
Multi-instance federation enabling cross-organization collaboration, work/personal separation, and enterprise control with data sovereignty.
|
||||
|
||||
**Key Features:**
|
||||
- Peer-to-peer federation (every instance can be master and/or spoke)
|
||||
- Authentik integration for enterprise SSO and RBAC
|
||||
- Agent Federation Protocol for cross-instance queries and commands
|
||||
- Data sovereignty (query in place, never replicate)
|
||||
- Single pane of glass aggregating multiple instances
|
||||
|
||||
---
|
||||
|
||||
### [Multi-Tenant RLS](./multi-tenant-rls.md)
|
||||
|
||||
**Status:** Implemented
|
||||
**Version:** 1.0
|
||||
**Date:** 2025-01-29
|
||||
|
||||
PostgreSQL Row-Level Security for workspace isolation and defense-in-depth multi-tenancy.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
When creating a new design document:
|
||||
|
||||
1. Copy the structure from an existing document
|
||||
2. Use ASCII diagrams for architecture (keep them simple)
|
||||
3. Include code examples in TypeScript
|
||||
4. Specify database schema in SQL (PostgreSQL dialect)
|
||||
5. Add implementation phases with clear milestones
|
||||
6. Update this README with a summary
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-01-29
|
||||
|
||||
848
docs/design/federation-architecture.md
Normal file
848
docs/design/federation-architecture.md
Normal file
@@ -0,0 +1,848 @@
|
||||
# Federation Architecture
|
||||
|
||||
**Version:** 0.0.1
|
||||
**Status:** Design Phase
|
||||
**Author:** Mosaic Stack Team
|
||||
**Date:** 2025-01-29
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Problem Statement](#problem-statement)
|
||||
2. [Architecture Overview](#architecture-overview)
|
||||
3. [Identity & Authentication](#identity--authentication)
|
||||
4. [Agent Federation Protocol](#agent-federation-protocol)
|
||||
5. [RBAC Model](#rbac-model)
|
||||
6. [Data Sovereignty](#data-sovereignty)
|
||||
7. [Implementation Phases](#implementation-phases)
|
||||
8. [Versioning](#versioning)
|
||||
|
||||
---
|
||||
|
||||
## Problem Statement
|
||||
|
||||
### Use Cases
|
||||
|
||||
1. **Work/Personal Separation**
|
||||
- Developer has personal projects at home and work projects at the office
|
||||
- Data must stay in its respective environment
|
||||
- Single pane of glass for unified visibility
|
||||
|
||||
2. **Enterprise Control**
|
||||
- Organization runs their own Mosaic Stack instance
|
||||
- Teams within the org have isolated workspaces
|
||||
- IT controls access, audit, compliance
|
||||
|
||||
3. **Cross-Organization Collaboration**
|
||||
- Partner companies need to share specific projects
|
||||
- Guest access with limited permissions
|
||||
- No data replication—query in place
|
||||
|
||||
### Requirements
|
||||
|
||||
- **Data Sovereignty** — Data stays where it's created, never crosses boundaries
|
||||
- **Unified Control** — Single interface to view/manage multiple instances
|
||||
- **Clean Severance** — Disconnect = lose access, no data to clean up
|
||||
- **Enterprise Auth** — SSO, RBAC, audit trails
|
||||
- **Peer-to-Peer** — Any instance can be both master and spoke
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Peer-to-Peer Federation Model
|
||||
|
||||
Every Mosaic Stack instance is a **peer** that can simultaneously act as:
|
||||
- **Master** — Control and query downstream spokes
|
||||
- **Spoke** — Expose capabilities to upstream masters
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ ENTERPRISE │
|
||||
│ (Corp HQ) │
|
||||
└────────┬────────┘
|
||||
│ speaks to
|
||||
┌──────────────┼──────────────┐
|
||||
▼ ▼ ▼
|
||||
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ IT Dept │ │ Dev Team │ │ HR Dept │
|
||||
└────┬─────┘ └────┬─────┘ └──────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌──────────┐ ┌──────────┐
|
||||
│ Jason │◄─►│ Mike │ ← peer sharing
|
||||
│ (Work) │ │ (Work) │
|
||||
└────┬─────┘ └──────────┘
|
||||
│
|
||||
│ speaks to (personal master)
|
||||
▼
|
||||
┌──────────┐
|
||||
│ Jason │◄─► [Future: Family instance?]
|
||||
│ (Home) │◄─► [Future: Trusted collaborator?]
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
### Component Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ IDENTITY PLANE │
|
||||
│ (Authentik) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ • Users (identities across instances) │
|
||||
│ • Groups (teams, departments, roles) │
|
||||
│ • Applications (Mosaic Stack instances) │
|
||||
│ • Federation trust (OIDC/SAML between IdPs) │
|
||||
└───────────────────────────┬─────────────────────────────────────┘
|
||||
│ OIDC / SAML
|
||||
┌───────────────────┼───────────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ Instance A │ │ Instance B │ │ Instance C │
|
||||
│ (Home) │ │ (Work) │ │ (Partner) │
|
||||
├───────────────┤ ├───────────────┤ ├───────────────┤
|
||||
│ Agent Layer │ │ Agent Layer │ │ Agent Layer │
|
||||
│ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │
|
||||
│ │ Jarvis │ │ │ │ Jarvis │ │ │ │ Partner │ │
|
||||
│ │ Prime │◄┼───┼─┤ Work │ │ │ │ Agent │ │
|
||||
│ └───────────┘ │ │ └───────────┘ │ │ └───────────┘ │
|
||||
├───────────────┤ ├───────────────┤ ├───────────────┤
|
||||
│ Workspaces: │ │ Workspaces: │ │ Workspaces: │
|
||||
│ • Personal │ │ • IT Ops │ │ • Shared Proj │
|
||||
│ • Side Proj │ │ • Dev Team │ │ │
|
||||
└───────────────┘ └───────────────┘ └───────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Identity & Authentication
|
||||
|
||||
### Authentik as Identity Provider
|
||||
|
||||
Authentik provides enterprise-grade identity management:
|
||||
|
||||
| Feature | Purpose |
|
||||
|---------|---------|
|
||||
| **OIDC/SAML** | Single sign-on across instances |
|
||||
| **User Directory** | Centralized user management |
|
||||
| **Groups** | Team/department organization |
|
||||
| **RBAC** | Role-based access control |
|
||||
| **Audit Logs** | Compliance and security tracking |
|
||||
| **MFA** | Multi-factor authentication |
|
||||
| **Federation** | Trust between external IdPs |
|
||||
|
||||
### Auth Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Identity Provider (Authentik) │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
|
||||
│ │ Users │ │ Groups │ │ Applications │ │
|
||||
│ ├─────────────┤ ├─────────────┤ ├─────────────────────────┤ │
|
||||
│ │ jason │ │ IT-Team │ │ mosaic-home │ │
|
||||
│ │ mike │ │ Dev-Team │ │ mosaic-work-usc │ │
|
||||
│ │ sarah │ │ Admins │ │ mosaic-partner-acme │ │
|
||||
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Policies & Flows │ │
|
||||
│ │ • Login flow (password + MFA) │ │
|
||||
│ │ • OAuth2/OIDC scopes (profile, email, groups) │ │
|
||||
│ │ • Conditional access (IP, device, time) │ │
|
||||
│ │ • External IdP federation (Google, Azure AD) │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────┼───────────────────┐
|
||||
│ OIDC │ OIDC │ OIDC
|
||||
▼ ▼ ▼
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Mosaic Home │ │ Mosaic Work │ │ Mosaic Ext │
|
||||
└─────────────┘ └─────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
### OIDC Token Claims
|
||||
|
||||
Mosaic Stack expects these claims from the IdP:
|
||||
|
||||
```json
|
||||
{
|
||||
"sub": "user-uuid-123",
|
||||
"preferred_username": "jason",
|
||||
"email": "jason@example.com",
|
||||
"groups": ["IT-Team", "Dev-Team", "Admins"],
|
||||
"roles": ["workspace:ws-123:owner", "workspace:ws-456:member"],
|
||||
"aud": "mosaic-home",
|
||||
"iss": "https://auth.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### Cross-Instance Identity
|
||||
|
||||
When federating between instances with different IdPs:
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Authentik A │◄── OIDC Trust ───►│ Authentik B │
|
||||
│ (Home IdP) │ │ (Work IdP) │
|
||||
└────────┬────────┘ └────────┬────────┘
|
||||
│ │
|
||||
│ │
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Mosaic Home │ │ Mosaic Work │
|
||||
│ │ │ │
|
||||
│ User: jason │◄── Federation ───►│ User: jason │
|
||||
│ (home identity)│ Protocol │ (work identity)│
|
||||
└─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
**Identity Mapping:**
|
||||
- Same email = same person (by convention)
|
||||
- Explicit identity linking via federation protocol
|
||||
- No implicit access—must be granted per instance
|
||||
|
||||
---
|
||||
|
||||
## Agent Federation Protocol
|
||||
|
||||
### Connection Lifecycle
|
||||
|
||||
```
|
||||
┌────────────┐ ┌────────────┐
|
||||
│ MASTER │ │ SPOKE │
|
||||
│ (Home) │ │ (Work) │
|
||||
└─────┬──────┘ └─────┬──────┘
|
||||
│ │
|
||||
│ 1. CONNECT (auth token + scopes) │
|
||||
│───────────────────────────────────────►│
|
||||
│ │
|
||||
│ 2. CAPABILITIES (available APIs) │
|
||||
│◄───────────────────────────────────────│
|
||||
│ │
|
||||
│ 3. QUERY / COMMAND (ongoing) │
|
||||
│◄──────────────────────────────────────►│
|
||||
│ │
|
||||
│ 4. EVENT (push notifications) │
|
||||
│◄───────────────────────────────────────│
|
||||
│ │
|
||||
│ 5. DISCONNECT (clean exit) │
|
||||
│───────────────────────────────────────►│
|
||||
│ │
|
||||
```
|
||||
|
||||
### Message Types
|
||||
|
||||
#### 1. `CONNECT` — Establish Federation Trust
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "connect",
|
||||
"version": "0.0.1",
|
||||
"masterIdentity": {
|
||||
"instanceId": "mosaic-home-jason",
|
||||
"userId": "jason",
|
||||
"instanceUrl": "https://mosaic.home.local"
|
||||
},
|
||||
"authToken": "oidc-access-token-or-api-key",
|
||||
"requestedScopes": [
|
||||
"calendar.read",
|
||||
"calendar.write",
|
||||
"tasks.read",
|
||||
"tasks.write",
|
||||
"agents.query",
|
||||
"agents.command"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. `CAPABILITIES` — Spoke Advertises Available APIs
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "capabilities",
|
||||
"spokeIdentity": {
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"instanceUrl": "https://mosaic.uscllc.com"
|
||||
},
|
||||
"grantedScopes": ["calendar.read", "tasks.read", "tasks.write"],
|
||||
"deniedScopes": ["calendar.write", "agents.command"],
|
||||
"availableCommands": [
|
||||
{
|
||||
"name": "tasks.list",
|
||||
"description": "List tasks in workspace",
|
||||
"params": { "workspaceId": "string", "status": "string?" }
|
||||
},
|
||||
{
|
||||
"name": "tasks.create",
|
||||
"description": "Create a new task",
|
||||
"params": { "title": "string", "description": "string?" }
|
||||
},
|
||||
{
|
||||
"name": "calendar.today",
|
||||
"description": "Get today's calendar events",
|
||||
"params": {}
|
||||
}
|
||||
],
|
||||
"availableQueries": [
|
||||
{
|
||||
"name": "status",
|
||||
"description": "Get instance status",
|
||||
"returns": "InstanceStatus"
|
||||
},
|
||||
{
|
||||
"name": "workspaces.list",
|
||||
"description": "List accessible workspaces",
|
||||
"returns": "Workspace[]"
|
||||
}
|
||||
],
|
||||
"eventSubscriptions": [
|
||||
"calendar.reminder",
|
||||
"tasks.assigned",
|
||||
"tasks.completed"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. `QUERY` — Read-Only Data Fetch
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "query",
|
||||
"id": "q-abc123",
|
||||
"name": "calendar.today",
|
||||
"params": { "includeAllDay": true }
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "query.result",
|
||||
"id": "q-abc123",
|
||||
"success": true,
|
||||
"data": [
|
||||
{ "title": "Standup", "time": "09:00", "duration": 30 },
|
||||
{ "title": "1:1 with Mike", "time": "14:00", "duration": 60 }
|
||||
],
|
||||
"provenance": {
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"timestamp": "2025-01-29T14:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. `COMMAND` — Execute an Action
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command",
|
||||
"id": "c-def456",
|
||||
"name": "tasks.create",
|
||||
"params": {
|
||||
"title": "Review PR #421",
|
||||
"description": "Security review for auth changes",
|
||||
"priority": 8,
|
||||
"workspaceId": "ws-dev-team"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Sync Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command.result",
|
||||
"id": "c-def456",
|
||||
"success": true,
|
||||
"data": {
|
||||
"taskId": "task-789",
|
||||
"url": "https://mosaic.uscllc.com/tasks/task-789"
|
||||
},
|
||||
"provenance": {
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"timestamp": "2025-01-29T14:31:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Async Response (for long-running):**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command.accepted",
|
||||
"id": "c-def456",
|
||||
"status": "pending",
|
||||
"pollUrl": "/federation/status/c-def456",
|
||||
"estimatedCompletion": "30s"
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. `EVENT` — Push Notification from Spoke
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "event",
|
||||
"name": "calendar.reminder",
|
||||
"data": {
|
||||
"title": "1:1 with Mike",
|
||||
"startsIn": "15m",
|
||||
"location": "Conference Room B"
|
||||
},
|
||||
"provenance": {
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"timestamp": "2025-01-29T13:45:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 6. `DISCONNECT` — Clean Severance
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "disconnect",
|
||||
"reason": "user-initiated",
|
||||
"revokeToken": true,
|
||||
"preserveHistory": false
|
||||
}
|
||||
```
|
||||
|
||||
### Agent-to-Agent Communication
|
||||
|
||||
Masters can command spokes to execute agent tasks:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "command",
|
||||
"id": "c-agent-001",
|
||||
"name": "agents.spawn",
|
||||
"params": {
|
||||
"taskTitle": "Review today's tickets",
|
||||
"taskDescription": "Check GLPI for new high-priority tickets",
|
||||
"inputContext": {
|
||||
"priority": "high",
|
||||
"category": "network"
|
||||
},
|
||||
"callbackUrl": "https://mosaic.home.local/federation/callback/c-agent-001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The spoke agent executes the task and calls back with results:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "callback",
|
||||
"id": "c-agent-001",
|
||||
"success": true,
|
||||
"data": {
|
||||
"ticketsFound": 3,
|
||||
"tickets": [
|
||||
{ "id": "GLPI-1234", "title": "Switch failure in Building A" },
|
||||
{ "id": "GLPI-1235", "title": "VPN connectivity issues" },
|
||||
{ "id": "GLPI-1236", "title": "Printer offline 3rd floor" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## RBAC Model
|
||||
|
||||
### Hierarchy
|
||||
|
||||
```
|
||||
Instance
|
||||
└── Workspace (like a Teams "Team")
|
||||
├── Roles: owner, admin, member, viewer, guest
|
||||
├── Teams (sub-groups within workspace)
|
||||
│ └── Roles: owner, admin, member
|
||||
├── Projects / Channels
|
||||
│ └── Permissions (inherit or override)
|
||||
└── Members (users or groups from IdP)
|
||||
```
|
||||
|
||||
### Role Permissions Matrix
|
||||
|
||||
| Permission | Owner | Admin | Member | Viewer | Guest |
|
||||
|------------|-------|-------|--------|--------|-------|
|
||||
| View workspace | ✓ | ✓ | ✓ | ✓ | ✓* |
|
||||
| Create content | ✓ | ✓ | ✓ | ✗ | ✗ |
|
||||
| Edit content | ✓ | ✓ | ✓ | ✗ | ✗ |
|
||||
| Delete content | ✓ | ✓ | ✗ | ✗ | ✗ |
|
||||
| Manage members | ✓ | ✓ | ✗ | ✗ | ✗ |
|
||||
| Manage teams | ✓ | ✓ | ✗ | ✗ | ✗ |
|
||||
| Configure workspace | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| Delete workspace | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
| Manage federation | ✓ | ✗ | ✗ | ✗ | ✗ |
|
||||
|
||||
*Guest: scoped to specific shared items only
|
||||
|
||||
### Federation RBAC
|
||||
|
||||
Cross-instance access is always scoped and limited:
|
||||
|
||||
```json
|
||||
{
|
||||
"federation": {
|
||||
"trustedInstances": [
|
||||
{
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"trustLevel": "verified",
|
||||
"maxRole": "member",
|
||||
"scopedWorkspaces": ["ws-shared-projects"],
|
||||
"allowedCapabilities": ["tasks.read", "tasks.write", "calendar.read"],
|
||||
"deniedCapabilities": ["admin.*", "federation.*"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Constraints:**
|
||||
- Federated users cannot exceed `maxRole` (e.g., member can't become admin)
|
||||
- Access limited to `scopedWorkspaces` only
|
||||
- Capabilities are explicitly allowlisted
|
||||
- Admin/federation capabilities always denied by default
|
||||
|
||||
---
|
||||
|
||||
## Data Sovereignty
|
||||
|
||||
### Core Principles
|
||||
|
||||
1. **Data Residency** — Data lives where it's created, never crosses boundaries
|
||||
2. **Query, Don't Replicate** — Master queries spoke, doesn't store results
|
||||
3. **Provenance Tagging** — Every piece of data tagged with source instance
|
||||
4. **Clean Exit** — Disconnect = lose access, no cleanup needed
|
||||
|
||||
### Data Flow
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ MASTER (Home) │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Aggregation Layer │ │
|
||||
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │
|
||||
│ │ │ Home Data │ │ Work Data │ │ Partner Data │ │ │
|
||||
│ │ │ (stored) │ │ (queried) │ │ (queried) │ │ │
|
||||
│ │ │ │ │ ⚡ live │ │ ⚡ live │ │ │
|
||||
│ │ └─────────────┘ └──────┬──────┘ └──────────┬──────────┘ │ │
|
||||
│ │ │ │ │ │
|
||||
│ └──────────────────────────┼─────────────────────┼─────────────┘ │
|
||||
│ │ │ │
|
||||
└─────────────────────────────┼─────────────────────┼───────────────┘
|
||||
│ │
|
||||
┌─────────▼─────────┐ ┌────────▼────────┐
|
||||
│ SPOKE (Work) │ │ SPOKE (Partner) │
|
||||
│ Data stays here │ │ Data stays here │
|
||||
└───────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### What's Stored vs Queried
|
||||
|
||||
| Data Type | Home Instance | Work Instance | Notes |
|
||||
|-----------|---------------|---------------|-------|
|
||||
| Personal tasks | ✓ Stored | — | Only at home |
|
||||
| Work tasks | Queried live | ✓ Stored | Never replicated |
|
||||
| Personal calendar | ✓ Stored | — | Only at home |
|
||||
| Work calendar | Queried live | ✓ Stored | Never replicated |
|
||||
| Federation metadata | ✓ Stored | ✓ Stored | Connection config only |
|
||||
| Query results cache | Ephemeral (5m TTL) | — | Optional, short-lived |
|
||||
|
||||
### Severance Procedure
|
||||
|
||||
When disconnecting from a spoke:
|
||||
|
||||
```
|
||||
1. Master initiates DISCONNECT
|
||||
2. Spoke revokes master's access token
|
||||
3. Spoke removes master from trusted instances
|
||||
4. Master removes spoke from connection list
|
||||
5. All live queries fail immediately
|
||||
6. No data cleanup needed—nothing was stored
|
||||
|
||||
Result:
|
||||
- Master retains: its own data, federation config (marked disconnected)
|
||||
- Spoke retains: its own data, audit log of the connection
|
||||
- Neither has: the other's data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Foundation (v0.0.x)
|
||||
|
||||
**Goal:** Multi-instance awareness, basic federation protocol
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] Instance identity model (instanceId, URL, public key)
|
||||
- [ ] Federation connection database schema
|
||||
- [ ] Basic CONNECT/DISCONNECT protocol
|
||||
- [ ] Manual connection setup (no auto-discovery)
|
||||
- [ ] Query/Command message handling (stub)
|
||||
|
||||
**Testing:**
|
||||
- Two local instances can connect
|
||||
- Connection persists across restarts
|
||||
- Disconnect cleans up properly
|
||||
|
||||
### Phase 2: Authentik Integration (v0.0.x)
|
||||
|
||||
**Goal:** Enterprise SSO with RBAC
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] Authentik OIDC provider setup guide
|
||||
- [ ] BetterAuth Authentik adapter
|
||||
- [ ] Group → Role mapping
|
||||
- [ ] Multi-workspace session handling
|
||||
- [ ] Audit logging for auth events
|
||||
|
||||
**Testing:**
|
||||
- Login via Authentik works
|
||||
- Groups map to roles correctly
|
||||
- Session isolation between workspaces
|
||||
|
||||
### Phase 3: Federation Protocol (v0.0.x)
|
||||
|
||||
**Goal:** Full query/command capability
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] QUERY message type with response streaming
|
||||
- [ ] COMMAND message type with async support
|
||||
- [ ] EVENT subscription and delivery
|
||||
- [ ] Capability negotiation
|
||||
- [ ] Error handling and retry logic
|
||||
|
||||
**Testing:**
|
||||
- Master can query spoke calendar
|
||||
- Master can create tasks on spoke
|
||||
- Events push from spoke to master
|
||||
- Errors handled gracefully
|
||||
|
||||
### Phase 4: Single Pane of Glass (v0.1.0 MVP)
|
||||
|
||||
**Goal:** Unified dashboard showing all instances
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] Connection manager UI
|
||||
- [ ] Aggregated calendar view
|
||||
- [ ] Aggregated task view
|
||||
- [ ] Instance status indicators
|
||||
- [ ] Visual provenance tagging (color/icon per instance)
|
||||
|
||||
**Testing:**
|
||||
- Dashboard shows data from multiple instances
|
||||
- Clear visual distinction between sources
|
||||
- Offline instance shows gracefully
|
||||
|
||||
### Phase 5: Agent Federation (v0.1.x)
|
||||
|
||||
**Goal:** Cross-instance agent coordination
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] Agent spawn command via federation
|
||||
- [ ] Callback mechanism for results
|
||||
- [ ] Agent status querying across instances
|
||||
- [ ] Cross-instance task assignment
|
||||
|
||||
**Testing:**
|
||||
- Home agent can spawn task on work instance
|
||||
- Results callback works
|
||||
- Agent health visible across instances
|
||||
|
||||
### Phase 6: Enterprise Features (v0.2.x)
|
||||
|
||||
**Goal:** Production-ready for organizations
|
||||
|
||||
**Deliverables:**
|
||||
- [ ] Admin console for federation management
|
||||
- [ ] Compliance audit reports
|
||||
- [ ] Rate limiting and quotas
|
||||
- [ ] Webhook integration
|
||||
- [ ] Multi-region support
|
||||
|
||||
---
|
||||
|
||||
## Versioning
|
||||
|
||||
### Semantic Versioning Policy
|
||||
|
||||
| Version | Meaning |
|
||||
|---------|---------|
|
||||
| `0.0.x` | Active development, breaking changes expected, internal use only |
|
||||
| `0.1.0` | **MVP** — First user-testable release, core features working |
|
||||
| `0.x.y` | Pre-stable iteration, API may change with notice |
|
||||
| `1.0.0` | Stable release, public API contract, breaking changes require major version |
|
||||
|
||||
### Version Milestones
|
||||
|
||||
| Version | Target | Features |
|
||||
|---------|--------|----------|
|
||||
| 0.0.1 | Design | This document |
|
||||
| 0.0.5 | Foundation | Basic federation protocol |
|
||||
| 0.0.10 | Auth | Authentik integration |
|
||||
| 0.1.0 | **MVP** | Single pane of glass, basic federation |
|
||||
| 0.2.0 | Agents | Cross-instance agent coordination |
|
||||
| 0.3.0 | Enterprise | Admin console, compliance |
|
||||
| 1.0.0 | Stable | Production-ready, API frozen |
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Transport Security
|
||||
|
||||
- All federation traffic over TLS 1.3
|
||||
- Certificate pinning for known instances (optional)
|
||||
- mTLS for high-security deployments
|
||||
|
||||
### Authentication
|
||||
|
||||
- OIDC tokens with short expiry (1h)
|
||||
- Refresh tokens with longer expiry (7d)
|
||||
- API keys for service-to-service (no user context)
|
||||
|
||||
### Authorization
|
||||
|
||||
- Capability-based access control
|
||||
- Explicit allowlists (deny by default)
|
||||
- No implicit transitivity (A→B→C doesn't mean A→C)
|
||||
|
||||
### Audit
|
||||
|
||||
- All federation connections logged
|
||||
- All queries/commands logged with user identity
|
||||
- Retention configurable per compliance requirements
|
||||
|
||||
### Secrets
|
||||
|
||||
- Never log tokens or credentials
|
||||
- Encrypt sensitive federation config at rest
|
||||
- Rotate API keys periodically
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Federation Management
|
||||
|
||||
```typescript
|
||||
// List connected instances
|
||||
GET /api/v1/federation/connections
|
||||
Response: FederationConnection[]
|
||||
|
||||
// Initiate connection to spoke
|
||||
POST /api/v1/federation/connect
|
||||
{
|
||||
"spokeUrl": "https://mosaic.work.example.com",
|
||||
"authToken": "...",
|
||||
"requestedScopes": ["calendar.read", "tasks.*"]
|
||||
}
|
||||
|
||||
// Disconnect from spoke
|
||||
DELETE /api/v1/federation/connections/:instanceId
|
||||
|
||||
// Get connection status
|
||||
GET /api/v1/federation/connections/:instanceId/status
|
||||
|
||||
// Update connection scopes
|
||||
PATCH /api/v1/federation/connections/:instanceId
|
||||
{
|
||||
"requestedScopes": ["calendar.*", "tasks.*"]
|
||||
}
|
||||
```
|
||||
|
||||
### Federated Queries
|
||||
|
||||
```typescript
|
||||
// Query a spoke
|
||||
POST /api/v1/federation/query
|
||||
{
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"query": "calendar.today",
|
||||
"params": { "includeAllDay": true }
|
||||
}
|
||||
|
||||
// Execute command on spoke
|
||||
POST /api/v1/federation/command
|
||||
{
|
||||
"instanceId": "mosaic-work-usc",
|
||||
"command": "tasks.create",
|
||||
"params": { "title": "Review PR", "priority": 8 }
|
||||
}
|
||||
```
|
||||
|
||||
### Spoke Configuration (for instances accepting connections)
|
||||
|
||||
```typescript
|
||||
// Get spoke settings
|
||||
GET /api/v1/federation/spoke/settings
|
||||
|
||||
// Update spoke settings
|
||||
PATCH /api/v1/federation/spoke/settings
|
||||
{
|
||||
"acceptConnections": true,
|
||||
"allowedMasters": ["mosaic-home-jason"],
|
||||
"defaultScopes": ["calendar.read", "tasks.read"],
|
||||
"maxScopes": ["calendar.*", "tasks.*"]
|
||||
}
|
||||
|
||||
// List connected masters
|
||||
GET /api/v1/federation/spoke/masters
|
||||
|
||||
// Revoke master access
|
||||
DELETE /api/v1/federation/spoke/masters/:instanceId
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| **Instance** | A single Mosaic Stack deployment |
|
||||
| **Master** | Instance that initiates connection and queries spoke |
|
||||
| **Spoke** | Instance that accepts connections and serves data |
|
||||
| **Peer** | An instance that can be both master and spoke |
|
||||
| **Federation** | Network of connected Mosaic Stack instances |
|
||||
| **Scope** | Permission to perform specific actions (e.g., `calendar.read`) |
|
||||
| **Capability** | API endpoint exposed by a spoke |
|
||||
| **Provenance** | Source attribution for data (which instance it came from) |
|
||||
| **Severance** | Clean disconnection with no data cleanup required |
|
||||
| **IdP** | Identity Provider (e.g., Authentik) |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [Authentik Documentation](https://goauthentik.io/docs/)
|
||||
- [OIDC Specification](https://openid.net/specs/openid-connect-core-1_0.html)
|
||||
- [Multi-Tenant RLS Design](./multi-tenant-rls.md)
|
||||
- [Agent Orchestration Design](./agent-orchestration.md)
|
||||
- [Architecture Decisions](./architecture-decisions.md)
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Identity Linking:** How do we link the same person across instances with different IdPs?
|
||||
2. **Conflict Resolution:** What happens if the same entity is modified on multiple instances?
|
||||
3. **Offline Handling:** How long to cache spoke data when offline?
|
||||
4. **Rate Limiting:** How to prevent spoke overload from aggressive masters?
|
||||
5. **Discovery:** Should instances be discoverable, or always manual connection?
|
||||
|
||||
---
|
||||
|
||||
**Next Steps:**
|
||||
1. Review and approve this design document
|
||||
2. Create GitHub issues for Phase 1 tasks
|
||||
3. Set up Authentik development instance
|
||||
4. Begin federation protocol implementation
|
||||
|
||||
**Questions/Feedback:** Open an issue in `mosaic-stack` repo with label `federation`.
|
||||
Reference in New Issue
Block a user