Architecture Overview
System architecture and design patterns for TMA Cloud.
System Architecture
TMA Cloud uses Single-Origin Architecture:
- Production: The Express backend serves both the built frontend and all APIs from the same origin.
- Development: The browser loads the app from the Vite dev server at
http://localhost:5173, which proxies/api/*and/s/*to the backend onhttp://localhost:3000.
Production Architecture
┌─────────┐
│ Browser │
└────┬────┘
│
│ HTTP Requests
│
┌────▼─────────────────────────────────────────────┐
│ Express Backend (:3000) │
│ ┌──────────────────────────────────────────┐ │
│ │ / → Static Frontend Files │ │
│ │ /api/* → API Endpoints │ │
│ │ /s/* → Share Links │ │
│ │ /health → Health Check │ │
│ │ /metrics → Prometheus Metrics │ │
│ └──────────────────────────────────────────┘ │
└────┬───────────────────┬─────────────────────────┘
│ │
│ │
┌────▼─────┐ ┌──────▼──────┐
│PostgreSQL│ │ Redis │
│ Database │ │ (Cache) │
└──────────┘ └─────────────┘
Development Architecture
┌─────────┐
│ Browser │
└────┬────┘
│
│ HTTP Requests
│
┌────▼──────────────────────────────────────┐
│ Vite Dev Server (:5173) │
│ ┌────────────────────────────────────┐ │
│ │ Frontend Development Server │ │
│ │ Proxies /api/* → Backend (:3000) │ │
│ │ Proxies /s/* → Backend (:3000) │ │
│ └────────────────────────────────────┘ │
└────┬──────────────────────────────────────┘
│
│ Proxy Requests
│
┌────▼─────────────────────────────────────┐
│ Express Backend (:3000) │
│ ┌────────────────────────────────────┐ │
│ │ API Endpoints │ │
│ │ Share Links │ │
│ └────────────────────────────────────┘ │
└────┬───────────────────┬─────────────────┘
│ │
│ │
┌────▼─────┐ ┌──────▼──────┐
│PostgreSQL│ │ Redis │
│ Database │ │ (Cache) │
└──────────┘ └─────────────┘
Benefits: No CORS issues, simplified deployment, cookie-based auth, no frontend env vars needed.
Custom Share Domain (Optional)
Configure custom share base URL in Settings → Share Base URL (admin only). When configured, share links use the custom domain. Share domain middleware blocks all routes except /s/*, /health, and /metrics.
Backend Structure
backend/
├── config/ # Configuration (database, redis, logger)
├── controllers/ # Request handlers
├── middleware/ # Express middleware (auth, error handling)
├── migrations/ # Database migrations
├── models/ # Data models
├── routes/ # API routes
├── services/ # Background services
└── utils/ # Utilities
Key Components:
- Controllers: Handle HTTP requests and business logic
- Middleware: Auth, error handling, rate limiting, share domain blocking
- Models: Database abstraction layer
- Services: Background processes (cleanup, scanning, audit logging, OnlyOffice auto-save)
- Caching: Redis-based caching with automatic invalidation
- Real-Time Events: Redis pub/sub + SSE for file event broadcasting
Frontend Structure
frontend/src/
├── components/ # React components
├── contexts/ # State management
├── hooks/ # Custom hooks
└── utils/ # Utilities
Key Features:
- Responsive Design: Separate mobile (≤1024px) and desktop (>1024px) UIs
- Contexts: AuthContext, AppContext, ThemeContext
- Viewers: Image and document viewers with device-specific implementations
Electron Desktop App
Optional Windows client. Loads the same frontend from the TMA Cloud server URL; no separate frontend build.
Electron Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Main Process (Node) │
│ src/main: createWindow, getServerUrl(), IPC │
│ Server URL: embedded at build, or userData/config.json, │
│ or electron/src/config/build-config.json (dev) │
└──────────────────────────────┬──────────────────────────────────┘
│ loadURL(serverUrl)
│ IPC
┌──────────────────────────────▼──────────────────────────────────┐
│ Renderer (BrowserWindow) │
│ Same React frontend as web; origin = server URL │
│ Preload (src/preload) exposes window.electronAPI to renderer │
└──────────────────────────────┬──────────────────────────────────┘
│ fetch /api/* (same origin, cookies)
▼
┌─────────────────────────────────────────────────────────────────┐
│ TMA Cloud Backend │
└─────────────────────────────────────────────────────────────────┘
Electron Folder Structure
electron/
├── src/
│ ├── main/ # Main process: window, server URL, IPC
│ ├── preload/ # contextBridge, exposes electronAPI
│ ├── config/ # build-config.json (serverUrl when run from source)
│ └── build/ # electron-builder configs + icon
├── scripts/ # prepare-client-build.js
└── dist-electron/ # Staging for packaging (generated)
Main process: Creates a single BrowserWindow; loads a loading page, then the server URL. Resolves server URL from embedded constant (at build time) or src/config/build-config.json (when run from source). Registers IPC handlers used by the renderer (e.g. OS clipboard on Windows). Clipboard: FileDropList first (Explorer), then OLE (Outlook, Snipping Tool, other apps), then text-as-paths (Copy as path, IDEs); script passed via env var, no temp files.
Preload: contextIsolation: true, nodeIntegration: false. Exposes a small API (e.g. electronAPI.clipboard) via contextBridge and ipcRenderer.invoke.
Renderer: Same React app as web. Detects Electron via window.electronAPI and uses it where needed; all API calls go to the same backend via fetch.
Some deployments enable an optional mode where the desktop app is only allowed. In that mode, normal browsers are blocked from the main app while share links continue to work.
Data Flow
Authentication Flow
┌─────────┐ POST /api/login ┌──────────┐
│ Browser │ ────────────────────────> │ Backend │
└─────────┘ └────┬─────┘
│ │
│ │ Validate credentials
│ │ Create session
│ │ Generate JWT token
│ │
│<────────────────────────────────────┘
│ Set httpOnly cookie
│
┌────▼─────────┐
│ AuthContext │
│ Updated │
└──────────────┘
File Upload Flow
┌──────────┐ POST /api/files/upload ┌──────────┐
│ Browser │ ─────────────────────────────> │ Backend │
│(FormData)│ └────┬─────┘
└──────────┘ │
│ Validate & save file
│ Stream to storage (local or S3)
│ Create database record
│ Update cache
│
┌─────────┐ Response with file info │
│ Browser │<─────────────────────────────────────┘
└─────────┘
Storage: Local disk (UPLOAD_DIR) or S3-compatible object storage (when STORAGE_DRIVER=s3). Same streaming and encryption for both.
Share Link Flow
┌─────────┐ POST /api/files/share ┌──────────┐
│ Browser │ ─────────────────────────────> │ Backend │
└─────────┘ └────┬─────┘
│
│ Create share link
│ Generate token
│ Link files
│
┌─────────┐ Response with share URL │
│ Browser │<────────────────────────────────────┘
└─────────┘
Database Schema
Key tables: users, files, share_links, share_link_files, audit_logs, sessions, app_settings
See Database Schema for details.
Security
- JWT tokens in httpOnly cookies
- Input validation and sanitization
- SQL injection protection (parameterized queries)
- XSS protection (HTML escaping)
- Path traversal protection
- Rate limiting
- Security headers (CSP, X-Frame-Options, etc.)
Logging & Audit
- Structured Logging: Pino with automatic secret masking
- Audit Trail: Queue-based system (pg-boss) with async worker
- Request Logging: All requests logged with context
See Logging and Audit Logs for details.
Technology Stack
Backend: Express.js, PostgreSQL, Redis, JWT, Pino, pg-boss
Frontend: React 19, TypeScript, Vite, Tailwind CSS
Integration: OnlyOffice, Google OAuth