Workflows¶
This page documents key operational workflows in TruSpace — how data, permissions, and events move through the system. Workflows are categorised as established (implemented and in production) or proposed (under discussion or in development).
Established Workflows¶
Document Upload & Encryption¶
- User selects a file in the frontend
- The backend receives the file bytes via
multipart/form-data(held in multer memory storage) - The file is encrypted with AES-256-CBC using a PBKDF2-derived key based on the workspace ID
- The ciphertext is added to the local IPFS node → a CID is generated
- IPFS Cluster pins the CID and replicates it to connected peers
- Document metadata (CID, filename, workspace ID, uploader) is written to IPFS as a separate small file
- The frontend receives the CID and displays the new document version
Document Retrieval & Decryption¶
- Frontend requests a document version by CID via
GET /api/documents/version/:cid - Backend fetches the ciphertext blob from IPFS (local node first, then peers)
- Backend decrypts with AES-256-CBC using the workspace key
- Plaintext bytes are streamed to the client
- Frontend renders the document
Direct IPFS access returns ciphertext
Because files are encrypted before IPFS storage, fetching a CID directly from the IPFS gateway returns the encrypted blob. Decryption only happens through the TruSpace API.
Proposed Workflows¶
#292 — Private Workspace Permissions Across IPFS Nodes¶
Status: Proposed
This workflow is under active development. The design is finalised; implementation is in progress.
Problem¶
User management and access rights are stored locally per node. Inviting a user from another node only updates the local database on the inviter's node. The remote node has no record of the permission, so the invited user cannot access the workspace from their own node.
Proposed Solution¶
Introduce a cross-node invitation system using:
USER_PERMISSIONSas a materialised view of who has access to what- A generic
EVENTStable as an append-only log - IPFS as the event bus — event files written to IPFS are detected and processed by remote nodes
- Email as the global user identifier across nodes (see ADR-002)
Workflow Steps¶
- User A on Node A selects a private workspace and enters the email of User B (on Node B)
- Node A creates a
USER_PERMISSIONSrecord for User B's email locally - Node A writes a
PERMISSION-EVENTrecord to its localEVENTStable - Node A writes the event as a small file to the IPFS event bus directory
- Node B detects the new event file on next login or manual refresh
- Node B creates the corresponding
USER_PERMISSIONSrecord locally - Node B marks the event as processed in its local
EVENTStable
The same flow applies to revocations (by the inviter), self-removals (by the invitee), and workspace deletions — each generating a distinct event type.
Idempotency is guaranteed: if a node receives the same event twice, the event_id lookup prevents duplicate processing.
Full Lifecycle Sequence Diagram¶
sequenceDiagram
participant A1 as User A1 (Node A)
participant NodeA as Node A
participant NodeB as Node B
participant B1 as User B1 (Node B)
participant IPFS as IPFS
%% Invite creation
A1->>NodeA: Invite User with Email & Role
NodeA->>NodeA: Insert USER_PERMISSION
NodeA->>NodeA: Insert 'invite' EVENT
NodeA->>IPFS: Write 'invite' EVENT file to every User on the workspace
%% Remote nodes process invite
NodeB->>IPFS: Detect new EVENT file
NodeB->>NodeB: Insert 'invite' USER_PERMISSION
NodeB->>NodeB: Insert 'invite' EVENT
%% Revoke by inviter
A1->>NodeA: Revoke permission
NodeA->>NodeA: INSERT 'removed' event
NodeA->>NodeA: DELETE USER_PERMISSION
NodeA->>IPFS: Write 'removed' EVENT file to every User on the workspace
NodeB->>IPFS: Detect new EVENT file
NodeB->>NodeB: INSERT 'removed' event
NodeB->>NodeB: DELETE USER_PERMISSION
%% Self-revoke or user deleted
B1->>NodeB: Revoke own permission
NodeB->>NodeB: INSERT 'removed' event
NodeB->>NodeB: DELETE USER_PERMISSION
NodeB->>IPFS: Write 'removed' EVENT file to every User on the workspace
NodeA->>IPFS: Detect new EVENT file
NodeA->>NodeA: INSERT 'removed' event
NodeA->>NodeA: DELETE USER_PERMISSION
%% Workspace removed
A1->>NodeA: Remove Workspace
NodeA->>NodeA: INSERT 'workspace removed' event
NodeA->>NodeA: DELETE USER_PERMISSION
NodeA->>IPFS: Write 'removed workspace' EVENT file to every User on the workspace
NodeB->>IPFS: Detect new EVENT file
NodeB->>NodeB: INSERT 'removed workspace' event
NodeB->>NodeB: DELETE USER_PERMISSION
%% Duplicate event guard
NodeA->>IPFS: Detect old EVENT file
NodeA->>NodeA: event_id already in DB — ignored
Proposed Database Changes¶
The USER_PERMISSIONS table gains a last_event_id column. The EVENTS table is introduced as a new append-only log:
erDiagram
USERS {
int id PK
string email
string username
string status
}
USER_PERMISSIONS {
int id PK
string workspace_id
string user_email FK
string role
string status
string last_event_id
datetime created_at
datetime updated_at
}
EVENTS {
string id PK
string type
json payload
datetime created_at
}
USERS ||--o{ USER_PERMISSIONS : "has"
Trade-offs¶
| Pros | Cons / Considerations |
|---|---|
| Each node stays authoritative for its own users | Emails propagate across nodes — privacy policy must reflect this |
| Email as global ID — no central registry needed | Requires idempotent event handling |
| Offline-safe — nodes catch up via IPFS replay | UI must handle pending, active, revoked, and self-removed states |
| Extensible to notifications, expirations, role changes | Eventual consistency — no real-time guarantee |
Contributing a Workflow¶
TruSpace no longer keeps a separate workflows/proposed/ and workflows/established/ folder structure — all workflows live directly in this documentation site (mkdocs/docs/architecture/workflows.md), with Mermaid diagrams embedded inline as fenced ```mermaid code blocks rather than as separate .mmd/.png files.
To add or update a workflow:
- Add a new section to this page (or a new page under
architecture/for larger topics) describing the workflow. - Include one or more Mermaid diagrams inline using fenced code blocks — MkDocs renders them automatically, no separate image generation step is required.
- Open a PR for review.
- Once the workflow is implemented/accepted, update the wording from "proposed" to reflect its established status, and cross-link it from Components or Data Model as relevant.
- Update
mkdocs.ymlnavigation if you added a new page.
Writing Mermaid diagrams¶
Because diagrams are embedded directly as text, there's no build step — just write the Mermaid syntax inside a fenced block:
```mermaid
sequenceDiagram
participant A as Service A
participant B as Service B
A->>B: Request
B-->>A: Response
```
If you want to preview a diagram before committing, use the Mermaid Live Editor or install the CLI locally:
npm install -g @mermaid-js/mermaid-cli
mmdc -i diagram.mmd -o diagram.png # optional, only if you need a standalone image