# jcreek/opennetworkdiagram architecture

> Architecture diagram of the GitHub repository jcreek/opennetworkdiagram, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-29). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/jcreek/opennetworkdiagram
- Repository: https://github.com/jcreek/opennetworkdiagram

## Overview

1. **Overall shape**
Open Network Diagram is a **SvelteKit-based single-page app** with a small **Node runtime server** for persistence. The app is designed around a JSON file as the source of truth, so the architecture is split between:
- a browser UI for viewing/editing diagrams,
- a server/API layer for loading and saving network data,
- static vendored assets for icons and demo data.

2. **Primary runtime modes**
The repo supports two meaningful deployment modes:
- **Self-hosted writable mode**: the UI edits `network.json` through the API and persists changes to disk.
- **Read-only/public mode**: used for demos or Netlify-style hosting, where the UI reads static data and writes are disabled.
This mode split is important because it changes whether the server’s persistence layer is active.

3. **UI layer**
The user-facing application lives under `src/routes` and `src/lib/components`. The main visible pieces are:
- `NetworkDiagram.svelte` for rendering the topology/diagram,
- `Modal.svelte` for editing machines/devices,
- route entry points in `+page.svelte` and `+layout.svelte`.
The UI is built to update the diagram live as the underlying JSON changes, rather than treating the diagram as a separate model.

4. **Data model and schema boundary**
The canonical data shape is defined in `src/lib/data/networkSchema.ts` and shared validation/core logic in `src/lib/shared/networkSchemaCore.mjs`. This is the boundary between arbitrary JSON input and the app’s internal expectations.
The schema covers the repository’s core entities: **machines, devices, VMs, software, hardware, ports, IP addresses, and roles**. This is the main contract that both UI editing and persistence must respect.

5. **Load/edit/save flow**
The data flow is:
- load JSON from the configured data source,
- validate/normalize it against the schema,
- let the UI edit it,
- persist the updated JSON back through the API/server.
`src/lib/data/loadNetworkData.ts` and `src/lib/data/networkEditor.ts` sit on the client-side data handling path, while `src/lib/server/networkPersistence.ts` and `src/lib/shared/networkPersistenceCore.mjs` handle the write path and atomic file operations.

6. **API boundary**
`src/routes/api/network-data/+server.ts` exposes the persistence API, documented in the README as `GET/PUT /api/network-data`.
This endpoint is the key boundary between browser state and durable storage:
- `GET` serves the current diagram JSON,
- `PUT` accepts edits from the UI,
- responses can include writability diagnostics when the app is running read-only.
The API is what makes the app usable both locally and in Docker with a mounted data volume.

7. **Diagram transformation pipeline**
The raw network JSON is not rendered directly. Instead, `src/lib/graph/transformNetworkData.ts` and `src/lib/graph/types.ts` convert the persisted schema into a graph-friendly structure for display.
This transformation layer is where the app derives diagram-specific concerns such as:
- node/edge relationships,
- network vs non-network presentation,
- VM expansion behavior,
- label/connection layout details.
It is a clear separation between stored domain data and visual representation.

8. **Icon system and local asset catalog**
The project includes a local icon registry in `src/lib/config/iconRegistry.ts` and a generated manifest in `src/lib/config/vendorIconManifest.ts`.
Icons are vendored into `static/icons/vendor` and sourced from `third_party/homarr-dashboard-icons`, with a helper script under `scripts/generate-vendor-icon-manifest.mjs`.
This means the UI does not depend on an external icon service at runtime, which matters for offline/self-hosted deployments.

9. **Theme and browser state**
The app has a small store layer in `src/lib/stores/theme.ts` for theme handling. This is client-side state only and is separate from the persisted network JSON.
That split helps keep local UX concerns distinct from the authoritative infrastructure model.

10. **Server/runtime packaging**
`server.mjs`, `Dockerfile`, `docker-compose.yml`, and `nginx/default.conf` indicate a deployment model where the built app can be served as a containerized Node/static app behind a web server.
The server is responsible for serving the UI and backing the API in writable deployments, while the Docker/compose setup mounts a host data directory so the JSON file survives restarts.

