Copy disabled (too large)
Download .txt
Showing preview only (12,044K chars total). Download the full file to get everything.
Repository: gelatinescreams/The-One-File
Branch: main
Commit: 976c1bf2a495
Files: 77
Total size: 11.5 MB
Directory structure:
gitextract_emfbp7w9/
├── .gitattributes
├── .github/
│ └── workflows/
│ └── docker-publish.yml
├── LICENSE
├── README.md
├── changelog.md
├── demos/
│ ├── csv-exports/
│ │ ├── the-one-file-corporate.csv
│ │ ├── the-one-file-homelab.csv
│ │ ├── the-one-file-networkening-corporate.csv
│ │ └── the-one-file-networkening-homelab.csv
│ ├── index.html
│ ├── json-exports/
│ │ ├── the-one-file-corporate-demo.json
│ │ ├── the-one-file-homelab-demo.json
│ │ ├── theonefile-networkening-corporate-demo.json
│ │ └── theonefile-networkening-homelab-demo.json
│ ├── markdown-exports/
│ │ ├── the-one-file-corporate.md
│ │ ├── the-one-file-homelab.md
│ │ ├── the-one-file-networkening-corporate.md
│ │ └── the-one-file-networkening-homelab.md
│ └── password-protected/
│ ├── password.txt
│ ├── the-one-file-corporate-demo.html
│ ├── the-one-file-homelab-demo.html
│ ├── theonefile-networkening-corporate-demo.html
│ └── theonefile-networkening-homelab-demo.html
├── import-export-save.md
├── keyboard-shortcuts.md
├── mobile-gestures.md
├── the-one-file.html
├── theonefile-networkening.html
└── theonefile_verse/
├── .dockerignore
├── .gitattributes
├── Dockerfile
├── README.md
├── api.md
├── changelog.md
├── demo-admin.html
├── docker-compose.yml
├── entrypoint.sh
├── package.json
├── public/
│ ├── admin-auth.js
│ ├── admin-dashboard.js
│ ├── admin-pages.js
│ ├── collab-init.js
│ ├── collab-save-hook.js
│ ├── collab.css
│ ├── collab.js
│ ├── index.html
│ ├── landing.js
│ └── theonefile.html
├── redis.conf
└── src/
├── auth.ts
├── config.ts
├── database.ts
├── index.ts
├── mailer.ts
├── network.ts
├── oidc.ts
├── rate-limit.ts
├── redis.ts
├── rooms.ts
├── routes/
│ ├── admin-apikeys.ts
│ ├── admin-auth-settings.ts
│ ├── admin-auth.ts
│ ├── admin-backups.ts
│ ├── admin-logs.ts
│ ├── admin-rooms.ts
│ ├── admin-settings.ts
│ ├── admin-users.ts
│ ├── instance-access.ts
│ ├── network-routes.ts
│ ├── public.ts
│ ├── room.ts
│ ├── setup.ts
│ └── user-auth.ts
├── security.ts
├── templates.ts
├── tokens.ts
└── websocket.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
*.min.js -diff
*.min.css -diff
================================================
FILE: .github/workflows/docker-publish.yml
================================================
name: Build TheOneFile Verse
on:
push:
branches:
- main
- master
paths:
- 'theonefile_verse/**'
- '.github/workflows/docker-publish.yml'
create:
tags:
- 'v*'
release:
types: [published]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/theonefile_verse
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,format=short
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ./theonefile_verse
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
================================================
FILE: LICENSE
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>
- GelatineScreams
================================================
FILE: README.md
================================================
<p align="center">
<img src="https://img.shields.io/badge/License-Unlicense-576169?style=for-the-badge&labelColor=01284b" alt="License: Unlicense">
<img src="https://img.shields.io/badge/TheOneFile-4.1.5-blue" alt="TheOneFile 4.1.5">
<a href="https://github.com/gelatinescreams/The-One-File/tree/main/theonefile_verse">
<img src="https://img.shields.io/badge/TheOneFile_Verse-1.9.0-blue" alt="TheOneFile_Verse Docker Version 1.9.0">
</a>
</p>

