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:
Jason Woltje
2026-01-29 17:25:57 -06:00
parent a5b984c7fd
commit 82a09373e0
2 changed files with 888 additions and 0 deletions

View File

@@ -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

View 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`.