A visual, node-based system / page relationship designer that lets teams map pages, their inputs/outputs, role-based visibility, and the arrows (data flow) that connect them. Built for OnSolve to document how internal systems, pages, and responsibilities fit together.
- Overview
- Features
- Technologies
- Architecture
- How It Works
- Data Model
- REST API
- Getting Started
- Docker
- Project Structure
- Mobile Handling
- License
The System Designer is a single-page diagramming tool where you:
- Add nodes β each node represents a page / system / module with a title, short meta, inputs, outputs, functionality notes, and the roles allowed to view it.
- Connect nodes with links β draw arrows (labeled data flows) from a source node to a target node.
- Persist automatically β every change is saved to MongoDB via a small Express REST API.
- Export / Import β download the whole diagram as JSON or a PNG snapshot, or paste JSON to restore.
It is intentionally desktop-only (mobile devices are shown a friendly "desktop required" screen).
| Feature | Description |
|---|---|
| π§© Visual Nodes | Draggable page cards showing title, meta, inputs, outputs, functions and roles. |
| π Link / Arrow Editor | Click New Link β click source β click target to create a labeled data-flow arrow. |
| π₯ Role Visibility | Each node can be tagged with roles (Staff, HR Team, Compliance Team, Accounts Team, Supervisor, Admin). |
| πΎ MongoDB Persistence | All nodes & links are stored in MongoDB with unique indexes on id. |
| π€ Export JSON / PNG | Export the full diagram to JSON (clipboard) or a rendered PNG snapshot. |
| π₯ Import JSON | Paste a previously exported diagram to restore state. |
| π§ Auto-layout | "Center All" arranges nodes in a tidy grid automatically. |
| ποΈ Reset / Clear | Reset to sensible seed defaults or clear the entire database. |
| π± Mobile Gating | Server- and client-side detection redirects mobile users to a blocking screen. |
| π³ Docker Ready | Ships with a minimal node:18-alpine Dockerfile. |
| Layer | Stack |
|---|---|
| Backend | Node.js, Express 4, MongoDB Driver 6 |
| Database | MongoDB (Atlas or self-hosted) |
| Frontend | Vanilla JavaScript (ES Modules), SVG, HTML5, CSS3 |
| Rendering | SVG <path> BΓ©zier curves for links, HTML foreignObject for PNG export |
| Containerization | Docker (node:18-alpine) |
| Tooling | npm, nodemon (dev), git |
flowchart TB
subgraph Browser["π Browser (Client)"]
UI["index.html + app.js<br/>(SVG Canvas, Node Editor)"]
end
subgraph Server["π₯οΈ Node.js / Express"]
API["REST API<br/>/api/state, /api/node, /api/link, /api/clear"]
UA["Mobile UA Detection<br/>(serves mobile-block.html)"]
end
subgraph DB["π MongoDB"]
NODES[("nodes collection<br/>unique index: id")]
LINKS[("links collection<br/>unique index: id")]
end
UI -- "fetch() GET/POST/DELETE" --> API
API -- "CRUD" --> NODES
API -- "CRUD" --> LINKS
Browser -- "GET / (mobile UA)" --> UA
UA -- "mobile-block.html" --> Browser
sequenceDiagram
participant U as User
participant B as Browser (app.js)
participant S as Express Server
participant M as MongoDB
U->>B: Open app (desktop)
B->>S: GET /api/state
S->>M: find() nodes + links
M-->>S: documents
S-->>B: { nodes, links }
B->>B: renderNodes() + renderLinks() (SVG)
U->>B: Add Node / New Link / Edit
B->>B: update in-memory model
B->>S: POST /api/node or /api/link
S->>M: upsert document
M-->>S: ok
S-->>B: { ok: true }
B->>B: setStatus("Saved β")
U->>B: Drag node
B->>B: update position (pointer events)
B->>S: POST /api/state (bulk upsert)
S->>M: bulkWrite nodes + links
In short:
- On load, the browser fetches the full diagram state from
/api/state. - The UI renders nodes as absolutely-positioned HTML cards and links as SVG BΓ©zier curves between node centers.
- Every user action updates an in-memory model and immediately persists it to MongoDB through the REST API.
- On failure (e.g. DB down), the client keeps a local copy and falls back to seed defaults so the UI never breaks.
| Field | Type | Notes |
|---|---|---|
id |
string | Unique business key (indexed) |
title |
string | Page / module name |
meta |
string | Short description |
inputs |
string (JSON) | Array of input labels |
outputs |
string (JSON) | Array of output labels |
left / top |
number | Canvas position |
roles |
string (JSON) | Array of visible roles |
functions |
string | Page responsibilities / notes |
| Field | Type | Notes |
|---|---|---|
id |
string | Unique business key (indexed) |
from_node |
string | Source node id |
to_node |
string | Target node id |
label |
string | Data-flow description |
Note: arrays are stored as JSON strings in Mongo and re-hydrated by the API mappers (
mapDbNodeDoc/mapDbLinkDoc).
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/state |
Fetch all nodes + links |
POST |
/api/state |
Bulk upsert nodes + links |
POST |
/api/node |
Create / update a single node |
DELETE |
/api/node/:id |
Delete a node and its links |
POST |
/api/link |
Create / update a single link |
DELETE |
/api/link/:id |
Delete a link |
DELETE |
/api/clear |
Delete all nodes + links |
Example:
curl -X POST http://localhost:3000/api/node \
-H "Content-Type: application/json" \
-d '{"id":"login","title":"Login Page","roles":["Admin","Staff"],"inputs":["credentials"],"outputs":["auth token"],"left":60,"top":48,"functions":"Authenticate users"}'- Node.js 18+
- A MongoDB instance (local or Atlas)
# 1. Install dependencies
npm install
# 2. (Optional) Configure environment
export MONGO_URI="mongodb://localhost:27017"
export DB_NAME="system_diagram_db"
export PORT=3000
# 3. Start the server
npm start
# or with auto-reload:
npm run dev
# 4. Open in a desktop browser
# http://localhost:3000If no
MONGO_URIis provided, the app falls back to a built-in connection string (seeserver.js). Override it for production.
# Build image
docker build -t system-designer .
# Run container
docker run -d -p 3000:3000 \
-e MONGO_URI="mongodb://your-host:27017" \
-e DB_NAME="system_diagram_db" \
--name system-designer \
system-designerThen open http://localhost:3000 on a desktop.
System-Designer---OnSolve/
βββ server.js # Express server + MongoDB API + mobile gating
βββ package.json # Dependencies & scripts
βββ Dockerfile # node:18-alpine container
βββ public/
βββ index.html # Main editor UI
βββ app.js # Frontend logic (ES module)
βββ styles.css # Theme & layout
βββ mobile-block.html # Shown to mobile visitors
The app is desktop-only for editing. Two layers of protection:
- Server-side β
server.jsinspects theUser-Agentheader and servesmobile-block.html(a branded "use a desktop" video screen) to mobile devices. - Client-side β
index.htmlandapp.jsalso detect mobile UA / small viewport and immediately redirect or hide the editor.
This guarantees mobile users never hit the heavy editing canvas.
Q: Why is the app desktop-only? A: The node editor relies on a large draggable canvas and precise pointer interactions that aren't well-suited to touch screens. Mobile visitors see a branded "use a desktop" screen instead.
Q: Where is my data stored?
A: Every node and link lives in MongoDB (nodes and links collections). There is no local file storage.
Q: Can I self-host the database?
A: Yes. Point MONGO_URI at any MongoDB instance β local, Dockerized, or Atlas.
Q: What happens if MongoDB is down? A: The UI falls back to seed defaults so you can still explore the editor; changes won't persist until the DB is reachable.
- Fork the repository and create a feature branch.
- Make your changes with clear, focused commits.
- Ensure
npm startboots and the editor loads on desktop. - Open a pull request describing the change and its motivation.
Please keep the desktop-only scope in mind and avoid introducing mobile editing until the roadmap items (e.g. responsive canvas) are addressed.
- Node DOM elements are cached in a
nodeElementsmap and only created/removed when the node set changes, avoiding full re-renders. - Links are re-rendered as lightweight SVG
<g>groups on every change; link hit-areas use a transparent, wide stroke for easy clicking. - The board is a large scrollable surface (
2000Γ1500minimum) so diagrams can grow without layout thrash. - PNG export rasterizes the live SVG + HTML nodes via
foreignObject, keeping the snapshot faithful to the on-screen design.
The client is built to stay usable even when the backend is unavailable:
- DB connection failure β
server.jslogs the error but still serves static files; API calls return500with a detail message. - Fetch failure β
app.jsfalls back to the built-in seed defaults so the canvas still renders. - Save failure β if a single-node/link save fails, the app retries with a bulk
POST /api/statebefore warning the user. - Delete failure β the UI re-fetches state from the DB to stay consistent with the server.
On first load (or after Reset), the app seeds a small example system for OnSolve:
| Node | Purpose | Visible To |
|---|---|---|
| Login Page | Authenticates users | Admin, Staff |
| Dashboard | Main app landing | Admin, Staff, Supervisor |
| Student Management | CRUD student records | Admin, Staff |
| Attendance | Record & view attendance | Admin, Staff |
| Reports | Generate PDF / CSV exports | Admin, Supervisor |
Links connect Login β Dashboard β Students β Attendance β Reports, plus Students β Reports, illustrating the data flow across the example system.
| Button | Behavior |
|---|---|
+ Add Node |
Prompts for a title and drops a new node in the visible canvas area |
+ New Link |
Enters link mode; click source then target to create an arrow |
Export JSON |
Copies the full diagram JSON to the clipboard |
Export PNG |
Renders the board (nodes + links) to a downloadable PNG |
Import |
Replaces the current diagram with pasted JSON |
Reset |
Restores the seed-default example diagram |
Center All |
Rearranges all nodes into a grid automatically |
Clear All |
Deletes every node and link from the database |
Planned and possible enhancements:
- Multi-user collaboration (real-time sync via WebSockets)
- Version history / snapshots of the diagram
- Role-based access control enforced server-side
- Read-only shareable links
- Export to other formats (SVG, PDF, Mermaid)
- Undo / redo stack in the editor
| Script | Command | Description |
|---|---|---|
npm start |
node server.js |
Run the production server |
npm run dev |
nodemon server.js |
Run with auto-reload on file changes |
| Variable | Default | Description |
|---|---|---|
PORT |
3000 |
Port the Express server listens on |
MONGO_URI |
built-in Atlas string | MongoDB connection string |
DB_NAME |
system_diagram_db |
Target database name |
Set these in your shell or a .env file (loaded by your process manager) before starting the server.
This project is licensed under the MIT License β see the LICENSE file for details.
Built for OnSolve β visualize your systems, one node at a time.