/ docs / MULTI_TENANT_ARCHITECTURE.md
MULTI_TENANT_ARCHITECTURE.md
  1  # Multi-Tenant Architecture: Identity-Agnostic Node Core
  2  
  3  > **Status**: Implementation Complete  
  4  > **Version**: 0.5  
  5  > **Date**: 2026-01-27
  6  
  7  ## Overview
  8  
  9  Refactor Abzu to separate **Machine Identity** (infrastructure) from **User Identity** (accounts). This enables household deployments, guest hosting, and node federation.
 10  
 11  ---
 12  
 13  ## Core Principle: Two Identity Types
 14  
 15  ```
 16  ┌─────────────────────────────────────────────────────────────┐
 17  │  MACHINE IDENTITY (Infrastructure)                          │
 18  │  - Mesh address derivation                                   │
 19  │  - DHT participation & routing                               │
 20  │  - Transport layer operations                                │
 21  │  - Persists with the node                                    │
 22  ├─────────────────────────────────────────────────────────────┤
 23  │  USER IDENTITY (Accounts)                                    │
 24  │  - Message signing & encryption                              │
 25  │  - Mailbox ownership                                         │
 26  │  - Contact relationships                                     │
 27  │  - Portable between nodes                                    │
 28  └─────────────────────────────────────────────────────────────┘
 29  ```
 30  
 31  ---
 32  
 33  ## Architecture
 34  
 35  ### Layer Separation
 36  
 37  ```
 38  ┌─────────────────────────────────────────────────────────────┐
 39  │  Federation Layer (future)                                  │
 40  │  Mailbox blob replication between trusted nodes             │
 41  ├─────────────────────────────────────────────────────────────┤
 42  │  Account Layer (NEW)                                        │
 43  │  AccountManager: hosts N user identities, permission model  │
 44  ├─────────────────────────────────────────────────────────────┤
 45  │  Node Layer (REFACTORED)                                    │
 46  │  AbzuNode: machine_identity for routing/DHT                 │
 47  ├─────────────────────────────────────────────────────────────┤
 48  │  Transport Layer (unchanged)                                │
 49  │  FakeTLS, QUIC — uses ephemeral keys per connection         │
 50  └─────────────────────────────────────────────────────────────┘
 51  ```
 52  
 53  ### Component Ownership
 54  
 55  | Component | Current | New Owner |
 56  |-----------|---------|-----------|
 57  | Machine Keypair | `Node.identity` | `Node.machine_identity` |
 58  | Mesh Address | Node | Node (derived from machine key) |
 59  | Routing Table | Node | Node (shared infrastructure) |
 60  | DHT Operations | Node | Node (signed by machine key) |
 61  | User Keypair | N/A | Account |
 62  | Message Signing | Node | Account |
 63  | Mailbox | Node | Account (1 per account) |
 64  | Contacts | Node | Account |
 65  | Storage | Flat | Per-Account encrypted |
 66  
 67  ---
 68  
 69  ## Account Model
 70  
 71  ### Account Types
 72  
 73  ```rust
 74  pub enum AccountType {
 75      Admin,      // Full control, can inspect Child accounts
 76      Adult,      // Equal authority, no inspection rights
 77      Child,      // Inspectable by Admin accounts
 78      Guest,      // Private, uses node as encrypted relay only
 79  }
 80  ```
 81  
 82  ### Account Structure
 83  
 84  ```rust
 85  pub struct Account {
 86      pub id: AccountId,
 87      pub keypair: Keypair,            // User's Ed25519 identity
 88      pub account_type: AccountType,
 89      pub mailbox_id: DhtKey,          // Derived from user pubkey
 90      pub storage: AccountStorage,     // Encrypted vault
 91  }
 92  
 93  pub struct AccountManager {
 94      node: Arc<AbzuNode>,             // Shared infrastructure
 95      accounts: DashMap<AccountId, Account>,
 96  }
 97  ```
 98  
 99  ### Child Key Derivation (Security)