11. **Data locations and environment-specific sources**
There are three important data locations:
- `data/network.json.example` for seeding a new writable install,
- `data/network.json` for default local/server persistence,
- `static/data/network.json` for the bundled read-only/demo dataset.
This separation supports both local editing and static hosting without changing application code.

12. **Operational boundaries and CI/CD**
The repo’s GitHub workflows and build targets reflect two different artifacts:
- a **Docker/runtime artifact** for self-hosted writable use,
- a **static/Netlify artifact** for read-only demo hosting.
The build variants are important because they encode the app’s operational boundary: writable persistence is only available when the runtime can access a filesystem-backed data path.

13. **Architecture summary for diagramming**
If you draw this system, model it as:
- a **browser UI** at the center,
- a **JSON schema/domain layer** beneath it,
- a **transformation layer** from domain data to graph visuals,
- a **server/API persistence layer** on the side for GET/PUT to a JSON file,
- **vendored static icons and demo data** as supporting assets.
The most important conceptual boundary is that the diagram is a projection of persisted JSON, not a separate hand-authored drawing model.

Main entry points: [`src/routes/+page.svelte`](https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/+page.svelte) (App page), [`src/routes/api/network-data/+server.ts`](https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/api/network-data/+server.ts) (Network API), [`src/lib/components/NetworkDiagram.svelte`](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/components/NetworkDiagram.svelte) (Network diagram), [`src/lib/data/loadNetworkData.ts`](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/loadNetworkData.ts) (Load data)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_browser["Browser app"]
  node_page["App page<br/>route<br/>[+page.svelte]"]
  node_layout["Layout<br/>route shell<br/>[+layout.svelte]"]
  node_diagram["Network diagram<br/>view component"]
  node_modal["Edit modal<br/>editor component<br/>[Modal.svelte]"]
  node_loader["Load data<br/>client data<br/>[loadNetworkData.ts]"]
  node_editor["Editor state<br/>client model<br/>[networkEditor.ts]"]
  node_theme(("Theme store<br/>ui state<br/>[theme.ts]"))
end

subgraph group_domain["Domain model"]
  node_schema["Network schema<br/>[networkSchema.ts]"]
  node_schema_core["Schema core<br/>shared validation"]
  node_graph_transform["Graph transform<br/>projection"]
  node_graph_types["Graph types<br/>render types<br/>[types.ts]"]
end

subgraph group_persistence["Persistence"]
  node_api["Network API<br/>endpoint<br/>[+server.ts]"]
  node_server_persist["File storage<br/>server persistence"]
  node_persist_core["Persist core<br/>shared I/O"]
end

subgraph group_assets["Assets"]
  node_icon_registry["Icon registry<br/>asset catalog<br/>[iconRegistry.ts]"]
  node_icon_manifest["Icon manifest<br/>generated catalog"]
  node_static_icons[("Vendor icons<br/>static assets")]
  node_demo_data["Demo data<br/>static json<br/>[network.json]"]
  node_seed_data["Seed data<br/>example json"]
end

subgraph group_deployment["Deployment"]
  node_server_runtime["Server runtime<br/>node entry<br/>[server.mjs]"]
  node_docker["Container build<br/>deployment config"]
  node_nginx["Web server<br/>reverse proxy<br/>[default.conf]"]
  node_netlify["Static deploy<br/>hosting config<br/>[netlify.toml]"]
end

node_page -->|"uses shell"| node_layout
node_page -->|"loads data"| node_loader
node_page -->|"renders"| node_diagram
node_page -->|"edits"| node_modal
node_loader -->|"GET data"| node_api
node_loader -->|"fallback data"| node_demo_data
node_editor -->|"validates"| node_schema
node_schema -->|"shares rules"| node_schema_core
node_diagram -->|"projects"| node_graph_transform
node_graph_transform -->|"uses types"| node_graph_types
node_diagram -->|"icons"| node_icon_registry
node_icon_registry -->|"reads manifest"| node_icon_manifest
node_icon_manifest -->|"references"| node_static_icons
node_modal -->|"mutates"| node_editor
node_api -->|"writes"| node_server_persist
node_api -->|"delegates I/O"| node_persist_core
node_server_persist -->|"uses core"| node_persist_core
node_server_persist -->|"seeds"| node_seed_data
node_server_runtime -->|"serves endpoint"| node_api
node_server_runtime -->|"packaged by"| node_docker
node_docker -->|"fronted by"| node_nginx
node_netlify -->|"publishes"| node_demo_data
node_theme -->|"ui state"| node_page