There can only be One File. Map networks, smart homes, sports plays, mind maps, infrastructure or anything with nodes and connections. Animated zones, replay video export, enterprise encryption, full styling. Works offline, opens anywhere, saves into itself.
*The Networkening edition adds live status monitoring and icons from [selfh.st/icons](https://selfh.st/icons/), [MDI](https://pictogrammers.com/library/mdi/), and [Simple Icons](https://simpleicons.org/).* Still one file.
*TheOneFile_Verse adds an easily deployable, Docker based, real time collaboration wrapper that enables multiple users to create, edit and share together!
   
### Version 4.1.5 /\ 3-26-26 : Enhanced 'Create', UI polish and squashing a sneaky bug and TheOneFile_Verse 1.8.6
* **Enhanced Create**
* Added more options to the Create New Node & Rack modals.
* Added icon preview box to the Create New Node & Rack modals.
* **Bug Fixes**
* **Core Edition & Networkening**
* Fixed Assigned Rack dropdown snapping back to "None" after changing in the edit Node and Rack sidebar/footer
* See [Changelog](changelog.md) for full update details
### TheOneFile_Verse /\ 1.8.6 3-26-26 : Further improvements to Network Auto Discovery scanner/editor one page setup
* Very close to a stable 2.0
* See [TheOneFile_Verse changelog](theonefile_verse/changelog.md) for full 1.8.6 list
<img width="1525" height="770" alt="Screenshot 2026-03-11 094906" src="https://github.com/user-attachments/assets/43196f4e-f6c4-4d9d-aae0-d311b2bf94ec" />
<img width="1521" height="770" alt="Screenshot 2026-03-11 094937" src="https://github.com/user-attachments/assets/c47e1cea-dd33-47ac-ac62-cef7fe92e3a3" />
### Demos
* **Core Edition**
* [Core: Corporation Demo](https://therecanonlybe.one/demos/?version=core&demo=corporate)
* [Core: Homelab Demo](https://therecanonlybe.one/demos/?version=core&demo=homelab)
* **Networkening Edition**
* [Networkening: Corporate Demo](https://therecanonlybe.one/demos/?version=networkening&demo=corporate)
* [Networkening: Homelab Demo](https://therecanonlybe.one/demos/?version=networkening&demo=homelab)
* **TheOneFile_Verse Edition**
* [TheOneFile_Verse online demo](https://multiverse.therecanonlybe.one/s/2ab95062-9d96-4e32-b373-d1994c210d82)
* *join from different browsers to see real time changes*
* [TheOneFile_Verse landing page](https://multiverse.therecanonlybe.one)
* [TheOneFile_Verse admin demo](https://therecanonlybe.one/theonefile_verse/demo-admin.html)
### Download
* [the-one-file.html](https://github.com/user-attachments/files/26288480/the-one-file.html)
* [theonefile-networkening.html](https://github.com/user-attachments/files/26288482/theonefile-networkening.html)
### Core vs Networkening vs TheOneFile_Verse
| Feature | theonefile.html | theonefile-networkening.html | TheOneFile_Verse |
|---------|---------|--------|--------|
| All core features | ✓ | ✓ | ✓ |
| Create/edit/save topologies | ✓ | ✓ | ✓ |
| Shapes, lines, styling | ✓ | ✓ | ✓ |
| U slot rack topologies | ✓ | ✓ | ✓ |
| **Add text labels anywhere** | ✓ | ✓ | ✓ |
| **Draw rectangles/boxes** | ✓ | ✓ | ✓ |
| **Free draw custom lines** | ✓ | ✓ | ✓ |
| **Keyboard shortcuts** | ✓ | ✓ | ✓ |
| Encryption, export | ✓ | ✓ | ✓ |
| Bulk operations | ✓ | ✓ | ✓ |
| Multi select | ✓ | ✓ | ✓ |
| **AES 256 GCM encryption (OPTIONAL)** | ✓ | ✓ | ✓ |
| Live node search | ✓ | ✓ | ✓ |
| Per device styling | ✓ | ✓ | ✓ |
| Mobile optimized | ✓ | ✓ | ✓ |
| Offline only | ✓ | | ✓ |
| No dependencies | ✓ | | ✓ |
| **[MDI Icons](https://pictogrammers.com/library/mdi/)** | | ✓ | ✓ |
| **[Simple Icons](https://simpleicons.org/?q=ping)** | | ✓ | ✓ |
| **[selfh.st/icons](https://selfh.st/icons/)** | | ✓ | ✓ |
| **Auto Status Checking** | | ✓ | ✓ |
| **Live Ping/Health Status** | | ✓ | ✓ |
| **Real time, multi user collaboration** | | ✓ | ✓ |
### Docker & TheOneFile_Verse
```bash
docker run -d -p 10101:10101 -v theonefile-data:/app/data ghcr.io/gelatinescreams/theonefile_verse:latest
```
Or with docker compose, create a `docker-compose.yml`:
```yaml
services:
theonefile_verse:
image: ghcr.io/gelatinescreams/theonefile_verse:latest
ports:
- "10101:10101"
volumes:
- ./data:/app/data
restart: unless-stopped
```
Then run:
```bash
docker compose up -d
```
Open `http://localhost:10101`
* [More information on TheOneFile_Verse](https://github.com/gelatinescreams/The-One-File/tree/main/theonefile_verse)
### Core + Networkening Editions Download:
* Core [the-one-file.html](https://github.com/user-attachments/files/24578723/the-one-file.html)
* Networkening [theonefile-networkening.html](https://github.com/user-attachments/files/24578724/theonefile-networkening.html)
### Features
* Zero coding knowledge required
* Zero config files
* Draw anywhere: add text labels, boxes, and custom lines to annotate your topology
* Full keyboard shortcut support for power users
* Advanced keyboard navigation with arrow keys, tab cycling, and focus controls
* Node locking to prevent accidental changes to positioned elements
* Node grouping to move related components together
* Touch optimized mobile interface with gesture support
### Canvas and Navigation
* Large zoomable and pannable workspace
* Minimap with viewport tracking
* Works with touch and mobile
* Clear grid and boundary indicators
* Precise zoom controls with level display
* Right click context menu for quick actions
* **Free Draw Mode** Draw custom polylines, rectangles, and text labels anywhere:
* Custom lines with points you place
* Rectangles (filled or outlined) for zones/boundaries
* Text labels with full styling (font, size, color, weight, alignment)
* Customizable colors, line styles (solid/dashed/dotted), and arrows
* Keyboard shortcuts for power users (undo/redo, copy/paste, zoom controls, node navigation)
* **Arrow key nudging** for pixel perfect positioning (1px or 10px with Shift)
* **Tab cycling** to quickly navigate through all nodes
* **Focus key** to auto zoom to selected nodes
### Nodes
* Multiple shapes for common devices including servers, routers, switches, firewalls, and clouds
* *Icon shapes from MDI, Simple Icons, and selfh.st/icons available in the theonefile-networkening.html version*
* Editable name, IP, role, tags, and notes
* *Editable icon shapes from MDI, Simple Icons, and selfh.st/icons available in the theonefile-networkening.html version*
* Resizable with full styling controls
* Custom fonts, colors, and text offsets
* **Per breakpoint styling** for desktop, tablet, mobile, and fold layouts : customize appearance independently for each screen size
* **Right click to clone** nodes with smart positioning
* **Multi select support** with click drag or right click selection
* **Lock nodes** to prevent accidental movement while editing
* **Group nodes** to move multiple related nodes as a single unit
* Visual indicators for locked and grouped nodes
#### Racks
* Create rack nodes to represent physical server racks
* Enter rack view by double clicking a rack node (or long press on mobile)
* Inside rack view, see a vertical rack with U unit markings
* Assign devices to specific U positions within racks
* Set device height in rack units (1U, 2U, 4U, etc.)
* Visual rack capacity indicator shows available vs used space
* Nodes assigned to racks appear in both topology and rack views
* Quick navigation: double tap empty space on mobile to exit rack view
* Automatic rack assignment when creating nodes while in rack view
### Layer System
* Choose between physical, logical, security and application layers for anything and easily toggle visibility between them
* Toggle layer visibility to focus on specific aspects of your topology
* Filter view to show only nodes and connections in selected layers
* Simplifies complex topologies by letting you focus on one aspect at a time
#### Lock and Group System
* **Lock individual or multiple nodes** to prevent accidental movement
* Visual lock indicator appears on locked nodes
* Locked nodes cannot be moved by mouse, touch, or keyboard
* Keyboard shortcut (L) for quick lock/unlock
* Works with multi selection for batch locking
* Lock button in mobile multi select menu
* **Group nodes to move together**
* Create groups of related nodes that move as a unit
* Visual group indicator (dashed outline) on grouped nodes
* Drag any member of a group to move all nodes in that group
* Keyboard shortcut (G) to create/dissolve groups
* Groups respect individual node lock status
* Group button in mobile multi select menu
* Perfect for logical grouping (clusters, zones, related infrastructure)
### Bulk Operations
* **Multi select nodes** for batch operations
* **Bulk Align**: Align selected nodes left, right, top, or bottom
* **Bulk Distribute**: Evenly space nodes horizontally or vertically
* **Bulk Clone**: Duplicate multiple nodes at once
* **Bulk Delete**: Remove multiple nodes simultaneously
* **Bulk Lock**: Lock or unlock multiple nodes at once
* **Bulk Group**: Create or dissolve node groups
* **Desktop and mobile toolbars** optimized for each platform
### Network Monitoring *(theonefile-networkening.html only)*
* **Live status indicators** on nodes (online/offline/checking)
* **Manual ping/status check** for individual nodes
* **Auto Status Checking** with configurable intervals (5-3600 seconds)
* Status check scheduling with next check timer
* Last run timestamp tracking
* Per node ping enable/disable settings
* Visual ping indicators with color coding
### Connections
* Smart routed lines between nodes
* Multiple links between the same devices
* Optional direction arrows
* Custom width, color, and labels
* Port labels (e.g., eth0, gi0/1)
* Notes for VLANs, protocols, policies, and bandwidth
### Legend (Bottom left)
* Can be hidden on both desktop and mobile
* Automatically built from line colors in use
* Editable labels
* note: only shows up after first line is generated.
### Save System
* Exports a brand new updated HTML file
* All data is embedded in the file
* Optional AES 256 GCM encryption for sensitive information
* Browser native crypto only
* No servers involved
* *Version theonefile-networkening.html uses 3 server calls from cdn.jsdelivr.net to load icons*
### Security & Encryption
**Industry Standard Protection:**
* **AES 256 GCM** encryption (authenticated encryption with 256 bit keys)
* **PBKDF2** key derivation with:
* 200,000 iterations (protection against brute force attacks)
* SHA 256 hashing algorithm
* Cryptographically secure random 16 byte salt per file
* Unique 12 byte initialization vector (IV) per encryption
* **Browser native Web Crypto API** no third party encryption libraries
* **Zero server communication** all encryption/decryption happens locally in your browser
* **Password confirmation** required before saving encrypted files
* **Non recoverable** no backdoors, no password reset, no recovery options
* If you forget your password, your data is permanently inaccessible
* This is a feature, not a bug so your data stays protected
* **3 attempt limit** on decryption to prevent brute force attempts
* **Encrypted data format**: Salt + IV + ciphertext embedded directly in the HTML file
### Mobile Experience
* **Completely rewritten mobile UI** in version 3.0
* **Resizable mobile footer** with drag handle for custom panel sizing
* **Touch optimized controls** throughout the interface
* **Mobile bulk operations modal** for efficient multi node editing with Lock and Group buttons
* **Enhanced double tap gestures**:
* Double tap nodes to select multiple (equivalent to right click on desktop)
* Double tap to clone and align nodes
* **NEW: Double tap empty space in rack view to quickly exit to topology view**
* Responsive layout that adapts to screen orientation
* Optimized for phones, tablets, and foldable devices
* Smart gesture detection prevents accidental actions during panning
### Keyboard Shortcuts
[keyboard-shortcuts.md](keyboard-shortcuts.md)
| Shortcut | Action |
|----------|--------|
| `Arrow Keys` | Move selected node(s) 1 pixel |
| `Shift + Arrow Keys` | Move selected node(s) 10 pixels |
| `Tab` | Cycle to next node |
| `Shift + Tab` | Cycle to previous node |
| `F` | Focus camera on selected node(s) |
| `L` | Lock/unlock selected node(s) |
| `G` | Group/ungroup selected nodes (requires 2+) |
| `Ctrl/Cmd + Z` | Undo |
| `Ctrl/Cmd + Y` | Redo |
| `Ctrl/Cmd + Shift + Z` | Redo (alternative) |
| `Ctrl/Cmd + C` | Copy selected node |
| `Ctrl/Cmd + V` | Paste node |
| `Ctrl/Cmd + D` | Duplicate selected node |
| `Ctrl/Cmd + A` | Select all nodes |
| `Ctrl/Cmd + Plus` | Zoom in |
| `Ctrl/Cmd + Minus` | Zoom out |
| `Ctrl/Cmd + 0` | Reset view |
| `Space + Drag` | Pan canvas |
| `Escape` | Clear selection |
| `Delete` | Delete selected item(s) |
| `Scroll` | Zoom in/out |
| `Shift + Click/Drag` | Multiple Select (marquee selection) |
## Recording
| Key | Action |
|-----|--------|
| R | Start/stop real time recording |
| Shift+R | Start/stop step by step recording |
| Space | Add step (step recording) / Play/Pause (playback) |
| P | Play recording |
### Mobile Gestures & Touch Controls
[mobile-gestures.md](mobile-gestures.md)
| Gesture | Action | Context |
|---------|--------|---------|
| **Double tap node** | Add to multi selection | Any view |
| **Double tap empty space** | Exit to topology view | Rack view only |
| **Long press rack node** | Enter rack view | Topology view |
| **Pinch** | Zoom in/out | Any view |
| **One finger drag (empty space)** | Pan canvas | Any view |
| **One finger drag (node)** | Move node | Any view |
| **Tap selected node** | Open properties panel | Any view |
| **Drag footer handle** | Resize mobile panel | Mobile only |
### Customization
* 100% control theme editor
* Per breakpoint node styling for responsive designs
* Custom color schemes and backgrounds
* Adjustable panel sizes and layouts
### Supported Browsers
* Chrome and Edge
* Firefox
* Safari desktop and mobile
* Modern Android and iOS browsers
If the browser is reasonably modern, it should work.
### Credits
Icon support for theonefile-networkening.html version powered by:
* [selfh.st/icons](https://selfh.st/icons/) : Popular self hosted icons
* [Material Design Icons](https://pictogrammers.com/library/mdi/) : 7,000+ open source icons
* [Simple Icons](https://simpleicons.org/) : Free SVG icons for popular brands
Thank you to all the icon creators and maintainers for making these resources freely available.
================================================
FILE: changelog.md
================================================
#### CHANGE LOG
### Version 4.1.5 /\ 3-26-26 Enhanced 'Create', UI polish and squashing a sneaky bug and TheOneFile_Verse 1.8.6
* **Enhanced Create**
* Added more options to the Create New Node & Rack modals.
* Added icon preview box to the Create New Node & Rack modals.
* **Bug Fixes**
* **Core Edition & Networkening**
* Fixed Assigned Rack dropdown snapping back to "None" after changing in the edit Node and Rack sidebar/footer
* **TheOneFile_Verse 1.8.6** Further improvements to Network Auto Discovery scanner/editor
* See [TheOneFile_Verse changelog](theonefile_verse/changelog.md) for full details
### Version 4.1.4 /\ 3-4-26 Testers finding the stragglers. Thank you to everyone!
* Added custom port label logic to the canvas that allows port labels to find the next blank space automatically. (this is v1 and will likely be upgraded). Thanks to [jbr1989](https://github.com/jbr1989) [#44](https://github.com/gelatinescreams/The-One-File/issues/44)
* Fixed an issue where port maps were not showing on the canvas. Thanks to [jbr1989](https://github.com/jbr1989) [#44](https://github.com/gelatinescreams/The-One-File/issues/44)
* Fixed an issue where port maps were not displaying correctly in b&w print preview. Thanks to [jbr1989](https://github.com/jbr1989) [#44](https://github.com/gelatinescreams/The-One-File/issues/44)
* Added version number to the bottom of settings modal for better versioning and TheOneFile_Verse tracking Thanks to [jbr1989](https://github.com/jbr1989) [#43](https://github.com/gelatinescreams/The-One-File/issues/43)
* **Core Edition**
* Fixed an issue where connections dropdown were not displaying correctly in node and rack information panel(s)
* **TheOneFile_Verse 1.8.0** Added a few settings, fixed some bugs, annoyances, security and production friendly hierarchical structure
* See [TheOneFile_Verse changelog](theonefile_verse/changelog.md) for full details
### Version 4.1.3 /\ 2-14-26 Styles, bugs and TheOneFile_Verse 1.5.2
* Fixed an issue where scrolling down on modals was not possible on some mobile environments
* Fixed an issue where draw and add connection buttons would show at inverse times
* Fixed an issue where the draw button would dissapear on mobile in some rare cases during import
* Fixed an issue where JSON import was not working in networkening edition
* Fixed one (1) missing and incorrect language keys from networkening edition
* **New Demo**
* **TheOneFile_Verse 1.5.2** Auth flow fixes, error logging, version tracking
* See [TheOneFile_Verse changelog](theonefile_verse/changelog.md) for full details
### Version 4.1.2 /\ 1-12-26 Image support, Notes Enhancements and Squashing Bugs
* **Image System**
* New image upload icon added to toolbar
* Drag and drop images added to canvas
* Each image has their own customizable styles
* Images are compressed for the one file purpose. NOT FOR ARCHIVING!
* **Notes System Enhancements**
* Added rich text editor to all notes
* Added notes linking to main notes hub with notes search
* Added search to all individual notes sections
* **Bug Fixes**
* Fixed outlined zones rendering on top of nodes
* Fixed z order issue where outlined zones appeared above nodes and racks
* Fixed wall style overwriting opacity with hardcoded value
* Fixed recordings not saving with HTML export in some rare cases
* Fixed and issue where zones and text labels not captured in recordings
* **Core Edition**
* Fixed errant translation keys for the language system
* **Networkening Edition**
* Fixed Zone line style dropdown not working. Big thank you to legendary tester [mohacc2008-ctrl](https://github.com/mohacc2008-ctrl)
* Fixed z order issue where outlined zones appeared above nodes and racks
* Fixed four (4) missing and incorrect language keys
### Version 4.1.1 /\ 1/12/26 Step by step recording
* **Added step by step recording**
* Step by step recording mode (green ●+ button) for manual frame capture
* Each step plays for 1 second in playback
* Keyboard shortcuts for recording: R (real time), Shift+R (step), Space (add step/play/pause), P (play)
### Version 4.1.0 /\ 1/12/26 The Vision Converges
* **Added custom language system**
* full GUI for language editing
* or import/export via json
* language system available in the main settings menu
* more translations are coming in the future
* **Expanded Mapping Modes**
* added Sports, MindMap, Smart Home and Blueprint
* each with their own custom sports grid
* **Expanded Grid System**
* new network grids available : dots, blueprint
* new sports grids available : basketball, american football, football(soccer), hockey, baseball, tennis
* **Full motion recording system**
* record and play back different situations on your map type
* saves replays to your data and/or export them as movies (webm)
* **Orthogonal Overhaul** Complete rewrite of the entire connections system.
* Create waypoints anywhere on the connection and drag it around.
* custom script that re evaluates routing in real time, no matter how many way points you need.
* double click on desktop and long press on mobile
* **Added a new welcome modal to make map mode switching easier**
* each tab has its own mapping type. unlimited options
* **Tons of performance tweaks**
* updated preset themes
* **Added new demo browser**
* **Tons Of visual fixes**
* **Added new print color option**
* **TheOneFile_Verse enhancements + fixes** [More information on TheOneFile_Verse](https://github.com/gelatinescreams/The-One-File/tree/main/theonefile_verse)
### Version 4.0.0 /\ 1/6/26 Stable + TheOneFile_Verse
* **4.0.0 Stable! Thank you to everyone!**
* **TheOneFile_Verse launch** An easily deployable, Docker based, real time collaboration wrapper that enables multiple users to work together!
* [TheOneFile_Verse online demo](https://multiverse.therecanonlybe.one/s/b208667b-7a9e-4a18-ac98-5cb6e73bb669)
* *join from different browsers to see real time changes*
* [More information on TheOneFile_Verse](https://github.com/gelatinescreams/The-One-File/tree/main/theonefile_verse)
* **Fixed an issue where nodes and racks did not display correctly in print export**
* **I am working on new demos with all the included features**
### Version 3.9.9.9 /\ 12/29/25 Upgraded Animations, minimap and editable options
* **Coverage zones now work on 11 device types**
* Camera, CCTV, Doorbell
* Motion Sensor, Smoke Detector
* Access Point, WiFi, Router
* Sensor, IoT, Sprinkler
* **Added new editable Detection Zone properties**
* Inner Radius : Add inner dead spots to zones
* Opacity : Control zone fill transparency
* Gradient Fade : Zone fades from center to edge
* Border Color : Separate color for zone outline
* Border Width : Thickness of zone outline
* Border Style : Solid, dashed, or dotted outlines
* Border Opacity : Transparency of zone outline
* **Added text labels to coverage zones**
* **Added editable text labels properties to coverage zones**
* **Added animation types**
* Sweep : Pan back and forth
* Pulse : Breathing/scale effect
* Rings : Expanding circles emanating outward
* Spin : Continuous rotation
* **Added Zone Presets**
* Security Cam, PTZ Cam, Motion Detect
* WiFi Strong, WiFi Extended
* Smoke Alarm, Sprinkler Arc
* **Save your own custom presets!**
* **Added new Bulk Operations for zones**
* Bulk Copy : Copy zone style from first selected node
* Bulk Paste : Apply copied style to all selected nodes
* Bulk Toggle : Enable/disable zones on all selected nodes
* **Updated Line legend to includes zones**
* Auto generated legend showing zone colors
* Editable labels for each zone color
* Click color swatch to select nodes with that zone color for faster editing
* **New Main Settings : Animations & Zones**
* Master toggles (all animations, all zones)
* Type toggles (sweep, pulse, rings, spin, connections)
* Category toggles (cameras, doorbells, motion sensors, smoke detectors, wifi/AP/router, sensors/IoT, sprinklers)
* **Minimap Improvements**
* Removed all animations and coverage zones from minimap (performance improvemnet and useless visually)
* Simplified node shapes in minimap
* Circles for regular nodes
* Squares for racks
* Outlined diamonds for animatable devices
* Added wall rectangles from free draw to minimap
* Added orthogonal routing display to minimap
* Fixed: resizing nodes now updates minimap immediately
* **Welcome Message addition**
* Click or tap anywhere to dismiss early.
* **Improved: HTTP Ping / Status Monitoring for Networkening edition**
* More reliable detection that now uses image load method to verify server actually responds with valid content. Built in fetch fallback for edge cases.
* Added response time tracking (e.g., "47ms")
* Batched checking now checks nodes in groups of 5 for faster bulk checks without overwhelming the network
* Added advanced timeout handling
* **General Bug Fixes**
### Version 3.9.9.8 /\ 12/22/25 Animations, walls, settings, themes and tidying up for 4.0
* **Theme System Overhaul**
* Added 8 preset themes organized by category
* Save your own custom themes for easy tab theming
* **Animated Connections with Flow**
* Show which way data is flowing for all, some, or any amount of custom connections
* Includes options for all the flow settings
* **CCTV/Camera nodes now have FOV Cone options for both stationary and PTZ cameras**
* Cone can be animated and animation carry over to minimap
* **Added 13 new device icons in a new "Smart Home" dropdown category:**
* Thermostat, Video Doorbell, Smart Lock, Smart Bulb, Smart Plug, Smart Speaker, Smart TV, Smart Hub, Smoke Detector, Motion Sensor, Garage Door, Sprinkler, Robot Vacuum
* **Bug fixes for Core + Networkening Editions**
* Removed unused code
* Fixed rotate actions and added -360 degrees on canvas assets
* Added defensive checks to prevent potential very edge case crashes
* Replaced port map links with buttons for better UI on both desktop and mobile
* Camera FOV cones render on the minimap with synchronized animation
* Line (✏️), Rectangle (▭), and Text (T) tool buttons now pulse with glow animation when active to add visual feedback so users know to click "Done" to exit drawing mode
* Resize Handles now scale with border width(s)
* Fixed a memory leak where pressing Escape to close the Rack Unit or U Height editor could cause erratic behavior after repeated use
* Port Map Export: Fixed CSV export producing malformed files when device names contained quotes or special characters
* Undo now works after importing JSON files
* Markdown import now validates connections and invalid links are skipped instead of creating broken edges
* Welcome message no longer disappears after saving and refreshing
* **Bug fixes for Networkening Edition**
* Removed localStorage icon caching
* Old exported cached icons are automatically cleaned up on first load
### Version 3.9.9.7 /\ 12/19/25 Import/export, saving and updates for editors
* **Improved the import/export system** [read more: import-export-save.md](import-export-save.md)
* **Added markdown export and import** Ala, Git versioning!
* Edit and create in your favorite markdown editor
* This also allows git versioning!
* **Added csv export and import**
* Edit and create in your favorite csv editor
* **Added print option**
* Removes the background and makes the entire canvas print friendly
* **New import/Export mobile menu**
* **Bug Fixes**
* Fixed minimap rendering nodes twice (performance)
* Fixed event listener memory leak in edge drag handlers
* Fixed Mac keyboard shortcuts (SORRY APPLE)
### Version 3.9.9.6 /\ 12/17/25 Stretching version numbers AND lines too!
* **Big performance update**
* **Orthogonal routing update** [changelog.md](changelog.md)
* New orthogonal routing option draws clean 90 degree angle connections
* Three routing styles available: Orthogonal, Curved, and Straight
* Change between all of them in the settings at any time OR mix and match them
* **Auto Recovery**
* If your browser crashes or you accidentally close the tab, your work is saved in your local browser
* If you want to clear this cache, use the Clear All option in settings
* **Enhanced Search** : Search now zooms in and out of the canvas automatically to group found items
* **Mobile Undo** : Add three finder tap anywhere on the canvas for undo on mobile devices
* **Performance Under The Hood**
* Multiple rapid changes are now batched into single redraws
* Minimap updates are throttled during pan and zoom
* Drop shadows and pulse animations automatically disabled when zoomed out below 50 percent
* Mouse and touch pan handlers optimized to prevent layout thrashing
* CSS containment added to panels and viewport for faster rendering
* Undo performance updates
* Minimap performance updates
* Custom Orthogonal gap function : edges show gaps where they cross other orthogonal edges
* Refactored update/import function
* Refactored background grid for performance
### Version 3.9.9.5 /\ 12/14/25 The ports enhancements update
* **Port connections section in node/rack panel** : See all ports connected to a device at a glance
* **Click to edit unassigned ports** : Assign ports directly from the devices
* **Port JumpTO** : Click ↗ to jump to that connection on canvas and highlight it
* **Edge color indicators** : Added color codes to the dedicated port view for easy reference
* **Duplicate port warning** : Added a vert simply alert when assigning a port already in use on that device
* **Squashed port bugs** : Squashed some small related ports bugs
### Version 3.9.9.4 /\ 12/14/25 Further fixes towards 4.0 Stable
* Fixed an issue where entering rack view would freeze the canvas on mobile
* Fixed an issue where node creation could be interrupted in rare cases
* Fixed pedantic HTML sanitations for inputs
* Added a function to sanitize inputs
### Version 3.9.9.3 /\ 12/13/25 Added Advanced Ports View
* Fixed [#27](https://github.com/gelatinescreams/The-One-File/issues/27)** thanks to [@lehnerpat](https://github.com/lehnerpat) for debugging
* Fixed an issue where modals were not closing correctly in the background
### Version 3.9.9.2 /\ 12/11/25 Added Advanced Ports View
* **Added New Ports View [#25](https://github.com/gelatinescreams/The-One-File/issues/25)** thanks to [@mohacc2008-ctrl](https://github.com/mohacc2008-ctrl) for the request
* **Squashed Bugs**
* * Fixed a bug where deleted tabs were not leaving the old canvas view
* * Fixed a bug where foldables and some tablets showed desktop elements
* * Started to refactor a few core elements for future updates
##### Version 3.9.9.1 /\ 12/10/25 Getting close to 4.0 Stable!
* **Fixed Search [#24](https://github.com/gelatinescreams/The-One-File/issues/24)**
* **Upgraded and fixed the undo system**
* * Edit node name/IP now undoable
* * Edit/delete/add tags now undoable
* * Edit/delete notes now undoable
* * Resize node (slider + reset) now undoable
* * Change shape now undoable
* * Style changes (colors, fonts, borders) now undoable
* * Edit width/color/direction/style now undoable
* * Delete edge now undoable
* * Edit/delete edge notes now undoable
* * Drag custom edge points now undoable
* * Edit color/border color/border width/style now undoable
* * Delete zone now undoable
* * Delete zone notes now undoable
* * All 9 text properties (font size, color, weight, style, align, decoration, bg color, bg enabled, opacity) now undoable
* **Squashed Bugs**
* * On mobile/tablet, users could still drag canvas elements (nodes, rectangles) even when View Only mode is enabled.
* * Ctrl+A (Select All) now shows correct total count (was only counting nodes)
* * (Shift multi select) Marquee select no longer accumulates between selections
* * Misc code refinement
##### Version 3.9.9 /\ 12/10/25 Hotfix release for desktop multi select
* **Added back mobile core functions from updating the audit system
##### Version 3.9.8.1 /\ 12/10/25 Hotfix release for desktop multi select
* **fixed a bug where mutli select with shift on desktop counted all entities it crossed
##### Version 3.9.8 /\ 12/10/25 View only mode + multi select for desktop
* **Added View Only Mode in Settings** Disables all editing while keeping pan and zoom
* * Click or tap any canvas item five times to inspect its details while in View Only Mode
* **Upgraded and fixed the Audit log.** Moved it to the stored JSON. Audit log now transfers with the save!
* * Added smart migration to merge old localStorage audit with new JSON storage
* **Added new core shapes to both versions.**
* **New desktop mutli entity select option added.** [#21](https://github.com/gelatinescreams/The-One-File/issues/21) + more : Special thanks to [@mitchplze](https://github.com/mitchplze)
* * Hold shift and click+drag on empty canvas to select multiple items at once
* * Selection box colors can be customized in Settings
##### Version 3.9.7 /\ 12/9/25 Squashing Bugs
* **Special thanks to @mitchplze for testing and reporting on some of these fixes**
* **Bug Fixes**
* * Fixed duplicate buttons appearing in saved files after multiple saves
* * Fixed toolbars staying in desktop layout when resizing window to mobile size
* * Fixed duplicate import button in Settings
* * Removed unused code to reduce file size
* * Zone line style (solid, dashed, dotted) can now be changed after creation.
* **Squashing more bugs** [#21](https://github.com/gelatinescreams/The-One-File/issues/21) + more : Special thanks to [@mitchplze](https://github.com/mitchplze)
* **Networkening Edition Fixes:**
* * Dropdown now shows "Custom Icon" when a web icon is selected. [#19](https://github.com/gelatinescreams/The-One-File/issues/19)
* * Switching to any core shape automatically clears the web icon [#19](https://github.com/gelatinescreams/The-One-File/issues/19)
* * Web icons keep their original colors until you change them [#19](https://github.com/gelatinescreams/The-One-File/issues/19)
* * Fixed web icon colors persisting when selecting a new icon. New icons now display their natural colors instead of inheriting previous custom colors. [#19](https://github.com/gelatinescreams/The-One-File/issues/19)
* * Fixed selfh.st icon search to only show icons that have SVG versions available. (for editability) [#19](https://github.com/gelatinescreams/The-One-File/issues/19)
##### Version 3.9.6 /\ 12/8/25 Rack canvas fixes
* **Can now view and edit nodes that are inside a given rack just by selecting a rack and using the sidebar / mobile footer**
* **Updated all keyboard shortcuts to work with new canvas draw tools**
* Fixed a bug where cloning racks with nodes inside would not clone the nodes
* Fixed a bug where deleting nodes and racks via the information panel was broken
* Fixed a bug where nodes were created at the bottom of canvas in rack view regardless of user view
* **They will now generate in the center of users view**
* Fixed a bug where page titles were overriden by tab titles
* Fixed a bug where canvas information panel from previous tabs would stay selected after tab switch
##### Version 3.9.5 /\ 12/7/25 The Styles Update!
* **Added all available styling options to settings**
* **Canvas Styling** Added seperated styling for the main canvas and rack view canvases
* Added additional syling options to free draw tools
##### Version 3.9.4 /\ 12/6/25 Canvas bug fixes
* **Help Tab** Added keyboard and mouse how:to in ?help
* **Various bug fixes including**
* Added additional styling options for free draw tools
* Fixed a bug where cloned nodes inside racks would clone to main canvas
* Fixed a bug where free drawn rectangle zones would not allow outlined style
* Fixed a bug where free drawn lines were not draggable after creation
* Fixed a bug where free drawn lines were not editable after creation
* Fixed a bug where free drawn rectangle zones were not editable after creation
* Fixed a bug where free drawn rectangles zones had no custom styling inputs
* Fixed a bug where free drawn tools were not grouped correctly with nodes and racks
##### Version 3.9.3 /\ 12/5/25 Mobile bug fixes
* **NEW 3.9.3** Mobile fixes.
* **Various bug fixes including**
* Rewrote every mobile touch event
* Cleaned mobile core
##### Version 3.9.2 /\ 12/5/25 Bug fixes
* **NEW 3.9.2** Styles per tab! You can now set different styles for each topology tab.
* **Various bug fixes including**
* Fixed a bug where rack and node colors were not applying correctly
* Added node and rack border along with fill to icons
* Fixed a bug where rack view can get stuck
* Fixed a bug where rack height and rack unit got swapped causing drag errors in rack view
* Fixed a bug where lines could be added to a node when the node was inside a rack
* Fixed a bug where lines would persist after a node is added to a rack
* Fixed various dragging and dropping bugs
* Changed the icons to not animate on desktop (this was implemented in version .2, well before the style sidebar)
##### Version 3.9 /\ 12/4/25
* **NEW 3.9** Tabs, snapshots, action audits and notes! (encrypted also)
* Tabs are now implemented. This allows unlimited locations of topologies, still one file!
* **NEW 3.9** General topology notes are now implemented. You can also encrypt per note.
* **NEW 3.9** Snapshots are now implemeted. Auto save and manual save is available.
* **NEW 3.9** Action audits are now implemeted. This allows you to audit whether or not the file has been tampered in an easy to read log.
* *Note: Both snapshots and audits are local browser only and do not trasnfer to another device. This feature is coming in 4.0*
* **NEW 3.7** The Rackening!!
* Add any rack size from 6-48 and open it as its own canvas with U slot placement of nodes, new and existing, enabling unlimited hierarchical rack layouts.
* **NEW 3.7** Layers upon layers!!
* Choose between physical, logical, security and application layers for anything and easily toggle visibility between them.
* **NEW 3.7** Added Racks and individual rack canvasses!
* **NEW 3.7** *Major workflow enhancement release with full keyboard control and mobile optimization*
* **NEW 3.7** The Rackening!!
* Add any rack size from 6-48 and open it as its own canvas with U slot placement of nodes, new and existing, enabling unlimited hierarchical rack layouts.
* **NEW 3.7** Layers upon layers!!
* Choose between physical, logical, security and application layers for anything and easily toggle visibility between them.
* **NEW 3.7** Added Racks and individual rack canvasses!
* **NEW 3.7** *Major workflow enhancement release with full keyboard control and mobile optimization*
##### Version 3.7 /\ 12/3/25
* **NEW 3.7 Advanced Keyboard Navigation**
* **Arrow Keys** Move selected nodes 1 pixel in any direction for precise positioning
* **Shift + Arrow Keys** Move selected nodes 10 pixels for faster adjustments
* **Tab** Cycle forward through all nodes in current view
* **Shift + Tab** Cycle backward through all nodes in current view
* **F** Focus camera on selected node(s) with automatic zoom and centering
* **NEW 3.7 Node Lock System** Prevent accidental movement of positioned nodes
* Lock individual nodes or multiple nodes at once
* Visual lock indicator on locked nodes
* Locked nodes cannot be moved by dragging or keyboard
* Works with multi selection for batch operations
* Lock status persists in saved files
* **NEW 3.7 Node Grouping System** Move related nodes together as a unit
* Group multiple nodes to move them as a single unit
* Visual group indicator (dashed outline) on grouped nodes
* Drag any group member and all nodes in the group move together
* Groups respect lock status (locked nodes stay in place)
* Create and dissolve groups dynamically with keyboard shortcut
* Group membership persists in saved files
* **NEW 3.7 Enhanced Mobile Experience**
* **Double tap empty space to exit rack view** Quick navigation without button press
* **Lock Toggle button** in mobile multi select menu for easy locking on touch devices
* **Group Toggle button** in mobile multi select menu for easy grouping on mobile
* Haptic feedback (vibration) for double tap actions on supported devices
* Smart gesture detection (pan vs tap) prevents accidental actions
* **NEW 3.7 Rack View Improvements**
* Nodes created while in rack view automatically assign to that rack
* Drawing tools (free draw, rectangles, text) properly disabled in rack view with clear feedback
* Improved workflow prevents accidentally placing elements in wrong view
* **A more detailed list of changes is included below**
* [Change Log](changelog.md)
##### Version 3.5.1 /\ 12/2/25
- **NEW 3.5.1** Small style fixes and mobile refactoring
##### Version 3.5 /\ 12/2/25
- **NEW 3.5** *Another major release. Thank you to Discord testers!!*
- **NEW 3.5 Add Text Labels Anywhere** Click the "T" button to place custom text annotations anywhere on your canvas with full styling control
- **NEW 3.5 Draw Rectangles/Boxes** Create visual boundaries, zones, or highlighted areas with filled or outlined rectangles in any color
* **NEW 3.5 Bulk Operations** Select multiple nodes at once with right click (or double tap on mobile) and perform batch operations:
* Align Left, Right, Top, or Bottom
* Distribute Horizontally or Vertically
* Clone all selected nodes
* Delete in bulk
* **NEW 3.5 Keyboard Shortcuts** Power user controls:
* `Ctrl/Cmd + Z` Undo
* `Ctrl/Cmd + Y` or `Ctrl/Cmd + Shift + Z` Redo
* `Ctrl/Cmd + C` Copy node
* `Ctrl/Cmd + V` Paste node
* `Ctrl/Cmd + Plus` Zoom in
* `Ctrl/Cmd + Minus` Zoom out
* `Ctrl/Cmd + 0` Reset view
* `Space + Drag` Pan canvas
- **NEW 3.5 Mobile Gestures** Touch optimized controls:
- **Double tap** to select multiple nodes
- **Double tap** to clone and align nodes
- Resizable mobile footer with drag handle
- Touch friendly bulk operations modal
- **NEW 3.5 Per Breakpoint Styling** Customize node appearance independently for Desktop, Tablet, Mobile, and Fold layouts
- **NEW 3.5 Live node search with visual highlighting**
- **NEW 3.5 Added MAC field to node**
- **NEW 3.5 Added Rack field to node**
- **NEW 3.5 Live node search with visual highlighting**
- **NEW 3.5 Upgraded Military Grade Encryption** AES 256 GCM encryption with PBKDF2 key derivation (200,000 iterations)
- Browser native encryption, zero server involvement
- Password protect sensitive network documentation
- Non recoverable (no backdoors, your data stays truly private)
- Perfect for break glass documentation with credentials
- NEW 3.1 Live Status Monitoring *(networkening version only)*
- NEW 3.1 Real time ping/status indicators on nodes *(networkening version only)*
- NEW 3.1 Visual online/offline/checking indicators *(networkening version only)*
##### Version 3.0 /\ 12/1/25
- NEW 3.0 Total mobile rewrite for core the-one-file.html
- NEW 3.0 Total css rewrite for core the-one-file.html
- NEW 3.0 : Ping/Live status for nodes added to theonefile-networkening.html
- Click here for a full online demo of the theonefile-networkening.html
- [Click here for a full online demo of the theonefile-networkening-corporate-demo.html](https://gelatinescreams.github.io/The-One-File/demos/theonefile-networkening-corporate-demo.html)
- [Click here for a full online demo of the theonefile-networkening-homelab-demo.html](https://gelatinescreams.github.io/The-One-File/demos/theonefile-networkening-homelab-demo.html)
- NEW 2.8 : Icon SEARCH with live preview
- Seperate online features version to include icons - OPTIONAL
- Use theonefile-networkening.html for this version
##### Version 2.8 /\ 11/29/25 The One File: The Networkening update!
- Totally collapsible mobile interface
- Mobile core added for future features
- NEW 2.8 : Icon SEARCH with live preview
- Seperate online features version to include web incons (OPTIONAL)
- Use theonefile-networkening.html for this version
- Icon support added (MDI, Simple Icons, Selfh.st)
##### Version 2.5 /\ 11/25/25 The One File: The Networkening update!
- NEW 2.5 : Icon SEARCH with live preview
================================================
FILE: demos/csv-exports/the-one-file-corporate.csv
================================================
#THEONEFILE_CONFIG:{"nodeData":{"core-router-1":{"shape":"router","name":"Core Router 1","ip":"10.0.0.1","role":"Core Routing","tags":["core","tier-1","redundant"],"notes":["Primary core router","BGP peering enabled"],"mac":"00:1A:2B:3C:4D:01","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-router-2":{"shape":"router","name":"Core Router 2","ip":"10.0.0.2","role":"Core Routing","tags":["core","tier-1","redundant"],"notes":["Secondary core router","HSRP standby"],"mac":"00:1A:2B:3C:4D:02","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"ping":{"enabled":true,"protocol":"custom","customUrl":"https://google.com","timeout":3000,"status":"online","lastCheck":"2025-12-09T00:15:04.343Z"}},"fw-external-1":{"shape":"firewall","name":"External FW 1","ip":"10.0.1.1","role":"Perimeter Security","tags":["security","perimeter","ha-pair"],"notes":["Palo Alto PA-5250","Active node"],"mac":"00:1A:2B:3C:4D:10","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fw-external-2":{"shape":"firewall","name":"External FW 2","ip":"10.0.1.2","role":"Perimeter Security","tags":["security","perimeter","ha-pair"],"notes":["Palo Alto PA-5250","Passive node"],"mac":"00:1A:2B:3C:4D:11","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fw-internal":{"shape":"firewall","name":"Internal FW","ip":"10.0.2.1","role":"Internal Segmentation","tags":["security","internal"],"notes":["East-West traffic inspection"],"mac":"00:1A:2B:3C:4D:12","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-switch-1":{"shape":"switch","name":"Core Switch 1","ip":"10.0.10.1","role":"Core Switching","tags":["core","layer3","redundant"],"notes":["Cisco Nexus 9000","VPC Domain 1"],"mac":"00:1A:2B:3C:4D:20","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-switch-2":{"shape":"switch","name":"Core Switch 2","ip":"10.0.10.2","role":"Core Switching","tags":["core","layer3","redundant"],"notes":["Cisco Nexus 9000","VPC Domain 1"],"mac":"00:1A:2B:3C:4D:21","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dc-rack-a1":{"shape":"server","name":"DC Rack A1","ip":"10.10.0.0/24","role":"Data Center Rack","tags":["datacenter","row-a","production"],"notes":["Row A, Position 1","Primary compute"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-a2":{"shape":"server","name":"DC Rack A2","ip":"10.10.1.0/24","role":"Data Center Rack","tags":["datacenter","row-a","production"],"notes":["Row A, Position 2","Primary compute"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-b1":{"shape":"server","name":"DC Rack B1","ip":"10.10.2.0/24","role":"Data Center Rack","tags":["datacenter","row-b","storage"],"notes":["Row B, Position 1","Storage systems"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-b2":{"shape":"server","name":"DC Rack B2","ip":"10.10.3.0/24","role":"Data Center Rack","tags":["datacenter","row-b","storage"],"notes":["Row B, Position 2","Storage systems"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dmz-rack":{"shape":"server","name":"DMZ Rack","ip":"172.16.0.0/24","role":"DMZ Infrastructure","tags":["dmz","security","public-facing",{"type":"icon","library":"selfhst","name":"booklogr"},{"type":"icon","library":"simple","name":"gmail"}],"notes":["Isolated DMZ zone","Public-facing services"],"mac":"","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"24","isRack":true,"locked":false,"groupId":null},"mgmt-rack":{"shape":"server","name":"Management Rack","ip":"192.168.100.0/24","role":"Management Infrastructure","tags":["management","oob","noc"],"notes":["Out-of-band management","NOC equipment"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"24","isRack":true,"locked":false,"groupId":null},"esxi-host-01":{"shape":"server","name":"ESXi Host 01","ip":"10.10.0.11","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:01","rackUnit":38,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-02":{"shape":"server","name":"ESXi Host 02","ip":"10.10.0.12","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:02","rackUnit":35,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-03":{"shape":"server","name":"ESXi Host 03","ip":"10.10.0.13","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:03","rackUnit":32,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-04":{"shape":"server","name":"ESXi Host 04","ip":"10.10.0.14","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:04","rackUnit":29,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-a1":{"shape":"switch","name":"ToR Switch A1","ip":"10.10.0.1","role":"Top of Rack","tags":["tor","access","rack-a1"],"notes":["Cisco Nexus 93180YC-FX","48x25G ports"],"mac":"00:1A:2B:3C:5D:01","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-05":{"shape":"server","name":"ESXi Host 05","ip":"10.10.1.11","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:01","rackUnit":38,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-06":{"shape":"server","name":"ESXi Host 06","ip":"10.10.1.12","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:02","rackUnit":35,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-07":{"shape":"server","name":"ESXi Host 07","ip":"10.10.1.13","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:03","rackUnit":32,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-08":{"shape":"server","name":"ESXi Host 08","ip":"10.10.1.14","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:04","rackUnit":29,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-a2":{"shape":"switch","name":"ToR Switch A2","ip":"10.10.1.1","role":"Top of Rack","tags":["tor","access","rack-a2"],"notes":["Cisco Nexus 93180YC-FX","48x25G ports"],"mac":"00:1A:2B:3C:5D:02","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"san-primary":{"shape":"database","name":"SAN Primary","ip":"10.10.2.10","role":"Primary Storage","tags":["storage","san","netapp"],"notes":["NetApp AFF A400","500TB Raw","FC 32Gb"],"mac":"00:A0:98:AA:01:01","rackUnit":36,"uHeight":"6","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"san-secondary":{"shape":"database","name":"SAN Secondary","ip":"10.10.2.11","role":"Secondary Storage","tags":["storage","san","netapp"],"notes":["NetApp AFF A400","500TB Raw","FC 32Gb"],"mac":"00:A0:98:AA:01:02","rackUnit":28,"uHeight":"6","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fc-switch-1":{"shape":"switch","name":"FC Switch 1","ip":"10.10.2.1","role":"Fibre Channel","tags":["storage","fc","fabric-a"],"notes":["Brocade G620","Fabric A"],"mac":"00:1A:2B:FC:01:01","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fc-switch-2":{"shape":"switch","name":"FC Switch 2","ip":"10.10.2.2","role":"Fibre Channel","tags":["storage","fc","fabric-b"],"notes":["Brocade G620","Fabric B"],"mac":"00:1A:2B:FC:01:02","rackUnit":41,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"backup-server-1":{"shape":"server","name":"Backup Server 1","ip":"10.10.3.10","role":"Backup Infrastructure","tags":["backup","veeam","protection"],"notes":["Veeam Backup Server","Dell R740xd","200TB"],"mac":"00:50:56:BB:01:01","rackUnit":36,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"backup-server-2":{"shape":"server","name":"Backup Server 2","ip":"10.10.3.11","role":"Backup Infrastructure","tags":["backup","veeam","protection"],"notes":["Veeam Backup Server","Dell R740xd","200TB"],"mac":"00:50:56:BB:01:02","rackUnit":33,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tape-library":{"shape":"database","name":"Tape Library","ip":"10.10.3.20","role":"Archival Storage","tags":["backup","tape","lto9"],"notes":["IBM TS4500","LTO-9","Long-term archive"],"mac":"00:50:56:BB:02:01","rackUnit":20,"uHeight":"10","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-b1":{"shape":"switch","name":"ToR Switch B1","ip":"10.10.2.3","role":"Top of Rack","tags":["tor","access","rack-b1"],"notes":["Cisco Nexus 93180YC-FX"],"mac":"00:1A:2B:3C:5D:03","rackUnit":40,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-b2":{"shape":"switch","name":"ToR Switch B2","ip":"10.10.3.1","role":"Top of Rack","tags":["tor","access","rack-b2"],"notes":["Cisco Nexus 93180YC-FX"],"mac":"00:1A:2B:3C:5D:04","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"web-server-1":{"shape":"server","name":"Web Server 1","ip":"172.16.0.11","role":"Web Frontend","tags":["dmz","web","nginx"],"notes":["NGINX reverse proxy","Public facing"],"mac":"00:50:56:CC:01:01","rackUnit":20,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"web-server-2":{"shape":"server","name":"Web Server 2","ip":"172.16.0.12","role":"Web Frontend","tags":["dmz","web","nginx"],"notes":["NGINX reverse proxy","Public facing"],"mac":"00:50:56:CC:01:02","rackUnit":18,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"waf-1":{"shape":"firewall","name":"WAF Appliance","ip":"172.16.0.5","role":"Web Application Firewall","tags":["dmz","security","waf"],"notes":["F5 BIG-IP ASM","OWASP protection"],"mac":"00:50:56:CC:02:01","rackUnit":22,"uHeight":"2","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"load-balancer-dmz":{"shape":"switch","name":"DMZ Load Balancer","ip":"172.16.0.3","role":"Load Balancing","tags":["dmz","lb","f5"],"notes":["F5 BIG-IP LTM","VIP: 172.16.0.100"],"mac":"00:50:56:CC:03:01","rackUnit":16,"uHeight":"2","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"mail-gateway":{"shape":"server","name":"Mail Gateway","ip":"172.16.0.25","role":"Email Security","tags":["dmz","email","security"],"notes":["Proofpoint Email Gateway","Spam/malware filtering"],"mac":"00:50:56:CC:04:01","rackUnit":14,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"dns-external-1":{"shape":"circle","name":"External DNS 1","ip":"172.16.0.53","role":"External DNS","tags":["dmz","dns","public"],"notes":["BIND DNS","Authoritative for corp.com"],"mac":"00:50:56:CC:05:01","rackUnit":12,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"dns-external-2":{"shape":"circle","name":"External DNS 2","ip":"172.16.0.54","role":"External DNS","tags":["dmz","dns","public"],"notes":["BIND DNS","Secondary for corp.com"],"mac":"00:50:56:CC:05:02","rackUnit":10,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"vcenter":{"shape":"server","name":"vCenter Server","ip":"192.168.100.10","role":"Virtualization Management","tags":["management","vmware","vcsa"],"notes":["vCenter Server Appliance 8.0","Single SSO domain"],"mac":"00:50:56:DD:01:01","rackUnit":20,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"nsx-manager":{"shape":"server","name":"NSX Manager","ip":"192.168.100.15","role":"Network Virtualization","tags":["management","vmware","nsx"],"notes":["NSX-T 4.1 Manager Cluster"],"mac":"00:50:56:DD:02:01","rackUnit":17,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"siem-server":{"shape":"server","name":"SIEM Server","ip":"192.168.100.50","role":"Security Monitoring","tags":["management","security","splunk"],"notes":["Splunk Enterprise","Security monitoring"],"mac":"00:50:56:DD:03:01","rackUnit":14,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"nms-server":{"shape":"server","name":"Network Monitoring","ip":"192.168.100.60","role":"Network Management","tags":["management","monitoring","prtg"],"notes":["PRTG Network Monitor","5000 sensors"],"mac":"00:50:56:DD:04:01","rackUnit":11,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"jump-server":{"shape":"server","name":"Jump Server","ip":"192.168.100.100","role":"Bastion Host","tags":["management","security","bastion"],"notes":["Windows Server 2022","MFA enabled"],"mac":"00:50:56:DD:05:01","rackUnit":9,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"ipam-server":{"shape":"server","name":"IPAM/DDI","ip":"192.168.100.70","role":"IP Management","tags":["management","dns","dhcp"],"notes":["Infoblox DDI","DNS/DHCP/IPAM"],"mac":"00:50:56:DD:06:01","rackUnit":7,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"wlc-primary":{"shape":"wifi","name":"WLC Primary","ip":"10.20.0.1","role":"Wireless Controller","tags":["wireless","cisco","9800"],"notes":["Cisco C9800-40","Primary controller"],"mac":"00:1A:2B:WL:01:01","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"wlc-secondary":{"shape":"wifi","name":"WLC Secondary","ip":"10.20.0.2","role":"Wireless Controller","tags":["wireless","cisco","9800"],"notes":["Cisco C9800-40","HA Secondary"],"mac":"00:1A:2B:WL:01:02","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-hq":{"shape":"phone","name":"HQ Mobile Zone","ip":"10.20.10.0/24","role":"Mobile Device Zone","tags":["wireless","byod","mobile"],"notes":["Corporate BYOD","MDM enrolled devices"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-guest":{"shape":"phone","name":"Guest WiFi Zone","ip":"10.30.0.0/24","role":"Guest Network","tags":["wireless","guest","isolated"],"notes":["Captive portal","Internet only"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-iot":{"shape":"phone","name":"IoT Device Zone","ip":"10.40.0.0/24","role":"IoT Network","tags":["wireless","iot","building"],"notes":["Building automation","Smart devices"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-ny":{"shape":"router","name":"NYC Branch Router","ip":"10.100.0.1","role":"Branch Gateway","tags":["branch","nyc","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-la":{"shape":"router","name":"LA Branch Router","ip":"10.101.0.1","role":"Branch Gateway","tags":["branch","la","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-chi":{"shape":"router","name":"Chicago Branch Router","ip":"10.102.0.1","role":"Branch Gateway","tags":["branch","chicago","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-lon":{"shape":"router","name":"London Branch Router","ip":"10.200.0.1","role":"Branch Gateway","tags":["branch","london","sd-wan"],"notes":["Cisco Viptela vEdge","EMEA region"],"mac":"00:1A:2B:BR:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-tokyo":{"shape":"router","name":"Tokyo Branch Router","ip":"10.201.0.1","role":"Branch Gateway","tags":["branch","tokyo","sd-wan"],"notes":["Cisco Viptela vEdge","APAC region"],"mac":"00:1A:2B:BR:05:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-aws":{"shape":"cloud","name":"AWS Cloud","ip":"vpc-0a1b2c3d","role":"Public Cloud","tags":["cloud","aws","hybrid"],"notes":["AWS US-East-1","VPC peering to HQ"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-azure":{"shape":"cloud","name":"Azure Cloud","ip":"vnet-corp-prod","role":"Public Cloud","tags":["cloud","azure","hybrid"],"notes":["Azure East US 2","ExpressRoute"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-gcp":{"shape":"cloud","name":"GCP Cloud","ip":"vpc-gcp-corp","role":"Public Cloud","tags":["cloud","gcp","dev"],"notes":["GCP us-central1","Dev/Test workloads"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"isp-primary":{"shape":"globe","name":"ISP Primary","ip":"203.0.113.1","role":"Internet Uplink","tags":["wan","internet","primary"],"notes":["AT&T MPLS","1 Gbps dedicated"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"isp-secondary":{"shape":"vm","name":"ISP Secondary","ip":"198.51.100.1","role":"Internet Uplink","tags":["wan","internet","backup"],"notes":["Verizon Business","500 Mbps backup"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"rotation":-17},"dc-internal-1":{"shape":"circle","name":"DC1 Int DNS","ip":"10.10.0.53","role":"Internal DNS/AD","tags":["dns","ad","dc1"],"notes":["Windows Server 2022","Primary DC"],"mac":"00:50:56:AD:01:01","rackUnit":26,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dc-internal-2":{"shape":"circle","name":"DC2 Int DNS","ip":"10.10.1.53","role":"Internal DNS/AD","tags":["dns","ad","dc2"],"notes":["Windows Server 2022","Secondary DC"],"mac":"00:50:56:AD:01:02","rackUnit":26,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"app-server-1":{"shape":"server","name":"App Server 01","ip":"10.10.0.101","role":"Application","tags":["app","iis","web"],"notes":["Windows Server 2022","IIS Application"],"mac":"00:50:56:AP:01:01","rackUnit":24,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"app-server-2":{"shape":"server","name":"App Server 02","ip":"10.10.0.102","role":"Application","tags":["app","iis","web"],"notes":["Windows Server 2022","IIS Application"],"mac":"00:50:56:AP:01:02","rackUnit":22,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"db-server-1":{"shape":"database","name":"SQL Server 01","ip":"10.10.0.201","role":"Database","tags":["db","sql","primary"],"notes":["SQL Server 2022 Enterprise","AlwaysOn Primary"],"mac":"00:50:56:DB:01:01","rackUnit":20,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"db-server-2":{"shape":"database","name":"SQL Server 02","ip":"10.10.1.201","role":"Database","tags":["db","sql","secondary"],"notes":["SQL Server 2022 Enterprise","AlwaysOn Secondary"],"mac":"00:50:56:DB:01:02","rackUnit":24,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-1":{"shape":"hexagon","name":"K8s Master 1","ip":"10.10.1.50","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:01","rackUnit":21,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-2":{"shape":"hexagon","name":"K8s Master 2","ip":"10.10.1.51","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:02","rackUnit":19,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-3":{"shape":"hexagon","name":"K8s Master 3","ip":"10.10.1.52","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:03","rackUnit":17,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-1":{"shape":"server","name":"K8s Worker 1","ip":"10.10.1.60","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:01","rackUnit":15,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-2":{"shape":"server","name":"K8s Worker 2","ip":"10.10.1.61","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:02","rackUnit":13,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-3":{"shape":"server","name":"K8s Worker 3","ip":"10.10.1.62","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:03","rackUnit":11,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-4":{"shape":"server","name":"K8s Worker 4","ip":"10.10.1.63","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:04","rackUnit":9,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"proxy-server-1":{"shape":"server","name":"Proxy Server 1","ip":"10.5.0.10","role":"Web Proxy","tags":["proxy","squid","filtering"],"notes":["Squid Proxy","Content filtering"],"mac":"00:50:56:PX:01:01","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"proxy-server-2":{"shape":"server","name":"Proxy Server 2","ip":"10.5.0.11","role":"Web Proxy","tags":["proxy","squid","filtering"],"notes":["Squid Proxy","HA pair"],"mac":"00:50:56:PX:01:02","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"vpn-concentrator":{"shape":"firewall","name":"VPN Concentrator","ip":"10.0.5.1","role":"Remote Access VPN","tags":["vpn","remote","security"],"notes":["Cisco ASA 5555-X","AnyConnect SSL VPN"],"mac":"00:1A:2B:VP:01:01","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"nac-server":{"shape":"server","name":"NAC Server","ip":"10.5.5.10","role":"Network Access Control","tags":["nac","ise","802.1x"],"notes":["Cisco ISE 3.1","RADIUS/TACACS+"],"mac":"00:50:56:NA:01:01","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"print-server":{"shape":"server","name":"Print Server","ip":"10.10.0.150","role":"Print Services","tags":["print","windows","services"],"notes":["Windows Print Server","50+ printers"],"mac":"00:50:56:PR:01:01","rackUnit":18,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"file-server":{"shape":"database","name":"File Server","ip":"10.10.0.160","role":"File Services","tags":["file","smb","dfs"],"notes":["Windows File Server","DFS namespace"],"mac":"00:50:56:FS:01:01","rackUnit":16,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ca-server":{"shape":"server","name":"Certificate Authority","ip":"192.168.100.80","role":"PKI Infrastructure","tags":["pki","ca","security"],"notes":["Windows CA","Enterprise Root CA"],"mac":"00:50:56:CA:01:01","rackUnit":5,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"sccm-server":{"shape":"server","name":"SCCM Server","ip":"192.168.100.90","role":"Endpoint Management","tags":["sccm","patching","software"],"notes":["MECM Primary Site","Software deployment"],"mac":"00:50:56:SC:01:01","rackUnit":3,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"voip-cluster":{"shape":"phone","name":"VoIP Cluster","ip":"10.50.0.0/24","role":"Voice Services","tags":["voip","cisco","ucm"],"notes":["Cisco UCM Cluster","3000 endpoints"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"video-conf":{"shape":"laptop","name":"Video Conference","ip":"10.51.0.0/24","role":"Video Services","tags":["video","webex","teams"],"notes":["Webex/Teams integration","Meeting rooms"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"security-cameras":{"shape":"camera","name":"Security Cameras","ip":"10.60.0.0/24","role":"Physical Security","tags":["cctv","surveillance","security"],"notes":["150+ IP cameras","30-day retention"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"nvr-cluster":{"shape":"server","name":"NVR Cluster","ip":"10.60.0.10","role":"Video Recording","tags":["nvr","surveillance","storage"],"notes":["Milestone XProtect","500TB storage"],"mac":"00:50:56:NV:01:01","rackUnit":15,"uHeight":"4","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dev-server-1":{"shape":"server","name":"Dev Server 1","ip":"10.80.0.10","role":"Development","tags":["dev","gitlab","ci-cd",{"type":"icon","library":"selfhst","name":"dokku"}],"notes":["GitLab Server","CI/CD pipelines"],"mac":"00:50:56:DV:01:01","rackUnit":"","uHeight":"2","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dev-server-2":{"shape":"server","name":"Dev Server 2","ip":"10.80.0.11","role":"Development","tags":["dev","jenkins","ci-cd"],"notes":["Jenkins Server","Build automation"],"mac":"00:50:56:DV:01:02","rackUnit":"","uHeight":"2","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"test-environment":{"shape":"shield","name":"Test Environment","ip":"10.81.0.0/24","role":"QA/Testing","tags":["test","qa","staging"],"notes":["Staging environment","Pre-prod validation"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"rotation":-36},"erp-system":{"shape":"database","name":"ERP System","ip":"10.90.0.10","role":"Business Application","tags":["erp","sap","business"],"notes":["SAP S/4HANA","Financial/HR systems"],"mac":"00:50:56:ER:01:01","rackUnit":"","uHeight":"4","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"crm-system":{"shape":"database","name":"CRM System","ip":"10.91.0.10","role":"Business Application","tags":["crm","salesforce","business"],"notes":["Salesforce integration","Sales/Marketing"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"endpoint-1000":{"shape":"laptop","name":"Corporate Endpoints","ip":"10.70.0.0/22","role":"User Workstations","tags":["endpoints","workstations","users"],"notes":["~1000 corporate laptops","Windows 11"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor1":{"shape":"switch","name":"Floor 1 Switch","ip":"10.1.1.1","role":"Distribution","tags":["distribution","floor-1","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor2":{"shape":"switch","name":"Floor 2 Switch","ip":"10.1.2.1","role":"Distribution","tags":["distribution","floor-2","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor3":{"shape":"switch","name":"Floor 3 Switch","ip":"10.1.3.1","role":"Distribution","tags":["distribution","floor-3","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor4":{"shape":"switch","name":"Floor 4 Switch","ip":"10.1.4.1","role":"Distribution","tags":["distribution","floor-4","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor1-zone1":{"shape":"wifi","name":"AP Floor 1 Zone 1","ip":"10.20.1.10","role":"Wireless Access","tags":["wifi","ap","floor-1"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor2-zone1":{"shape":"wifi","name":"AP Floor 2 Zone 1","ip":"10.20.2.10","role":"Wireless Access","tags":["wifi","ap","floor-2"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor3-zone1":{"shape":"wifi","name":"AP Floor 3 Zone 1","ip":"10.20.3.10","role":"Wireless Access","tags":["wifi","ap","floor-3"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor4-zone1":{"shape":"wifi","name":"AP Floor 4 Zone 1","ip":"10.20.4.10","role":"Wireless Access","tags":["wifi","ap","floor-4"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ups-dc-1":{"shape":"rectangle","name":"UPS DC-1","ip":"192.168.200.10","role":"Power Management","tags":["power","ups","datacenter"],"notes":["APC Symmetra","80kVA","30 min runtime"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ups-dc-2":{"shape":"rectangle","name":"UPS DC-2","ip":"192.168.200.11","role":"Power Management","tags":["power","ups","datacenter"],"notes":["APC Symmetra","80kVA","Redundant"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"pdu-rack-a1":{"shape":"rectangle","name":"PDU Rack A1","ip":"192.168.200.21","role":"Power Distribution","tags":["power","pdu","rack-a1"],"notes":["APC Switched PDU","Per-outlet metering"],"mac":"","rackUnit":1,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"pdu-rack-a2":{"shape":"rectangle","name":"PDU Rack A2","ip":"192.168.200.22","role":"Power Distribution","tags":["power","pdu","rack-a2"],"notes":["APC Switched PDU","Per-outlet metering"],"mac":"","rackUnit":1,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cooling-1":{"shape":"rectangle","name":"CRAC Unit 1","ip":"192.168.200.30","role":"Cooling","tags":["cooling","hvac","datacenter"],"notes":["Liebert CRV","Row-based cooling"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cooling-2":{"shape":"rectangle","name":"CRAC Unit 2","ip":"192.168.200.31","role":"Cooling","tags":["cooling","hvac","datacenter"],"notes":["Liebert CRV","N+1 redundancy"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"camera-a":{"shape":"camera","name":"camera A","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","ping":{"enabled":false,"protocol":"http","customUrl":"","timeout":3000,"status":"unknown","lastCheck":null},"locked":false,"groupId":null,"fovEnabled":true,"fovRotation":104,"fovDistance":500,"fovSweep":60,"fovSpeed":10,"fovAnimate":true},"camera-a-copy":{"shape":"camera","name":"camera B","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","ping":{"enabled":false,"protocol":"http","customUrl":"","timeout":3000,"status":"unknown","lastCheck":null},"locked":false,"groupId":null,"fovEnabled":true,"fovRotation":162,"fovDistance":500,"fovSweep":60,"fovSpeed":10,"fovAnimate":false}},"edgeData":{"list":[{"id":"isp1-router1","from":"isp-primary","to":"core-router-1","width":6,"color":"#10b981","direction":"both","type":"main","notes":["Primary WAN link"],"fromPort":"Gi0/0","toPort":"Gi1/0/1","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"isp2-router2","from":"isp-secondary","to":"core-router-2","width":6,"color":"#10b981","direction":"both","type":"main","notes":["Backup WAN link"],"fromPort":"Gi0/0","toPort":"Gi1/0/1","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-router2","from":"core-router-1","to":"core-router-2","width":4,"color":"#f59e0b","direction":"both","type":"main","notes":["HSRP Peering"],"fromPort":"Gi1/0/24","toPort":"Gi1/0/24","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-fw1","from":"core-router-1","to":"fw-external-1","width":4,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router2-fw2","from":"core-router-2","to":"fw-external-2","width":4,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-fw2","from":"fw-external-1","to":"fw-external-2","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["HA heartbeat"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-coresw1","from":"fw-external-1","to":"core-switch-1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw2-coresw2","from":"fw-external-2","to":"core-switch-2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-coresw2","from":"core-switch-1","to":"core-switch-2","width":5,"color":"#3b82f6","direction":"both","type":"main","notes":["VPC peer-link"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-fwint","from":"core-switch-1","to":"fw-internal","width":3,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-fwint","from":"core-switch-2","to":"fw-internal","width":3,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-racka1","from":"core-switch-1","to":"dc-rack-a1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-racka1","from":"core-switch-2","to":"dc-rack-a1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-racka2","from":"core-switch-1","to":"dc-rack-a2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-racka2","from":"core-switch-2","to":"dc-rack-a2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-rackb1","from":"core-switch-1","to":"dc-rack-b1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-rackb1","from":"core-switch-2","to":"dc-rack-b1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-rackb2","from":"core-switch-1","to":"dc-rack-b2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-rackb2","from":"core-switch-2","to":"dc-rack-b2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-dmz","from":"fw-external-1","to":"dmz-rack","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["DMZ segment"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw2-dmz","from":"fw-external-2","to":"dmz-rack","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["DMZ segment"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-mgmt","from":"core-switch-1","to":"mgmt-rack","width":3,"color":"#8b5cf6","direction":"both","type":"main","notes":["OOB management"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-wlc1","from":"core-switch-1","to":"wlc-primary","width":3,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-wlc2","from":"core-switch-2","to":"wlc-secondary","width":3,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true},{"id":"wlc1-wlc2","from":"wlc-primary","to":"wlc-secondary","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":["HA pair"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-hq","from":"wlc-primary","to":"mobile-zone-hq","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-guest","from":"wlc-primary","to":"mobile-zone-guest","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-iot","from":"wlc-primary","to":"mobile-zone-iot","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-ny","from":"core-router-1","to":"branch-router-ny","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-la","from":"core-router-1","to":"branch-router-la","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-chi","from":"core-router-1","to":"branch-router-chi","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-lon","from":"core-router-1","to":"branch-router-lon","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-tokyo","from":"core-router-1","to":"branch-router-tokyo","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-aws","from":"core-router-1","to":"cloud-aws","width":3,"color":"#f97316","direction":"both","type":"main","notes":["Direct Connect"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router2-azure","from":"core-router-2","to":"cloud-azure","width":3,"color":"#0ea5e9","direction":"both","type":"main","notes":["ExpressRoute"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-gcp","from":"fw-internal","to":"cloud-gcp","width":2,"color":"#22c55e","direction":"both","type":"main","notes":["VPN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-floor1","from":"core-switch-1","to":"dist-switch-floor1","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-floor2","from":"core-switch-1","to":"dist-switch-floor2","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-floor3","from":"core-switch-2","to":"dist-switch-floor3","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-floor4","from":"core-switch-2","to":"dist-switch-floor4","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor1-endpoints","from":"dist-switch-floor1","to":"endpoint-1000","width":2,"color":"#94a3b8","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor1-ap1","from":"dist-switch-floor1","to":"ap-floor1-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor2-ap2","from":"dist-switch-floor2","to":"ap-floor2-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor3-ap3","from":"dist-switch-floor3","to":"ap-floor3-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor4-ap4","from":"dist-switch-floor4","to":"ap-floor4-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-proxy1","from":"fw-internal","to":"proxy-server-1","width":2,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-proxy2","from":"fw-internal","to":"proxy-server-2","width":2,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwext1-vpn","from":"fw-external-1","to":"vpn-concentrator","width":3,"color":"#8b5cf6","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-nac","from":"core-switch-1","to":"nac-server","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-voip","from":"core-switch-1","to":"voip-cluster","width":3,"color":"#22c55e","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-video","from":"core-switch-2","to":"video-conf","width":3,"color":"#22c55e","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-cameras","from":"core-switch-1","to":"security-cameras","width":2,"color":"#94a3b8","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-dev1","from":"fw-internal","to":"dev-server-1","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-dev2","from":"fw-internal","to":"dev-server-2","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true,"animationSpeed":"1.5"},{"id":"fwint-test","from":"fw-internal","to":"test-environment","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-erp","from":"core-switch-1","to":"erp-system","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwext1-crm","from":"fw-external-1","to":"crm-system","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":["Salesforce cloud"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups1-racka1","from":"ups-dc-1","to":"dc-rack-a1","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed A"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups2-racka2","from":"ups-dc-2","to":"dc-rack-a2","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed B"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups1-rackb1","from":"ups-dc-1","to":"dc-rack-b1","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed A"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true,"animationSpeed":"4"},{"id":"ups2-rackb2","from":"ups-dc-2","to":"dc-rack-b2","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed B"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"cooling1-racka1","from":"cooling-1","to":"dc-rack-a1","width":2,"color":"#38bdf8","direction":"forward","type":"main","notes":["Cooling zone"],"fromPort":"","toPort":"","lineStyle":"dotted","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"cooling2-rackb1","from":"cooling-2","to":"dc-rack-b1","width":2,"color":"#38bdf8","direction":"forward","type":"main","notes":["Cooling zone"],"fromPort":"","toPort":"","lineStyle":"dotted","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"custom-1765237881452","type":"custom","color":"#c800ff","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":3492.3994140625,"y":1526.9556884765625},{"x":3500.609619140625,"y":1830.7386474609375},{"x":3303.561279296875,"y":1732.2144775390625}],"notes":[],"routing":"orthogonal"}]},"rectData":{"list":[{"id":"rect-1765237540610","x":2879.214599609375,"y":159.71981811523438,"width":992.196044921875,"height":538.8650817871094,"color":"#f97316","style":"filled","lineStyle":"solid","notes":[]},{"id":"rect-1765237681216","x":448.3926696777344,"y":1671.651123046875,"width":916.3436584472656,"height":924.27734375,"color":"#c800ff","style":"outlined","lineStyle":"solid","notes":[]},{"id":"rect-1766437913740","x":904.5889892578125,"y":115.40318298339844,"width":110.93878173828125,"height":919.6242218017578,"color":"#5215f9","style":"filled","lineStyle":"wall","notes":[],"borderWidth":13},{"id":"rect-1766437935414","x":130.93685150146484,"y":1072.3624877929688,"width":872.9131851196289,"height":99.260986328125,"color":"#5215f9","style":"filled","lineStyle":"wall","notes":[],"borderWidth":13}]},"textData":{"list":[{"id":"text-1765237828167","x":3411.458740234375,"y":1390.00439453125,"content":"Double click on desktop\nor long press on mobile\nto enter rack canvas view","fontSize":46,"color":"#e2e8f0","fontWeight":"bold","fontStyle":"italic","textAlign":"middle","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766446595277","x":654.3878479003906,"y":1367.7945556640625,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766446610211","x":180.63662719726562,"y":1128.822998046875,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766453024797","x":968.6458740234375,"y":1028.6621398925781,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1,"rotation":-89,"_dragStartX":972.46826171875,"_dragStartY":1009.5499572753906},{"id":"text-1766453070975","x":613.1589965820312,"y":1139.512939453125,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766453072857","x":968.64599609375,"y":474.40818786621094,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1,"rotation":269,"_dragStartX":1480.85302734375,"_dragStartY":822.2503356933594},{"id":"text-1766458222326","x":3167.812744140625,"y":2190.516357421875,"content":"","fontSize":18,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1}]},"edgeLegend":{"#10b981":"Trusted Lan","#f59e0b":"Secure Lan","#ef4444":"DMZ","#475569":"Main ISP","#3b82f6":"Alternate ISP","#8b5cf6":"you can edit me too","#06b6d4":"you can edit me too","#a855f7":"you can edit me too","#f97316":"you can edit me too","#0ea5e9":"you can edit me too","#22c55e":"you can edit me too","#94a3b8":"you can edit me too","#fbbf24":"you can edit me too","#38bdf8":"you can edit me too","#c800ff":"you can edit me too"},"nodePositions":{"core-router-1":{"x":3720.166015625,"y":245.9932403564453},"core-router-2":{"x":2499.883407638303,"y":329.99503430389154},"fw-external-1":{"x":3221.7385182723783,"y":1016.1364499992887},"fw-external-2":{"x":1915.5213706410505,"y":224.43528858865443},"fw-internal":{"x":1746.9168185079352,"y":477.5300527221864},"core-switch-1":{"x":449.39860669455675,"y":384.4578707617695},"core-switch-2":{"x":761.1664921394672,"y":180.89283910873155},"dc-rack-a1":{"x":783.7017241128451,"y":647.4086870405963},"dc-rack-a2":{"x":209.25701628255229,"y":228.01593190351014},"dc-rack-b1":{"x":3184.3186625759854,"y":1627.4495531027196},"dc-rack-b2":{"x":245.37065918741246,"y":499.6191264194081},"dmz-rack":{"x":2176.4105289561007,"y":610.8312056412005},"mgmt-rack":{"x":1601.2987201807314,"y":1281.4753424975324},"esxi-host-01":{"x":2162.2166789540615,"y":2608.110619289529},"esxi-host-02":{"x":2205.94717202368,"y":2689.67539624076},"esxi-host-03":{"x":2154.6015436939074,"y":2771.203009774913},"esxi-host-04":{"x":2195.986926025096,"y":2845},"tor-switch-a1":{"x":2146.8943639962963,"y":2845},"esxi-host-05":{"x":2185.9099961569727,"y":2845},"esxi-host-06":{"x":2139.099728450725,"y":2845},"esxi-host-07":{"x":2175.7223818764883,"y":2845},"esxi-host-08":{"x":2131.2222777148922,"y":2845},"tor-switch-a2":{"x":2165.4301485385085,"y":2845},"san-primary":{"x":2123.2667017518106,"y":2845},"san-secondary":{"x":2155.0394237844876,"y":2845},"fc-switch-1":{"x":2115.2377370375634,"y":2845},"fc-switch-2":{"x":2144.5563938942755,"y":2845},"backup-server-1":{"x":2107.1401637413705,"y":2845},"backup-server-2":{"x":2133.987300103025,"y":2845},"tape-library":{"x":2098.9788028796397,"y":2845},"tor-switch-b1":{"x":2123.338434885373,"y":2845},"tor-switch-b2":{"x":2090.7585134456995,"y":2845},"web-server-1":{"x":2112.6161382091163,"y":2845},"web-server-2":{"x":2082.484189516922,"y":2845},"waf-1":{"x":2101.826793760617,"y":2845},"load-balancer-dmz":{"x":2074.1607573409574,"y":2845},"mail-gateway":{"x":2090.97682514417,"y":2845},"dns-external-1":{"x":2065.7931724028163,"y":2845},"dns-external-2":{"x":2080.0726920576153,"y":2845},"vcenter":{"x":2057.3864164745437,"y":2845},"nsx-manager":{"x":2069.1208864464534,"y":2845},"siem-server":{"x":2048.945494649244,"y":2845},"nms-server":{"x":2058.1279286387635,"y":2845},"jump-server":{"x":2040.4754323612206,"y":2845},"ipam-server":{"x":2047.1003634632284,"y":2845},"wlc-primary":{"x":1575.9723612611924,"y":2306.135986328125},"wlc-secondary":{"x":1468.1361870166274,"y":1563.733642578125},"mobile-zone-hq":{"x":2354.901177346808,"y":2806.0078125},"mobile-zone-guest":{"x":2307.6605605284435,"y":2611.047119140625},"mobile-zone-iot":{"x":2229.397686389302,"y":2299.110107421875},"branch-router-ny":{"x":3151.903101363964,"y":633.6580810546875},"branch-router-la":{"x":3083.8876194705945,"y":506.90625},"branch-router-chi":{"x":3355.02409980103,"y":393.1805725097656},"branch-router-lon":{"x":3113.609823320121,"y":260.4093322753906},"branch-router-tokyo":{"x":3699.3234994733834,"y":471.4241027832031},"cloud-aws":{"x":3436.528122523513,"y":545.9614868164062},"cloud-azure":{"x":2592.566210818907,"y":2724.068115234375},"cloud-gcp":{"x":2827.3183770424234,"y":2731.397216796875},"isp-primary":{"x":3712.192068081962,"y":615.64990234375},"isp-secondary":{"x":3253.9473366098055,"y":1993.2629089355469},"dc-internal-1":{"x":1958.4243458877936,"y":2845},"dc-internal-2":{"x":1963.768951182132,"y":2845},"app-server-1":{"x":1947.3819379304134,"y":2845},"app-server-2":{"x":1955.2862087394126,"y":2845},"db-server-1":{"x":1936.3708569559828,"y":2845},"db-server-2":{"x":1946.8300873488822,"y":2845},"k8s-master-1":{"x":1925.397658583093,"y":2845},"k8s-master-2":{"x":1938.405621494142,"y":2845},"k8s-master-3":{"x":1914.4688758763386,"y":2845},"k8s-worker-1":{"x":1930.017826812177,"y":2845},"k8s-worker-2":{"x":1903.5910154567553,"y":2845},"k8s-worker-3":{"x":1921.6716971072178,"y":2845},"k8s-worker-4":{"x":1892.7705536280016,"y":2845},"proxy-server-1":{"x":1806.1152433697903,"y":653.7529296875},"proxy-server-2":{"x":2937.4207928721535,"y":2628.7880859375},"vpn-concentrator":{"x":3642.252088474593,"y":946.7255249023438},"nac-server":{"x":1153.2626148502184,"y":1172.1895751953125},"print-server":{"x":1896.9328460745962,"y":2845},"file-server":{"x":1860.7177871362182,"y":2845},"ca-server":{"x":1888.8027739274805,"y":2845},"sccm-server":{"x":1850.1909418511675,"y":2845},"voip-cluster":{"x":1777.038465328039,"y":1616.8961181640625},"video-conf":{"x":1993.8373941679588,"y":2244.936309814453},"security-cameras":{"x":1674.413336949044,"y":2046.0380859375},"nvr-cluster":{"x":1829.4110389706402,"y":2845},"dev-server-1":{"x":2800.5894350649614,"y":1175.623291015625},"dev-server-2":{"x":1945.0822182484326,"y":1164.5184783935547},"test-environment":{"x":2932.0863047891075,"y":862.4592895507812},"erp-system":{"x":789.9880103985649,"y":473.7113342285156},"crm-system":{"x":3514.6003232048542,"y":1137.7720947265625},"endpoint-1000":{"x":991.6812012057328,"y":2284.42236328125},"dist-switch-floor1":{"x":654.2091033261356,"y":2020.0086669921875},"dist-switch-floor2":{"x":853.8845527112826,"y":1843.2872314453125},"dist-switch-floor3":{"x":1899.4353951584517,"y":1456.5068359375},"dist-switch-floor4":{"x":488.5289313756234,"y":181.47256469726562},"ap-floor1-zone1":{"x":1140.16846970184,"y":2070.2916259765625},"ap-floor2-zone1":{"x":688.1952143592268,"y":2384.4775390625},"ap-floor3-zone1":{"x":2145.3803027919676,"y":1890.2816162109375},"ap-floor4-zone1":{"x":517.646146409649,"y":565.59716796875},"ups-dc-1":{"x":771.1406786539856,"y":295.9266662597656},"ups-dc-2":{"x":216.2410855890687,"y":330.3345947265625},"pdu-rack-a1":{"x":1804.774444371901,"y":2845},"pdu-rack-a2":{"x":1741.6184034693686,"y":2845},"cooling-1":{"x":245.7080801919958,"y":626.1914672851562},"cooling-2":{"x":1603.293611085831,"y":981.0621185302734},"camera-a":{"x":166.57075412676295,"y":145},"camera-a-copy":{"x":1040.653076171875,"y":738.42822265625}},"nodeSizes":{"isp-secondary":139,"test-environment":121,"dev-server-1":128,"core-router-2":120,"camera-a":45,"camera-a-copy":45},"nodeStyles":{"dc-rack-b2":{"all":{"circleColor":"#ff0000"}},"dc-rack-a1":{"all":{"circleColor":"#ff0000"}},"dc-rack-b1":{"all":{"circleColor":"#ff0000","titleSize":59}},"isp-secondary":{"all":{"icon":{"library":"selfhst","name":"alist"},"circleColor":"#4d2c58","circleBorder":"#000000","titleColor":"#006eff"}},"core-router-2":{"all":{"icon":{"library":"selfhst","name":"actual-budget"},"pingOffsetX":-15,"pingOffsetY":-38}},"fw-external-1":{"all":{"icon":{"library":"selfhst","name":"anonaddy"}}},"cloud-aws":{"all":{"icon":{"library":"selfhst","name":"ansible"}}},"isp-primary":{"all":{"icon":{"library":"selfhst","name":"wikidocs"}}},"branch-router-tokyo":{"all":{"icon":{"library":"selfhst","name":"adguard-home"}}},"core-router-1":{"all":{"icon":{"library":"selfhst","name":"borg"}}},"test-environment":{"all":{"icon":{"library":"simple","name":"apple"}}},"dev-server-1":{"all":{"icon":{"library":"simple","name":"amazonwebservices"}}}},"page":{"title":"The One File Corporate","background":"","topbarBg":"rgba(9, 12, 20, 0.9)","topbarBorder":"#1f2533","panel":"#0b0e13","panelAlt":"#10141b","accent":"#4fd1c5","sidebarBg":"#10141b","btnBg":"#0b0e13","btnText":"#e2e8f0","tagFill":"#1e293b","tagText":"#e2e8f0","tagBorder":"#475569","inputBg":"#0b0e13","inputText":"#e2e8f0","inputBorder":"#1f2937","inputFont":"Inter, system-ui, sans-serif","inputFontSize":14,"toolbarBg":"#0f172a","toolbarBorder":"#1f2937","toolbarText":"#94a3b8","toolbarBtnBg":"#0b0e13","toolbarBtnText":"#e2e8f0","minimapDots":"#94a3b8","canvasHintEnabled":true,"canvasHintText":"","canvasHintBg":"#0f172a","canvasHintColor":"#94a3b8","danger":"#f56565","textMain":"#e2e8f0","textSoft":"#94a3b8","topbarHeight":103,"sidebarWidth":350,"mobileFooterHeight":40,"sidebarCollapsed":false,"nodeFill":"#1e293b","nodeStroke":"#475569","nodeTitle":"#e2e8f0","nodeSub":"#94a3b8","nodeTitleSize":41,"nodeSubSize":27,"nodeFont":"monospace","defaultEdge":"#475569","selectionHandle":"#f59e0b","selectionHandleSize":8,"groupIndicator":"#4fd1c5","canvasGradientTop":"#1e2532","canvasGradientBottom":"#050608","canvasBorder":"#475569","canvasGrid":"#475569","canvasGridSize":50,"canvasGridEnabled":true,"rackFrameFill":"#0f172a","rackGridEnabled":true,"rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","viewOnly":false,"defaultEdgeRouting":"orthogonal","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":4,"autoPingEnabled":false,"autoPingInterval":30},"canvas":{"zoom":0.8752084596859406,"panX":-191.26917538063572,"panY":-261.51832729948296},"savedTopologyView":{"zoom":0.9111098220009686,"panX":-207.26076103009882,"panY":-201.83911371533202},"documentTabs":[{"id":"main","name":"Corporate Site B","nodes":{"core-router-1":{"shape":"router","name":"Core Router 1","ip":"10.0.0.1","role":"Core Routing","tags":["core","tier-1","redundant"],"notes":["Primary core router","BGP peering enabled"],"mac":"00:1A:2B:3C:4D:01","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-router-2":{"shape":"router","name":"Core Router 2","ip":"10.0.0.2","role":"Core Routing","tags":["core","tier-1","redundant"],"notes":["Secondary core router","HSRP standby"],"mac":"00:1A:2B:3C:4D:02","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"ping":{"enabled":true,"protocol":"custom","customUrl":"https://google.com","timeout":3000,"status":"online","lastCheck":"2025-12-09T00:15:04.343Z"}},"fw-external-1":{"shape":"firewall","name":"External FW 1","ip":"10.0.1.1","role":"Perimeter Security","tags":["security","perimeter","ha-pair"],"notes":["Palo Alto PA-5250","Active node"],"mac":"00:1A:2B:3C:4D:10","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fw-external-2":{"shape":"firewall","name":"External FW 2","ip":"10.0.1.2","role":"Perimeter Security","tags":["security","perimeter","ha-pair"],"notes":["Palo Alto PA-5250","Passive node"],"mac":"00:1A:2B:3C:4D:11","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fw-internal":{"shape":"firewall","name":"Internal FW","ip":"10.0.2.1","role":"Internal Segmentation","tags":["security","internal"],"notes":["East-West traffic inspection"],"mac":"00:1A:2B:3C:4D:12","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-switch-1":{"shape":"switch","name":"Core Switch 1","ip":"10.0.10.1","role":"Core Switching","tags":["core","layer3","redundant"],"notes":["Cisco Nexus 9000","VPC Domain 1"],"mac":"00:1A:2B:3C:4D:20","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"core-switch-2":{"shape":"switch","name":"Core Switch 2","ip":"10.0.10.2","role":"Core Switching","tags":["core","layer3","redundant"],"notes":["Cisco Nexus 9000","VPC Domain 1"],"mac":"00:1A:2B:3C:4D:21","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dc-rack-a1":{"shape":"server","name":"DC Rack A1","ip":"10.10.0.0/24","role":"Data Center Rack","tags":["datacenter","row-a","production"],"notes":["Row A, Position 1","Primary compute"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-a2":{"shape":"server","name":"DC Rack A2","ip":"10.10.1.0/24","role":"Data Center Rack","tags":["datacenter","row-a","production"],"notes":["Row A, Position 2","Primary compute"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-b1":{"shape":"server","name":"DC Rack B1","ip":"10.10.2.0/24","role":"Data Center Rack","tags":["datacenter","row-b","storage"],"notes":["Row B, Position 1","Storage systems"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dc-rack-b2":{"shape":"server","name":"DC Rack B2","ip":"10.10.3.0/24","role":"Data Center Rack","tags":["datacenter","row-b","storage"],"notes":["Row B, Position 2","Storage systems"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"dmz-rack":{"shape":"server","name":"DMZ Rack","ip":"172.16.0.0/24","role":"DMZ Infrastructure","tags":["dmz","security","public-facing",{"type":"icon","library":"selfhst","name":"booklogr"},{"type":"icon","library":"simple","name":"gmail"}],"notes":["Isolated DMZ zone","Public-facing services"],"mac":"","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"24","isRack":true,"locked":false,"groupId":null},"mgmt-rack":{"shape":"server","name":"Management Rack","ip":"192.168.100.0/24","role":"Management Infrastructure","tags":["management","oob","noc"],"notes":["Out-of-band management","NOC equipment"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"24","isRack":true,"locked":false,"groupId":null},"esxi-host-01":{"shape":"server","name":"ESXi Host 01","ip":"10.10.0.11","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:01","rackUnit":38,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-02":{"shape":"server","name":"ESXi Host 02","ip":"10.10.0.12","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:02","rackUnit":35,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-03":{"shape":"server","name":"ESXi Host 03","ip":"10.10.0.13","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:03","rackUnit":32,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-04":{"shape":"server","name":"ESXi Host 04","ip":"10.10.0.14","role":"Hypervisor","tags":["vmware","compute","cluster-a"],"notes":["Dell PowerEdge R750","512GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:01:04","rackUnit":29,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-a1":{"shape":"switch","name":"ToR Switch A1","ip":"10.10.0.1","role":"Top of Rack","tags":["tor","access","rack-a1"],"notes":["Cisco Nexus 93180YC-FX","48x25G ports"],"mac":"00:1A:2B:3C:5D:01","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-05":{"shape":"server","name":"ESXi Host 05","ip":"10.10.1.11","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:01","rackUnit":38,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-06":{"shape":"server","name":"ESXi Host 06","ip":"10.10.1.12","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:02","rackUnit":35,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-07":{"shape":"server","name":"ESXi Host 07","ip":"10.10.1.13","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:03","rackUnit":32,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"esxi-host-08":{"shape":"server","name":"ESXi Host 08","ip":"10.10.1.14","role":"Hypervisor","tags":["vmware","compute","cluster-b"],"notes":["Dell PowerEdge R750","768GB RAM","vSphere 8.0"],"mac":"00:50:56:AA:02:04","rackUnit":29,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-a2":{"shape":"switch","name":"ToR Switch A2","ip":"10.10.1.1","role":"Top of Rack","tags":["tor","access","rack-a2"],"notes":["Cisco Nexus 93180YC-FX","48x25G ports"],"mac":"00:1A:2B:3C:5D:02","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"san-primary":{"shape":"database","name":"SAN Primary","ip":"10.10.2.10","role":"Primary Storage","tags":["storage","san","netapp"],"notes":["NetApp AFF A400","500TB Raw","FC 32Gb"],"mac":"00:A0:98:AA:01:01","rackUnit":36,"uHeight":"6","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"san-secondary":{"shape":"database","name":"SAN Secondary","ip":"10.10.2.11","role":"Secondary Storage","tags":["storage","san","netapp"],"notes":["NetApp AFF A400","500TB Raw","FC 32Gb"],"mac":"00:A0:98:AA:01:02","rackUnit":28,"uHeight":"6","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fc-switch-1":{"shape":"switch","name":"FC Switch 1","ip":"10.10.2.1","role":"Fibre Channel","tags":["storage","fc","fabric-a"],"notes":["Brocade G620","Fabric A"],"mac":"00:1A:2B:FC:01:01","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"fc-switch-2":{"shape":"switch","name":"FC Switch 2","ip":"10.10.2.2","role":"Fibre Channel","tags":["storage","fc","fabric-b"],"notes":["Brocade G620","Fabric B"],"mac":"00:1A:2B:FC:01:02","rackUnit":41,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"backup-server-1":{"shape":"server","name":"Backup Server 1","ip":"10.10.3.10","role":"Backup Infrastructure","tags":["backup","veeam","protection"],"notes":["Veeam Backup Server","Dell R740xd","200TB"],"mac":"00:50:56:BB:01:01","rackUnit":36,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"backup-server-2":{"shape":"server","name":"Backup Server 2","ip":"10.10.3.11","role":"Backup Infrastructure","tags":["backup","veeam","protection"],"notes":["Veeam Backup Server","Dell R740xd","200TB"],"mac":"00:50:56:BB:01:02","rackUnit":33,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tape-library":{"shape":"database","name":"Tape Library","ip":"10.10.3.20","role":"Archival Storage","tags":["backup","tape","lto9"],"notes":["IBM TS4500","LTO-9","Long-term archive"],"mac":"00:50:56:BB:02:01","rackUnit":20,"uHeight":"10","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-b1":{"shape":"switch","name":"ToR Switch B1","ip":"10.10.2.3","role":"Top of Rack","tags":["tor","access","rack-b1"],"notes":["Cisco Nexus 93180YC-FX"],"mac":"00:1A:2B:3C:5D:03","rackUnit":40,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"tor-switch-b2":{"shape":"switch","name":"ToR Switch B2","ip":"10.10.3.1","role":"Top of Rack","tags":["tor","access","rack-b2"],"notes":["Cisco Nexus 93180YC-FX"],"mac":"00:1A:2B:3C:5D:04","rackUnit":42,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"web-server-1":{"shape":"server","name":"Web Server 1","ip":"172.16.0.11","role":"Web Frontend","tags":["dmz","web","nginx"],"notes":["NGINX reverse proxy","Public facing"],"mac":"00:50:56:CC:01:01","rackUnit":20,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"web-server-2":{"shape":"server","name":"Web Server 2","ip":"172.16.0.12","role":"Web Frontend","tags":["dmz","web","nginx"],"notes":["NGINX reverse proxy","Public facing"],"mac":"00:50:56:CC:01:02","rackUnit":18,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"waf-1":{"shape":"firewall","name":"WAF Appliance","ip":"172.16.0.5","role":"Web Application Firewall","tags":["dmz","security","waf"],"notes":["F5 BIG-IP ASM","OWASP protection"],"mac":"00:50:56:CC:02:01","rackUnit":22,"uHeight":"2","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"load-balancer-dmz":{"shape":"switch","name":"DMZ Load Balancer","ip":"172.16.0.3","role":"Load Balancing","tags":["dmz","lb","f5"],"notes":["F5 BIG-IP LTM","VIP: 172.16.0.100"],"mac":"00:50:56:CC:03:01","rackUnit":16,"uHeight":"2","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"mail-gateway":{"shape":"server","name":"Mail Gateway","ip":"172.16.0.25","role":"Email Security","tags":["dmz","email","security"],"notes":["Proofpoint Email Gateway","Spam/malware filtering"],"mac":"00:50:56:CC:04:01","rackUnit":14,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"dns-external-1":{"shape":"circle","name":"External DNS 1","ip":"172.16.0.53","role":"External DNS","tags":["dmz","dns","public"],"notes":["BIND DNS","Authoritative for corp.com"],"mac":"00:50:56:CC:05:01","rackUnit":12,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"dns-external-2":{"shape":"circle","name":"External DNS 2","ip":"172.16.0.54","role":"External DNS","tags":["dmz","dns","public"],"notes":["BIND DNS","Secondary for corp.com"],"mac":"00:50:56:CC:05:02","rackUnit":10,"uHeight":"1","layer":"security","assignedRack":"dmz-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"vcenter":{"shape":"server","name":"vCenter Server","ip":"192.168.100.10","role":"Virtualization Management","tags":["management","vmware","vcsa"],"notes":["vCenter Server Appliance 8.0","Single SSO domain"],"mac":"00:50:56:DD:01:01","rackUnit":20,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"nsx-manager":{"shape":"server","name":"NSX Manager","ip":"192.168.100.15","role":"Network Virtualization","tags":["management","vmware","nsx"],"notes":["NSX-T 4.1 Manager Cluster"],"mac":"00:50:56:DD:02:01","rackUnit":17,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"siem-server":{"shape":"server","name":"SIEM Server","ip":"192.168.100.50","role":"Security Monitoring","tags":["management","security","splunk"],"notes":["Splunk Enterprise","Security monitoring"],"mac":"00:50:56:DD:03:01","rackUnit":14,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"nms-server":{"shape":"server","name":"Network Monitoring","ip":"192.168.100.60","role":"Network Management","tags":["management","monitoring","prtg"],"notes":["PRTG Network Monitor","5000 sensors"],"mac":"00:50:56:DD:04:01","rackUnit":11,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"jump-server":{"shape":"server","name":"Jump Server","ip":"192.168.100.100","role":"Bastion Host","tags":["management","security","bastion"],"notes":["Windows Server 2022","MFA enabled"],"mac":"00:50:56:DD:05:01","rackUnit":9,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"ipam-server":{"shape":"server","name":"IPAM/DDI","ip":"192.168.100.70","role":"IP Management","tags":["management","dns","dhcp"],"notes":["Infoblox DDI","DNS/DHCP/IPAM"],"mac":"00:50:56:DD:06:01","rackUnit":7,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"wlc-primary":{"shape":"wifi","name":"WLC Primary","ip":"10.20.0.1","role":"Wireless Controller","tags":["wireless","cisco","9800"],"notes":["Cisco C9800-40","Primary controller"],"mac":"00:1A:2B:WL:01:01","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"wlc-secondary":{"shape":"wifi","name":"WLC Secondary","ip":"10.20.0.2","role":"Wireless Controller","tags":["wireless","cisco","9800"],"notes":["Cisco C9800-40","HA Secondary"],"mac":"00:1A:2B:WL:01:02","rackUnit":"","uHeight":"2","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-hq":{"shape":"phone","name":"HQ Mobile Zone","ip":"10.20.10.0/24","role":"Mobile Device Zone","tags":["wireless","byod","mobile"],"notes":["Corporate BYOD","MDM enrolled devices"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-guest":{"shape":"phone","name":"Guest WiFi Zone","ip":"10.30.0.0/24","role":"Guest Network","tags":["wireless","guest","isolated"],"notes":["Captive portal","Internet only"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"mobile-zone-iot":{"shape":"phone","name":"IoT Device Zone","ip":"10.40.0.0/24","role":"IoT Network","tags":["wireless","iot","building"],"notes":["Building automation","Smart devices"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-ny":{"shape":"router","name":"NYC Branch Router","ip":"10.100.0.1","role":"Branch Gateway","tags":["branch","nyc","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-la":{"shape":"router","name":"LA Branch Router","ip":"10.101.0.1","role":"Branch Gateway","tags":["branch","la","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-chi":{"shape":"router","name":"Chicago Branch Router","ip":"10.102.0.1","role":"Branch Gateway","tags":["branch","chicago","sd-wan"],"notes":["Cisco Viptela vEdge","SD-WAN enabled"],"mac":"00:1A:2B:BR:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-lon":{"shape":"router","name":"London Branch Router","ip":"10.200.0.1","role":"Branch Gateway","tags":["branch","london","sd-wan"],"notes":["Cisco Viptela vEdge","EMEA region"],"mac":"00:1A:2B:BR:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"branch-router-tokyo":{"shape":"router","name":"Tokyo Branch Router","ip":"10.201.0.1","role":"Branch Gateway","tags":["branch","tokyo","sd-wan"],"notes":["Cisco Viptela vEdge","APAC region"],"mac":"00:1A:2B:BR:05:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-aws":{"shape":"cloud","name":"AWS Cloud","ip":"vpc-0a1b2c3d","role":"Public Cloud","tags":["cloud","aws","hybrid"],"notes":["AWS US-East-1","VPC peering to HQ"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-azure":{"shape":"cloud","name":"Azure Cloud","ip":"vnet-corp-prod","role":"Public Cloud","tags":["cloud","azure","hybrid"],"notes":["Azure East US 2","ExpressRoute"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cloud-gcp":{"shape":"cloud","name":"GCP Cloud","ip":"vpc-gcp-corp","role":"Public Cloud","tags":["cloud","gcp","dev"],"notes":["GCP us-central1","Dev/Test workloads"],"mac":"","rackUnit":"","uHeight":"1","layer":"logical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"isp-primary":{"shape":"globe","name":"ISP Primary","ip":"203.0.113.1","role":"Internet Uplink","tags":["wan","internet","primary"],"notes":["AT&T MPLS","1 Gbps dedicated"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"isp-secondary":{"shape":"vm","name":"ISP Secondary","ip":"198.51.100.1","role":"Internet Uplink","tags":["wan","internet","backup"],"notes":["Verizon Business","500 Mbps backup"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"rotation":-17},"dc-internal-1":{"shape":"circle","name":"DC1 Int DNS","ip":"10.10.0.53","role":"Internal DNS/AD","tags":["dns","ad","dc1"],"notes":["Windows Server 2022","Primary DC"],"mac":"00:50:56:AD:01:01","rackUnit":26,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dc-internal-2":{"shape":"circle","name":"DC2 Int DNS","ip":"10.10.1.53","role":"Internal DNS/AD","tags":["dns","ad","dc2"],"notes":["Windows Server 2022","Secondary DC"],"mac":"00:50:56:AD:01:02","rackUnit":26,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"app-server-1":{"shape":"server","name":"App Server 01","ip":"10.10.0.101","role":"Application","tags":["app","iis","web"],"notes":["Windows Server 2022","IIS Application"],"mac":"00:50:56:AP:01:01","rackUnit":24,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"app-server-2":{"shape":"server","name":"App Server 02","ip":"10.10.0.102","role":"Application","tags":["app","iis","web"],"notes":["Windows Server 2022","IIS Application"],"mac":"00:50:56:AP:01:02","rackUnit":22,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"db-server-1":{"shape":"database","name":"SQL Server 01","ip":"10.10.0.201","role":"Database","tags":["db","sql","primary"],"notes":["SQL Server 2022 Enterprise","AlwaysOn Primary"],"mac":"00:50:56:DB:01:01","rackUnit":20,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"db-server-2":{"shape":"database","name":"SQL Server 02","ip":"10.10.1.201","role":"Database","tags":["db","sql","secondary"],"notes":["SQL Server 2022 Enterprise","AlwaysOn Secondary"],"mac":"00:50:56:DB:01:02","rackUnit":24,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-1":{"shape":"hexagon","name":"K8s Master 1","ip":"10.10.1.50","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:01","rackUnit":21,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-2":{"shape":"hexagon","name":"K8s Master 2","ip":"10.10.1.51","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:02","rackUnit":19,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-master-3":{"shape":"hexagon","name":"K8s Master 3","ip":"10.10.1.52","role":"Container Orchestration","tags":["kubernetes","master","container"],"notes":["K8s Control Plane","etcd member"],"mac":"00:50:56:K8:01:03","rackUnit":17,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-1":{"shape":"server","name":"K8s Worker 1","ip":"10.10.1.60","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:01","rackUnit":15,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-2":{"shape":"server","name":"K8s Worker 2","ip":"10.10.1.61","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:02","rackUnit":13,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-3":{"shape":"server","name":"K8s Worker 3","ip":"10.10.1.62","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:03","rackUnit":11,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"k8s-worker-4":{"shape":"server","name":"K8s Worker 4","ip":"10.10.1.63","role":"Container Workload","tags":["kubernetes","worker","container"],"notes":["K8s Worker Node","64GB RAM"],"mac":"00:50:56:K8:02:04","rackUnit":9,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"proxy-server-1":{"shape":"server","name":"Proxy Server 1","ip":"10.5.0.10","role":"Web Proxy","tags":["proxy","squid","filtering"],"notes":["Squid Proxy","Content filtering"],"mac":"00:50:56:PX:01:01","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"proxy-server-2":{"shape":"server","name":"Proxy Server 2","ip":"10.5.0.11","role":"Web Proxy","tags":["proxy","squid","filtering"],"notes":["Squid Proxy","HA pair"],"mac":"00:50:56:PX:01:02","rackUnit":"","uHeight":"1","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"vpn-concentrator":{"shape":"firewall","name":"VPN Concentrator","ip":"10.0.5.1","role":"Remote Access VPN","tags":["vpn","remote","security"],"notes":["Cisco ASA 5555-X","AnyConnect SSL VPN"],"mac":"00:1A:2B:VP:01:01","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"nac-server":{"shape":"server","name":"NAC Server","ip":"10.5.5.10","role":"Network Access Control","tags":["nac","ise","802.1x"],"notes":["Cisco ISE 3.1","RADIUS/TACACS+"],"mac":"00:50:56:NA:01:01","rackUnit":"","uHeight":"2","layer":"security","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"print-server":{"shape":"server","name":"Print Server","ip":"10.10.0.150","role":"Print Services","tags":["print","windows","services"],"notes":["Windows Print Server","50+ printers"],"mac":"00:50:56:PR:01:01","rackUnit":18,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"file-server":{"shape":"database","name":"File Server","ip":"10.10.0.160","role":"File Services","tags":["file","smb","dfs"],"notes":["Windows File Server","DFS namespace"],"mac":"00:50:56:FS:01:01","rackUnit":16,"uHeight":"2","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ca-server":{"shape":"server","name":"Certificate Authority","ip":"192.168.100.80","role":"PKI Infrastructure","tags":["pki","ca","security"],"notes":["Windows CA","Enterprise Root CA"],"mac":"00:50:56:CA:01:01","rackUnit":5,"uHeight":"1","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"sccm-server":{"shape":"server","name":"SCCM Server","ip":"192.168.100.90","role":"Endpoint Management","tags":["sccm","patching","software"],"notes":["MECM Primary Site","Software deployment"],"mac":"00:50:56:SC:01:01","rackUnit":3,"uHeight":"2","layer":"logical","assignedRack":"mgmt-rack","rackCapacity":"24","isRack":false,"locked":false,"groupId":null},"voip-cluster":{"shape":"phone","name":"VoIP Cluster","ip":"10.50.0.0/24","role":"Voice Services","tags":["voip","cisco","ucm"],"notes":["Cisco UCM Cluster","3000 endpoints"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"video-conf":{"shape":"laptop","name":"Video Conference","ip":"10.51.0.0/24","role":"Video Services","tags":["video","webex","teams"],"notes":["Webex/Teams integration","Meeting rooms"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"security-cameras":{"shape":"camera","name":"Security Cameras","ip":"10.60.0.0/24","role":"Physical Security","tags":["cctv","surveillance","security"],"notes":["150+ IP cameras","30-day retention"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"nvr-cluster":{"shape":"server","name":"NVR Cluster","ip":"10.60.0.10","role":"Video Recording","tags":["nvr","surveillance","storage"],"notes":["Milestone XProtect","500TB storage"],"mac":"00:50:56:NV:01:01","rackUnit":15,"uHeight":"4","layer":"physical","assignedRack":"dc-rack-b2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dev-server-1":{"shape":"server","name":"Dev Server 1","ip":"10.80.0.10","role":"Development","tags":["dev","gitlab","ci-cd",{"type":"icon","library":"selfhst","name":"dokku"}],"notes":["GitLab Server","CI/CD pipelines"],"mac":"00:50:56:DV:01:01","rackUnit":"","uHeight":"2","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dev-server-2":{"shape":"server","name":"Dev Server 2","ip":"10.80.0.11","role":"Development","tags":["dev","jenkins","ci-cd"],"notes":["Jenkins Server","Build automation"],"mac":"00:50:56:DV:01:02","rackUnit":"","uHeight":"2","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"test-environment":{"shape":"shield","name":"Test Environment","ip":"10.81.0.0/24","role":"QA/Testing","tags":["test","qa","staging"],"notes":["Staging environment","Pre-prod validation"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null,"rotation":-36},"erp-system":{"shape":"database","name":"ERP System","ip":"10.90.0.10","role":"Business Application","tags":["erp","sap","business"],"notes":["SAP S/4HANA","Financial/HR systems"],"mac":"00:50:56:ER:01:01","rackUnit":"","uHeight":"4","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"crm-system":{"shape":"database","name":"CRM System","ip":"10.91.0.10","role":"Business Application","tags":["crm","salesforce","business"],"notes":["Salesforce integration","Sales/Marketing"],"mac":"","rackUnit":"","uHeight":"1","layer":"application","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"endpoint-1000":{"shape":"laptop","name":"Corporate Endpoints","ip":"10.70.0.0/22","role":"User Workstations","tags":["endpoints","workstations","users"],"notes":["~1000 corporate laptops","Windows 11"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor1":{"shape":"switch","name":"Floor 1 Switch","ip":"10.1.1.1","role":"Distribution","tags":["distribution","floor-1","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor2":{"shape":"switch","name":"Floor 2 Switch","ip":"10.1.2.1","role":"Distribution","tags":["distribution","floor-2","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor3":{"shape":"switch","name":"Floor 3 Switch","ip":"10.1.3.1","role":"Distribution","tags":["distribution","floor-3","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dist-switch-floor4":{"shape":"switch","name":"Floor 4 Switch","ip":"10.1.4.1","role":"Distribution","tags":["distribution","floor-4","access"],"notes":["Cisco C9300-48P","PoE+ enabled"],"mac":"00:1A:2B:FL:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor1-zone1":{"shape":"wifi","name":"AP Floor 1 Zone 1","ip":"10.20.1.10","role":"Wireless Access","tags":["wifi","ap","floor-1"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:01:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor2-zone1":{"shape":"wifi","name":"AP Floor 2 Zone 1","ip":"10.20.2.10","role":"Wireless Access","tags":["wifi","ap","floor-2"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:02:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor3-zone1":{"shape":"wifi","name":"AP Floor 3 Zone 1","ip":"10.20.3.10","role":"Wireless Access","tags":["wifi","ap","floor-3"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:03:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ap-floor4-zone1":{"shape":"wifi","name":"AP Floor 4 Zone 1","ip":"10.20.4.10","role":"Wireless Access","tags":["wifi","ap","floor-4"],"notes":["Cisco 9120AX","Wi-Fi 6"],"mac":"00:1A:2B:AP:04:01","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ups-dc-1":{"shape":"rectangle","name":"UPS DC-1","ip":"192.168.200.10","role":"Power Management","tags":["power","ups","datacenter"],"notes":["APC Symmetra","80kVA","30 min runtime"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"ups-dc-2":{"shape":"rectangle","name":"UPS DC-2","ip":"192.168.200.11","role":"Power Management","tags":["power","ups","datacenter"],"notes":["APC Symmetra","80kVA","Redundant"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"pdu-rack-a1":{"shape":"rectangle","name":"PDU Rack A1","ip":"192.168.200.21","role":"Power Distribution","tags":["power","pdu","rack-a1"],"notes":["APC Switched PDU","Per-outlet metering"],"mac":"","rackUnit":1,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a1","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"pdu-rack-a2":{"shape":"rectangle","name":"PDU Rack A2","ip":"192.168.200.22","role":"Power Distribution","tags":["power","pdu","rack-a2"],"notes":["APC Switched PDU","Per-outlet metering"],"mac":"","rackUnit":1,"uHeight":"1","layer":"physical","assignedRack":"dc-rack-a2","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cooling-1":{"shape":"rectangle","name":"CRAC Unit 1","ip":"192.168.200.30","role":"Cooling","tags":["cooling","hvac","datacenter"],"notes":["Liebert CRV","Row-based cooling"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"cooling-2":{"shape":"rectangle","name":"CRAC Unit 2","ip":"192.168.200.31","role":"Cooling","tags":["cooling","hvac","datacenter"],"notes":["Liebert CRV","N+1 redundancy"],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"camera-a":{"shape":"camera","name":"camera A","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","ping":{"enabled":false,"protocol":"http","customUrl":"","timeout":3000,"status":"unknown","lastCheck":null},"locked":false,"groupId":null,"fovEnabled":true,"fovRotation":104,"fovDistance":500,"fovSweep":60,"fovSpeed":10,"fovAnimate":true},"camera-a-copy":{"shape":"camera","name":"camera B","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","ping":{"enabled":false,"protocol":"http","customUrl":"","timeout":3000,"status":"unknown","lastCheck":null},"locked":false,"groupId":null,"fovEnabled":true,"fovRotation":162,"fovDistance":500,"fovSweep":60,"fovSpeed":10,"fovAnimate":false}},"edges":{"list":[{"id":"isp1-router1","from":"isp-primary","to":"core-router-1","width":6,"color":"#10b981","direction":"both","type":"main","notes":["Primary WAN link"],"fromPort":"Gi0/0","toPort":"Gi1/0/1","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"isp2-router2","from":"isp-secondary","to":"core-router-2","width":6,"color":"#10b981","direction":"both","type":"main","notes":["Backup WAN link"],"fromPort":"Gi0/0","toPort":"Gi1/0/1","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-router2","from":"core-router-1","to":"core-router-2","width":4,"color":"#f59e0b","direction":"both","type":"main","notes":["HSRP Peering"],"fromPort":"Gi1/0/24","toPort":"Gi1/0/24","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-fw1","from":"core-router-1","to":"fw-external-1","width":4,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router2-fw2","from":"core-router-2","to":"fw-external-2","width":4,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-fw2","from":"fw-external-1","to":"fw-external-2","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["HA heartbeat"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-coresw1","from":"fw-external-1","to":"core-switch-1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw2-coresw2","from":"fw-external-2","to":"core-switch-2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-coresw2","from":"core-switch-1","to":"core-switch-2","width":5,"color":"#3b82f6","direction":"both","type":"main","notes":["VPC peer-link"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-fwint","from":"core-switch-1","to":"fw-internal","width":3,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-fwint","from":"core-switch-2","to":"fw-internal","width":3,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-racka1","from":"core-switch-1","to":"dc-rack-a1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-racka1","from":"core-switch-2","to":"dc-rack-a1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-racka2","from":"core-switch-1","to":"dc-rack-a2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-racka2","from":"core-switch-2","to":"dc-rack-a2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-rackb1","from":"core-switch-1","to":"dc-rack-b1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-rackb1","from":"core-switch-2","to":"dc-rack-b1","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-rackb2","from":"core-switch-1","to":"dc-rack-b2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-rackb2","from":"core-switch-2","to":"dc-rack-b2","width":4,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw1-dmz","from":"fw-external-1","to":"dmz-rack","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["DMZ segment"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fw2-dmz","from":"fw-external-2","to":"dmz-rack","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":["DMZ segment"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-mgmt","from":"core-switch-1","to":"mgmt-rack","width":3,"color":"#8b5cf6","direction":"both","type":"main","notes":["OOB management"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-wlc1","from":"core-switch-1","to":"wlc-primary","width":3,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-wlc2","from":"core-switch-2","to":"wlc-secondary","width":3,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true},{"id":"wlc1-wlc2","from":"wlc-primary","to":"wlc-secondary","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":["HA pair"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-hq","from":"wlc-primary","to":"mobile-zone-hq","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-guest","from":"wlc-primary","to":"mobile-zone-guest","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"wlc1-mobile-iot","from":"wlc-primary","to":"mobile-zone-iot","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-ny","from":"core-router-1","to":"branch-router-ny","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-la","from":"core-router-1","to":"branch-router-la","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-chi","from":"core-router-1","to":"branch-router-chi","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-lon","from":"core-router-1","to":"branch-router-lon","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-branch-tokyo","from":"core-router-1","to":"branch-router-tokyo","width":3,"color":"#a855f7","direction":"both","type":"main","notes":["SD-WAN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router1-aws","from":"core-router-1","to":"cloud-aws","width":3,"color":"#f97316","direction":"both","type":"main","notes":["Direct Connect"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"router2-azure","from":"core-router-2","to":"cloud-azure","width":3,"color":"#0ea5e9","direction":"both","type":"main","notes":["ExpressRoute"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-gcp","from":"fw-internal","to":"cloud-gcp","width":2,"color":"#22c55e","direction":"both","type":"main","notes":["VPN tunnel"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-floor1","from":"core-switch-1","to":"dist-switch-floor1","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-floor2","from":"core-switch-1","to":"dist-switch-floor2","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-floor3","from":"core-switch-2","to":"dist-switch-floor3","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-floor4","from":"core-switch-2","to":"dist-switch-floor4","width":3,"color":"#475569","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor1-endpoints","from":"dist-switch-floor1","to":"endpoint-1000","width":2,"color":"#94a3b8","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor1-ap1","from":"dist-switch-floor1","to":"ap-floor1-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor2-ap2","from":"dist-switch-floor2","to":"ap-floor2-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor3-ap3","from":"dist-switch-floor3","to":"ap-floor3-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"floor4-ap4","from":"dist-switch-floor4","to":"ap-floor4-zone1","width":2,"color":"#06b6d4","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-proxy1","from":"fw-internal","to":"proxy-server-1","width":2,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-proxy2","from":"fw-internal","to":"proxy-server-2","width":2,"color":"#ef4444","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwext1-vpn","from":"fw-external-1","to":"vpn-concentrator","width":3,"color":"#8b5cf6","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-nac","from":"core-switch-1","to":"nac-server","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-voip","from":"core-switch-1","to":"voip-cluster","width":3,"color":"#22c55e","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw2-video","from":"core-switch-2","to":"video-conf","width":3,"color":"#22c55e","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-cameras","from":"core-switch-1","to":"security-cameras","width":2,"color":"#94a3b8","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-dev1","from":"fw-internal","to":"dev-server-1","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwint-dev2","from":"fw-internal","to":"dev-server-2","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true,"animationSpeed":"1.5"},{"id":"fwint-test","from":"fw-internal","to":"test-environment","width":2,"color":"#a855f7","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"coresw1-erp","from":"core-switch-1","to":"erp-system","width":3,"color":"#f59e0b","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"fwext1-crm","from":"fw-external-1","to":"crm-system","width":2,"color":"#f59e0b","direction":"both","type":"main","notes":["Salesforce cloud"],"fromPort":"","toPort":"","lineStyle":"dashed","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups1-racka1","from":"ups-dc-1","to":"dc-rack-a1","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed A"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups2-racka2","from":"ups-dc-2","to":"dc-rack-a2","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed B"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"ups1-rackb1","from":"ups-dc-1","to":"dc-rack-b1","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed A"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal","animate":true,"animationSpeed":"4"},{"id":"ups2-rackb2","from":"ups-dc-2","to":"dc-rack-b2","width":2,"color":"#fbbf24","direction":"forward","type":"main","notes":["Power feed B"],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"cooling1-racka1","from":"cooling-1","to":"dc-rack-a1","width":2,"color":"#38bdf8","direction":"forward","type":"main","notes":["Cooling zone"],"fromPort":"","toPort":"","lineStyle":"dotted","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"cooling2-rackb1","from":"cooling-2","to":"dc-rack-b1","width":2,"color":"#38bdf8","direction":"forward","type":"main","notes":["Cooling zone"],"fromPort":"","toPort":"","lineStyle":"dotted","_pairIndex":0,"_pairTotal":1,"routing":"orthogonal"},{"id":"custom-1765237881452","type":"custom","color":"#c800ff","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":3492.3994140625,"y":1526.9556884765625},{"x":3500.609619140625,"y":1830.7386474609375},{"x":3303.561279296875,"y":1732.2144775390625}],"notes":[],"routing":"orthogonal"}]},"positions":{"core-router-1":{"x":3720.166015625,"y":245.9932403564453},"core-router-2":{"x":2499.883407638303,"y":329.99503430389154},"fw-external-1":{"x":3221.7385182723783,"y":1016.1364499992887},"fw-external-2":{"x":1915.5213706410505,"y":224.43528858865443},"fw-internal":{"x":1746.9168185079352,"y":477.5300527221864},"core-switch-1":{"x":449.39860669455675,"y":384.4578707617695},"core-switch-2":{"x":761.1664921394672,"y":180.89283910873155},"dc-rack-a1":{"x":783.7017241128451,"y":647.4086870405963},"dc-rack-a2":{"x":209.25701628255229,"y":228.01593190351014},"dc-rack-b1":{"x":3184.3186625759854,"y":1627.4495531027196},"dc-rack-b2":{"x":245.37065918741246,"y":499.6191264194081},"dmz-rack":{"x":2176.4105289561007,"y":610.8312056412005},"mgmt-rack":{"x":1601.2987201807314,"y":1281.4753424975324},"esxi-host-01":{"x":2162.2166789540615,"y":2608.110619289529},"esxi-host-02":{"x":2205.94717202368,"y":2689.67539624076},"esxi-host-03":{"x":2154.6015436939074,"y":2771.203009774913},"esxi-host-04":{"x":2195.986926025096,"y":2845},"tor-switch-a1":{"x":2146.8943639962963,"y":2845},"esxi-host-05":{"x":2185.9099961569727,"y":2845},"esxi-host-06":{"x":2139.099728450725,"y":2845},"esxi-host-07":{"x":2175.7223818764883,"y":2845},"esxi-host-08":{"x":2131.2222777148922,"y":2845},"tor-switch-a2":{"x":2165.4301485385085,"y":2845},"san-primary":{"x":2123.2667017518106,"y":2845},"san-secondary":{"x":2155.0394237844876,"y":2845},"fc-switch-1":{"x":2115.2377370375634,"y":2845},"fc-switch-2":{"x":2144.5563938942755,"y":2845},"backup-server-1":{"x":2107.1401637413705,"y":2845},"backup-server-2":{"x":2133.987300103025,"y":2845},"tape-library":{"x":2098.9788028796397,"y":2845},"tor-switch-b1":{"x":2123.338434885373,"y":2845},"tor-switch-b2":{"x":2090.7585134456995,"y":2845},"web-server-1":{"x":2112.6161382091163,"y":2845},"web-server-2":{"x":2082.484189516922,"y":2845},"waf-1":{"x":2101.826793760617,"y":2845},"load-balancer-dmz":{"x":2074.1607573409574,"y":2845},"mail-gateway":{"x":2090.97682514417,"y":2845},"dns-external-1":{"x":2065.7931724028163,"y":2845},"dns-external-2":{"x":2080.0726920576153,"y":2845},"vcenter":{"x":2057.3864164745437,"y":2845},"nsx-manager":{"x":2069.1208864464534,"y":2845},"siem-server":{"x":2048.945494649244,"y":2845},"nms-server":{"x":2058.1279286387635,"y":2845},"jump-server":{"x":2040.4754323612206,"y":2845},"ipam-server":{"x":2047.1003634632284,"y":2845},"wlc-primary":{"x":1575.9723612611924,"y":2306.135986328125},"wlc-secondary":{"x":1468.1361870166274,"y":1563.733642578125},"mobile-zone-hq":{"x":2354.901177346808,"y":2806.0078125},"mobile-zone-guest":{"x":2307.6605605284435,"y":2611.047119140625},"mobile-zone-iot":{"x":2229.397686389302,"y":2299.110107421875},"branch-router-ny":{"x":3151.903101363964,"y":633.6580810546875},"branch-router-la":{"x":3083.8876194705945,"y":506.90625},"branch-router-chi":{"x":3355.02409980103,"y":393.1805725097656},"branch-router-lon":{"x":3113.609823320121,"y":260.4093322753906},"branch-router-tokyo":{"x":3699.3234994733834,"y":471.4241027832031},"cloud-aws":{"x":3436.528122523513,"y":545.9614868164062},"cloud-azure":{"x":2592.566210818907,"y":2724.068115234375},"cloud-gcp":{"x":2827.3183770424234,"y":2731.397216796875},"isp-primary":{"x":3712.192068081962,"y":615.64990234375},"isp-secondary":{"x":3253.9473366098055,"y":1993.2629089355469},"dc-internal-1":{"x":1958.4243458877936,"y":2845},"dc-internal-2":{"x":1963.768951182132,"y":2845},"app-server-1":{"x":1947.3819379304134,"y":2845},"app-server-2":{"x":1955.2862087394126,"y":2845},"db-server-1":{"x":1936.3708569559828,"y":2845},"db-server-2":{"x":1946.8300873488822,"y":2845},"k8s-master-1":{"x":1925.397658583093,"y":2845},"k8s-master-2":{"x":1938.405621494142,"y":2845},"k8s-master-3":{"x":1914.4688758763386,"y":2845},"k8s-worker-1":{"x":1930.017826812177,"y":2845},"k8s-worker-2":{"x":1903.5910154567553,"y":2845},"k8s-worker-3":{"x":1921.6716971072178,"y":2845},"k8s-worker-4":{"x":1892.7705536280016,"y":2845},"proxy-server-1":{"x":1806.1152433697903,"y":653.7529296875},"proxy-server-2":{"x":2937.4207928721535,"y":2628.7880859375},"vpn-concentrator":{"x":3642.252088474593,"y":946.7255249023438},"nac-server":{"x":1153.2626148502184,"y":1172.1895751953125},"print-server":{"x":1896.9328460745962,"y":2845},"file-server":{"x":1860.7177871362182,"y":2845},"ca-server":{"x":1888.8027739274805,"y":2845},"sccm-server":{"x":1850.1909418511675,"y":2845},"voip-cluster":{"x":1777.038465328039,"y":1616.8961181640625},"video-conf":{"x":1993.8373941679588,"y":2244.936309814453},"security-cameras":{"x":1674.413336949044,"y":2046.0380859375},"nvr-cluster":{"x":1829.4110389706402,"y":2845},"dev-server-1":{"x":2800.5894350649614,"y":1175.623291015625},"dev-server-2":{"x":1945.0822182484326,"y":1164.5184783935547},"test-environment":{"x":2932.0863047891075,"y":862.4592895507812},"erp-system":{"x":789.9880103985649,"y":473.7113342285156},"crm-system":{"x":3514.6003232048542,"y":1137.7720947265625},"endpoint-1000":{"x":991.6812012057328,"y":2284.42236328125},"dist-switch-floor1":{"x":654.2091033261356,"y":2020.0086669921875},"dist-switch-floor2":{"x":853.8845527112826,"y":1843.2872314453125},"dist-switch-floor3":{"x":1899.4353951584517,"y":1456.5068359375},"dist-switch-floor4":{"x":488.5289313756234,"y":181.47256469726562},"ap-floor1-zone1":{"x":1140.16846970184,"y":2070.2916259765625},"ap-floor2-zone1":{"x":688.1952143592268,"y":2384.4775390625},"ap-floor3-zone1":{"x":2145.3803027919676,"y":1890.2816162109375},"ap-floor4-zone1":{"x":517.646146409649,"y":565.59716796875},"ups-dc-1":{"x":771.1406786539856,"y":295.9266662597656},"ups-dc-2":{"x":216.2410855890687,"y":330.3345947265625},"pdu-rack-a1":{"x":1804.774444371901,"y":2845},"pdu-rack-a2":{"x":1741.6184034693686,"y":2845},"cooling-1":{"x":245.7080801919958,"y":626.1914672851562},"cooling-2":{"x":1603.293611085831,"y":981.0621185302734},"camera-a":{"x":166.57075412676295,"y":145},"camera-a-copy":{"x":1040.653076171875,"y":738.42822265625}},"sizes":{"isp-secondary":139,"test-environment":121,"dev-server-1":128,"core-router-2":120,"camera-a":45,"camera-a-copy":45},"styles":{"dc-rack-b2":{"all":{"circleColor":"#ff0000"}},"dc-rack-a1":{"all":{"circleColor":"#ff0000"}},"dc-rack-b1":{"all":{"circleColor":"#ff0000","titleSize":59}},"isp-secondary":{"all":{"icon":{"library":"selfhst","name":"alist"},"circleColor":"#4d2c58","circleBorder":"#000000","titleColor":"#006eff"}},"core-router-2":{"all":{"icon":{"library":"selfhst","name":"actual-budget"},"pingOffsetX":-15,"pingOffsetY":-38}},"fw-external-1":{"all":{"icon":{"library":"selfhst","name":"anonaddy"}}},"cloud-aws":{"all":{"icon":{"library":"selfhst","name":"ansible"}}},"isp-primary":{"all":{"icon":{"library":"selfhst","name":"wikidocs"}}},"branch-router-tokyo":{"all":{"icon":{"library":"selfhst","name":"adguard-home"}}},"core-router-1":{"all":{"icon":{"library":"selfhst","name":"borg"}}},"test-environment":{"all":{"icon":{"library":"simple","name":"apple"}}},"dev-server-1":{"all":{"icon":{"library":"simple","name":"amazonwebservices"}}}},"legend":{"#10b981":"Trusted Lan","#f59e0b":"Secure Lan","#ef4444":"DMZ","#475569":"Main ISP","#3b82f6":"Alternate ISP","#8b5cf6":"you can edit me too","#06b6d4":"you can edit me too","#a855f7":"you can edit me too","#f97316":"you can edit me too","#0ea5e9":"you can edit me too","#22c55e":"you can edit me too","#94a3b8":"you can edit me too","#fbbf24":"you can edit me too","#38bdf8":"you can edit me too","#c800ff":"you can edit me too"},"rects":{"list":[{"id":"rect-1765237540610","x":2879.214599609375,"y":159.71981811523438,"width":992.196044921875,"height":538.8650817871094,"color":"#f97316","style":"filled","lineStyle":"solid","notes":[]},{"id":"rect-1765237681216","x":448.3926696777344,"y":1671.651123046875,"width":916.3436584472656,"height":924.27734375,"color":"#c800ff","style":"outlined","lineStyle":"solid","notes":[]},{"id":"rect-1766437913740","x":904.5889892578125,"y":115.40318298339844,"width":110.93878173828125,"height":919.6242218017578,"color":"#5215f9","style":"filled","lineStyle":"wall","notes":[],"borderWidth":13},{"id":"rect-1766437935414","x":130.93685150146484,"y":1072.3624877929688,"width":872.9131851196289,"height":99.260986328125,"color":"#5215f9","style":"filled","lineStyle":"wall","notes":[],"borderWidth":13}]},"texts":{"list":[{"id":"text-1765237828167","x":3411.458740234375,"y":1390.00439453125,"content":"Double click on desktop\nor long press on mobile\nto enter rack canvas view","fontSize":46,"color":"#e2e8f0","fontWeight":"bold","fontStyle":"italic","textAlign":"middle","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766446595277","x":654.3878479003906,"y":1367.7945556640625,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766446610211","x":180.63662719726562,"y":1128.822998046875,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766453024797","x":968.6458740234375,"y":1028.6621398925781,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1,"rotation":-89,"_dragStartX":972.46826171875,"_dragStartY":1009.5499572753906},{"id":"text-1766453070975","x":613.1589965820312,"y":1139.512939453125,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1},{"id":"text-1766453072857","x":968.64599609375,"y":474.40818786621094,"content":"SITE A","fontSize":101,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1,"rotation":269,"_dragStartX":1480.85302734375,"_dragStartY":822.2503356933594},{"id":"text-1766458222326","x":3167.812744140625,"y":2190.516357421875,"content":"","fontSize":18,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1}]},"pageState":{"title":"The One File Corporate","background":"","topbarBg":"rgba(9, 12, 20, 0.9)","topbarBorder":"#1f2533","panel":"#0b0e13","panelAlt":"#10141b","accent":"#4fd1c5","sidebarBg":"#10141b","btnBg":"#0b0e13","btnText":"#e2e8f0","tagFill":"#1e293b","tagText":"#e2e8f0","tagBorder":"#475569","inputBg":"#0b0e13","inputText":"#e2e8f0","inputBorder":"#1f2937","inputFont":"Inter, system-ui, sans-serif","inputFontSize":14,"toolbarBg":"#0f172a","toolbarBorder":"#1f2937","toolbarText":"#94a3b8","toolbarBtnBg":"#0b0e13","toolbarBtnText":"#e2e8f0","minimapDots":"#94a3b8","canvasHintEnabled":true,"canvasHintText":"","canvasHintBg":"#0f172a","canvasHintColor":"#94a3b8","danger":"#f56565","textMain":"#e2e8f0","textSoft":"#94a3b8","topbarHeight":103,"sidebarWidth":350,"mobileFooterHeight":40,"sidebarCollapsed":false,"nodeFill":"#1e293b","nodeStroke":"#475569","nodeTitle":"#e2e8f0","nodeSub":"#94a3b8","nodeTitleSize":41,"nodeSubSize":27,"nodeFont":"monospace","defaultEdge":"#475569","selectionHandle":"#f59e0b","selectionHandleSize":8,"groupIndicator":"#4fd1c5","canvasGradientTop":"#1e2532","canvasGradientBottom":"#050608","canvasBorder":"#475569","canvasGrid":"#475569","canvasGridSize":50,"canvasGridEnabled":true,"rackFrameFill":"#0f172a","rackGridEnabled":true,"rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","viewOnly":false,"defaultEdgeRouting":"orthogonal","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":4,"autoPingEnabled":false,"autoPingInterval":30}},{"id":"tab-1765235136918","name":"Homelab 2","nodes":{"internet":{"shape":"stop-sign","name":"Internet","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"internet-copy":{"shape":"firewall","name":"OPNSENSE","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"opnsense-copy":{"shape":"firewall","name":"Docker","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"docker-copy":{"shape":"firewall","name":"Docker2","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"docker-copy-1":{"shape":"firewall","name":"Docker3","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"docker-copy-2":{"shape":"firewall","name":"Docker 4","ip":"0.0.0.0","role":"","tags":[{"type":"icon","library":"selfhst","name":"docker"},{"type":"icon","library":"selfhst","name":"authentik"},{"type":"icon","library":"selfhst","name":"immich"}],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"opnsense-copy-1":{"shape":"firewall","name":"OPNSENSE GUEST","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"phone":{"shape":"phone","name":"Phone","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"desktop":{"shape":"pc","name":"Desktop","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"dns":{"shape":"cloud","name":"DNS","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"racked":{"shape":"server","name":"Racked","ip":"","role":"Rack","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":true,"locked":false,"groupId":null},"thermostat":{"shape":"thermostat","name":"Thermostat","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"video-doorbell":{"shape":"doorbell","name":"Video Doorbell","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"smart-lock":{"shape":"smart-lock","name":"Smart Lock","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"smart-bulb":{"shape":"smart-bulb","name":"Smart Bulb","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null},"robot-vacuum":{"shape":"vacuum","name":"Robot Vacuum","ip":"0.0.0.0","role":"","tags":[],"notes":[],"mac":"","rackUnit":"","uHeight":"1","layer":"physical","assignedRack":"","rackCapacity":"42","isRack":false,"locked":false,"groupId":null}},"edges":{"list":[{"id":"internet-internet-copy-1765238145151","from":"internet","to":"internet-copy","width":4,"color":"#55e208","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"internet-copy-opnsense-copy-1765238187451","from":"internet-copy","to":"opnsense-copy","width":4,"color":"#4c00ff","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"internet-copy-docker-copy-1765238242477","from":"internet-copy","to":"docker-copy","width":4,"color":"#4c00ff","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"internet-copy-docker-copy-1-1765238244637","from":"internet-copy","to":"docker-copy-1","width":4,"color":"#4c00ff","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"internet-copy-docker-copy-2-1765238246233","from":"internet-copy","to":"docker-copy-2","width":4,"color":"#4c00ff","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"internet-opnsense-copy-1-1765238266117","from":"internet","to":"opnsense-copy-1","width":4,"color":"#80ff00","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"opnsense-copy-1-dns-1765238347996","from":"opnsense-copy-1","to":"dns","width":4,"color":"#fb00ff","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"dns-desktop-1765238386101","from":"dns","to":"desktop","width":4,"color":"#ff00d0","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"phone-dns-1765238391156","from":"phone","to":"dns","width":4,"color":"#ff00d0","direction":"both","type":"main","notes":[],"fromPort":"","toPort":"","lineStyle":"solid","_pairIndex":0,"_pairTotal":1},{"id":"custom-1765239449323","type":"custom","color":"#f97316","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":2936.464111328125,"y":786.07958984375},{"x":3184.112060546875,"y":887.6153564453125},{"x":2763.110107421875,"y":981.7216796875}],"notes":[]}]},"positions":{"internet":{"x":1757.7735887323333,"y":298.77284240722656},"internet-copy":{"x":2066.9677515897347,"y":473.4119134177565},"opnsense-copy":{"x":1773.8400660428597,"y":666.5758233298659},"docker-copy":{"x":1931.1978950081452,"y":782.2775961320921},"docker-copy-1":{"x":2158.1262397347077,"y":767.7122274797483},"docker-copy-2":{"x":2342.2663764534577,"y":631.7681967180296},"opnsense-copy-1":{"x":2757.879480087803,"y":307.6117116091891},"phone":{"x":3312.857751572178,"y":502.58220111114224},"desktop":{"x":2971.700036728428,"y":480.7287465212985},"dns":{"x":3200.4643189549906,"y":320.469591247861},"racked":{"x":2645.5845448279656,"y":970.7820678889219},"thermostat":{"x":1323.0595481711202,"y":574.6132617105841},"video-doorbell":{"x":1188.4284446554952,"y":455.3684191812872},"smart-lock":{"x":1292.286782057839,"y":790.0231738199591},"smart-bulb":{"x":1496.156899245339,"y":716.9377246012091},"robot-vacuum":{"x":2288.5581443625265,"y":978.5069995035528}},"sizes":{"core-router-1":36,"internet":168,"phone":121,"desktop":147,"racked":137,"docker-copy-2":82},"styles":{"internet":{"all":{"icon":{"library":"selfhst","name":"amazon-web-services"},"circleColor":"#db0000","circleBorder":"#000000","titleSize":52,"subSize":46}},"opnsense-copy-1":{"all":{"icon":{"library":"selfhst","name":"opnsense-v1"}}},"internet-copy":{"all":{"icon":{"library":"selfhst","name":"opnsense"}}},"docker-copy-2":{"all":{"icon":{"library":"selfhst","name":"docker"}}},"docker-copy-1":{"all":{"icon":{"library":"selfhst","name":"authportal"}}},"docker-copy":{"all":{"icon":{"library":"selfhst","name":"jotty"}}},"opnsense-copy":{"all":{"icon":{"library":"selfhst","name":"portainer"}}},"racked":{"all":{"icon":{"library":"mdi","name":"server-security"},"circleColor":"#010813","circleBorder":"#ffffff"}}},"legend":{"#475569":"you can edit me too","#65758b":"you can edit me too","#63748c":"you can edit me too","#5e6f87":"you can edit me too","#586a84":"you can edit me too","#4f627d":"you can edit me too","#455873":"you can edit me too","#3d506c":"you can edit me too","#354964":"you can edit me too","#2e415c":"you can edit me too","#293c56":"you can edit me too","#273a53":"you can edit me too","#253750":"you can edit me too","#23354d":"you can edit me too","#203046":"you can edit me too","#1e2d43":"you can edit me too","#1a283d":"you can edit me too","#172435":"you can edit me too","#141f2e":"you can edit me too","#111a27":"you can edit me too","#0f1824":"you can edit me too","#0d1521":"you can edit me too","#0c131d":"you can edit me too","#0c1d1c":"you can edit me too","#0c1c1d":"you can edit me too","#0c191d":"you can edit me too","#0c141d":"you can edit me too","#0c0d1d":"you can edit me too","#130c1d":"you can edit me too","#1b0c1d":"you can edit me too","#1d0c17":"you can edit me too","#1d0c10":"you can edit me too","#1d0c0c":"you can edit me too","#3b1b1b":"you can edit me too","#3c1a1a":"you can edit me too","#3f1c1c":"you can edit me too","#401c1c":"you can edit me too","#451c1c":"you can edit me too","#461b1b":"you can edit me too","#4c1a1a":"you can edit me too","#521919":"you can edit me too","#571919":"you can edit me too","#5d1818":"you can edit me too","#631717":"you can edit me too","#651515":"you can edit me too","#6a1616":"you can edit me too","#6f1515":"you can edit me too","#711414":"you can edit me too","#761414":"you can edit me too","#771313":"you can edit me too","#7c1313":"you can edit me too","#811313":"you can edit me too","#821212":"you can edit me too","#871212":"you can edit me too","#881111":"you can edit me too","#8d1111":"you can edit me too","#8e1010":"you can edit me too","#8f0f0f":"you can edit me too","#900e0e":"you can edit me too","#8e0b0b":"you can edit me too","#8c0d0d":"you can edit me too","#880c0c":"you can edit me too","#830c0c":"you can edit me too","#7e0c0c":"you can edit me too","#790c0c":"you can edit me too","#730c0c":"you can edit me too","#6f0b0b":"you can edit me too","#0b6f64":"you can edit me too","#0b6f5f":"you can edit me too","#0b6f56":"you can edit me too","#0b6f49":"you can edit me too","#0b6f31":"you can edit me too","#0b6f1f":"you can edit me too","#0b6f0d":"you can edit me too","#176f0b":"you can edit me too","#266f0b":"you can edit me too","#296f0b":"you can edit me too","#2e6f0b":"you can edit me too","#1a2d10":"you can edit me too","#1c3111":"you can edit me too","#213814":"you can edit me too","#233c15":"you can edit me too","#254017":"you can edit me too","#294918":"you can edit me too","#2b4d1a":"you can edit me too","#2d511a":"you can edit me too","#315a1b":"you can edit me too","#35631c":"you can edit me too","#37681d":"you can edit me too","#3b721d":"you can edit me too","#3f7b1e":"you can edit me too","#42851e":"you can edit me too","#46901d":"you can edit me too","#499a1d":"you can edit me too","#4b9f1d":"you can edit me too","#4ca61c":"you can edit me too","#50b01c":"you can edit me too","#51b71a":"you can edit me too","#50b918":"you can edit me too","#51c115":"you can edit me too","#53c615":"you can edit me too","#53c814":"you can edit me too","#52c913":"you can edit me too","#54d011":"you can edit me too","#53d110":"you can edit me too","#55d510":"you can edit me too","#55d70f":"you can edit me too","#54d80e":"you can edit me too","#54da0b":"you can edit me too","#56df0c":"you can edit me too","#53db0a":"you can edit me too","#55e00b":"you can edit me too","#55e109":"you can edit me too","#55e208":"ISP LINE","#4c00ff":"MY Guest NETWORK","#80ff00":"you can edit me too","#3b4234":"you can edit me too","#3a3442":"you can edit me too","#3b3442":"you can edit me too","#3c3442":"you can edit me too","#3d3442":"you can edit me too","#3e3442":"you can edit me too","#3f3442":"you can edit me too","#403442":"you can edit me too","#413442":"you can edit me too","#653d66":"you can edit me too","#683f69":"you can edit me too","#6c416c":"you can edit me too","#6f4370":"you can edit me too","#704270":"you can edit me too","#734474":"you can edit me too","#784479":"you can edit me too","#7d447e":"you can edit me too","#7e437f":"you can edit me too","#834384":"you can edit me too","#844285":"you can edit me too","#89418b":"you can edit me too","#8e428f":"you can edit me too","#904091":"you can edit me too","#923e93":"you can edit me too","#973e98":"you can edit me too","#943c96":"you can edit me too","#993c9a":"you can edit me too","#963a98":"you can edit me too","#973899":"you can edit me too","#99369b":"you can edit me too","#9a359c":"you can edit me too","#9b349d":"you can edit me too","#9d329f":"you can edit me too","#9e31a0":"you can edit me too","#a02fa2":"you can edit me too","#9d2d9f":"you can edit me too","#9f2ba1":"you can edit me too","#a129a3":"you can edit me too","#a327a5":"you can edit me too","#a525a7":"you can edit me too","#a723a9":"you can edit me too","#a921ab":"you can edit me too","#ab1fad":"you can edit me too","#ad1daf":"you can edit me too","#ae1cb0":"you can edit me too","#b019b3":"you can edit me too","#b118b4":"you can edit me too","#b316b6":"you can edit me too","#b816bb":"you can edit me too","#b514b8":"you can edit me too","#ba14bd":"you can edit me too","#b712ba":"you can edit me too","#bb13be":"you can edit me too","#b811bb":"you can edit me too","#be10c1":"you can edit me too","#bb0ebe":"you can edit me too","#bd0cc0":"you can edit me too","#be0bc1":"you can edit me too","#c108c4":"you can edit me too","#be06c1":"you can edit me too","#c103c4":"you can edit me too","#c301c6":"you can edit me too","#c400c7":"you can edit me too","#c900cc":"you can edit me too","#ce00d1":"you can edit me too","#d300d6":"you can edit me too","#d800db":"you can edit me too","#dd00e0":"you can edit me too","#e200e6":"you can edit me too","#ec00f0":"you can edit me too","#f100f5":"you can edit me too","#f600fa":"you can edit me too","#fb00ff":"you can edit me too","#ff00d0":"iPhone (always guest iPhone)","#f97316":"you can edit me too"},"rects":{"list":[{"id":"rect-1765238219615","x":2680.053955078125,"y":251.44879150390625,"width":814.10400390625,"height":389.26678466796875,"color":"#ec0999","style":"filled","lineStyle":"solid","notes":[]}]},"texts":{"list":[{"id":"text-1765238422602","x":2466.35986328125,"y":741.6801147460938,"content":"Double click on desktop\nor long press on mobile\nto enter rack canvas view","fontSize":40,"color":"#e2e8f0","fontWeight":"normal","fontStyle":"normal","textAlign":"start","textDecoration":"none","bgColor":"#000000","bgEnabled":false,"opacity":1}]},"pageState":{"title":"The One File","background":"","topbarBg":"rgba(9, 12, 20, 0.9)","topbarBorder":"#1f2533","panel":"#2f0e0e","panelAlt":"#10141b","accent":"#a75252","sidebarBg":"#10141b","btnBg":"#0b0e13","btnText":"#e2e8f0","tagFill":"#1e293b","tagText":"#e2e8f0","tagBorder":"#475569","inputBg":"#0b0e13","inputText":"#e2e8f0","inputBorder":"#1f2937","inputFont":"Inter, system-ui, sans-serif","inputFontSize":14,"toolbarBg":"#441215","toolbarBorder":"#1f2937","toolbarText":"#94a3b8","toolbarBtnBg":"#0b0e13","toolbarBtnText":"#e2e8f0","minimapDots":"#94a3b8","canvasHintEnabled":true,"canvasHintText":"","canvasHintBg":"#0f172a","canvasHintColor":"#94a3b8","danger":"#f56565","textMain":"#e2e8f0","textSoft":"#94a3b8","topbarHeight":112,"sidebarWidth":350,"mobileFooterHeight":40,"sidebarCollapsed":false,"nodeFill":"#1e293b","nodeStroke":"#475569","nodeTitle":"#e2e8f0","nodeSub":"#94a3b8","nodeTitleSize":18,"nodeSubSize":13,"nodeFont":"Inter, system-ui, sans-serif","defaultEdge":"#475569","selectionHandle":"#f59e0b","selectionHandleSize":8,"groupIndicator":"#4fd1c5","canvasGradientTop":"#1e2532","canvasGradientBottom":"#050608","canvasBorder":"#475569","canvasGrid":"#475569","canvasGridSize":50,"canvasGridEnabled":true,"rackFrameFill":"#0f172a","rackGridEnabled":true,"rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","viewOnly":false,"defaultEdgeRouting":"curved","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":1.5}}],"currentTabIndex":0,"encryptedSections":{},"auditLog":[{"timestamp":1766459400738,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766459392434,"type":"export","description":"Exported CSV: the-one-file.csv","details":{},"tab":"Homelab 2"},{"timestamp":1766459386369,"type":"export","description":"Exported Markdown: the-one-file.md","details":{},"tab":"Homelab 2"},{"timestamp":1766459379962,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766459374396,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766459370112,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766459361896,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766459352785,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459352343,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459352224,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459351722,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459351541,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459350380,"type":"node","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459350178,"type":"node","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459350049,"type":"node","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459346233,"type":"node","description":"change shape","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335960,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335846,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335742,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335630,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335398,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335292,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459335188,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332894,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332780,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332661,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332556,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332450,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459332346,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459331643,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459331492,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459331378,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459331274,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459330996,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459330868,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459330764,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459330637,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459327262,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459327136,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459326544,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459326438,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459326334,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459326176,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459325232,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459325088,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459324279,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459323835,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459323732,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459323200,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459323093,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459322989,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459322883,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459322780,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459321176,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459321070,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459320748,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459320642,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459320492,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459319706,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459319600,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459319055,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459318467,"type":"style","description":"style change","details
gitextract_emfbp7w9/
├── .gitattributes
├── .github/
│ └── workflows/
│ └── docker-publish.yml
├── LICENSE
├── README.md
├── changelog.md
├── demos/
│ ├── csv-exports/
│ │ ├── the-one-file-corporate.csv
│ │ ├── the-one-file-homelab.csv
│ │ ├── the-one-file-networkening-corporate.csv
│ │ └── the-one-file-networkening-homelab.csv
│ ├── index.html
│ ├── json-exports/
│ │ ├── the-one-file-corporate-demo.json
│ │ ├── the-one-file-homelab-demo.json
│ │ ├── theonefile-networkening-corporate-demo.json
│ │ └── theonefile-networkening-homelab-demo.json
│ ├── markdown-exports/
│ │ ├── the-one-file-corporate.md
│ │ ├── the-one-file-homelab.md
│ │ ├── the-one-file-networkening-corporate.md
│ │ └── the-one-file-networkening-homelab.md
│ └── password-protected/
│ ├── password.txt
│ ├── the-one-file-corporate-demo.html
│ ├── the-one-file-homelab-demo.html
│ ├── theonefile-networkening-corporate-demo.html
│ └── theonefile-networkening-homelab-demo.html
├── import-export-save.md
├── keyboard-shortcuts.md
├── mobile-gestures.md
├── the-one-file.html
├── theonefile-networkening.html
└── theonefile_verse/
├── .dockerignore
├── .gitattributes
├── Dockerfile
├── README.md
├── api.md
├── changelog.md
├── demo-admin.html
├── docker-compose.yml
├── entrypoint.sh
├── package.json
├── public/
│ ├── admin-auth.js
│ ├── admin-dashboard.js
│ ├── admin-pages.js
│ ├── collab-init.js
│ ├── collab-save-hook.js
│ ├── collab.css
│ ├── collab.js
│ ├── index.html
│ ├── landing.js
│ └── theonefile.html
├── redis.conf
└── src/
├── auth.ts
├── config.ts
├── database.ts
├── index.ts
├── mailer.ts
├── network.ts
├── oidc.ts
├── rate-limit.ts
├── redis.ts
├── rooms.ts
├── routes/
│ ├── admin-apikeys.ts
│ ├── admin-auth-settings.ts
│ ├── admin-auth.ts
│ ├── admin-backups.ts
│ ├── admin-logs.ts
│ ├── admin-rooms.ts
│ ├── admin-settings.ts
│ ├── admin-users.ts
│ ├── instance-access.ts
│ ├── network-routes.ts
│ ├── public.ts
│ ├── room.ts
│ ├── setup.ts
│ └── user-auth.ts
├── security.ts
├── templates.ts
├── tokens.ts
└── websocket.ts
SYMBOL INDEX (787 symbols across 34 files)
FILE: theonefile_verse/public/admin-auth.js
function getTheme (line 6) | function getTheme() {
function setTheme (line 11) | function setTheme(t) {
FILE: theonefile_verse/public/admin-dashboard.js
function refreshCsrf (line 6) | function refreshCsrf() {
function csrfHeaders (line 12) | function csrfHeaders(extra) {
function getTheme (line 20) | function getTheme() {
function setTheme (line 25) | function setTheme(theme) {
function toggleTheme (line 33) | function toggleTheme() {
function updateThemeToggleVisibility (line 38) | function updateThemeToggleVisibility() {
function h (line 61) | function h(tag, props) {
function _append (line 77) | function _append(parent, child) {
function clearNode (line 87) | function clearNode(el) {
function setContent (line 90) | function setContent(container, children) {
function showTab (line 106) | function showTab(name) {
function loadData (line 133) | async function loadData(query) {
function searchRooms (line 157) | function searchRooms(q) {
function loadSettings (line 162) | async function loadSettings() {
function renderSettings (line 173) | function renderSettings() {
function saveAdminPath (line 229) | async function saveAdminPath() {
function saveRateLimitSettings (line 269) | async function saveRateLimitSettings() {
function saveForcedTheme (line 280) | async function saveForcedTheme() {
function toggleSetting (line 290) | async function toggleSetting(key) {
function setInstancePassword (line 302) | async function setInstancePassword() {
function saveUpdateInterval (line 318) | async function saveUpdateInterval() {
function triggerUpdate (line 328) | async function triggerUpdate() {
function checkForUpdates (line 350) | async function checkForUpdates() {
function changeSourceMode (line 376) | async function changeSourceMode() {
function uploadFile (line 396) | async function uploadFile() {
function updateSourceUI (line 417) | function updateSourceUI() {
function saveRoomDefaults (line 470) | async function saveRoomDefaults() {
function showStatus (line 484) | function showStatus(msg, type) {
function showAuthStatus (line 490) | function showAuthStatus(msg, type) {
function renderStats (line 496) | function renderStats() {
function renderRooms (line 514) | function renderRooms() {
function toggleSelect (line 551) | function toggleSelect(id, checked) {
function toggleAll (line 561) | function toggleAll(checked) {
function clearSelection (line 571) | function clearSelection() {
function updateBulkUI (line 577) | function updateBulkUI() {
function deleteSelected (line 588) | async function deleteSelected() {
function viewRoom (line 601) | function viewRoom(id) {
function closeModal (line 640) | function closeModal() {
function joinRoom (line 644) | function joinRoom(id) {
function deleteRoom (line 648) | async function deleteRoom(id) {
function logout (line 663) | async function logout() {
function saveWebhookUrl (line 675) | async function saveWebhookUrl() {
function saveDiscoveryPrefix (line 685) | async function saveDiscoveryPrefix() {
function saveBackupSettings (line 695) | async function saveBackupSettings() {
function loadActivityLogs (line 706) | async function loadActivityLogs() {
function loadAuditLogs (line 720) | async function loadAuditLogs() {
function renderActivityLogs (line 734) | function renderActivityLogs(logs) {
function renderAuditLogs (line 750) | function renderAuditLogs(logs) {
function loadBackups (line 766) | async function loadBackups() {
function renderBackups (line 776) | function renderBackups(backups) {
function createBackup (line 799) | async function createBackup() {
function downloadBackup (line 814) | async function downloadBackup(id) {
function restoreBackup (line 818) | async function restoreBackup(id) {
function deleteBackup (line 834) | async function deleteBackup(id) {
function exportAll (line 843) | async function exportAll() {
function loadApiKeys (line 847) | async function loadApiKeys() {
function renderApiKeys (line 857) | function renderApiKeys(keys) {
function showCreateApiKey (line 878) | function showCreateApiKey() {
function closeApiKeyModal (line 883) | function closeApiKeyModal() {
function createApiKey (line 887) | async function createApiKey() {
function revokeApiKey (line 918) | async function revokeApiKey(id) {
function loadUsers (line 927) | async function loadUsers(q) {
function searchUsers (line 942) | function searchUsers(q) {
function renderUsers (line 947) | function renderUsers() {
function showCreateUser (line 983) | function showCreateUser() {
function closeUserModal (line 987) | function closeUserModal() {
function createUser (line 995) | async function createUser() {
function deleteUser (line 1023) | async function deleteUser(id) {
function editUser (line 1033) | function editUser(id) {
function closeEditUserModal (line 1046) | function closeEditUserModal() {
function saveUserEdit (line 1050) | async function saveUserEdit() {
function resetUserPassword (line 1079) | async function resetUserPassword() {
function loadAuthSettings (line 1103) | async function loadAuthSettings() {
function renderAuthSettings (line 1113) | function renderAuthSettings() {
function saveAuthSettings (line 1128) | async function saveAuthSettings() {
function toggleAuthSetting (line 1138) | async function toggleAuthSetting(key) {
function updateAuthNumber (line 1149) | async function updateAuthNumber(key, value) {
function loadOidcProviders (line 1161) | async function loadOidcProviders() {
function renderOidcProviders (line 1172) | function renderOidcProviders() {
function showAddOidcProvider (line 1195) | function showAddOidcProvider() {
function editOidcProvider (line 1211) | function editOidcProvider(id) {
function closeOidcModal (line 1229) | function closeOidcModal() {
function saveOidcProvider (line 1233) | async function saveOidcProvider() {
function deleteOidcProvider (line 1272) | async function deleteOidcProvider(id) {
function loadSmtpConfigs (line 1285) | async function loadSmtpConfigs() {
function renderSmtpConfigs (line 1296) | function renderSmtpConfigs() {
function showAddSmtpConfig (line 1322) | function showAddSmtpConfig() {
function editSmtpConfig (line 1338) | function editSmtpConfig(id) {
function closeSmtpModal (line 1356) | function closeSmtpModal() {
function saveSmtpConfig (line 1360) | async function saveSmtpConfig() {
function testSmtpConfig (line 1399) | async function testSmtpConfig() {
function deleteSmtpConfig (line 1427) | async function deleteSmtpConfig(id) {
function loadEmailTemplates (line 1444) | async function loadEmailTemplates() {
function renderEmailTemplates (line 1455) | function renderEmailTemplates(templates) {
function sanitizeTemplateHtml (line 1472) | function sanitizeTemplateHtml(html) {
function editTemplate (line 1491) | function editTemplate(id) {
function closeTemplateModal (line 1507) | function closeTemplateModal() {
function showWysiwygView (line 1512) | function showWysiwygView() {
function showHtmlSourceView (line 1518) | function showHtmlSourceView() {
function toggleTemplateView (line 1525) | function toggleTemplateView() {
function execCmd (line 1535) | function execCmd(cmd) {
function execCmdArg (line 1540) | function execCmdArg(cmd, arg) {
function insertTemplateVar (line 1546) | function insertTemplateVar(varName) {
function insertLink (line 1552) | function insertLink() {
function insertImage (line 1559) | function insertImage() {
function insertButton (line 1566) | function insertButton() {
function saveTemplate (line 1578) | async function saveTemplate() {
function previewTemplate (line 1611) | function previewTemplate() {
function closeTemplatePreview (line 1629) | function closeTemplatePreview() {
function loadEmailLogs (line 1640) | async function loadEmailLogs() {
function renderEmailLogs (line 1655) | function renderEmailLogs() {
function clearEmailLogs (line 1672) | async function clearEmailLogs() {
function clearActivityLogs (line 1684) | async function clearActivityLogs() {
function clearAuditLogs (line 1696) | async function clearAuditLogs() {
FILE: theonefile_verse/public/admin-pages.js
function withFormLoading (line 4) | function withFormLoading(form, fn) {
function build2FAForm (line 19) | function build2FAForm(form) {
function checkPasswordStrength (line 149) | function checkPasswordStrength(pwd) {
FILE: theonefile_verse/public/collab-init.js
function isBlockedKey (line 9) | function isBlockedKey(key) {
FILE: theonefile_verse/public/collab.js
function refreshCsrf (line 16) | function refreshCsrf() {
function h (line 26) | function h(tag, props, ...children) {
function _append (line 42) | function _append(parent, child) {
function clearNode (line 52) | function clearNode(el) {
function setContent (line 55) | function setContent(container, children) {
function generateUUID (line 62) | function generateUUID() {
function getOrCreateUserId (line 73) | function getOrCreateUserId() {
function getStoredUserName (line 83) | function getStoredUserName() {
function setStoredUserName (line 87) | function setStoredUserName(name) {
function getRandomSyncQuote (line 129) | function getRandomSyncQuote() {
function showSyncingOverlay (line 135) | function showSyncingOverlay() {
function hideSyncingOverlay (line 154) | function hideSyncingOverlay() {
function leaveRoom (line 166) | function leaveRoom() {
function generateHighlanderName (line 179) | function generateHighlanderName() {
function isValidColor (line 183) | function isValidColor(color) {
function sanitizeColor (line 187) | function sanitizeColor(color) {
function getOrCreateUserColor (line 191) | function getOrCreateUserColor() {
function pickUniqueColor (line 201) | function pickUniqueColor() {
function getInitials (line 211) | function getInitials(name) {
function fetchWsToken (line 247) | async function fetchWsToken() {
function setConnectionState (line 267) | function setConnectionState(state) {
function connect (line 288) | async function connect() {
function scheduleReconnect (line 323) | function scheduleReconnect() {
function sendMessage (line 333) | function sendMessage(type, data) {
function sanitizeUser (line 339) | function sanitizeUser(user) {
function handleMessage (line 346) | function handleMessage(msg) {
function handleNameRejected (line 496) | function handleNameRejected(reason) {
function addChatMessage (line 506) | function addChatMessage(msg) {
function playChatSound (line 530) | function playChatSound(isMention) {
function sendChatMessage (line 546) | function sendChatMessage(text) {
function setReplyTo (line 567) | function setReplyTo(msg) {
function clearReply (line 578) | function clearReply() {
function sendTypingIndicator (line 584) | function sendTypingIndicator() {
function updateTypingIndicator (line 591) | function updateTypingIndicator() {
function showToast (line 612) | function showToast(message) {
function updateChatBadge (line 631) | function updateChatBadge() {
function highlightMentions (line 643) | function highlightMentions(text) {
function formatTimeAgo (line 662) | function formatTimeAgo(timestamp) {
function renderChatMessages (line 670) | function renderChatMessages() {
function getCanvasState (line 700) | function getCanvasState() {
function screenToCanvasCoords (line 705) | function screenToCanvasCoords(screenX, screenY) {
function canvasToScreenCoords (line 724) | function canvasToScreenCoords(canvasX, canvasY) {
function safeElementId (line 743) | function safeElementId(userId) {
function updateRemoteCursor (line 747) | function updateRemoteCursor(userId, user) {
function refreshAllRemoteCursors (line 806) | function refreshAllRemoteCursors() {
function removeRemoteCursor (line 814) | function removeRemoteCursor(userId) {
function trackCursor (line 819) | function trackCursor() {
function getGlobal (line 864) | function getGlobal(name) {
function setGlobal (line 869) | function setGlobal(name, value) {
function captureState (line 874) | function captureState() {
function hashState (line 942) | function hashState(state) {
function sendFullState (line 952) | function sendFullState() {
function applyRemoteState (line 959) | function applyRemoteState(state) {
function syncStateIfChanged (line 1045) | function syncStateIfChanged() {
function startStatePolling (line 1055) | function startStatePolling() {
function sendPresence (line 1076) | function sendPresence() {
function trackSelection (line 1085) | function trackSelection() {
function setupAuditLogInjection (line 1114) | function setupAuditLogInjection() {
function getCurrentTabName (line 1138) | function getCurrentTabName() {
function renderUsers (line 1147) | function renderUsers() {
function renderUserIndicators (line 1171) | function renderUserIndicators() {
function removeUserIndicators (line 1197) | function removeUserIndicators(userId) {
function updateCharCount (line 1201) | function updateCharCount() {
function toggleEmojiPicker (line 1216) | function toggleEmojiPicker() {
function insertEmoji (line 1222) | function insertEmoji(emoji) {
function updateExpiryCountdown (line 1235) | function updateExpiryCountdown() {
function injectCollabBar (line 1264) | function injectCollabBar() {
function generateQR (line 1573) | function generateQR() {
function renderQR (line 1588) | function renderQR(container, url) {
function showNameModal (line 1602) | function showNameModal(isChange = false, errorMsg = null) {
function checkPassword (line 1665) | async function checkPassword() {
function init (line 1712) | async function init() {
function stripCollabFromHTML (line 1756) | function stripCollabFromHTML(htmlString) {
function hookSaveFunction (line 1815) | function hookSaveFunction() {
function buildProbeList (line 1819) | function buildProbeList(ping) {
function updateProbeResultsPanel (line 1834) | function updateProbeResultsPanel(nodeId) {
function overridePingFunctions (line 1859) | function overridePingFunctions() {
function injectProbeUI (line 1971) | function injectProbeUI() {
function loadProbeConfig (line 2039) | function loadProbeConfig() {
function saveProbeConfig (line 2075) | function saveProbeConfig() {
function parsePorts (line 2109) | function parsePorts(str) {
function getLayerName (line 2213) | function getLayerName(val) {
function fetchDiscoveryIcon (line 2225) | function fetchDiscoveryIcon(library, name, el, size) {
function getShapePreviewSVG (line 2248) | function getShapePreviewSVG(shape) {
function updateDiscoveryProgress (line 2254) | function updateDiscoveryProgress(percent, scanned, total, rangeIndex, to...
function addDiscoveryResult (line 2266) | function addDiscoveryResult(host) {
function finalizeDiscovery (line 2277) | function finalizeDiscovery(totalFound) {
function handleDeepScanProgress (line 2292) | function handleDeepScanProgress(scanId, ip, percent) {
function handleDeepScanUpdate (line 2303) | function handleDeepScanUpdate(scanId, ip, newPorts, newServices, contain...
function handleDeepScanComplete (line 2346) | function handleDeepScanComplete(scanId, ip) {
function buildDeepScanCell (line 2353) | function buildDeepScanCell(ip) {
function getCurrentCIDR (line 2369) | function getCurrentCIDR() {
function getDiscoveryCIDRs (line 2379) | function getDiscoveryCIDRs() {
function renderRangePills (line 2385) | function renderRangePills() {
function updateRackDropdowns (line 2405) | function updateRackDropdowns() {
function renderDiscoveryResults (line 2503) | function renderDiscoveryResults() {
function escapeHtml (line 2816) | function escapeHtml(str) {
function injectDiscoveryUI (line 2821) | function injectDiscoveryUI() {
function startCollab (line 3794) | function startCollab() {
FILE: theonefile_verse/public/landing.js
function withLoading (line 4) | function withLoading(fn) {
function showToast (line 13) | function showToast(message, type) {
function h (line 31) | function h(tag, props) {
function _append (line 47) | function _append(parent, child) {
function clearNode (line 57) | function clearNode(el) {
function setContent (line 60) | function setContent(container, children) {
function getTheme (line 69) | function getTheme() {
function setTheme (line 74) | function setTheme(theme) {
function toggleTheme (line 82) | function toggleTheme() {
function updateThemeToggleVisibility (line 87) | function updateThemeToggleVisibility() {
function generateUUID (line 117) | function generateUUID() {
function getOrCreateUserId (line 125) | function getOrCreateUserId(roomId) {
function openModal (line 132) | function openModal(type) { document.getElementById(type + '-modal').clas...
function closeModal (line 134) | function closeModal(type) {
function clearAllAuthForms (line 143) | function clearAllAuthForms() {
function showError (line 153) | function showError(type, msg) {
function handleFile (line 171) | async function handleFile(file) {
function clearFile (line 189) | function clearFile() {
function parseTopologyFile (line 197) | function parseTopologyFile(content, filename) {
function createRoom (line 218) | async function createRoom() {
function joinRoom (line 266) | async function joinRoom() {
function loadAuthState (line 305) | async function loadAuthState() {
function updateAuthUI (line 320) | function updateAuthUI() {
function renderOidcProviders (line 352) | function renderOidcProviders(containerId, mode) {
function startOidcLogin (line 384) | async function startOidcLogin(providerId) {
function loginWithPassword (line 398) | async function loginWithPassword() {
function verify2FA (line 428) | async function verify2FA() {
function openSettingsModal (line 449) | async function openSettingsModal() {
function load2FAStatus (line 454) | async function load2FAStatus() {
function setup2FA (line 478) | async function setup2FA() {
function verify2FASetup (line 521) | async function verify2FASetup() {
function disable2FA (line 557) | async function disable2FA() {
function requestEmailChange (line 579) | async function requestEmailChange() {
function registerUser (line 607) | async function registerUser() {
function requestPasswordReset (line 639) | async function requestPasswordReset() {
function requestMagicLink (line 659) | async function requestMagicLink() {
function logout (line 679) | async function logout() {
FILE: theonefile_verse/src/auth.ts
function hashPassword (line 6) | async function hashPassword(password: string): Promise<string> {
function verifyPassword (line 14) | async function verifyPassword(password: string, hash: string): Promise<b...
function isLegacyHash (line 27) | function isLegacyHash(hash: string): boolean {
function upgradePasswordHash (line 31) | async function upgradePasswordHash(userId: string, password: string): Pr...
function validatePassword (line 42) | function validatePassword(password: string): { valid: boolean; error?: s...
function validateEmail (line 58) | function validateEmail(email: string): { valid: boolean; error?: string } {
function normalizeEmail (line 69) | function normalizeEmail(email: string): string {
function registerUser (line 73) | async function registerUser(
constant MAX_FAILED_ATTEMPTS (line 144) | const MAX_FAILED_ATTEMPTS = 5;
constant LOCKOUT_DURATION_MINUTES (line 145) | const LOCKOUT_DURATION_MINUTES = 15;
function loginWithPassword (line 147) | async function loginWithPassword(
constant MAX_SESSIONS_PER_USER (line 234) | const MAX_SESSIONS_PER_USER = 10;
function createSessionToken (line 236) | async function createSessionToken(
function rotateSessionToken (line 265) | async function rotateSessionToken(
function createVerificationToken (line 288) | async function createVerificationToken(userId: string): Promise<string> {
function verifyEmail (line 309) | async function verifyEmail(token: string): Promise<{ success: boolean; e...
constant MIN_REQUEST_TIME_MS (line 343) | const MIN_REQUEST_TIME_MS = 200;
function normalizeResponseTime (line 345) | async function normalizeResponseTime(startTime: number): Promise<void> {
function requestPasswordReset (line 352) | async function requestPasswordReset(
function resetPassword (line 388) | async function resetPassword(
function requestMagicLink (line 432) | async function requestMagicLink(
function loginWithMagicLink (line 472) | async function loginWithMagicLink(
function logout (line 513) | async function logout(token: string): Promise<void> {
function logoutAll (line 518) | function logoutAll(userId: string): number {
function changePassword (line 522) | async function changePassword(
function updateProfile (line 556) | function updateProfile(
function deleteAccount (line 580) | function deleteAccount(userId: string): { success: boolean; error?: stri...
type ParsedSession (line 598) | interface ParsedSession extends db.UserSession {
function parseUserAgent (line 605) | function parseUserAgent(ua: string | null): { browser: string; os: strin...
function formatIPLocation (line 630) | function formatIPLocation(ip: string | null): string {
function getUserSessions (line 637) | function getUserSessions(userId: string): ParsedSession[] {
function getUserOidcLinks (line 651) | function getUserOidcLinks(userId: string): db.UserOidcLink[] {
function unlinkOidcProvider (line 655) | function unlinkOidcProvider(userId: string, linkId: string): { success: ...
function adminCreateUser (line 676) | async function adminCreateUser(
function adminUpdateUser (line 729) | function adminUpdateUser(
function adminResetPassword (line 768) | async function adminResetPassword(
function adminDeleteUser (line 791) | function adminDeleteUser(userId: string): { success: boolean; error?: st...
function cleanupExpiredTokens (line 795) | function cleanupExpiredTokens(): { sessions: number; tokens: number } {
function base32Encode (line 802) | function base32Encode(buffer: Uint8Array): string {
function base32Decode (line 821) | function base32Decode(encoded: string): Uint8Array {
function generateTOTPCode (line 840) | function generateTOTPCode(secret: Uint8Array, counter: number): string {
function verifyTOTPCode (line 858) | function verifyTOTPCode(secret: string, code: string): boolean {
function setupTOTP (line 870) | async function setupTOTP(userId: string): Promise<{ success: boolean; se...
function verifyAndEnableTOTP (line 895) | async function verifyAndEnableTOTP(userId: string, code: string): Promis...
function disableTOTP (line 932) | async function disableTOTP(userId: string, password: string): Promise<{ ...
function verifyBackupCode (line 962) | async function verifyBackupCode(userId: string, code: string): Promise<b...
function loginWith2FA (line 992) | async function loginWith2FA(
function requestEmailChange (line 1064) | async function requestEmailChange(
function confirmEmailChange (line 1123) | async function confirmEmailChange(token: string): Promise<{ success: boo...
FILE: theonefile_verse/src/config.ts
constant APP_VERSION (line 7) | const APP_VERSION = pkg.version || "unknown";
constant PORT (line 8) | const PORT = parseInt(process.env.PORT || "10101");
constant DATA_DIR (line 9) | const DATA_DIR = process.env.DATA_DIR || "./data";
constant ROOMS_DIR (line 10) | const ROOMS_DIR = join(DATA_DIR, "rooms");
constant ADMIN_CONFIG_PATH (line 11) | const ADMIN_CONFIG_PATH = join(DATA_DIR, "admin.json");
constant SETTINGS_PATH (line 12) | const SETTINGS_PATH = join(DATA_DIR, "settings.json");
constant ENV_UPDATE_INTERVAL (line 14) | const ENV_UPDATE_INTERVAL = parseInt(process.env.UPDATE_INTERVAL || "0");
constant ENV_SKIP_UPDATE (line 15) | const ENV_SKIP_UPDATE = process.env.SKIP_UPDATE === "true";
constant ENV_ADMIN_PASSWORD (line 16) | const ENV_ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || "";
constant ENV_TRUSTED_PROXY_COUNT (line 17) | const ENV_TRUSTED_PROXY_COUNT = process.env.TRUSTED_PROXY_COUNT ? parseI...
constant ENV_TRUSTED_PROXIES (line 18) | const ENV_TRUSTED_PROXIES = process.env.TRUSTED_PROXIES ? process.env.TR...
constant UUID_REGEX (line 20) | const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]...
function isValidUUID (line 22) | function isValidUUID(id: string): boolean {
type AdminConfig (line 26) | interface AdminConfig {
type InstanceSettings (line 31) | interface InstanceSettings {
function loadSettings (line 99) | function loadSettings(): InstanceSettings {
function saveSettings (line 121) | function saveSettings(settings: InstanceSettings): void {
function getSettings (line 134) | function getSettings(): InstanceSettings { return instanceSettings; }
function updateSettings (line 135) | function updateSettings(s: InstanceSettings): void { instanceSettings = ...
function reloadSettings (line 136) | function reloadSettings(): void { instanceSettings = loadSettings(); }
function loadAdminConfig (line 138) | function loadAdminConfig(): AdminConfig | null {
function saveAdminConfig (line 150) | function saveAdminConfig(config: AdminConfig): void {
function isAdminConfigured (line 155) | function isAdminConfigured(): boolean {
function needsAdminMigration (line 159) | function needsAdminMigration(): boolean {
function hasAdminUser (line 163) | function hasAdminUser(): boolean {
function getOldAdminPasswordHash (line 167) | function getOldAdminPasswordHash(): string | null {
function verifyAdminPassword (line 171) | async function verifyAdminPassword(password: string): Promise<boolean> {
function verifyInstancePassword (line 191) | async function verifyInstancePassword(password: string): Promise<boolean> {
function isInstanceLocked (line 196) | function isInstanceLocked(): boolean {
function getAdminPath (line 200) | function getAdminPath(): string {
function isCustomAdminPath (line 206) | function isCustomAdminPath(path: string): boolean {
function validateAdminPath (line 211) | function validateAdminPath(newPath: string): { valid: boolean; error?: s...
function isAdminRoute (line 228) | function isAdminRoute(path: string): boolean {
function getExternalOrigin (line 233) | function getExternalOrigin(req: Request): string {
FILE: theonefile_verse/src/database.ts
function sanitizeSearchQuery (line 5) | function sanitizeSearchQuery(query: string): string | null {
constant DATA_DIR (line 10) | const DATA_DIR = process.env.DATA_DIR || "./data";
constant DB_PATH (line 11) | const DB_PATH = join(DATA_DIR, "theonefile.db");
constant ROOMS_DIR (line 12) | const ROOMS_DIR = join(DATA_DIR, "rooms");
constant ADMIN_CONFIG_PATH (line 13) | const ADMIN_CONFIG_PATH = join(DATA_DIR, "admin.json");
constant SETTINGS_PATH (line 14) | const SETTINGS_PATH = join(DATA_DIR, "settings.json");
function migrateAddColumn (line 22) | function migrateAddColumn(table: string, column: string, definition: str...
type OidcState (line 342) | interface OidcState {
type CsrfToken (line 354) | interface CsrfToken {
type Room (line 361) | interface Room {
type AuditLog (line 373) | interface AuditLog {
type ActivityLog (line 384) | interface ActivityLog {
type ApiKey (line 395) | interface ApiKey {
type Backup (line 406) | interface Backup {
type User (line 415) | interface User {
type UserOidcLink (line 436) | interface UserOidcLink {
type UserSession (line 448) | interface UserSession {
type UserToken (line 458) | interface UserToken {
type SmtpConfig (line 469) | interface SmtpConfig {
type OidcProvider (line 488) | interface OidcProvider {
type UserPreferences (line 507) | interface UserPreferences {
type EmailTemplate (line 514) | interface EmailTemplate {
type EmailLog (line 524) | interface EmailLog {
function rowToRoom (line 656) | function rowToRoom(row: any): Room | null {
function createRoom (line 671) | function createRoom(room: Room): void {
function getRoom (line 686) | function getRoom(id: string): Room | null {
function updateRoom (line 690) | function updateRoom(id: string, lastActivity: string, topology: any): vo...
function updateRoomSettings (line 694) | function updateRoomSettings(id: string, allowGuests: boolean, ownerUserI...
function deleteRoom (line 698) | function deleteRoom(id: string): boolean {
function listRooms (line 703) | function listRooms(limit?: number, offset?: number): Room[] {
function searchRooms (line 710) | function searchRooms(query: string, limit: number = 50, offset: number =...
function countRooms (line 719) | function countRooms(): number {
function getSetting (line 724) | function getSetting(key: string): string | null {
function setSetting (line 729) | function setSetting(key: string, value: string): void {
function deleteSetting (line 733) | function deleteSetting(key: string): void {
function getAllSettings (line 737) | function getAllSettings(): Record<string, string> {
function addAuditLog (line 746) | function addAuditLog(log: AuditLog): void {
function getAuditLogs (line 758) | function getAuditLogs(limit: number = 100, offset: number = 0): AuditLog...
function searchAuditLogs (line 771) | function searchAuditLogs(query: string, limit: number = 100, offset: num...
function addActivityLog (line 787) | function addActivityLog(log: ActivityLog): void {
function getActivityLogs (line 799) | function getActivityLogs(roomId: string, limit: number = 100, offset: nu...
function getAllActivityLogs (line 812) | function getAllActivityLogs(limit: number = 100, offset: number = 0): Ac...
function createApiKey (line 825) | function createApiKey(apiKey: ApiKey): void {
function getApiKeyById (line 837) | function getApiKeyById(id: string): ApiKey | null {
function getApiKeyByHash (line 852) | function getApiKeyByHash(hash: string): ApiKey | null {
function updateApiKeyLastUsed (line 867) | function updateApiKeyLastUsed(id: string): void {
function listApiKeys (line 871) | function listApiKeys(): Omit<ApiKey, "keyHash">[] {
function deactivateApiKey (line 883) | function deactivateApiKey(id: string): boolean {
function createBackupRecord (line 888) | function createBackupRecord(backup: Backup): void {
function listBackups (line 899) | function listBackups(): Backup[] {
function deleteBackupRecord (line 910) | function deleteBackupRecord(id: string): boolean {
function getOldAutoBackups (line 915) | function getOldAutoBackups(keepCount: number): Backup[] {
function migrateFromFlatFiles (line 926) | function migrateFromFlatFiles(): { rooms: number; settings: boolean; adm...
function getDatabase (line 985) | function getDatabase(): Database {
function closeDatabase (line 989) | function closeDatabase(): void {
function healthCheck (line 993) | function healthCheck(): boolean {
function logAuthEvent (line 1002) | function logAuthEvent(
function rowToUser (line 1040) | function rowToUser(row: any): User | null {
function createUser (line 1064) | function createUser(user: User): void {
function createUserAtomic (line 1071) | function createUserAtomic(user: User): { created: boolean; wasFirst: boo...
function getUserById (line 1089) | function getUserById(id: string): User | null {
function getUserByEmail (line 1093) | function getUserByEmail(email: string): User | null {
function updateUser (line 1097) | function updateUser(user: User): void {
function incrementFailedLogin (line 1108) | function incrementFailedLogin(userId: string): void {
function resetFailedLogin (line 1112) | function resetFailedLogin(userId: string): void {
function lockUserAccount (line 1116) | function lockUserAccount(userId: string, until: Date): void {
function deleteUser (line 1120) | function deleteUser(id: string): boolean {
function listUsers (line 1124) | function listUsers(limit: number = 100, offset: number = 0): User[] {
function searchUsers (line 1128) | function searchUsers(query: string, limit: number = 100, offset: number ...
function countUsers (line 1135) | function countUsers(): number {
function countUsersByRole (line 1139) | function countUsersByRole(role: string): number {
function listUsersByRole (line 1143) | function listUsersByRole(role: string): User[] {
function verifyAllAdminEmails (line 1149) | function verifyAllAdminEmails(): number {
function rowToSession (line 1165) | function rowToSession(row: any): UserSession | null {
function createUserSession (line 1178) | function createUserSession(session: UserSession): void {
function getSessionByTokenHash (line 1182) | function getSessionByTokenHash(tokenHash: string): UserSession | null {
function getSessionsByUserId (line 1186) | function getSessionsByUserId(userId: string): UserSession[] {
function deleteSession (line 1190) | function deleteSession(id: string): boolean {
function deleteSessionByTokenHash (line 1194) | function deleteSessionByTokenHash(tokenHash: string): boolean {
function deleteAllUserSessions (line 1198) | function deleteAllUserSessions(userId: string): number {
function cleanupExpiredSessions (line 1202) | function cleanupExpiredSessions(): number {
function rowToUserToken (line 1222) | function rowToUserToken(row: any): UserToken | null {
function createUserToken (line 1236) | function createUserToken(token: UserToken): void {
function getUserTokenByHash (line 1240) | function getUserTokenByHash(tokenHash: string): UserToken | null {
function markUserTokenUsed (line 1244) | function markUserTokenUsed(id: string): void {
function incrementTokenFailedAttempts (line 1248) | function incrementTokenFailedAttempts(id: string): number {
function deleteUserToken (line 1254) | function deleteUserToken(id: string): boolean {
function deleteUserTokensByType (line 1258) | function deleteUserTokensByType(userId: string, type: string): number {
function cleanupExpiredUserTokens (line 1262) | function cleanupExpiredUserTokens(): number {
function rowToOidcLink (line 1277) | function rowToOidcLink(row: any): UserOidcLink | null {
function createOidcLink (line 1292) | function createOidcLink(link: UserOidcLink): void {
function getOidcLinkById (line 1296) | function getOidcLinkById(id: string): UserOidcLink | null {
function getOidcLinkByProvider (line 1300) | function getOidcLinkByProvider(provider: string, providerUserId: string)...
function getOidcLinksByUser (line 1304) | function getOidcLinksByUser(userId: string): UserOidcLink[] {
function deleteOidcLink (line 1308) | function deleteOidcLink(id: string): boolean {
function updateOidcLinkTokens (line 1312) | function updateOidcLinkTokens(id: string, accessToken: string | null, re...
function rowToOidcProvider (line 1331) | function rowToOidcProvider(row: any): OidcProvider | null {
function createOidcProvider (line 1353) | function createOidcProvider(provider: OidcProvider): void {
function getOidcProvider (line 1361) | function getOidcProvider(id: string): OidcProvider | null {
function getOidcProviderByName (line 1365) | function getOidcProviderByName(name: string): OidcProvider | null {
function listOidcProviders (line 1369) | function listOidcProviders(): OidcProvider[] {
function listActiveOidcProviders (line 1373) | function listActiveOidcProviders(): OidcProvider[] {
function updateOidcProvider (line 1377) | function updateOidcProvider(provider: OidcProvider): void {
function deleteOidcProvider (line 1385) | function deleteOidcProvider(id: string): boolean {
function rowToSmtpConfig (line 1404) | function rowToSmtpConfig(row: any): SmtpConfig | null {
function createSmtpConfig (line 1426) | function createSmtpConfig(config: SmtpConfig): void {
function getSmtpConfig (line 1435) | function getSmtpConfig(id: string): SmtpConfig | null {
function getDefaultSmtpConfig (line 1439) | function getDefaultSmtpConfig(): SmtpConfig | null {
function listSmtpConfigs (line 1443) | function listSmtpConfigs(): SmtpConfig[] {
function updateSmtpConfig (line 1447) | function updateSmtpConfig(config: SmtpConfig): void {
function deleteSmtpConfig (line 1456) | function deleteSmtpConfig(id: string): boolean {
function rowToEmailTemplate (line 1471) | function rowToEmailTemplate(row: any): EmailTemplate | null {
function createEmailTemplate (line 1484) | function createEmailTemplate(template: EmailTemplate): void {
function getEmailTemplate (line 1488) | function getEmailTemplate(id: string): EmailTemplate | null {
function getEmailTemplateByName (line 1492) | function getEmailTemplateByName(name: string): EmailTemplate | null {
function listEmailTemplates (line 1496) | function listEmailTemplates(): EmailTemplate[] {
function updateEmailTemplate (line 1500) | function updateEmailTemplate(template: EmailTemplate): void {
function deleteEmailTemplate (line 1504) | function deleteEmailTemplate(id: string): boolean {
function rowToEmailLog (line 1517) | function rowToEmailLog(row: any): EmailLog | null {
function createEmailLog (line 1531) | function createEmailLog(log: EmailLog): void {
function listEmailLogs (line 1535) | function listEmailLogs(limit: number = 100, offset: number = 0): EmailLo...
function countEmailLogs (line 1539) | function countEmailLogs(): number {
function countEmailLogsByStatus (line 1543) | function countEmailLogsByStatus(status: string): number {
function clearEmailLogs (line 1547) | function clearEmailLogs(): number {
function clearAuditLogs (line 1551) | function clearAuditLogs(): number {
function clearActivityLogs (line 1555) | function clearActivityLogs(): number {
function rowToUserPreferences (line 1567) | function rowToUserPreferences(row: any): UserPreferences | null {
function saveUserPreferences (line 1577) | function saveUserPreferences(prefs: UserPreferences): void {
function getUserPreferences (line 1581) | function getUserPreferences(userId: string): UserPreferences | null {
function initializeDefaultEmailTemplates (line 1586) | function initializeDefaultEmailTemplates(): void {
function rowToOidcState (line 1683) | function rowToOidcState(row: any): OidcState | null {
function createOidcState (line 1698) | function createOidcState(oidcState: OidcState): void {
function getOidcState (line 1712) | function getOidcState(state: string): OidcState | null {
function deleteOidcState (line 1716) | function deleteOidcState(state: string): boolean {
function cleanupExpiredOidcStates (line 1720) | function cleanupExpiredOidcStates(): number {
function countOidcStates (line 1724) | function countOidcStates(): number {
function deleteOldestOidcStates (line 1728) | function deleteOldestOidcStates(count: number): number {
function rowToCsrfToken (line 1744) | function rowToCsrfToken(row: any): CsrfToken | null {
function createCsrfToken (line 1754) | function createCsrfToken(csrfToken: CsrfToken): void {
function getCsrfToken (line 1763) | function getCsrfToken(token: string): CsrfToken | null {
function markCsrfTokenUsed (line 1767) | function markCsrfTokenUsed(token: string): boolean {
function deleteCsrfToken (line 1771) | function deleteCsrfToken(token: string): boolean {
function cleanupExpiredCsrfTokens (line 1775) | function cleanupExpiredCsrfTokens(): number {
function countCsrfTokens (line 1779) | function countCsrfTokens(): number {
function deleteOldestCsrfTokens (line 1783) | function deleteOldestCsrfTokens(count: number): number {
function recordEmailRateLimit (line 1792) | function recordEmailRateLimit(email: string, action: string): void {
function countEmailRateLimitAttempts (line 1796) | function countEmailRateLimitAttempts(email: string, action: string, wind...
function cleanupEmailRateLimits (line 1801) | function cleanupEmailRateLimits(maxAgeSeconds: number = 3600): number {
FILE: theonefile_verse/src/index.ts
constant CONFIGURED_ORIGINS (line 11) | const CONFIGURED_ORIGINS = process.env.CORS_ORIGIN?.split(",").map(o => ...
function handleRequest (line 28) | async function handleRequest(req: Request, server: any): Promise<Respons...
method fetch (line 135) | async fetch(req, server) {
function shutdown (line 190) | function shutdown() {
FILE: theonefile_verse/src/mailer.ts
function escapeHtml (line 6) | function escapeHtml(str: string): string {
type EmailMessage (line 15) | interface EmailMessage {
type SendResult (line 22) | interface SendResult {
type SmtpResponse (line 28) | interface SmtpResponse {
function sendEmail (line 34) | async function sendEmail(message: EmailMessage): Promise<SendResult> {
function sendEmailWithConfig (line 43) | async function sendEmailWithConfig(
function logAndReturn (line 72) | function logAndReturn(
class SmtpClient (line 93) | class SmtpClient {
method constructor (line 101) | constructor(config: db.SmtpConfig) {
method log (line 105) | private log(...args: any[]) {
method connect (line 109) | async connect(): Promise<void> {
method handleData (line 191) | private handleData(data: Buffer) {
method handleError (line 196) | private handleError(error: Error) {
method handleClose (line 204) | private handleClose() {
method processBuffer (line 212) | private processBuffer() {
method readResponse (line 237) | private readResponse(): Promise<SmtpResponse> {
method command (line 259) | private async command(cmd: string, expectedCodes: number[] = [250]): P...
method ehlo (line 274) | async ehlo(): Promise<string[]> {
method startTls (line 279) | async startTls(): Promise<string[]> {
method authenticate (line 341) | async authenticate(username: string, password: string, capabilities: s...
method mailFrom (line 358) | async mailFrom(email: string): Promise<void> {
method rcptTo (line 362) | async rcptTo(email: string): Promise<void> {
method data (line 366) | async data(content: string): Promise<void> {
method quit (line 381) | async quit(): Promise<void> {
method close (line 388) | close() {
function sendViaSMTP (line 398) | async function sendViaSMTP(
function stripCRLF (line 463) | function stripCRLF(str: string): string {
function buildMessage (line 467) | function buildMessage(message: EmailMessage, config: db.SmtpConfig): str...
function encodeSubject (line 515) | function encodeSubject(subject: string): string {
function encodeQuotedPrintable (line 523) | function encodeQuotedPrintable(text: string): string {
function sendTemplatedEmail (line 573) | async function sendTemplatedEmail(
function sendVerificationEmail (line 599) | async function sendVerificationEmail(
function sendPasswordResetEmail (line 610) | async function sendPasswordResetEmail(
function sendMagicLinkEmail (line 621) | async function sendMagicLinkEmail(
function sendRoomInvitationEmail (line 632) | async function sendRoomInvitationEmail(
function testSmtpConfig (line 643) | async function testSmtpConfig(config: db.SmtpConfig): Promise<SendResult> {
function getEmailStats (line 652) | function getEmailStats(): {
FILE: theonefile_verse/src/network.ts
constant IPV4_RE (line 1) | const IPV4_RE = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
constant HOSTNAME_RE (line 2) | const HOSTNAME_RE = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-...
constant CIDR_RE (line 3) | const CIDR_RE = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})$/;
type ProbeConfig (line 5) | interface ProbeConfig {
type ProbeResult (line 12) | interface ProbeResult {
type BatchTarget (line 20) | interface BatchTarget {
type BatchResult (line 27) | interface BatchResult {
type DiscoveryOptions (line 33) | interface DiscoveryOptions {
type DiscoveredHost (line 44) | interface DiscoveredHost {
type DiscoveryHandle (line 59) | interface DiscoveryHandle {
constant PORT_SERVICE_MAP (line 67) | const PORT_SERVICE_MAP: Record<number, string> = {
constant DEFAULT_SCAN_PORTS (line 164) | const DEFAULT_SCAN_PORTS = [22, 23, 25, 53, 80, 110, 135, 139, 143, 161,...
type ServiceIconEntry (line 166) | interface ServiceIconEntry {
constant SERVICE_ICON_MAP (line 172) | const SERVICE_ICON_MAP: ServiceIconEntry[] = [
constant DEFAULT_ICON (line 244) | const DEFAULT_ICON = { library: "selfhst", name: "linux" };
function validateIPv4 (line 246) | function validateIPv4(ip: string): boolean {
function validateHostname (line 256) | function validateHostname(host: string): boolean {
function validateTarget (line 261) | function validateTarget(target: string): boolean {
function isRFC1918 (line 265) | function isRFC1918(ip: string): boolean {
function validatePort (line 278) | function validatePort(port: number): boolean {
function ipToInt (line 282) | function ipToInt(ip: string): number {
function intToIp (line 287) | function intToIp(n: number): string {
function validateCIDR (line 291) | function validateCIDR(cidr: string, allowPublic: boolean, maxPrefix: num...
function probeICMP (line 320) | async function probeICMP(target: string, timeoutMs: number): Promise<Pro...
function probeTCP (line 343) | async function probeTCP(target: string, port: number, timeoutMs: number)...
function probeHTTP (line 367) | async function probeHTTP(target: string, config: ProbeConfig, timeoutMs:...
function probeDNS (line 388) | async function probeDNS(target: string, timeoutMs: number): Promise<Prob...
function probeTarget (line 416) | async function probeTarget(target: string, probes: ProbeConfig[], timeou...
function probeBatch (line 454) | async function probeBatch(targets: BatchTarget[]): Promise<Record<string...
function getServiceIcon (line 470) | function getServiceIcon(ports: number[]): { library: string; name: strin...
constant GENERIC_ICON_NAMES (line 479) | const GENERIC_ICON_NAMES = new Set(["terminal", "windows", "vnc", "cups"...
function getServiceIcons (line 481) | function getServiceIcons(ports: number[]): { library: string; name: stri...
function getDefaultPortList (line 500) | function getDefaultPortList(): { port: number; service: string; icon: st...
function getServicesForPorts (line 511) | function getServicesForPorts(ports: number[]): Record<number, string> {
function reverseDNS (line 520) | async function reverseDNS(ip: string, timeoutMs: number): Promise<string> {
function resolveNetBIOS (line 536) | async function resolveNetBIOS(ip: string, timeoutMs: number): Promise<st...
function resolveMDNS (line 556) | async function resolveMDNS(ip: string, timeoutMs: number): Promise<strin...
function resolveHTTPServer (line 572) | async function resolveHTTPServer(ip: string, timeoutMs: number): Promise...
type DNSFingerprint (line 588) | interface DNSFingerprint {
function fingerprintDNS (line 594) | async function fingerprintDNS(ip: string, openPorts: number[], timeoutMs...
function resolveSNMP (line 651) | async function resolveSNMP(ip: string, community: string, timeoutMs: num...
function bestHostname (line 679) | function bestHostname(host: DiscoveredHost): string {
function cidrToIPs (line 683) | function cidrToIPs(cidr: string): string[] {
function startDiscovery (line 697) | async function startDiscovery(
function cancelDiscovery (line 842) | function cancelDiscovery(taskId: string): boolean {
function hasActiveDiscovery (line 850) | function hasActiveDiscovery(roomId: string): boolean {
function hasActiveDiscoveryForRoom (line 857) | function hasActiveDiscoveryForRoom(roomId: string, taskPrefix: string): ...
function validateProbeConfig (line 864) | function validateProbeConfig(probes: unknown): probes is ProbeConfig[] {
constant DOCKER_TRIGGER_PORTS (line 876) | const DOCKER_TRIGGER_PORTS = [2375, 2376, 9443, 5001];
constant DOCKER_DEEP_SCAN_PORTS (line 878) | const DOCKER_DEEP_SCAN_PORTS: number[] = [];
type DockerContainer (line 882) | interface DockerContainer {
type DeepScanHandle (line 889) | interface DeepScanHandle {
function queryDockerAPI (line 898) | async function queryDockerAPI(ip: string, timeoutMs: number): Promise<Do...
function startDeepScan (line 928) | async function startDeepScan(
function cancelDeepScan (line 1009) | function cancelDeepScan(scanId: string): boolean {
function hasActiveDeepScan (line 1017) | function hasActiveDeepScan(ip: string): boolean {
FILE: theonefile_verse/src/oidc.ts
constant DEBUG_OIDC (line 3) | const DEBUG_OIDC = process.env.DEBUG_OIDC === 'true';
function logOidcError (line 14) | function logOidcError(message: string, ...args: any[]): void {
function logOidcDebug (line 22) | function logOidcDebug(message: string, ...args: any[]): void {
constant MAX_OIDC_STATES (line 28) | const MAX_OIDC_STATES = 10000;
constant OIDC_STATE_TTL_MS (line 29) | const OIDC_STATE_TTL_MS = 10 * 60 * 1000;
constant ID_TOKEN_CLOCK_SKEW_MS (line 30) | const ID_TOKEN_CLOCK_SKEW_MS = parseInt(process.env.OIDC_CLOCK_SKEW_SECO...
constant CSRF_TOKEN_TTL_MS (line 31) | const CSRF_TOKEN_TTL_MS = 60 * 60 * 1000;
constant MAX_CSRF_TOKENS (line 32) | const MAX_CSRF_TOKENS = 10000;
function cleanupOldestOidcStates (line 34) | function cleanupOldestOidcStates(): void {
function generateRandomString (line 46) | function generateRandomString(length: number): string {
function generateCodeVerifier (line 52) | function generateCodeVerifier(): string {
function generateCodeChallenge (line 58) | async function generateCodeChallenge(verifier: string): Promise<string> {
function base64UrlEncode (line 65) | function base64UrlEncode(buffer: Uint8Array): string {
constant ENCRYPTION_KEY_LENGTH (line 73) | const ENCRYPTION_KEY_LENGTH = 32;
constant PBKDF2_ITERATIONS (line 74) | const PBKDF2_ITERATIONS = 600000;
constant PBKDF2_SALT_LENGTH (line 75) | const PBKDF2_SALT_LENGTH = 16;
function deriveKeyFromSecret (line 78) | async function deriveKeyFromSecret(secret: string, salt: Uint8Array): Pr...
function getEncryptionKeyMaterial (line 102) | async function getEncryptionKeyMaterial(): Promise<Uint8Array> {
function getEncryptionKey (line 146) | async function getEncryptionKey(salt: Uint8Array): Promise<CryptoKey> {
function encryptSecret (line 171) | async function encryptSecret(plaintext: string): Promise<string> {
function decryptSecret (line 190) | async function decryptSecret(ciphertext: string): Promise<string> {
type OidcDiscovery (line 226) | interface OidcDiscovery {
function discoverOidcEndpoints (line 236) | async function discoverOidcEndpoints(issuerUrl: string): Promise<OidcDis...
type OidcAuthUrl (line 255) | interface OidcAuthUrl {
type OidcUserInfo (line 260) | interface OidcUserInfo {
type OidcTokenResponse (line 269) | interface OidcTokenResponse {
function generateAuthorizationUrl (line 277) | async function generateAuthorizationUrl(
function exchangeCodeForTokens (line 340) | async function exchangeCodeForTokens(
constant MAX_JWKS_CACHE_ENTRIES (line 448) | const MAX_JWKS_CACHE_ENTRIES = 100;
function cleanupJwksCache (line 451) | function cleanupJwksCache(): void {
function sleep (line 463) | async function sleep(ms: number): Promise<void> {
function fetchJwks (line 467) | async function fetchJwks(jwksUri: string): Promise<JsonWebKey[]> {
function getHashAlgorithm (line 506) | function getHashAlgorithm(alg: string): string {
function importJwkForVerify (line 512) | async function importJwkForVerify(jwk: JsonWebKey, headerAlg?: string): ...
function verifyJwtSignature (line 532) | async function verifyJwtSignature(token: string, jwks: JsonWebKey[]): Pr...
function parseIdToken (line 572) | async function parseIdToken(
function processOidcCallback (line 666) | async function processOidcCallback(
constant MAX_SESSIONS_PER_USER (line 853) | const MAX_SESSIONS_PER_USER = 10;
function createUserSessionToken (line 855) | async function createUserSessionToken(
function hashToken (line 884) | async function hashToken(token: string): Promise<string> {
function generateSecureToken (line 891) | function generateSecureToken(bytes: number = 32): string {
function validateUserSessionToken (line 897) | async function validateUserSessionToken(
function refreshOidcTokens (line 926) | async function refreshOidcTokens(linkId: string): Promise<{
function revokeUserOidcTokens (line 1009) | async function revokeUserOidcTokens(userId: string): Promise<void> {
type AuthSettings (line 1069) | interface AuthSettings {
function getAuthSettings (line 1084) | function getAuthSettings(): AuthSettings {
function saveAuthSettings (line 1112) | function saveAuthSettings(settings: Partial<AuthSettings>): void {
function getIdTokenMaxAgeMs (line 1118) | function getIdTokenMaxAgeMs(): number {
function sanitizeIconUrl (line 1123) | function sanitizeIconUrl(url: string | null): string | null {
function getActiveProviders (line 1134) | function getActiveProviders(): { id: string; name: string; iconUrl: stri...
function getSessionCookie (line 1142) | function getSessionCookie(name: string, value: string, maxAge: number = ...
function getClearCookie (line 1150) | function getClearCookie(name: string): string {
function getSessionCookieName (line 1158) | function getSessionCookieName(baseName: string): string {
function cleanupOldestCsrfTokens (line 1163) | function cleanupOldestCsrfTokens(): void {
function generateCsrfToken (line 1169) | function generateCsrfToken(): string {
function validateCsrfToken (line 1186) | function validateCsrfToken(token: string): boolean {
function getCsrfCookie (line 1206) | function getCsrfCookie(token: string): string {
function validateRedirectUrl (line 1212) | function validateRedirectUrl(redirectUrl: string | null, baseUrl: string...
FILE: theonefile_verse/src/rate-limit.ts
type RateLimitEntry (line 6) | interface RateLimitEntry {
constant MAX_RATE_LIMIT_ENTRIES (line 11) | const MAX_RATE_LIMIT_ENTRIES = 10000;
type WsTokenBucket (line 14) | interface WsTokenBucket {
constant WS_RATE_LIMITS (line 19) | const WS_RATE_LIMITS = {
constant MAX_WS_RATE_LIMIT_BUCKETS (line 28) | const MAX_WS_RATE_LIMIT_BUCKETS = 50000;
function checkWsRateLimit (line 31) | function checkWsRateLimit(connectionId: string, messageType: string): bo...
function checkRateLimit (line 50) | async function checkRateLimit(ip: string, endpoint: string, settings: In...
function checkEmailRateLimit (line 83) | async function checkEmailRateLimit(email: string, action: string, settin...
constant MAX_WS_CONNECTIONS_PER_IP (line 102) | const MAX_WS_CONNECTIONS_PER_IP = 50;
constant WS_CONNECTION_WINDOW (line 103) | const WS_CONNECTION_WINDOW = 3600 * 1000;
function checkWsConnectionLimit (line 105) | function checkWsConnectionLimit(clientIp: string): boolean {
function startRateLimitCleanupIntervals (line 119) | function startRateLimitCleanupIntervals(): void {
FILE: theonefile_verse/src/redis.ts
constant REDIS_URL (line 3) | const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379";
function connectRedis (line 11) | async function connectRedis(): Promise<boolean> {
function isRedisConnected (line 46) | function isRedisConnected(): boolean {
constant RATE_LIMIT_LUA (line 50) | const RATE_LIMIT_LUA = `
function checkRateLimitRedis (line 56) | async function checkRateLimitRedis(
function setSessionToken (line 73) | async function setSessionToken(
function getSessionToken (line 89) | async function getSessionToken(token: string): Promise<{ type: string; c...
function deleteSessionToken (line 101) | async function deleteSessionToken(token: string): Promise<boolean> {
function setUserPresence (line 113) | async function setUserPresence(
function getUserPresence (line 131) | async function getUserPresence(roomId: string, userId: string): Promise<...
function getAllUserPresence (line 143) | async function getAllUserPresence(roomId: string): Promise<Map<string, a...
function removeUserPresence (line 171) | async function removeUserPresence(roomId: string, userId: string): Promi...
function setRoomStateCache (line 183) | async function setRoomStateCache(roomId: string, state: any, ttlSeconds:...
function getRoomStateCache (line 195) | async function getRoomStateCache(roomId: string): Promise<any | null> {
function deleteRoomStateCache (line 207) | async function deleteRoomStateCache(roomId: string): Promise<boolean> {
function publishMessage (line 219) | async function publishMessage(channel: string, message: string): Promise...
function subscribeToChannel (line 231) | async function subscribeToChannel(
function unsubscribeFromChannel (line 253) | async function unsubscribeFromChannel(
function publishToRoom (line 278) | async function publishToRoom(roomId: string, message: any): Promise<void> {
function subscribeToRoom (line 282) | async function subscribeToRoom(
function incrementCounter (line 301) | async function incrementCounter(key: string): Promise<number> {
function getCounter (line 312) | async function getCounter(key: string): Promise<number> {
function setWithExpiry (line 324) | async function setWithExpiry(key: string, value: string, ttlSeconds: num...
function getValue (line 336) | async function getValue(key: string): Promise<string | null> {
function deleteKey (line 347) | async function deleteKey(key: string): Promise<boolean> {
function ping (line 359) | async function ping(): Promise<boolean> {
function disconnectRedis (line 369) | async function disconnectRedis(): Promise<void> {
function getRedisClient (line 386) | function getRedisClient(): RedisClientType | null {
FILE: theonefile_verse/src/rooms.ts
type Room (line 12) | interface Room {
type RoomMeta (line 24) | interface RoomMeta {
function hashPassword (line 35) | async function hashPassword(password: string): Promise<string> {
function verifyPassword (line 39) | async function verifyPassword(password: string, hash: string): Promise<b...
function loadRoom (line 43) | function loadRoom(id: string): Room | null {
function saveRoom (line 48) | function saveRoom(room: Room): void {
function deleteRoomData (line 61) | function deleteRoomData(id: string): boolean {
function scheduleDestruction (line 74) | function scheduleDestruction(roomId: string, delayMs: number): void {
function resetDestructionTimer (line 87) | function resetDestructionTimer(roomId: string): void {
function extractThemePresets (line 97) | function extractThemePresets(): Array<{key: string, label: string}> {
constant GITHUB_RAW_URL (line 121) | const GITHUB_RAW_URL = "https://raw.githubusercontent.com/gelatinescream...
function getExpectedTheOneFileHash (line 125) | function getExpectedTheOneFileHash(): string | null {
function setExpectedTheOneFileHash (line 129) | function setExpectedTheOneFileHash(hash: string): void {
function extractVersionFromHtml (line 133) | function extractVersionFromHtml(html: string): string {
function isNewerVersion (line 138) | function isNewerVersion(latest: string, current: string): boolean {
function computeSha256Hash (line 151) | async function computeSha256Hash(content: string): Promise<string> {
function fetchLatestFromGitHub (line 159) | async function fetchLatestFromGitHub(): Promise<boolean> {
function setTheOneFileHtml (line 191) | function setTheOneFileHtml(html: string): void {
function getTheOneFilePath (line 196) | function getTheOneFilePath(): string {
function restartUpdateTimer (line 202) | function restartUpdateTimer(): void {
function clearUpdateTimer (line 212) | function clearUpdateTimer(): void {
function initializeTheOneFile (line 217) | async function initializeTheOneFile(): Promise<void> {
type ValidationResult (line 242) | interface ValidationResult {
type TopologyValidationResult (line 248) | interface TopologyValidationResult {
constant TOPOLOGY_LIMITS (line 254) | const TOPOLOGY_LIMITS = {
function checkJsonDepthAndSize (line 262) | function checkJsonDepthAndSize(obj: any, currentDepth: number = 0): { va...
constant ALLOWED_TAGS (line 299) | const ALLOWED_TAGS = new Set([
constant ALLOWED_ATTRS (line 311) | const ALLOWED_ATTRS = new Set([
function isAllowedDataAttr (line 331) | function isAllowedDataAttr(name: string): boolean {
function sanitizeUrl (line 336) | function sanitizeUrl(url: string): string {
function sanitizeHtmlString (line 347) | function sanitizeHtmlString(str: string): string {
function sanitizeTopologyStrings (line 384) | function sanitizeTopologyStrings(obj: any): any {
function validateTopology (line 398) | function validateTopology(topology: any): TopologyValidationResult {
function validateTheOneFileHtml (line 452) | function validateTheOneFileHtml(html: string): ValidationResult {
function isValidWebhookUrl (line 482) | function isValidWebhookUrl(url: string): boolean {
function sendWebhook (line 512) | async function sendWebhook(event: string, data: any): Promise<void> {
constant BACKUPS_DIR (line 530) | const BACKUPS_DIR = join(DATA_DIR, "backups");
function createBackup (line 533) | async function createBackup(autoGenerated: boolean = false): Promise<{ i...
function restoreBackup (line 558) | async function restoreBackup(backupId: string): Promise<{ success: boole...
function getBackupsDir (line 582) | function getBackupsDir(): string {
function restartBackupTimer (line 588) | function restartBackupTimer(): void {
function clearBackupTimer (line 598) | function clearBackupTimer(): void {
FILE: theonefile_verse/src/routes/admin-apikeys.ts
function handle (line 6) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-auth-settings.ts
function handle (line 6) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-auth.ts
function handle (line 11) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-backups.ts
function handle (line 8) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-logs.ts
function handle (line 4) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-rooms.ts
function handle (line 6) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-settings.ts
constant GITHUB_RAW_URL (line 6) | const GITHUB_RAW_URL = "https://raw.githubusercontent.com/gelatinescream...
function handle (line 8) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/admin-users.ts
function handle (line 6) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/instance-access.ts
function handle (line 8) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/network-routes.ts
function handle (line 9) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/public.ts
constant STATIC_FILES (line 9) | const STATIC_FILES: Record<string, { path: string; type: string; cache: ...
function handle (line 21) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/room.ts
constant ROOM_ACCESS_COOKIE_REGEX (line 9) | const ROOM_ACCESS_COOKIE_REGEX = /(?:^|;\s*)room_access=([^;]+)/;
constant HOST_ROOM_ACCESS_COOKIE_REGEX (line 10) | const HOST_ROOM_ACCESS_COOKIE_REGEX = /(?:^|;\s*)__Host-room_access=([^;...
function extractRoomAccessCookie (line 12) | function extractRoomAccessCookie(cookies: string, prodMode: boolean): st...
function handle (line 17) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/setup.ts
function handle (line 9) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/routes/user-auth.ts
function handle (line 9) | async function handle(req: Request, path: string, url: URL, corsHeaders:...
FILE: theonefile_verse/src/security.ts
constant IPV4_REGEX (line 6) | const IPV4_REGEX = /^(\d{1,3}\.){3}\d{1,3}$/;
constant IPV6_REGEX (line 7) | const IPV6_REGEX = /^([\da-fA-F]{0,4}:){2,7}[\da-fA-F]{0,4}$/;
function isValidIP (line 9) | function isValidIP(ip: string): boolean {
function getClientIP (line 13) | function getClientIP(req: Request): string {
function getSecurityHeaders (line 37) | function getSecurityHeaders(pageType: 'admin' | 'public' | 'room' | 'api...
function serveHtml (line 67) | function serveHtml(html: string, pageType: 'admin' | 'public' | 'room' =...
function apiError (line 76) | function apiError(e: any, corsHeaders: Record<string, string>, message =...
function validateRequestCsrf (line 81) | function validateRequestCsrf(req: Request, body?: any): boolean {
function csrfReject (line 96) | function csrfReject(corsHeaders: Record<string, string>): Response {
function getTokenFromRequest (line 100) | function getTokenFromRequest(req: Request): string | null {
function getUserTokenFromRequest (line 109) | function getUserTokenFromRequest(req: Request): string | null {
function relativeRedirect (line 120) | function relativeRedirect(path: string, status: number = 302): Response {
function validateAdminUser (line 124) | async function validateAdminUser(req: Request): Promise<db.User | null> {
function validateAdminOrApiKey (line 136) | async function validateAdminOrApiKey(
FILE: theonefile_verse/src/templates.ts
function getPasswordResetHtml (line 1083) | function getPasswordResetHtml(token: string): string {
FILE: theonefile_verse/src/tokens.ts
type TokenEntry (line 5) | interface TokenEntry {
constant ADMIN_TOKENS (line 10) | const ADMIN_TOKENS = new Map<string, TokenEntry>();
constant INSTANCE_TOKENS (line 11) | const INSTANCE_TOKENS = new Map<string, number>();
constant TOKEN_EXPIRY (line 12) | const TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000;
constant ROOM_ACCESS_TOKENS (line 14) | const ROOM_ACCESS_TOKENS = new Map<string, { roomId: string; expiresAt: ...
constant ROOM_ACCESS_EXPIRY (line 15) | const ROOM_ACCESS_EXPIRY = 24 * 60 * 60 * 1000;
type WsSessionToken (line 17) | interface WsSessionToken {
constant WS_SESSION_TOKENS (line 24) | const WS_SESSION_TOKENS = new Map<string, WsSessionToken>();
constant WS_TOKEN_EXPIRY (line 25) | const WS_TOKEN_EXPIRY = 5 * 60 * 1000;
function generateWsSessionToken (line 27) | async function generateWsSessionToken(roomId: string, collabUserId: stri...
function validateWsSessionToken (line 44) | async function validateWsSessionToken(token: string, roomId: string): Pr...
constant MAX_WS_SESSION_TOKENS (line 64) | const MAX_WS_SESSION_TOKENS = 50000;
function generateRoomAccessToken (line 66) | function generateRoomAccessToken(roomId: string): string {
function validateRoomAccessToken (line 78) | function validateRoomAccessToken(token: string, roomId: string): boolean {
function generateAdminToken (line 85) | async function generateAdminToken(): Promise<string> {
function validateAdminToken (line 96) | async function validateAdminToken(token: string): Promise<boolean> {
function generateInstanceToken (line 115) | function generateInstanceToken(): string {
function validateInstanceToken (line 121) | function validateInstanceToken(token: string): boolean {
function storeInstanceToken (line 131) | function storeInstanceToken(token: string): void {
function removeInstanceToken (line 135) | function removeInstanceToken(token: string): void {
function removeAdminToken (line 139) | async function removeAdminToken(token: string): Promise<void> {
function hashApiKey (line 143) | async function hashApiKey(key: string): Promise<string> {
function validateApiKey (line 150) | async function validateApiKey(key: string): Promise<db.ApiKey | null> {
function startTokenCleanupIntervals (line 159) | function startTokenCleanupIntervals(): void {
function cleanupExpiredRoomTokens (line 201) | function cleanupExpiredRoomTokens(): void {
FILE: theonefile_verse/src/websocket.ts
type WsData (line 10) | interface WsData {
method open (line 19) | open(ws: any) {
method message (line 34) | async message(ws: any, message: any) {
method close (line 208) | close(ws: any) {
Copy disabled (too large)
Download .json
Condensed preview — 77 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (12,802K chars).
[
{
"path": ".gitattributes",
"chars": 96,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n*.min.js -diff\n*.min.css -diff"
},
{
"path": ".github/workflows/docker-publish.yml",
"chars": 1674,
"preview": "name: Build TheOneFile Verse\n\non:\n push:\n branches:\n - main\n - master\n paths:\n - 'theonefile_verse"
},
{
"path": "LICENSE",
"chars": 1230,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 15332,
"preview": "<p align=\"center\">\n <img src=\"https://img.shields.io/badge/License-Unlicense-576169?style=for-the-badge&labelColor=0128"
},
{
"path": "changelog.md",
"chars": 28277,
"preview": "#### CHANGE LOG\n\n### Version 4.1.5 /\\ 3-26-26 Enhanced 'Create', UI polish and squashing a sneaky bug and TheOneFile_Ver"
},
{
"path": "demos/csv-exports/the-one-file-corporate.csv",
"chars": 217381,
"preview": "#THEONEFILE_CONFIG:{\"nodeData\":{\"core-router-1\":{\"shape\":\"router\",\"name\":\"Core Router 1\",\"ip\":\"10.0.0.1\",\"role\":\"Core Ro"
},
{
"path": "demos/csv-exports/the-one-file-homelab.csv",
"chars": 152439,
"preview": "#THEONEFILE_CONFIG:{\"nodeData\":{\"internet\":{\"shape\":\"stop-sign\",\"name\":\"Internet\",\"ip\":\"0.0.0.0\",\"role\":\"\",\"tags\":[],\"no"
},
{
"path": "demos/csv-exports/the-one-file-networkening-corporate.csv",
"chars": 220620,
"preview": "#THEONEFILE_CONFIG:{\"nodeData\":{\"core-router-1\":{\"shape\":\"router\",\"name\":\"Core Router 1\",\"ip\":\"10.0.0.1\",\"role\":\"Core Ro"
},
{
"path": "demos/csv-exports/the-one-file-networkening-homelab.csv",
"chars": 153431,
"preview": "#THEONEFILE_CONFIG:{\"nodeData\":{\"internet\":{\"shape\":\"square\",\"name\":\"Internet\",\"ip\":\"0.0.0.0\",\"role\":\"\",\"tags\":[],\"notes"
},
{
"path": "demos/index.html",
"chars": 16826,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, in"
},
{
"path": "demos/json-exports/the-one-file-corporate-demo.json",
"chars": 325812,
"preview": "{\n \"nodeData\": {\n \"core-router-1\": {\n \"shape\": \"router\",\n \"name\": \"Core Router 1\",\n \"ip\": \"10.0.0.1\","
},
{
"path": "demos/json-exports/the-one-file-homelab-demo.json",
"chars": 246261,
"preview": "{\n \"nodeData\": {\n \"internet\": {\n \"shape\": \"stop-sign\",\n \"name\": \"Internet\",\n \"ip\": \"0.0.0.0\",\n \""
},
{
"path": "demos/json-exports/theonefile-networkening-corporate-demo.json",
"chars": 320062,
"preview": "{\n \"nodeData\": {\n \"core-router-1\": {\n \"shape\": \"router\",\n \"name\": \"Core Router 1\",\n \"ip\": \"10.0.0.1\","
},
{
"path": "demos/json-exports/theonefile-networkening-homelab-demo.json",
"chars": 237330,
"preview": "{\n \"nodeData\": {\n \"internet\": {\n \"shape\": \"square\",\n \"name\": \"Internet\",\n \"ip\": \"0.0.0.0\",\n \"rol"
},
{
"path": "demos/markdown-exports/the-one-file-corporate.md",
"chars": 392479,
"preview": "<!--THEONEFILE_CONFIG\n{\n \"nodeData\": {\n \"core-router-1\": {\n \"shape\": \"router\",\n \"name\": \"Core Router 1\",\n "
},
{
"path": "demos/markdown-exports/the-one-file-homelab.md",
"chars": 261522,
"preview": "<!--THEONEFILE_CONFIG\n{\n \"nodeData\": {\n \"internet\": {\n \"shape\": \"stop-sign\",\n \"name\": \"Internet\",\n \"i"
},
{
"path": "demos/markdown-exports/the-one-file-networkening-corporate.md",
"chars": 386761,
"preview": "<!--THEONEFILE_CONFIG\n{\n \"nodeData\": {\n \"core-router-1\": {\n \"shape\": \"router\",\n \"name\": \"Core Router 1\",\n "
},
{
"path": "demos/markdown-exports/the-one-file-networkening-homelab.md",
"chars": 250914,
"preview": "<!--THEONEFILE_CONFIG\n{\n \"nodeData\": {\n \"internet\": {\n \"shape\": \"square\",\n \"name\": \"Internet\",\n \"ip\":"
},
{
"path": "demos/password-protected/password.txt",
"chars": 7,
"preview": "lambert"
},
{
"path": "demos/password-protected/the-one-file-corporate-demo.html",
"chars": 1158671,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #0b0e13; --panel-alt: #10141b; --sidebar-bg: #10141b; --btn-bg: #0b0e1"
},
{
"path": "demos/password-protected/the-one-file-homelab-demo.html",
"chars": 1051098,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #2f0e0e; --panel-alt: #10141b; --sidebar-bg: #10141b; --btn-bg: #0b0e1"
},
{
"path": "demos/password-protected/theonefile-networkening-corporate-demo.html",
"chars": 1216075,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #0b0e13; --panel-alt: #10141b; --accent: #4fd1c5; --danger: #f56565; -"
},
{
"path": "demos/password-protected/theonefile-networkening-homelab-demo.html",
"chars": 1105008,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #2f0e0e; --panel-alt: #10141b; --accent: #a75252; --danger: #f56565; -"
},
{
"path": "import-export-save.md",
"chars": 6910,
"preview": "# Export and Import\n\n| Format | Export | Import | Full Backup | Editable |\n|--------|--------|--------|-------------|--"
},
{
"path": "keyboard-shortcuts.md",
"chars": 1631,
"preview": "# Keyboard Shortcuts\n\n## Navigation & Movement\n| Shortcut | Action |\n|----------|--------|\n| `Arrow Keys` | Move selecte"
},
{
"path": "mobile-gestures.md",
"chars": 2275,
"preview": "# Mobile Gestures & Touch Controls\n\n| Gesture | Action | Context |\n|---------|--------|---------|\n| **Tap node** | Selec"
},
{
"path": "the-one-file.html",
"chars": 1059974,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #0b0e13; --panel-alt: #10141b; --sidebar-bg: #10141b; --btn-bg: #0b0e1"
},
{
"path": "theonefile-networkening.html",
"chars": 1120851,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #0b0e13; --panel-alt: #10141b; --accent: #4fd1c5; --danger: #f56565; -"
},
{
"path": "theonefile_verse/.dockerignore",
"chars": 100,
"preview": "node_modules\n.git\n.gitignore\n*.md\ndata\n.env\n.env.*\ndocker-compose.yml\n.dockerignore\ndemo-admin.html\n"
},
{
"path": "theonefile_verse/.gitattributes",
"chars": 40,
"preview": "*.sh text eol=lf\nDockerfile text eol=lf\n"
},
{
"path": "theonefile_verse/Dockerfile",
"chars": 706,
"preview": "FROM oven/bun:alpine\nWORKDIR /app\nRUN apk add --no-cache su-exec iputils bind-tools samba-client avahi-tools net-snmp-to"
},
{
"path": "theonefile_verse/README.md",
"chars": 9750,
"preview": "### TheOneFile_Verse\n\n<p align=\"center\">\n <img src=\"https://img.shields.io/badge/License-Unlicense-576169?style=for-the"
},
{
"path": "theonefile_verse/api.md",
"chars": 9251,
"preview": "# TheOneFile Verse API Documentation\n\nBase URL: `http://localhost:10101` (or your deployed instance)\n\n## Authentication\n"
},
{
"path": "theonefile_verse/changelog.md",
"chars": 19642,
"preview": "### TheOneFile_Verse changelog\n\n**4/6/26 Theonefile_verse 1.9.0 Beta 2** : **Production ready hierarchical architecture "
},
{
"path": "theonefile_verse/demo-admin.html",
"chars": 85302,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, in"
},
{
"path": "theonefile_verse/docker-compose.yml",
"chars": 1593,
"preview": "services:\n theonefile_verse:\n image: ghcr.io/gelatinescreams/theonefile_verse:latest\n ports:\n - \"10101:10101"
},
{
"path": "theonefile_verse/entrypoint.sh",
"chars": 209,
"preview": "#!/bin/sh\nset -e\nchown -R appuser:appgroup /app/data\nif ! su-exec appuser test -w /app/data; then\n echo \"FATAL: /app/da"
},
{
"path": "theonefile_verse/package.json",
"chars": 222,
"preview": "{\n \"name\": \"theonefile_verse\",\n \"version\": \"1.9.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"bun run --watch src"
},
{
"path": "theonefile_verse/public/admin-auth.js",
"chars": 2015,
"preview": "(function() {\n 'use strict';\n\n var forcedTheme = null;\n\n function getTheme() {\n if (forcedTheme && forcedTheme !=="
},
{
"path": "theonefile_verse/public/admin-dashboard.js",
"chars": 72480,
"preview": "(function() {\n 'use strict';\n var pageData = JSON.parse((document.getElementById('page-data') || {}).textContent || '{"
},
{
"path": "theonefile_verse/public/admin-pages.js",
"chars": 18202,
"preview": "(function() {\n 'use strict';\n\n function withFormLoading(form, fn) {\n return async function(e) {\n e.preventDefa"
},
{
"path": "theonefile_verse/public/collab-init.js",
"chars": 7858,
"preview": "(function(){\n window.COLLAB_MODE = true;\n\n var origGetItem = localStorage.getItem.bind(localStorage);\n var origSetIte"
},
{
"path": "theonefile_verse/public/collab-save-hook.js",
"chars": 1724,
"preview": "(function(){\n var pendingHtmlBlobs = new Map();\n var origCreateObjectURL = URL.createObjectURL;\n var origRevokeObject"
},
{
"path": "theonefile_verse/public/collab.css",
"chars": 20656,
"preview": "#collab-bar {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n top: env(safe-area-inset-top, 0);\n height: 48px;\n "
},
{
"path": "theonefile_verse/public/collab.js",
"chars": 184019,
"preview": "(function() {\n 'use strict';\n\n const roomConfigEl = document.getElementById('room-config');\n if (!roomConfigEl) retur"
},
{
"path": "theonefile_verse/public/index.html",
"chars": 20395,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, in"
},
{
"path": "theonefile_verse/public/landing.js",
"chars": 32112,
"preview": "(function() {\n 'use strict';\n\n function withLoading(fn) {\n return async function() {\n var btn = this instanceo"
},
{
"path": "theonefile_verse/public/theonefile.html",
"chars": 1120851,
"preview": "<!DOCTYPE html> \n <html lang=\"en\" style=\"--panel: #0b0e13; --panel-alt: #10141b; --accent: #4fd1c5; --danger: #f56565; -"
},
{
"path": "theonefile_verse/redis.conf",
"chars": 61,
"preview": "maxmemory 200mb\nmaxmemory-policy volatile-lru\nappendonly yes\n"
},
{
"path": "theonefile_verse/src/auth.ts",
"chars": 35565,
"preview": "import * as db from \"./database\";\nimport * as oidc from \"./oidc\";\nimport * as mailer from \"./mailer\";\nimport { createHma"
},
{
"path": "theonefile_verse/src/config.ts",
"chars": 8542,
"preview": "import { readFileSync, existsSync } from \"fs\";\nimport { join } from \"path\";\nimport * as db from \"./database\";\nimport * a"
},
{
"path": "theonefile_verse/src/database.ts",
"chars": 61110,
"preview": "import { Database } from \"bun:sqlite\";\nimport { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync } from \"fs\""
},
{
"path": "theonefile_verse/src/index.ts",
"chars": 8055,
"preview": "import * as db from \"./database\";\nimport * as redis from \"./redis\";\nimport * as oidc from \"./oidc\";\nimport { APP_VERSION"
},
{
"path": "theonefile_verse/src/mailer.ts",
"chars": 18593,
"preview": "import * as db from \"./database\";\nimport { decryptSecret } from \"./oidc\";\nimport { connect as tlsConnect, TLSSocket } fr"
},
{
"path": "theonefile_verse/src/network.ts",
"chars": 35187,
"preview": "const IPV4_RE = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/;\nconst HOSTNAME_RE = /^[a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-"
},
{
"path": "theonefile_verse/src/oidc.ts",
"chars": 38452,
"preview": "import * as db from \"./database\";\n\nconst DEBUG_OIDC = process.env.DEBUG_OIDC === 'true';\n\nif (DEBUG_OIDC) {\n const auth"
},
{
"path": "theonefile_verse/src/rate-limit.ts",
"chars": 5341,
"preview": "import * as redis from \"./redis\";\nimport * as db from \"./database\";\nimport * as oidc from \"./oidc\";\nimport { type Instan"
},
{
"path": "theonefile_verse/src/redis.ts",
"chars": 10675,
"preview": "import { createClient, RedisClientType } from \"redis\";\n\nconst REDIS_URL = process.env.REDIS_URL || \"redis://localhost:63"
},
{
"path": "theonefile_verse/src/rooms.ts",
"chars": 23868,
"preview": "import { existsSync, mkdirSync } from \"fs\";\nimport { unlink } from \"fs/promises\";\nimport { join } from \"path\";\nimport * "
},
{
"path": "theonefile_verse/src/routes/admin-apikeys.ts",
"chars": 3714,
"preview": "import * as db from \"../database\";\nimport { getClientIP, apiError, validateAdminOrApiKey } from \"../security\";\nimport { "
},
{
"path": "theonefile_verse/src/routes/admin-auth-settings.ts",
"chars": 15417,
"preview": "import * as oidc from \"../oidc\";\nimport * as db from \"../database\";\nimport * as mailer from \"../mailer\";\nimport { getCli"
},
{
"path": "theonefile_verse/src/routes/admin-auth.ts",
"chars": 7014,
"preview": "import * as auth from \"../auth\";\nimport * as oidc from \"../oidc\";\nimport * as db from \"../database\";\nimport * as redis f"
},
{
"path": "theonefile_verse/src/routes/admin-backups.ts",
"chars": 4325,
"preview": "import { join } from \"path\";\nimport { unlink } from \"fs/promises\";\nimport * as db from \"../database\";\nimport { getClient"
},
{
"path": "theonefile_verse/src/routes/admin-logs.ts",
"chars": 2501,
"preview": "import * as db from \"../database\";\nimport { getClientIP, validateAdminOrApiKey } from \"../security\";\n\nexport async funct"
},
{
"path": "theonefile_verse/src/routes/admin-rooms.ts",
"chars": 2225,
"preview": "import * as db from \"../database\";\nimport { isValidUUID } from \"../config\";\nimport { getClientIP, validateAdminOrApiKey "
},
{
"path": "theonefile_verse/src/routes/admin-settings.ts",
"chars": 14346,
"preview": "import * as db from \"../database\";\nimport { getSettings, updateSettings, saveSettings, validateAdminPath, ENV_ADMIN_PASS"
},
{
"path": "theonefile_verse/src/routes/admin-users.ts",
"chars": 5723,
"preview": "import * as auth from \"../auth\";\nimport * as db from \"../database\";\nimport { getClientIP, apiError, validateAdminUser } "
},
{
"path": "theonefile_verse/src/routes/instance-access.ts",
"chars": 2377,
"preview": "import * as oidc from \"../oidc\";\nimport { ENV_ADMIN_PASSWORD, isInstanceLocked, isAdminRoute, getSettings, verifyAdminPa"
},
{
"path": "theonefile_verse/src/routes/network-routes.ts",
"chars": 12112,
"preview": "import * as network from \"../network\";\nimport * as db from \"../database\";\nimport { getSettings, isValidUUID } from \"../c"
},
{
"path": "theonefile_verse/src/routes/public.ts",
"chars": 5268,
"preview": "import { join } from \"path\";\nimport * as oidc from \"../oidc\";\nimport * as db from \"../database\";\nimport * as redis from "
},
{
"path": "theonefile_verse/src/routes/room.ts",
"chars": 10550,
"preview": "import * as oidc from \"../oidc\";\nimport * as db from \"../database\";\nimport { getSettings, isValidUUID } from \"../config\""
},
{
"path": "theonefile_verse/src/routes/setup.ts",
"chars": 2843,
"preview": "import * as auth from \"../auth\";\nimport * as oidc from \"../oidc\";\nimport * as db from \"../database\";\nimport { isAdminCon"
},
{
"path": "theonefile_verse/src/routes/user-auth.ts",
"chars": 27067,
"preview": "import * as auth from \"../auth\";\nimport * as oidc from \"../oidc\";\nimport * as redis from \"../redis\";\nimport { getSetting"
},
{
"path": "theonefile_verse/src/security.ts",
"chars": 6638,
"preview": "import * as oidc from \"./oidc\";\nimport * as db from \"./database\";\nimport { getSettings, getExternalOrigin } from \"./conf"
},
{
"path": "theonefile_verse/src/templates.ts",
"chars": 84640,
"preview": "export const setupPageHtml = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" c"
},
{
"path": "theonefile_verse/src/tokens.ts",
"chars": 6596,
"preview": "import * as redis from \"./redis\";\nimport * as oidc from \"./oidc\";\nimport * as db from \"./database\";\n\ninterface TokenEntr"
},
{
"path": "theonefile_verse/src/websocket.ts",
"chars": 10022,
"preview": "import * as redis from \"./redis\";\nimport * as oidc from \"./oidc\";\nimport * as db from \"./database\";\nimport * as auth fro"
}
]
About this extraction
This page contains the full source code of the gelatinescreams/The-One-File GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 77 files (11.5 MB), approximately 3.0M tokens, and a symbol index with 787 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.