100  
101  > [!IMPORTANT]
102  > Child private keys are NOT stored in plaintext for Admin inspection.
103  
104  Options for parental oversight:
105  
106  1. **Sub-key derivation**: Child key derived from Admin master key
107  2. **Dual encryption**: Messages encrypted to both Child and Admin pubkeys
108  3. **Capability escrow**: Child's read-capability encrypted to Admin
109  
110  ---
111  
112  ## Guest Model
113  
114  > [!NOTE]
115  > True Guests hold their own keys on their own device.
116  
117  **Guest ≠ Stored User**. A Guest uses the node as an **encrypted relay**:
118  
119  - Guest's private key stays on their device (phone/laptop)
120  - Node only stores/forwards encrypted blobs
121  - Node cannot read Guest content
122  - Guest can switch to a different relay node anytime
123  
124  If someone gives you their private key, they're not a Guest — they're a dependent User.
125  
126  ---
127  
128  ## Account Portability
129  
130  Accounts are **mandatory portable**:
131  
132  ```rust
133  struct AccountExport {
134      keypair: EncryptedKeypair,  // Password-protected
135      mailbox_data: Vec<u8>,      // Encrypted blob
136      contacts: Vec<u8>,          // Encrypted blob
137      metadata: AccountMetadata,
138  }
139  
140  impl Account {
141      fn export(&self, password: &str) -> AccountExport;
142      fn import(export: AccountExport, password: &str) -> Result<Account>;
143  }
144  ```
145  
146  User can export → move to any Abzu node → import.
147  
148  ---
149  
150  ## Refactor Plan
151  
152  ### Phase 1: Identity Split ✅ COMPLETE
153  
154  **Goal**: Split single identity into machine vs user within existing single-tenant code.
155  
156  | Change | Description |
157  |--------|-------------|
158  | Renamed `Node.identity` → `Node.machine_identity` | Explicit naming |
159  | Added user identity tracking | Managed through AccountManager |
160  | Routing uses `machine_identity` | Infrastructure operations |
161  | Chat/signing uses account identity | User operations |
162  
163  **Checkpoint**: All tests pass. Behavior unchanged.
164  
165  ### Phase 2: AccountManager ✅ COMPLETE
166  
167  **Goal**: Extract user_identity into Account struct.
168  
169  | Component | Implementation |
170  |-----------|----------------|
171  | `Account` struct | Implemented in `abzu-account/` crate |
172  | `AccountStorage` | Per-account encrypted storage (planned) |
173  | `AccountManager` | Account CRUD with async API |
174  
175  **Checkpoint**: Single account works. All tests pass.
176  
177  ### Phase 3: Multi-Account + Permissions ✅ COMPLETE
178  
179  **Goal**: Multiple accounts with permission model.
180  
181  | Feature | Implementation |
182  |---------|----------------|
183  | Multiple accounts | N accounts per node via AccountManager |
184  | Account types | Admin, Adult, Child, Guest implemented |
185  | Permission model | Admin can delete Child, Guest is private |
186  | SDK integration | AbzuClient exposes all account methods |
187  
188  **Checkpoint**: Admin can inspect Child. Guest is private. 205+ tests pass.
189  
190  ### Phase 4: SDK Integration ✅ COMPLETE
191  
192  **Goal**: High-level SDK exposes account management.
193  
194  | Feature | Implementation |
195  |---------|----------------|
196  | AbzuClient account API | `create_account`, `list_accounts`, `delete_account`, `switch_account` |
197  | Current account tracking | `current_account`, `account_count` |
198  | FFI mapping | `SdkError::AccountError` → `AbzuError::AccountError` |
199  | Comprehensive tests | 11 new async tests for account management |
200  
201  **Checkpoint**: Full account lifecycle via SDK. All workspace tests pass.
202  
203  ### Phase 5: Federation (Future)
204  
205  **Goal**: Mailbox replication between trusted nodes.
206  
207  | Feature | Implementation |
208  |---------|----------------|
209  | Trusted node registry | Explicit peer list |
210  | Mailbox blob sync | Encrypted blobs only |
211  | Availability handoff | Partner serves blobs when primary offline |
212  | Account export/import | Password-protected portable identities |
213  
214  ---
215  
216  ## Verification Strategy
217  
218  ### Git Worktrees (Not Shadow Repos)
219  
220  Use git worktrees for comparative testing — not physical directory copies:
221  
222  ```bash
223  # Before Phase 1
224  git tag v0.5.0-pre-multitenant
225  
226  # Create worktree for comparison
227  git worktree add ../abzu-baseline v0.5.0-pre-multitenant
228  
229  # After Phase 1, compare
230  cargo test --workspace                              # Current
231  cargo test --manifest-path ../abzu-baseline/Cargo.toml  # Baseline
232  ```
233  
234  ### Rollback Tags
235  
236  ```bash
237  git tag -a v0.5.0-pre-multitenant -m "Before multi-tenant refactor"
238  git tag -a v0.5.1-identity-split -m "Machine/User identity separated"
239  git tag -a v0.5.2-account-manager -m "AccountManager implemented"
240  git tag -a v0.5.3-multi-account -m "Multi-account + permissions"
241  ```
242  
243  ### Test Requirements
244  
245  | Phase | Requirement | Status |
246  |-------|-------------|--------|
247  | Phase 1 | All tests pass, behavior identical | ✅ Complete |
248  | Phase 2 | Single account works, new Account tests | ✅ Complete |
249  | Phase 3 | Multi-account tests, permission tests | ✅ Complete |
250  | Phase 4 | SDK integration tests | ✅ Complete |
251  | Phase 5 | Federation sync tests | ⏳ Future |
252  
253  ---
254  
255  ## Rate Limiting
256  
257  ### Tiered Model
258  
259  | Level | Purpose |
260  |-------|---------|
261  | **Per-Account** | Prevent one user from monopolizing node resources |
262  | **Per-Node (Global)** | Protect node from mesh blacklisting |
263  
264  ---
265  
266  ## API Evolution
267  
268  ### Before (Current)
269  
270  ```rust
271  let node = AbzuNode::with_identity(keypair, config)?;
272  node.send_message(recipient, payload).await?;
273  ```
274  
275  ### After Phase 1 (Identity Split)
276  
277  ```rust
278  let node = AbzuNode::new(config)?;  // machine_identity auto-generated
279  // user_identity is internal, soon to become Account
280  node.send_message(recipient, payload).await?;
281  ```
282  
283  ### After Phase 3 (Multi-Account)
284  
285  ```rust
286  let node = AbzuNode::new(config)?;
287  let admin = node.create_account(keypair1, AccountType::Admin)?;
288  let child = node.create_account(keypair2, AccountType::Child)?;
289  
290  node.send_message(&admin, recipient, payload).await?;
291  ```
292  
293  ---
294  
295  ## Open Questions (Resolved)
296  
297  | Question | Resolution |
298  |----------|------------|
299  | Guest identity location? | **Client-side only** — node is encrypted relay |
300  | Federation scope? | **Mailbox blobs only** — not full node state |
301  | Account portability? | **Mandatory** — export/import supported |
302  | Rate limiting? | **Tiered** — per-account + per-node |
303  
304  ---
305  
306  ## Next Steps
307  
308  - [x] Review and incorporate external feedback
309  - [x] Create `v0.5.0-pre-multitenant` tag
310  - [x] Phase 1: Identity split
311  - [x] Phase 2: AccountManager implementation
312  - [x] Phase 3: Multi-account + permissions
313  - [x] Phase 4: SDK integration
314  - [ ] Phase 5: Federation (future)
315  - [ ] Account export/import API
316  - [ ] Child key derivation refinement