click node_page "https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/+page.svelte"
click node_layout "https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/+layout.svelte"
click node_diagram "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/components/NetworkDiagram.svelte"
click node_modal "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/components/Modal.svelte"
click node_loader "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/loadNetworkData.ts"
click node_editor "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/networkEditor.ts"
click node_schema "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/networkSchema.ts"
click node_schema_core "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/shared/networkSchemaCore.mjs"
click node_graph_transform "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/graph/transformNetworkData.ts"
click node_graph_types "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/graph/types.ts"
click node_api "https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/api/network-data/+server.ts"
click node_server_persist "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/server/networkPersistence.ts"
click node_persist_core "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/shared/networkPersistenceCore.mjs"
click node_theme "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/stores/theme.ts"
click node_icon_registry "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/config/iconRegistry.ts"
click node_icon_manifest "https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/config/vendorIconManifest.ts"
click node_static_icons "https://github.com/jcreek/opennetworkdiagram/tree/main/static/icons/vendor"
click node_demo_data "https://github.com/jcreek/opennetworkdiagram/blob/main/static/data/network.json"
click node_seed_data "https://github.com/jcreek/opennetworkdiagram/blob/main/data/network.json.example"
click node_server_runtime "https://github.com/jcreek/opennetworkdiagram/blob/main/server.mjs"
click node_docker "https://github.com/jcreek/opennetworkdiagram/tree/main/Dockerfile"
click node_nginx "https://github.com/jcreek/opennetworkdiagram/blob/main/nginx/default.conf"
click node_netlify "https://github.com/jcreek/opennetworkdiagram/blob/main/netlify.toml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_page,node_layout,node_diagram,node_modal,node_loader,node_editor,node_theme toneBlue
class node_schema,node_schema_core,node_graph_transform,node_graph_types toneAmber
class node_api,node_server_persist,node_persist_core toneMint
class node_icon_registry,node_icon_manifest,node_static_icons,node_demo_data,node_seed_data toneRose
class node_server_runtime,node_docker,node_nginx,node_netlify toneIndigo
```

## Components

### Browser app

Client-side SvelteKit UI and state

- [App page](https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/+page.svelte): route · Top-level SvelteKit entry for the main diagram view · `src/routes/+page.svelte`
- [Layout](https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/+layout.svelte): route shell · Shared page shell and app framing · `src/routes/+layout.svelte`
- [Network diagram](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/components/NetworkDiagram.svelte): view component · Renders the topology and live diagram interactions · `src/lib/components/NetworkDiagram.svelte`
- [Edit modal](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/components/Modal.svelte): editor component · Machine and device editing UI · `src/lib/components/Modal.svelte`
- [Load data](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/loadNetworkData.ts): client data · Fetches and prepares network data for the UI · `src/lib/data/loadNetworkData.ts`
- [Editor state](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/networkEditor.ts): client model · Client-side mutation and normalization helpers · `src/lib/data/networkEditor.ts`
- [Theme store](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/stores/theme.ts): ui state · Client-only theme and appearance state · `src/lib/stores/theme.ts`

### Domain model

Shared schema and edit logic

- [Network schema](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/data/networkSchema.ts): schema · Canonical network JSON contract · `src/lib/data/networkSchema.ts`
- [Schema core](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/shared/networkSchemaCore.mjs): shared validation · Shared schema and validation logic · `src/lib/shared/networkSchemaCore.mjs`
- [Graph transform](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/graph/transformNetworkData.ts): projection · Turns persisted network JSON into renderable graph data · `src/lib/graph/transformNetworkData.ts`
- [Graph types](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/graph/types.ts): render types · Types for diagram nodes and edges · `src/lib/graph/types.ts`

### Persistence

Server-side JSON storage and API

- [Network API](https://github.com/jcreek/opennetworkdiagram/blob/main/src/routes/api/network-data/+server.ts): endpoint · GET and PUT API for the current network JSON · `src/routes/api/network-data/+server.ts`
- [File storage](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/server/networkPersistence.ts): server persistence · Atomic read/write persistence for the network file · `src/lib/server/networkPersistence.ts`
- [Persist core](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/shared/networkPersistenceCore.mjs): shared I/O · Shared JSON file operations and write semantics · `src/lib/shared/networkPersistenceCore.mjs`

### Assets

Vendored icons and demo data

- [Icon registry](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/config/iconRegistry.ts): asset catalog · Maps diagram entities to vendored icons · `src/lib/config/iconRegistry.ts`
- [Icon manifest](https://github.com/jcreek/opennetworkdiagram/blob/main/src/lib/config/vendorIconManifest.ts): generated catalog · Generated list of available vendor icons · `src/lib/config/vendorIconManifest.ts`
- [Vendor icons](https://github.com/jcreek/opennetworkdiagram/tree/main/static/icons/vendor): static assets · Bundled icon files used at runtime without external services · `static/icons/vendor`
- [Demo data](https://github.com/jcreek/opennetworkdiagram/blob/main/static/data/network.json): static json · Read-only bundled network dataset for demo or public hosting · `static/data/network.json`
- [Seed data](https://github.com/jcreek/opennetworkdiagram/blob/main/data/network.json.example): example json · Example JSON for a fresh writable install · `data/network.json.example`

### Deployment

Container and hosting packaging

- [Server runtime](https://github.com/jcreek/opennetworkdiagram/blob/main/server.mjs): node entry · Container or local Node server that serves the app and API · `server.mjs`
- [Container build](https://github.com/jcreek/opennetworkdiagram/tree/main/Dockerfile): deployment config · Docker image and compose setup for writable self-hosted use · `Dockerfile`
- [Web server](https://github.com/jcreek/opennetworkdiagram/blob/main/nginx/default.conf): reverse proxy · Nginx config used in packaged deployments · `nginx/default.conf`
- [Static deploy](https://github.com/jcreek/opennetworkdiagram/blob/main/netlify.toml): hosting config · Read-only public hosting configuration · `netlify.toml`

## Connections

- App page → Layout: uses shell · The main route is rendered inside the shared layout
- App page → Load data: loads data · The page initializes the current network state from the data source
- App page → Network diagram: renders · The page passes transformed state into the diagram view
- App page → Edit modal: edits · Editing flows open the modal from the page UI
- Load data → Network API: GET data · Client loading fetches current JSON from the API when writable mode is active
- Load data → Demo data: fallback data · Public or static mode can load the bundled dataset
- Editor state → Network schema: validates · Client edits are checked against the canonical schema
- Network schema → Schema core: shares rules · The UI schema builds on shared validation logic
- Network diagram → Graph transform: projects · Rendered graph state is derived from persisted network data
- Graph transform → Graph types: uses types · The projection emits the diagram-specific graph structure
- Network diagram → Icon registry: icons · Diagram nodes are decorated using the local icon catalog
- Icon registry → Icon manifest: reads manifest · The registry is backed by a generated icon list
- Icon manifest → Vendor icons: references · The manifest points to vendored icon assets
- Edit modal → Editor state: mutates · The edit modal updates the client-side network model
- Network API → File storage: writes · PUT requests are persisted to the server-side JSON store
- Network API → Persist core: delegates I/O · The endpoint relies on shared persistence operations
- File storage → Persist core: uses core · Server persistence is implemented on top of shared file logic
- File storage → Seed data: seeds · Fresh writable installs can start from the example JSON
- Server runtime → Network API: serves endpoint · The Node runtime hosts the network-data API
- Server runtime → Container build: packaged by · The runtime is the target of the containerized deployment
- Container build → Web server: fronted by · Packaged deployments include an Nginx layer
- Static deploy → Demo data: publishes · Static hosting uses the bundled read-only dataset
- Theme store → App page: ui state · Theme is client-only presentation state for the app
