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 - GelatineScreams ================================================ FILE: README.md ================================================

License: Unlicense TheOneFile 4.1.5 TheOneFile_Verse Docker Version 1.9.0

![The One File](assets/theonefile.jpg) 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! ![The One File corporate preview](assets/corporate-preview.gif) ![The One File routing preview](assets/routing-preview.gif) ![The One File homelab preview](assets/homelab-preview.gif) ![The One File mobile previews](assets/mobilepreviews.jpg) ### 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 Screenshot 2026-03-11 094906 Screenshot 2026-03-11 094937 ### 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":{},"tab":"Corporate Site B"},{"timestamp":1766459318363,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459318258,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317846,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317742,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317464,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317314,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459313457,"type":"node","description":"change shape","details":{},"tab":"Corporate Site B"},{"timestamp":1766459310142,"type":"node","description":"change shape","details":{},"tab":"Corporate Site B"},{"timestamp":1766459306160,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459305289,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459305132,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304675,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304530,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304396,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304290,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304157,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303660,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303534,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303414,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303247,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303144,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303002,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302875,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302725,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302613,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302507,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459301997,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459301893,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766458459721,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766458438687,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438583,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438437,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438333,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438187,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438083,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437937,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437833,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437687,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437583,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437437,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437333,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437187,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458436932,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458435139,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434986,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434840,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434736,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434590,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434486,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434340,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434236,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434090,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433986,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433840,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433736,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433590,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433334,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458429157,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458429053,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458428947,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426794,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426691,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426584,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426481,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458423513,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458421278,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458416555,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458404891,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458392272,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458378068,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458367460,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458356226,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458338198,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766458258865,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766458249051,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248926,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248793,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248683,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248556,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248451,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248325,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248221,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248092,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247989,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247885,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247784,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247284,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246701,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246523,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246410,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246129,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245955,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245737,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245627,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245425,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245247,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245133,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244923,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244741,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244313,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244198,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244055,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243873,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243637,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243399,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243218,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458241018,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458237254,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458235033,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234835,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234694,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234425,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227773,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227623,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227441,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227279,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227155,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226967,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226847,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226733,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226563,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226421,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458222326,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458213989,"type":"connection","description":"delete edge","details":{},"tab":"Corporate Site B"},{"timestamp":1766458209437,"type":"text","description":"delete text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458195427,"type":"import","description":"Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766455847368,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844054,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843762,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843560,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843371,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843162,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842852,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842747,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842601,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842449,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842348,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842098,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841678,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841053,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840901,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840650,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839427,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839234,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839061,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837247,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837081,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836893,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836377,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836198,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455835455,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455834630,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831880,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831676,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831451,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830817,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830687,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830176,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830048,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829944,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829816,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378795,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378693,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378459,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378316,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378180,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378069,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377956,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377677,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377558,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377448,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377318,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377209,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090317,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090213,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090112,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090009,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453089903,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088895,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088793,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088689,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088584,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088480,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088250,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453087236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086485,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086373,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086142,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086043,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453072857,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453070975,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453054439,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453053127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052450,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052106,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051948,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051806,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051334,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453050207,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042179,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041797,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041570,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039703,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039291,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039168,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039065,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038481,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038365,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038237,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038105,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038001,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037850,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037745,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037495,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037378,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037182,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037078,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036972,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036860,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036147,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035945,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035825,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035720,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035443,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035337,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035233,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035026,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453034917,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453031063,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030955,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030833,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030732,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030225,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030104,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029968,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029796,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029474,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453024797,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766451118553,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450929324,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450817210,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450257424,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450255024,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450254395,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450253241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450251598,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450250392,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450248756,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450244072,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450242166,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450240998,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450236492,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450233672,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450232384,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450231012,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450230254,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450229302,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450228132,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766446610211,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604404,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604305,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603952,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603599,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603348,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603202,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602953,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602850,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602600,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602453,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602349,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602101,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602000,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601848,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601601,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601301,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601154,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601049,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600948,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600802,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598595,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598461,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598171,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598017,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446597219,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446595278,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766445633355,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445632515,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445631735,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445630757,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445627846,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445625085,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445618645,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445617784,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608998,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608720,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608540,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608376,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608204,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608038,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607852,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607678,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607506,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607319,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607154,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604410,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604244,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604066,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603900,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603743,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603563,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603406,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603226,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603052,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602880,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602641,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445576567,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445570290,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445567192,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445566766,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445565520,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445398115,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445390895,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445385694,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766445383241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445382911,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445381695,"type":"edit","description":"edit node name","details":{},"tab":"Corporate Site B"},{"timestamp":1766445375383,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445374665,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445373273,"type":"node","description":"paste node","details":{},"tab":"Corporate Site B"},{"timestamp":1766445372205,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157980,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157430,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438152691,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151948,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151286,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438146174,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438145649,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438144555,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438143655,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438142504,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438130077,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438129561,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128772,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128398,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122820,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122062,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119836,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119588,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438095045,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438093965,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438062827,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766438047679,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438044161,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438041852,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039668,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039562,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039421,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039260,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039150,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039039,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438028508,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438021410,"type":"edit","description":"toggle fov","details":{},"tab":"Corporate Site B"},{"timestamp":1766438019234,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438017562,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438014356,"type":"node","description":"add node","details":{},"tab":"Corporate Site B"},{"timestamp":1766437981696,"type":"edit","description":"apply routing to all","details":{},"tab":"Corporate Site B"},{"timestamp":1766437966551,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437964879,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437963627,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961813,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961193,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437957989,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437956467,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437953437,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437952239,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437950807,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437944990,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437943699,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437935414,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437919019,"type":"zone","description":"delete zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437917758,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437913740,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437882832,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766263279163,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766263270414,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766263260682,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766263259518,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766263249401,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766263246362,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766190721141,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190717499,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766190710946,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190705273,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190703463,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766190695709,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190688417,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1765402888416,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402884873,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1765402878108,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402866440,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402865008,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1765402860428,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402858103,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"}],"savedStyleSets":[]} # # The One File Corporate - Node List # Exported from The One File on 2025-12-23T03:10:03.226Z name,ip,role,shape,tags,layer,mac,rackUnit,uHeight,assignedRack,rackCapacity,isRack,locked,groupId,x,y,size,notes,styles Core Router 1,10.0.0.1,Core Routing,router,core;tier-1;redundant,physical,00:1A:2B:3C:4D:01,,2,,42,false,false,,3720,246,50,Primary core router|BGP peering enabled,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""borg""}}}" Core Router 2,10.0.0.2,Core Routing,router,core;tier-1;redundant,physical,00:1A:2B:3C:4D:02,,2,,42,false,false,,2500,330,120,Secondary core router|HSRP standby,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""actual-budget""},""pingOffsetX"":-15,""pingOffsetY"":-38}}" External FW 1,10.0.1.1,Perimeter Security,firewall,security;perimeter;ha-pair,security,00:1A:2B:3C:4D:10,,2,,42,false,false,,3222,1016,50,Palo Alto PA-5250|Active node,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""anonaddy""}}}" External FW 2,10.0.1.2,Perimeter Security,firewall,security;perimeter;ha-pair,security,00:1A:2B:3C:4D:11,,2,,42,false,false,,1916,224,50,Palo Alto PA-5250|Passive node, Internal FW,10.0.2.1,Internal Segmentation,firewall,security;internal,security,00:1A:2B:3C:4D:12,,2,,42,false,false,,1747,478,50,East-West traffic inspection, Core Switch 1,10.0.10.1,Core Switching,switch,core;layer3;redundant,physical,00:1A:2B:3C:4D:20,,2,,42,false,false,,449,384,50,Cisco Nexus 9000|VPC Domain 1, Core Switch 2,10.0.10.2,Core Switching,switch,core;layer3;redundant,physical,00:1A:2B:3C:4D:21,,2,,42,false,false,,761,181,50,Cisco Nexus 9000|VPC Domain 1, DC Rack A1,10.10.0.0/24,Data Center Rack,server,datacenter;row-a;production,physical,,,1,,42,true,false,,784,647,50,"Row A, Position 1|Primary compute","{""all"":{""circleColor"":""#ff0000""}}" DC Rack A2,10.10.1.0/24,Data Center Rack,server,datacenter;row-a;production,physical,,,1,,42,true,false,,209,228,50,"Row A, Position 2|Primary compute", DC Rack B1,10.10.2.0/24,Data Center Rack,server,datacenter;row-b;storage,physical,,,1,,42,true,false,,3184,1627,50,"Row B, Position 1|Storage systems","{""all"":{""circleColor"":""#ff0000"",""titleSize"":59}}" DC Rack B2,10.10.3.0/24,Data Center Rack,server,datacenter;row-b;storage,physical,,,1,,42,true,false,,245,500,50,"Row B, Position 2|Storage systems","{""all"":{""circleColor"":""#ff0000""}}" DMZ Rack,172.16.0.0/24,DMZ Infrastructure,server,dmz;security;public-facing;[object Object];[object Object],security,,,1,,24,true,false,,2176,611,50,Isolated DMZ zone|Public-facing services, Management Rack,192.168.100.0/24,Management Infrastructure,server,management;oob;noc,logical,,,1,,24,true,false,,1601,1281,50,Out-of-band management|NOC equipment, ESXi Host 01,10.10.0.11,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:01,38,2,dc-rack-a1,42,false,false,,2162,2608,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 02,10.10.0.12,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:02,35,2,dc-rack-a1,42,false,false,,2206,2690,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 03,10.10.0.13,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:03,32,2,dc-rack-a1,42,false,false,,2155,2771,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 04,10.10.0.14,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:04,29,2,dc-rack-a1,42,false,false,,2196,2845,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ToR Switch A1,10.10.0.1,Top of Rack,switch,tor;access;rack-a1,physical,00:1A:2B:3C:5D:01,42,1,dc-rack-a1,42,false,false,,2147,2845,50,Cisco Nexus 93180YC-FX|48x25G ports, ESXi Host 05,10.10.1.11,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:01,38,2,dc-rack-a2,42,false,false,,2186,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 06,10.10.1.12,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:02,35,2,dc-rack-a2,42,false,false,,2139,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 07,10.10.1.13,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:03,32,2,dc-rack-a2,42,false,false,,2176,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 08,10.10.1.14,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:04,29,2,dc-rack-a2,42,false,false,,2131,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ToR Switch A2,10.10.1.1,Top of Rack,switch,tor;access;rack-a2,physical,00:1A:2B:3C:5D:02,42,1,dc-rack-a2,42,false,false,,2165,2845,50,Cisco Nexus 93180YC-FX|48x25G ports, SAN Primary,10.10.2.10,Primary Storage,database,storage;san;netapp,physical,00:A0:98:AA:01:01,36,6,dc-rack-b1,42,false,false,,2123,2845,50,NetApp AFF A400|500TB Raw|FC 32Gb, SAN Secondary,10.10.2.11,Secondary Storage,database,storage;san;netapp,physical,00:A0:98:AA:01:02,28,6,dc-rack-b1,42,false,false,,2155,2845,50,NetApp AFF A400|500TB Raw|FC 32Gb, FC Switch 1,10.10.2.1,Fibre Channel,switch,storage;fc;fabric-a,physical,00:1A:2B:FC:01:01,42,1,dc-rack-b1,42,false,false,,2115,2845,50,Brocade G620|Fabric A, FC Switch 2,10.10.2.2,Fibre Channel,switch,storage;fc;fabric-b,physical,00:1A:2B:FC:01:02,41,1,dc-rack-b1,42,false,false,,2145,2845,50,Brocade G620|Fabric B, Backup Server 1,10.10.3.10,Backup Infrastructure,server,backup;veeam;protection,physical,00:50:56:BB:01:01,36,2,dc-rack-b2,42,false,false,,2107,2845,50,Veeam Backup Server|Dell R740xd|200TB, Backup Server 2,10.10.3.11,Backup Infrastructure,server,backup;veeam;protection,physical,00:50:56:BB:01:02,33,2,dc-rack-b2,42,false,false,,2134,2845,50,Veeam Backup Server|Dell R740xd|200TB, Tape Library,10.10.3.20,Archival Storage,database,backup;tape;lto9,physical,00:50:56:BB:02:01,20,10,dc-rack-b2,42,false,false,,2099,2845,50,IBM TS4500|LTO-9|Long-term archive, ToR Switch B1,10.10.2.3,Top of Rack,switch,tor;access;rack-b1,physical,00:1A:2B:3C:5D:03,40,1,dc-rack-b1,42,false,false,,2123,2845,50,Cisco Nexus 93180YC-FX, ToR Switch B2,10.10.3.1,Top of Rack,switch,tor;access;rack-b2,physical,00:1A:2B:3C:5D:04,42,1,dc-rack-b2,42,false,false,,2091,2845,50,Cisco Nexus 93180YC-FX, Web Server 1,172.16.0.11,Web Frontend,server,dmz;web;nginx,security,00:50:56:CC:01:01,20,1,dmz-rack,24,false,false,,2113,2845,50,NGINX reverse proxy|Public facing, Web Server 2,172.16.0.12,Web Frontend,server,dmz;web;nginx,security,00:50:56:CC:01:02,18,1,dmz-rack,24,false,false,,2082,2845,50,NGINX reverse proxy|Public facing, WAF Appliance,172.16.0.5,Web Application Firewall,firewall,dmz;security;waf,security,00:50:56:CC:02:01,22,2,dmz-rack,24,false,false,,2102,2845,50,F5 BIG-IP ASM|OWASP protection, DMZ Load Balancer,172.16.0.3,Load Balancing,switch,dmz;lb;f5,security,00:50:56:CC:03:01,16,2,dmz-rack,24,false,false,,2074,2845,50,F5 BIG-IP LTM|VIP: 172.16.0.100, Mail Gateway,172.16.0.25,Email Security,server,dmz;email;security,security,00:50:56:CC:04:01,14,1,dmz-rack,24,false,false,,2091,2845,50,Proofpoint Email Gateway|Spam/malware filtering, External DNS 1,172.16.0.53,External DNS,circle,dmz;dns;public,security,00:50:56:CC:05:01,12,1,dmz-rack,24,false,false,,2066,2845,50,BIND DNS|Authoritative for corp.com, External DNS 2,172.16.0.54,External DNS,circle,dmz;dns;public,security,00:50:56:CC:05:02,10,1,dmz-rack,24,false,false,,2080,2845,50,BIND DNS|Secondary for corp.com, vCenter Server,192.168.100.10,Virtualization Management,server,management;vmware;vcsa,logical,00:50:56:DD:01:01,20,2,mgmt-rack,24,false,false,,2057,2845,50,vCenter Server Appliance 8.0|Single SSO domain, NSX Manager,192.168.100.15,Network Virtualization,server,management;vmware;nsx,logical,00:50:56:DD:02:01,17,2,mgmt-rack,24,false,false,,2069,2845,50,NSX-T 4.1 Manager Cluster, SIEM Server,192.168.100.50,Security Monitoring,server,management;security;splunk,logical,00:50:56:DD:03:01,14,2,mgmt-rack,24,false,false,,2049,2845,50,Splunk Enterprise|Security monitoring, Network Monitoring,192.168.100.60,Network Management,server,management;monitoring;prtg,logical,00:50:56:DD:04:01,11,1,mgmt-rack,24,false,false,,2058,2845,50,PRTG Network Monitor|5000 sensors, Jump Server,192.168.100.100,Bastion Host,server,management;security;bastion,logical,00:50:56:DD:05:01,9,1,mgmt-rack,24,false,false,,2040,2845,50,Windows Server 2022|MFA enabled, IPAM/DDI,192.168.100.70,IP Management,server,management;dns;dhcp,logical,00:50:56:DD:06:01,7,2,mgmt-rack,24,false,false,,2047,2845,50,Infoblox DDI|DNS/DHCP/IPAM, WLC Primary,10.20.0.1,Wireless Controller,wifi,wireless;cisco;9800,physical,00:1A:2B:WL:01:01,,2,,42,false,false,,1576,2306,50,Cisco C9800-40|Primary controller, WLC Secondary,10.20.0.2,Wireless Controller,wifi,wireless;cisco;9800,physical,00:1A:2B:WL:01:02,,2,,42,false,false,,1468,1564,50,Cisco C9800-40|HA Secondary, HQ Mobile Zone,10.20.10.0/24,Mobile Device Zone,phone,wireless;byod;mobile,physical,,,1,,42,false,false,,2355,2806,50,Corporate BYOD|MDM enrolled devices, Guest WiFi Zone,10.30.0.0/24,Guest Network,phone,wireless;guest;isolated,physical,,,1,,42,false,false,,2308,2611,50,Captive portal|Internet only, IoT Device Zone,10.40.0.0/24,IoT Network,phone,wireless;iot;building,physical,,,1,,42,false,false,,2229,2299,50,Building automation|Smart devices, NYC Branch Router,10.100.0.1,Branch Gateway,router,branch;nyc;sd-wan,physical,00:1A:2B:BR:01:01,,1,,42,false,false,,3152,634,50,Cisco Viptela vEdge|SD-WAN enabled, LA Branch Router,10.101.0.1,Branch Gateway,router,branch;la;sd-wan,physical,00:1A:2B:BR:02:01,,1,,42,false,false,,3084,507,50,Cisco Viptela vEdge|SD-WAN enabled, Chicago Branch Router,10.102.0.1,Branch Gateway,router,branch;chicago;sd-wan,physical,00:1A:2B:BR:03:01,,1,,42,false,false,,3355,393,50,Cisco Viptela vEdge|SD-WAN enabled, London Branch Router,10.200.0.1,Branch Gateway,router,branch;london;sd-wan,physical,00:1A:2B:BR:04:01,,1,,42,false,false,,3114,260,50,Cisco Viptela vEdge|EMEA region, Tokyo Branch Router,10.201.0.1,Branch Gateway,router,branch;tokyo;sd-wan,physical,00:1A:2B:BR:05:01,,1,,42,false,false,,3699,471,50,Cisco Viptela vEdge|APAC region,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""adguard-home""}}}" AWS Cloud,vpc-0a1b2c3d,Public Cloud,cloud,cloud;aws;hybrid,logical,,,1,,42,false,false,,3437,546,50,AWS US-East-1|VPC peering to HQ,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""ansible""}}}" Azure Cloud,vnet-corp-prod,Public Cloud,cloud,cloud;azure;hybrid,logical,,,1,,42,false,false,,2593,2724,50,Azure East US 2|ExpressRoute, GCP Cloud,vpc-gcp-corp,Public Cloud,cloud,cloud;gcp;dev,logical,,,1,,42,false,false,,2827,2731,50,GCP us-central1|Dev/Test workloads, ISP Primary,203.0.113.1,Internet Uplink,globe,wan;internet;primary,physical,,,1,,42,false,false,,3712,616,50,AT&T MPLS|1 Gbps dedicated,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""wikidocs""}}}" ISP Secondary,198.51.100.1,Internet Uplink,vm,wan;internet;backup,physical,,,1,,42,false,false,,3254,1993,139,Verizon Business|500 Mbps backup,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""alist""},""circleColor"":""#4d2c58"",""circleBorder"":""#000000"",""titleColor"":""#006eff""}}" DC1 Int DNS,10.10.0.53,Internal DNS/AD,circle,dns;ad;dc1,physical,00:50:56:AD:01:01,26,1,dc-rack-a1,42,false,false,,1958,2845,50,Windows Server 2022|Primary DC, DC2 Int DNS,10.10.1.53,Internal DNS/AD,circle,dns;ad;dc2,physical,00:50:56:AD:01:02,26,1,dc-rack-a2,42,false,false,,1964,2845,50,Windows Server 2022|Secondary DC, App Server 01,10.10.0.101,Application,server,app;iis;web,physical,00:50:56:AP:01:01,24,1,dc-rack-a1,42,false,false,,1947,2845,50,Windows Server 2022|IIS Application, App Server 02,10.10.0.102,Application,server,app;iis;web,physical,00:50:56:AP:01:02,22,1,dc-rack-a1,42,false,false,,1955,2845,50,Windows Server 2022|IIS Application, SQL Server 01,10.10.0.201,Database,database,db;sql;primary,physical,00:50:56:DB:01:01,20,2,dc-rack-a1,42,false,false,,1936,2845,50,SQL Server 2022 Enterprise|AlwaysOn Primary, SQL Server 02,10.10.1.201,Database,database,db;sql;secondary,physical,00:50:56:DB:01:02,24,2,dc-rack-a2,42,false,false,,1947,2845,50,SQL Server 2022 Enterprise|AlwaysOn Secondary, K8s Master 1,10.10.1.50,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:01,21,1,dc-rack-a2,42,false,false,,1925,2845,50,K8s Control Plane|etcd member, K8s Master 2,10.10.1.51,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:02,19,1,dc-rack-a2,42,false,false,,1938,2845,50,K8s Control Plane|etcd member, K8s Master 3,10.10.1.52,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:03,17,1,dc-rack-a2,42,false,false,,1914,2845,50,K8s Control Plane|etcd member, K8s Worker 1,10.10.1.60,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:01,15,1,dc-rack-a2,42,false,false,,1930,2845,50,K8s Worker Node|64GB RAM, K8s Worker 2,10.10.1.61,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:02,13,1,dc-rack-a2,42,false,false,,1904,2845,50,K8s Worker Node|64GB RAM, K8s Worker 3,10.10.1.62,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:03,11,1,dc-rack-a2,42,false,false,,1922,2845,50,K8s Worker Node|64GB RAM, K8s Worker 4,10.10.1.63,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:04,9,1,dc-rack-a2,42,false,false,,1893,2845,50,K8s Worker Node|64GB RAM, Proxy Server 1,10.5.0.10,Web Proxy,server,proxy;squid;filtering,security,00:50:56:PX:01:01,,1,,42,false,false,,1806,654,50,Squid Proxy|Content filtering, Proxy Server 2,10.5.0.11,Web Proxy,server,proxy;squid;filtering,security,00:50:56:PX:01:02,,1,,42,false,false,,2937,2629,50,Squid Proxy|HA pair, VPN Concentrator,10.0.5.1,Remote Access VPN,firewall,vpn;remote;security,security,00:1A:2B:VP:01:01,,2,,42,false,false,,3642,947,50,Cisco ASA 5555-X|AnyConnect SSL VPN, NAC Server,10.5.5.10,Network Access Control,server,nac;ise;802.1x,security,00:50:56:NA:01:01,,2,,42,false,false,,1153,1172,50,Cisco ISE 3.1|RADIUS/TACACS+, Print Server,10.10.0.150,Print Services,server,print;windows;services,physical,00:50:56:PR:01:01,18,1,dc-rack-a1,42,false,false,,1897,2845,50,Windows Print Server|50+ printers, File Server,10.10.0.160,File Services,database,file;smb;dfs,physical,00:50:56:FS:01:01,16,2,dc-rack-a1,42,false,false,,1861,2845,50,Windows File Server|DFS namespace, Certificate Authority,192.168.100.80,PKI Infrastructure,server,pki;ca;security,logical,00:50:56:CA:01:01,5,1,mgmt-rack,24,false,false,,1889,2845,50,Windows CA|Enterprise Root CA, SCCM Server,192.168.100.90,Endpoint Management,server,sccm;patching;software,logical,00:50:56:SC:01:01,3,2,mgmt-rack,24,false,false,,1850,2845,50,MECM Primary Site|Software deployment, VoIP Cluster,10.50.0.0/24,Voice Services,phone,voip;cisco;ucm,application,,,1,,42,false,false,,1777,1617,50,Cisco UCM Cluster|3000 endpoints, Video Conference,10.51.0.0/24,Video Services,laptop,video;webex;teams,application,,,1,,42,false,false,,1994,2245,50,Webex/Teams integration|Meeting rooms, Security Cameras,10.60.0.0/24,Physical Security,camera,cctv;surveillance;security,physical,,,1,,42,false,false,,1674,2046,50,150+ IP cameras|30-day retention, NVR Cluster,10.60.0.10,Video Recording,server,nvr;surveillance;storage,physical,00:50:56:NV:01:01,15,4,dc-rack-b2,42,false,false,,1829,2845,50,Milestone XProtect|500TB storage, Dev Server 1,10.80.0.10,Development,server,dev;gitlab;ci-cd;[object Object],application,00:50:56:DV:01:01,,2,,42,false,false,,2801,1176,128,GitLab Server|CI/CD pipelines,"{""all"":{""icon"":{""library"":""simple"",""name"":""amazonwebservices""}}}" Dev Server 2,10.80.0.11,Development,server,dev;jenkins;ci-cd,application,00:50:56:DV:01:02,,2,,42,false,false,,1945,1165,50,Jenkins Server|Build automation, Test Environment,10.81.0.0/24,QA/Testing,shield,test;qa;staging,application,,,1,,42,false,false,,2932,862,121,Staging environment|Pre-prod validation,"{""all"":{""icon"":{""library"":""simple"",""name"":""apple""}}}" ERP System,10.90.0.10,Business Application,database,erp;sap;business,application,00:50:56:ER:01:01,,4,,42,false,false,,790,474,50,SAP S/4HANA|Financial/HR systems, CRM System,10.91.0.10,Business Application,database,crm;salesforce;business,application,,,1,,42,false,false,,3515,1138,50,Salesforce integration|Sales/Marketing, Corporate Endpoints,10.70.0.0/22,User Workstations,laptop,endpoints;workstations;users,physical,,,1,,42,false,false,,992,2284,50,~1000 corporate laptops|Windows 11, Floor 1 Switch,10.1.1.1,Distribution,switch,distribution;floor-1;access,physical,00:1A:2B:FL:01:01,,1,,42,false,false,,654,2020,50,Cisco C9300-48P|PoE+ enabled, Floor 2 Switch,10.1.2.1,Distribution,switch,distribution;floor-2;access,physical,00:1A:2B:FL:02:01,,1,,42,false,false,,854,1843,50,Cisco C9300-48P|PoE+ enabled, Floor 3 Switch,10.1.3.1,Distribution,switch,distribution;floor-3;access,physical,00:1A:2B:FL:03:01,,1,,42,false,false,,1899,1457,50,Cisco C9300-48P|PoE+ enabled, Floor 4 Switch,10.1.4.1,Distribution,switch,distribution;floor-4;access,physical,00:1A:2B:FL:04:01,,1,,42,false,false,,489,181,50,Cisco C9300-48P|PoE+ enabled, AP Floor 1 Zone 1,10.20.1.10,Wireless Access,wifi,wifi;ap;floor-1,physical,00:1A:2B:AP:01:01,,1,,42,false,false,,1140,2070,50,Cisco 9120AX|Wi-Fi 6, AP Floor 2 Zone 1,10.20.2.10,Wireless Access,wifi,wifi;ap;floor-2,physical,00:1A:2B:AP:02:01,,1,,42,false,false,,688,2384,50,Cisco 9120AX|Wi-Fi 6, AP Floor 3 Zone 1,10.20.3.10,Wireless Access,wifi,wifi;ap;floor-3,physical,00:1A:2B:AP:03:01,,1,,42,false,false,,2145,1890,50,Cisco 9120AX|Wi-Fi 6, AP Floor 4 Zone 1,10.20.4.10,Wireless Access,wifi,wifi;ap;floor-4,physical,00:1A:2B:AP:04:01,,1,,42,false,false,,518,566,50,Cisco 9120AX|Wi-Fi 6, UPS DC-1,192.168.200.10,Power Management,rectangle,power;ups;datacenter,physical,,,1,,42,false,false,,771,296,50,APC Symmetra|80kVA|30 min runtime, UPS DC-2,192.168.200.11,Power Management,rectangle,power;ups;datacenter,physical,,,1,,42,false,false,,216,330,50,APC Symmetra|80kVA|Redundant, PDU Rack A1,192.168.200.21,Power Distribution,rectangle,power;pdu;rack-a1,physical,,1,1,dc-rack-a1,42,false,false,,1805,2845,50,APC Switched PDU|Per-outlet metering, PDU Rack A2,192.168.200.22,Power Distribution,rectangle,power;pdu;rack-a2,physical,,1,1,dc-rack-a2,42,false,false,,1742,2845,50,APC Switched PDU|Per-outlet metering, CRAC Unit 1,192.168.200.30,Cooling,rectangle,cooling;hvac;datacenter,physical,,,1,,42,false,false,,246,626,50,Liebert CRV|Row-based cooling, CRAC Unit 2,192.168.200.31,Cooling,rectangle,cooling;hvac;datacenter,physical,,,1,,42,false,false,,1603,981,50,Liebert CRV|N+1 redundancy, camera A,0.0.0.0,,camera,,physical,,,1,,,false,false,,167,145,45,, camera B,0.0.0.0,,camera,,physical,,,1,,,false,false,,1041,738,45,, ================================================ FILE: demos/csv-exports/the-one-file-homelab.csv ================================================ #THEONEFILE_CONFIG:{"nodeData":{"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}},"edgeData":{"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":[]}]},"rectData":{"list":[{"id":"rect-1765238219615","x":2680.053955078125,"y":251.44879150390625,"width":814.10400390625,"height":389.26678466796875,"color":"#ec0999","style":"filled","lineStyle":"solid","notes":[]}]},"textData":{"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}]},"edgeLegend":{"#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"},"nodePositions":{"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}},"nodeSizes":{"core-router-1":36,"internet":168,"phone":121,"desktop":147,"racked":137,"docker-copy-2":82},"nodeStyles":{"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"}}},"page":{"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},"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":1,"encryptedSections":{},"auditLog":[{"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":{},"tab":"Corporate Site B"},{"timestamp":1766459318363,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459318258,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317846,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317742,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317464,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459317314,"type":"style","description":"style change","details":{},"tab":"Corporate Site B"},{"timestamp":1766459313457,"type":"node","description":"change shape","details":{},"tab":"Corporate Site B"},{"timestamp":1766459310142,"type":"node","description":"change shape","details":{},"tab":"Corporate Site B"},{"timestamp":1766459306160,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459305289,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459305132,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304675,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304530,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304396,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304290,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459304157,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303660,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303534,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303414,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303247,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303144,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459303002,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302875,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302725,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302613,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459302507,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459301997,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766459301893,"type":"node","description":"rotate node","details":{},"tab":"Corporate Site B"},{"timestamp":1766458459721,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766458438687,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438583,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438437,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438333,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438187,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458438083,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437937,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437833,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437687,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437583,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437437,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437333,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458437187,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458436932,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458435139,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434986,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434840,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434736,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434590,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434486,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434340,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434236,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458434090,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433986,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433840,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433736,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433590,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458433334,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458429157,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458429053,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458428947,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426794,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426691,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426584,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458426481,"type":"style","description":"style change","details":{},"tab":"Homelab 2"},{"timestamp":1766458423513,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458421278,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458416555,"type":"node","description":"change shape","details":{},"tab":"Homelab 2"},{"timestamp":1766458404891,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458392272,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458378068,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458367460,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458356226,"type":"node","description":"add node","details":{},"tab":"Homelab 2"},{"timestamp":1766458338198,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766458258865,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766458249051,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248926,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248793,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248683,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248556,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248451,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248325,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248221,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458248092,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247989,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247885,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247784,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458247284,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246701,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246523,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246410,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458246129,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245955,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245737,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245627,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245425,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245247,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458245133,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244923,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244741,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244313,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244198,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458244055,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243873,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243637,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243399,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458243218,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458241018,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458237254,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458235033,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234835,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234694,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458234425,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227773,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227623,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227441,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227279,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458227155,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226967,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226847,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226733,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226563,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458226421,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458222326,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458213989,"type":"connection","description":"delete edge","details":{},"tab":"Corporate Site B"},{"timestamp":1766458209437,"type":"text","description":"delete text","details":{},"tab":"Corporate Site B"},{"timestamp":1766458195427,"type":"import","description":"Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766455847368,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844054,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843762,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843560,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843371,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843162,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842852,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842747,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842601,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842449,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842348,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842098,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841678,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841053,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840901,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840650,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839427,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839234,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839061,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837247,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837081,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836893,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836377,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836198,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455835455,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455834630,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831880,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831676,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831451,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830817,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830687,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830176,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830048,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829944,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829816,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378795,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378693,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378459,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378316,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378180,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378069,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377956,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377677,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377558,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377448,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377318,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377209,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090317,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090213,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090112,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090009,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453089903,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088895,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088793,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088689,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088584,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088480,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088250,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453087236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086485,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086373,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086142,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086043,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453072857,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453070975,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453054439,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453053127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052450,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052106,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051948,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051806,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051334,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453050207,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042179,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041797,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041570,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039703,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039291,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039168,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039065,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038481,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038365,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038237,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038105,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038001,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037850,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037745,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037495,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037378,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037182,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037078,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036972,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036860,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036147,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035945,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035825,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035720,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035443,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035337,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035233,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035026,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453034917,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453031063,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030955,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030833,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030732,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030225,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030104,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029968,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029796,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029474,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453024797,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766451118553,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450929324,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450817210,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450257424,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450255024,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450254395,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450253241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450251598,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450250392,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450248756,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450244072,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450242166,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450240998,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450236492,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450233672,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450232384,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450231012,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450230254,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450229302,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450228132,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766446610211,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604404,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604305,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603952,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603599,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603348,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603202,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602953,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602850,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602600,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602453,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602349,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602101,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602000,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601848,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601601,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601301,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601154,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601049,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600948,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600802,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598595,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598461,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598171,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598017,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446597219,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446595278,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766445633355,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445632515,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445631735,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445630757,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445627846,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445625085,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445618645,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445617784,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608998,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608720,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608540,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608376,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608204,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608038,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607852,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607678,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607506,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607319,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607154,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604410,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604244,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604066,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603900,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603743,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603563,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603406,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603226,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603052,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602880,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602641,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445576567,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445570290,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445567192,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445566766,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445565520,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445398115,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445390895,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445385694,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766445383241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445382911,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445381695,"type":"edit","description":"edit node name","details":{},"tab":"Corporate Site B"},{"timestamp":1766445375383,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445374665,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445373273,"type":"node","description":"paste node","details":{},"tab":"Corporate Site B"},{"timestamp":1766445372205,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157980,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157430,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438152691,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151948,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151286,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438146174,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438145649,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438144555,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438143655,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438142504,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438130077,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438129561,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128772,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128398,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122820,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122062,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119836,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119588,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438095045,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438093965,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438062827,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766438047679,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438044161,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438041852,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039668,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039562,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039421,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039260,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039150,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039039,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438028508,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438021410,"type":"edit","description":"toggle fov","details":{},"tab":"Corporate Site B"},{"timestamp":1766438019234,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438017562,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438014356,"type":"node","description":"add node","details":{},"tab":"Corporate Site B"},{"timestamp":1766437981696,"type":"edit","description":"apply routing to all","details":{},"tab":"Corporate Site B"},{"timestamp":1766437966551,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437964879,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437963627,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961813,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961193,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437957989,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437956467,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437953437,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437952239,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437950807,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437944990,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437943699,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437935414,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437919019,"type":"zone","description":"delete zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437917758,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437913740,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437882832,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766263279163,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766263270414,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766263260682,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766263259518,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766263249401,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766263246362,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766190721141,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190717499,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766190710946,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190705273,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190703463,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766190695709,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190688417,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1765402888416,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402884873,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1765402878108,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402866440,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402865008,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1765402860428,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402858103,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"}],"savedStyleSets":[]} # # The One File - Node List # Exported from The One File on 2025-12-23T03:09:52.432Z name,ip,role,shape,tags,layer,mac,rackUnit,uHeight,assignedRack,rackCapacity,isRack,locked,groupId,x,y,size,notes,styles Internet,0.0.0.0,,stop-sign,,physical,,,1,,42,false,false,,1758,299,168,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""amazon-web-services""},""circleColor"":""#db0000"",""circleBorder"":""#000000"",""titleSize"":52,""subSize"":46}}" OPNSENSE,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2067,473,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""opnsense""}}}" Docker,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,1774,667,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""portainer""}}}" Docker2,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,1931,782,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""jotty""}}}" Docker3,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2158,768,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""authportal""}}}" Docker 4,0.0.0.0,,firewall,[object Object];[object Object];[object Object],physical,,,1,,42,false,false,,2342,632,82,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""docker""}}}" OPNSENSE GUEST,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2758,308,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""opnsense-v1""}}}" Phone,0.0.0.0,,phone,,physical,,,1,,42,false,false,,3313,503,121,, Desktop,0.0.0.0,,pc,,physical,,,1,,42,false,false,,2972,481,147,, DNS,0.0.0.0,,cloud,,physical,,,1,,42,false,false,,3200,320,50,, Racked,,Rack,server,,physical,,,1,,42,true,false,,2646,971,137,,"{""all"":{""icon"":{""library"":""mdi"",""name"":""server-security""},""circleColor"":""#010813"",""circleBorder"":""#ffffff""}}" Thermostat,0.0.0.0,,thermostat,,physical,,,1,,42,false,false,,1323,575,50,, Video Doorbell,0.0.0.0,,doorbell,,physical,,,1,,42,false,false,,1188,455,50,, Smart Lock,0.0.0.0,,smart-lock,,physical,,,1,,42,false,false,,1292,790,50,, Smart Bulb,0.0.0.0,,smart-bulb,,physical,,,1,,42,false,false,,1496,717,50,, Robot Vacuum,0.0.0.0,,vacuum,,physical,,,1,,42,false,false,,2289,979,50,, ================================================ FILE: demos/csv-exports/the-one-file-networkening-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":"globe","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},"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":"hexagon","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},"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"},{"id":"custom-1765239355462","type":"custom","color":"#f97316","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":2467.182861328125,"y":156.12173461914062},{"x":2146.36376953125,"y":146.32574462890625},{"x":2305.548828125,"y":244.28573608398438}],"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-1765239331126","x":2454.5615234375,"y":160.73322105407715,"content":"Google is live!","fontSize":56,"color":"#e2e8f0","fontWeight":"bold","fontStyle":"normal","textAlign":"start","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}]},"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":2702.3789772348055,"y":467.890869140625},"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":2566.9100352578575,"y":885.2827758789062},"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":148,"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"}}},"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"}}}},"iconCache":{"selfhst-borg":"","selfhst-actual-budget":"","selfhst-anonaddy":"","selfhst-adguard-home":"","selfhst-ansible":"","selfhst-wikidocs":"","selfhst-alist":"","simple-amazonwebservices":"Amazon Web Services","simple-apple":"Apple","selfhst-amazon-web-services":"","selfhst-opnsense":"","selfhst-portainer":"","selfhst-jotty":"","selfhst-authportal":"","selfhst-docker":"","selfhst-opnsense-v1":"","mdi-server-security":""},"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"viewOnly":false,"defaultEdgeRouting":"orthogonal","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":4,"autoPingEnabled":false,"autoPingInterval":30},"autoPingEnabled":false,"autoPingInterval":30,"canvas":{"zoom":0.9921985961590549,"panX":-5.584863670202822,"panY":-99.90831573327841},"savedTopologyView":{"zoom":0.9325110211947125,"panX":-563.7108933103631,"panY":-561.6887674556383},"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":"globe","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},"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":"hexagon","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},"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"},{"id":"custom-1765239355462","type":"custom","color":"#f97316","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":2467.182861328125,"y":156.12173461914062},{"x":2146.36376953125,"y":146.32574462890625},{"x":2305.548828125,"y":244.28573608398438}],"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":2702.3789772348055,"y":467.890869140625},"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":2566.9100352578575,"y":885.2827758789062},"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":148,"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"}}},"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-1765239331126","x":2454.5615234375,"y":160.73322105407715,"content":"Google is live!","fontSize":56,"color":"#e2e8f0","fontWeight":"bold","fontStyle":"normal","textAlign":"start","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}]},"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"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":"square","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}},"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":2103.968290880771,"y":268},"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}},"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":"#ffffff","circleBorder":"#ffffff"}},"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"viewOnly":false,"defaultEdgeRouting":"curved","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":1.5}}],"currentTabIndex":0,"encryptedSections":{},"auditLog":[{"timestamp":1766459536815,"type":"export","description":"Exported JSON: the-one-file-corporate.json","details":{},"tab":"Corporate Site B"},{"timestamp":1766459534490,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766459525616,"type":"export","description":"Exported CSV: the-one-file.csv","details":{},"tab":"Homelab 2"},{"timestamp":1766459518367,"type":"export","description":"Exported Markdown: the-one-file.md","details":{},"tab":"Homelab 2"},{"timestamp":1766459511746,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766459504374,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766459500911,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766459497380,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766459491436,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766459483682,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766459477676,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766457578277,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766457564726,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766457564253,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766457560309,"type":"import","description":"Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766455847368,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844054,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843762,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843560,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843371,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843162,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842852,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842747,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842601,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842449,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842348,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842098,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841678,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841053,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840901,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840650,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839427,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839234,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839061,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837247,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837081,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836893,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836377,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836198,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455835455,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455834630,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831880,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831676,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831451,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830817,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830687,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830176,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830048,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829944,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829816,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378795,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378693,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378459,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378316,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378180,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378069,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377956,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377677,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377558,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377448,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377318,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377209,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090317,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090213,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090112,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090009,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453089903,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088895,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088793,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088689,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088584,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088480,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088250,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453087236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086485,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086373,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086142,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086043,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453072857,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453070975,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453054439,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453053127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052450,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052106,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051948,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051806,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051334,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453050207,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042179,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041797,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041570,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039703,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039291,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039168,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039065,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038481,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038365,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038237,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038105,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038001,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037850,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037745,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037495,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037378,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037182,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037078,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036972,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036860,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036147,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035945,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035825,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035720,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035443,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035337,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035233,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035026,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453034917,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453031063,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030955,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030833,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030732,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030225,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030104,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029968,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029796,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029474,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453024797,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766451118553,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450929324,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450817210,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450257424,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450255024,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450254395,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450253241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450251598,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450250392,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450248756,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450244072,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450242166,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450240998,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450236492,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450233672,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450232384,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450231012,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450230254,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450229302,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450228132,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766446610211,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604404,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604305,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603952,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603599,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603348,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603202,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602953,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602850,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602600,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602453,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602349,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602101,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602000,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601848,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601601,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601301,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601154,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601049,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600948,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600802,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598595,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598461,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598171,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598017,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446597219,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446595278,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766445633355,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445632515,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445631735,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445630757,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445627846,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445625085,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445618645,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445617784,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608998,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608720,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608540,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608376,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608204,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608038,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607852,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607678,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607506,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607319,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607154,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604410,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604244,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604066,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603900,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603743,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603563,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603406,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603226,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603052,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602880,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602641,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445576567,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445570290,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445567192,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445566766,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445565520,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445398115,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445390895,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445385694,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766445383241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445382911,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445381695,"type":"edit","description":"edit node name","details":{},"tab":"Corporate Site B"},{"timestamp":1766445375383,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445374665,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445373273,"type":"node","description":"paste node","details":{},"tab":"Corporate Site B"},{"timestamp":1766445372205,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157980,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157430,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438152691,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151948,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151286,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438146174,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438145649,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438144555,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438143655,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438142504,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438130077,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438129561,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128772,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128398,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122820,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122062,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119836,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119588,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438095045,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438093965,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438062827,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766438047679,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438044161,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438041852,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039668,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039562,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039421,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039260,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039150,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039039,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438028508,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438021410,"type":"edit","description":"toggle fov","details":{},"tab":"Corporate Site B"},{"timestamp":1766438019234,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438017562,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438014356,"type":"node","description":"add node","details":{},"tab":"Corporate Site B"},{"timestamp":1766437981696,"type":"edit","description":"apply routing to all","details":{},"tab":"Corporate Site B"},{"timestamp":1766437966551,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437964879,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437963627,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961813,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961193,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437957989,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437956467,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437953437,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437952239,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437950807,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437944990,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437943699,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437935414,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437919019,"type":"zone","description":"delete zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437917758,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437913740,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437882832,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766263279163,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766263270414,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766263260682,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766263259518,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766263249401,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766263246362,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766190721141,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190717499,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766190710946,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190705273,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190703463,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766190695709,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190688417,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1765402888416,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402884873,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1765402878108,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402866440,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402865008,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1765402860428,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402858103,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"}],"savedStyleSets":[]} # # The One File Corporate - Node List # Exported from The One File on 2025-12-23T03:12:20.239Z name,ip,role,shape,tags,layer,mac,rackUnit,uHeight,assignedRack,rackCapacity,isRack,locked,groupId,x,y,size,notes,styles Core Router 1,10.0.0.1,Core Routing,router,core;tier-1;redundant,physical,00:1A:2B:3C:4D:01,,2,,42,false,false,,3720,246,50,Primary core router|BGP peering enabled,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""borg""}}}" Core Router 2,10.0.0.2,Core Routing,router,core;tier-1;redundant,physical,00:1A:2B:3C:4D:02,,2,,42,false,false,,2500,330,120,Secondary core router|HSRP standby,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""actual-budget""},""pingOffsetX"":-15,""pingOffsetY"":-38}}" External FW 1,10.0.1.1,Perimeter Security,firewall,security;perimeter;ha-pair,security,00:1A:2B:3C:4D:10,,2,,42,false,false,,3222,1016,50,Palo Alto PA-5250|Active node,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""anonaddy""}}}" External FW 2,10.0.1.2,Perimeter Security,firewall,security;perimeter;ha-pair,security,00:1A:2B:3C:4D:11,,2,,42,false,false,,1916,224,50,Palo Alto PA-5250|Passive node, Internal FW,10.0.2.1,Internal Segmentation,firewall,security;internal,security,00:1A:2B:3C:4D:12,,2,,42,false,false,,1747,478,50,East-West traffic inspection, Core Switch 1,10.0.10.1,Core Switching,switch,core;layer3;redundant,physical,00:1A:2B:3C:4D:20,,2,,42,false,false,,449,384,50,Cisco Nexus 9000|VPC Domain 1, Core Switch 2,10.0.10.2,Core Switching,switch,core;layer3;redundant,physical,00:1A:2B:3C:4D:21,,2,,42,false,false,,761,181,50,Cisco Nexus 9000|VPC Domain 1, DC Rack A1,10.10.0.0/24,Data Center Rack,server,datacenter;row-a;production,physical,,,1,,42,true,false,,784,647,50,"Row A, Position 1|Primary compute","{""all"":{""circleColor"":""#ff0000""}}" DC Rack A2,10.10.1.0/24,Data Center Rack,server,datacenter;row-a;production,physical,,,1,,42,true,false,,209,228,50,"Row A, Position 2|Primary compute", DC Rack B1,10.10.2.0/24,Data Center Rack,server,datacenter;row-b;storage,physical,,,1,,42,true,false,,3184,1627,50,"Row B, Position 1|Storage systems","{""all"":{""circleColor"":""#ff0000"",""titleSize"":59}}" DC Rack B2,10.10.3.0/24,Data Center Rack,server,datacenter;row-b;storage,physical,,,1,,42,true,false,,245,500,50,"Row B, Position 2|Storage systems","{""all"":{""circleColor"":""#ff0000""}}" DMZ Rack,172.16.0.0/24,DMZ Infrastructure,server,dmz;security;public-facing;[object Object];[object Object],security,,,1,,24,true,false,,2176,611,50,Isolated DMZ zone|Public-facing services, Management Rack,192.168.100.0/24,Management Infrastructure,server,management;oob;noc,logical,,,1,,24,true,false,,1601,1281,50,Out-of-band management|NOC equipment, ESXi Host 01,10.10.0.11,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:01,38,2,dc-rack-a1,42,false,false,,2162,2608,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 02,10.10.0.12,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:02,35,2,dc-rack-a1,42,false,false,,2206,2690,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 03,10.10.0.13,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:03,32,2,dc-rack-a1,42,false,false,,2155,2771,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ESXi Host 04,10.10.0.14,Hypervisor,server,vmware;compute;cluster-a,physical,00:50:56:AA:01:04,29,2,dc-rack-a1,42,false,false,,2196,2845,50,Dell PowerEdge R750|512GB RAM|vSphere 8.0, ToR Switch A1,10.10.0.1,Top of Rack,switch,tor;access;rack-a1,physical,00:1A:2B:3C:5D:01,42,1,dc-rack-a1,42,false,false,,2147,2845,50,Cisco Nexus 93180YC-FX|48x25G ports, ESXi Host 05,10.10.1.11,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:01,38,2,dc-rack-a2,42,false,false,,2186,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 06,10.10.1.12,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:02,35,2,dc-rack-a2,42,false,false,,2139,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 07,10.10.1.13,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:03,32,2,dc-rack-a2,42,false,false,,2176,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ESXi Host 08,10.10.1.14,Hypervisor,server,vmware;compute;cluster-b,physical,00:50:56:AA:02:04,29,2,dc-rack-a2,42,false,false,,2131,2845,50,Dell PowerEdge R750|768GB RAM|vSphere 8.0, ToR Switch A2,10.10.1.1,Top of Rack,switch,tor;access;rack-a2,physical,00:1A:2B:3C:5D:02,42,1,dc-rack-a2,42,false,false,,2165,2845,50,Cisco Nexus 93180YC-FX|48x25G ports, SAN Primary,10.10.2.10,Primary Storage,database,storage;san;netapp,physical,00:A0:98:AA:01:01,36,6,dc-rack-b1,42,false,false,,2123,2845,50,NetApp AFF A400|500TB Raw|FC 32Gb, SAN Secondary,10.10.2.11,Secondary Storage,database,storage;san;netapp,physical,00:A0:98:AA:01:02,28,6,dc-rack-b1,42,false,false,,2155,2845,50,NetApp AFF A400|500TB Raw|FC 32Gb, FC Switch 1,10.10.2.1,Fibre Channel,switch,storage;fc;fabric-a,physical,00:1A:2B:FC:01:01,42,1,dc-rack-b1,42,false,false,,2115,2845,50,Brocade G620|Fabric A, FC Switch 2,10.10.2.2,Fibre Channel,switch,storage;fc;fabric-b,physical,00:1A:2B:FC:01:02,41,1,dc-rack-b1,42,false,false,,2145,2845,50,Brocade G620|Fabric B, Backup Server 1,10.10.3.10,Backup Infrastructure,server,backup;veeam;protection,physical,00:50:56:BB:01:01,36,2,dc-rack-b2,42,false,false,,2107,2845,50,Veeam Backup Server|Dell R740xd|200TB, Backup Server 2,10.10.3.11,Backup Infrastructure,server,backup;veeam;protection,physical,00:50:56:BB:01:02,33,2,dc-rack-b2,42,false,false,,2134,2845,50,Veeam Backup Server|Dell R740xd|200TB, Tape Library,10.10.3.20,Archival Storage,database,backup;tape;lto9,physical,00:50:56:BB:02:01,20,10,dc-rack-b2,42,false,false,,2099,2845,50,IBM TS4500|LTO-9|Long-term archive, ToR Switch B1,10.10.2.3,Top of Rack,switch,tor;access;rack-b1,physical,00:1A:2B:3C:5D:03,40,1,dc-rack-b1,42,false,false,,2123,2845,50,Cisco Nexus 93180YC-FX, ToR Switch B2,10.10.3.1,Top of Rack,switch,tor;access;rack-b2,physical,00:1A:2B:3C:5D:04,42,1,dc-rack-b2,42,false,false,,2091,2845,50,Cisco Nexus 93180YC-FX, Web Server 1,172.16.0.11,Web Frontend,server,dmz;web;nginx,security,00:50:56:CC:01:01,20,1,dmz-rack,24,false,false,,2113,2845,50,NGINX reverse proxy|Public facing, Web Server 2,172.16.0.12,Web Frontend,server,dmz;web;nginx,security,00:50:56:CC:01:02,18,1,dmz-rack,24,false,false,,2082,2845,50,NGINX reverse proxy|Public facing, WAF Appliance,172.16.0.5,Web Application Firewall,firewall,dmz;security;waf,security,00:50:56:CC:02:01,22,2,dmz-rack,24,false,false,,2102,2845,50,F5 BIG-IP ASM|OWASP protection, DMZ Load Balancer,172.16.0.3,Load Balancing,switch,dmz;lb;f5,security,00:50:56:CC:03:01,16,2,dmz-rack,24,false,false,,2074,2845,50,F5 BIG-IP LTM|VIP: 172.16.0.100, Mail Gateway,172.16.0.25,Email Security,server,dmz;email;security,security,00:50:56:CC:04:01,14,1,dmz-rack,24,false,false,,2091,2845,50,Proofpoint Email Gateway|Spam/malware filtering, External DNS 1,172.16.0.53,External DNS,circle,dmz;dns;public,security,00:50:56:CC:05:01,12,1,dmz-rack,24,false,false,,2066,2845,50,BIND DNS|Authoritative for corp.com, External DNS 2,172.16.0.54,External DNS,circle,dmz;dns;public,security,00:50:56:CC:05:02,10,1,dmz-rack,24,false,false,,2080,2845,50,BIND DNS|Secondary for corp.com, vCenter Server,192.168.100.10,Virtualization Management,server,management;vmware;vcsa,logical,00:50:56:DD:01:01,20,2,mgmt-rack,24,false,false,,2057,2845,50,vCenter Server Appliance 8.0|Single SSO domain, NSX Manager,192.168.100.15,Network Virtualization,server,management;vmware;nsx,logical,00:50:56:DD:02:01,17,2,mgmt-rack,24,false,false,,2069,2845,50,NSX-T 4.1 Manager Cluster, SIEM Server,192.168.100.50,Security Monitoring,server,management;security;splunk,logical,00:50:56:DD:03:01,14,2,mgmt-rack,24,false,false,,2049,2845,50,Splunk Enterprise|Security monitoring, Network Monitoring,192.168.100.60,Network Management,server,management;monitoring;prtg,logical,00:50:56:DD:04:01,11,1,mgmt-rack,24,false,false,,2058,2845,50,PRTG Network Monitor|5000 sensors, Jump Server,192.168.100.100,Bastion Host,server,management;security;bastion,logical,00:50:56:DD:05:01,9,1,mgmt-rack,24,false,false,,2040,2845,50,Windows Server 2022|MFA enabled, IPAM/DDI,192.168.100.70,IP Management,server,management;dns;dhcp,logical,00:50:56:DD:06:01,7,2,mgmt-rack,24,false,false,,2047,2845,50,Infoblox DDI|DNS/DHCP/IPAM, WLC Primary,10.20.0.1,Wireless Controller,wifi,wireless;cisco;9800,physical,00:1A:2B:WL:01:01,,2,,42,false,false,,1576,2306,50,Cisco C9800-40|Primary controller, WLC Secondary,10.20.0.2,Wireless Controller,wifi,wireless;cisco;9800,physical,00:1A:2B:WL:01:02,,2,,42,false,false,,1468,1564,50,Cisco C9800-40|HA Secondary, HQ Mobile Zone,10.20.10.0/24,Mobile Device Zone,phone,wireless;byod;mobile,physical,,,1,,42,false,false,,2355,2806,50,Corporate BYOD|MDM enrolled devices, Guest WiFi Zone,10.30.0.0/24,Guest Network,phone,wireless;guest;isolated,physical,,,1,,42,false,false,,2308,2611,50,Captive portal|Internet only, IoT Device Zone,10.40.0.0/24,IoT Network,phone,wireless;iot;building,physical,,,1,,42,false,false,,2229,2299,50,Building automation|Smart devices, NYC Branch Router,10.100.0.1,Branch Gateway,router,branch;nyc;sd-wan,physical,00:1A:2B:BR:01:01,,1,,42,false,false,,3152,634,50,Cisco Viptela vEdge|SD-WAN enabled, LA Branch Router,10.101.0.1,Branch Gateway,router,branch;la;sd-wan,physical,00:1A:2B:BR:02:01,,1,,42,false,false,,3084,507,50,Cisco Viptela vEdge|SD-WAN enabled, Chicago Branch Router,10.102.0.1,Branch Gateway,router,branch;chicago;sd-wan,physical,00:1A:2B:BR:03:01,,1,,42,false,false,,3355,393,50,Cisco Viptela vEdge|SD-WAN enabled, London Branch Router,10.200.0.1,Branch Gateway,router,branch;london;sd-wan,physical,00:1A:2B:BR:04:01,,1,,42,false,false,,3114,260,50,Cisco Viptela vEdge|EMEA region, Tokyo Branch Router,10.201.0.1,Branch Gateway,router,branch;tokyo;sd-wan,physical,00:1A:2B:BR:05:01,,1,,42,false,false,,3699,471,50,Cisco Viptela vEdge|APAC region,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""adguard-home""}}}" AWS Cloud,vpc-0a1b2c3d,Public Cloud,cloud,cloud;aws;hybrid,logical,,,1,,42,false,false,,3437,546,50,AWS US-East-1|VPC peering to HQ,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""ansible""}}}" Azure Cloud,vnet-corp-prod,Public Cloud,cloud,cloud;azure;hybrid,logical,,,1,,42,false,false,,2593,2724,50,Azure East US 2|ExpressRoute, GCP Cloud,vpc-gcp-corp,Public Cloud,cloud,cloud;gcp;dev,logical,,,1,,42,false,false,,2827,2731,50,GCP us-central1|Dev/Test workloads, ISP Primary,203.0.113.1,Internet Uplink,globe,wan;internet;primary,physical,,,1,,42,false,false,,3712,616,50,AT&T MPLS|1 Gbps dedicated,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""wikidocs""}}}" ISP Secondary,198.51.100.1,Internet Uplink,globe,wan;internet;backup,physical,,,1,,42,false,false,,2702,468,139,Verizon Business|500 Mbps backup,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""alist""}}}" DC1 Int DNS,10.10.0.53,Internal DNS/AD,circle,dns;ad;dc1,physical,00:50:56:AD:01:01,26,1,dc-rack-a1,42,false,false,,1958,2845,50,Windows Server 2022|Primary DC, DC2 Int DNS,10.10.1.53,Internal DNS/AD,circle,dns;ad;dc2,physical,00:50:56:AD:01:02,26,1,dc-rack-a2,42,false,false,,1964,2845,50,Windows Server 2022|Secondary DC, App Server 01,10.10.0.101,Application,server,app;iis;web,physical,00:50:56:AP:01:01,24,1,dc-rack-a1,42,false,false,,1947,2845,50,Windows Server 2022|IIS Application, App Server 02,10.10.0.102,Application,server,app;iis;web,physical,00:50:56:AP:01:02,22,1,dc-rack-a1,42,false,false,,1955,2845,50,Windows Server 2022|IIS Application, SQL Server 01,10.10.0.201,Database,database,db;sql;primary,physical,00:50:56:DB:01:01,20,2,dc-rack-a1,42,false,false,,1936,2845,50,SQL Server 2022 Enterprise|AlwaysOn Primary, SQL Server 02,10.10.1.201,Database,database,db;sql;secondary,physical,00:50:56:DB:01:02,24,2,dc-rack-a2,42,false,false,,1947,2845,50,SQL Server 2022 Enterprise|AlwaysOn Secondary, K8s Master 1,10.10.1.50,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:01,21,1,dc-rack-a2,42,false,false,,1925,2845,50,K8s Control Plane|etcd member, K8s Master 2,10.10.1.51,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:02,19,1,dc-rack-a2,42,false,false,,1938,2845,50,K8s Control Plane|etcd member, K8s Master 3,10.10.1.52,Container Orchestration,hexagon,kubernetes;master;container,physical,00:50:56:K8:01:03,17,1,dc-rack-a2,42,false,false,,1914,2845,50,K8s Control Plane|etcd member, K8s Worker 1,10.10.1.60,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:01,15,1,dc-rack-a2,42,false,false,,1930,2845,50,K8s Worker Node|64GB RAM, K8s Worker 2,10.10.1.61,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:02,13,1,dc-rack-a2,42,false,false,,1904,2845,50,K8s Worker Node|64GB RAM, K8s Worker 3,10.10.1.62,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:03,11,1,dc-rack-a2,42,false,false,,1922,2845,50,K8s Worker Node|64GB RAM, K8s Worker 4,10.10.1.63,Container Workload,server,kubernetes;worker;container,physical,00:50:56:K8:02:04,9,1,dc-rack-a2,42,false,false,,1893,2845,50,K8s Worker Node|64GB RAM, Proxy Server 1,10.5.0.10,Web Proxy,server,proxy;squid;filtering,security,00:50:56:PX:01:01,,1,,42,false,false,,1806,654,50,Squid Proxy|Content filtering, Proxy Server 2,10.5.0.11,Web Proxy,server,proxy;squid;filtering,security,00:50:56:PX:01:02,,1,,42,false,false,,2937,2629,50,Squid Proxy|HA pair, VPN Concentrator,10.0.5.1,Remote Access VPN,firewall,vpn;remote;security,security,00:1A:2B:VP:01:01,,2,,42,false,false,,3642,947,50,Cisco ASA 5555-X|AnyConnect SSL VPN, NAC Server,10.5.5.10,Network Access Control,server,nac;ise;802.1x,security,00:50:56:NA:01:01,,2,,42,false,false,,1153,1172,50,Cisco ISE 3.1|RADIUS/TACACS+, Print Server,10.10.0.150,Print Services,server,print;windows;services,physical,00:50:56:PR:01:01,18,1,dc-rack-a1,42,false,false,,1897,2845,50,Windows Print Server|50+ printers, File Server,10.10.0.160,File Services,database,file;smb;dfs,physical,00:50:56:FS:01:01,16,2,dc-rack-a1,42,false,false,,1861,2845,50,Windows File Server|DFS namespace, Certificate Authority,192.168.100.80,PKI Infrastructure,server,pki;ca;security,logical,00:50:56:CA:01:01,5,1,mgmt-rack,24,false,false,,1889,2845,50,Windows CA|Enterprise Root CA, SCCM Server,192.168.100.90,Endpoint Management,server,sccm;patching;software,logical,00:50:56:SC:01:01,3,2,mgmt-rack,24,false,false,,1850,2845,50,MECM Primary Site|Software deployment, VoIP Cluster,10.50.0.0/24,Voice Services,phone,voip;cisco;ucm,application,,,1,,42,false,false,,1777,1617,50,Cisco UCM Cluster|3000 endpoints, Video Conference,10.51.0.0/24,Video Services,laptop,video;webex;teams,application,,,1,,42,false,false,,1994,2245,50,Webex/Teams integration|Meeting rooms, Security Cameras,10.60.0.0/24,Physical Security,camera,cctv;surveillance;security,physical,,,1,,42,false,false,,1674,2046,50,150+ IP cameras|30-day retention, NVR Cluster,10.60.0.10,Video Recording,server,nvr;surveillance;storage,physical,00:50:56:NV:01:01,15,4,dc-rack-b2,42,false,false,,1829,2845,50,Milestone XProtect|500TB storage, Dev Server 1,10.80.0.10,Development,server,dev;gitlab;ci-cd;[object Object],application,00:50:56:DV:01:01,,2,,42,false,false,,2801,1176,128,GitLab Server|CI/CD pipelines,"{""all"":{""icon"":{""library"":""simple"",""name"":""amazonwebservices""}}}" Dev Server 2,10.80.0.11,Development,server,dev;jenkins;ci-cd,application,00:50:56:DV:01:02,,2,,42,false,false,,1945,1165,50,Jenkins Server|Build automation, Test Environment,10.81.0.0/24,QA/Testing,hexagon,test;qa;staging,application,,,1,,42,false,false,,2567,885,148,Staging environment|Pre-prod validation,"{""all"":{""icon"":{""library"":""simple"",""name"":""apple""}}}" ERP System,10.90.0.10,Business Application,database,erp;sap;business,application,00:50:56:ER:01:01,,4,,42,false,false,,790,474,50,SAP S/4HANA|Financial/HR systems, CRM System,10.91.0.10,Business Application,database,crm;salesforce;business,application,,,1,,42,false,false,,3515,1138,50,Salesforce integration|Sales/Marketing, Corporate Endpoints,10.70.0.0/22,User Workstations,laptop,endpoints;workstations;users,physical,,,1,,42,false,false,,992,2284,50,~1000 corporate laptops|Windows 11, Floor 1 Switch,10.1.1.1,Distribution,switch,distribution;floor-1;access,physical,00:1A:2B:FL:01:01,,1,,42,false,false,,654,2020,50,Cisco C9300-48P|PoE+ enabled, Floor 2 Switch,10.1.2.1,Distribution,switch,distribution;floor-2;access,physical,00:1A:2B:FL:02:01,,1,,42,false,false,,854,1843,50,Cisco C9300-48P|PoE+ enabled, Floor 3 Switch,10.1.3.1,Distribution,switch,distribution;floor-3;access,physical,00:1A:2B:FL:03:01,,1,,42,false,false,,1899,1457,50,Cisco C9300-48P|PoE+ enabled, Floor 4 Switch,10.1.4.1,Distribution,switch,distribution;floor-4;access,physical,00:1A:2B:FL:04:01,,1,,42,false,false,,489,181,50,Cisco C9300-48P|PoE+ enabled, AP Floor 1 Zone 1,10.20.1.10,Wireless Access,wifi,wifi;ap;floor-1,physical,00:1A:2B:AP:01:01,,1,,42,false,false,,1140,2070,50,Cisco 9120AX|Wi-Fi 6, AP Floor 2 Zone 1,10.20.2.10,Wireless Access,wifi,wifi;ap;floor-2,physical,00:1A:2B:AP:02:01,,1,,42,false,false,,688,2384,50,Cisco 9120AX|Wi-Fi 6, AP Floor 3 Zone 1,10.20.3.10,Wireless Access,wifi,wifi;ap;floor-3,physical,00:1A:2B:AP:03:01,,1,,42,false,false,,2145,1890,50,Cisco 9120AX|Wi-Fi 6, AP Floor 4 Zone 1,10.20.4.10,Wireless Access,wifi,wifi;ap;floor-4,physical,00:1A:2B:AP:04:01,,1,,42,false,false,,518,566,50,Cisco 9120AX|Wi-Fi 6, UPS DC-1,192.168.200.10,Power Management,rectangle,power;ups;datacenter,physical,,,1,,42,false,false,,771,296,50,APC Symmetra|80kVA|30 min runtime, UPS DC-2,192.168.200.11,Power Management,rectangle,power;ups;datacenter,physical,,,1,,42,false,false,,216,330,50,APC Symmetra|80kVA|Redundant, PDU Rack A1,192.168.200.21,Power Distribution,rectangle,power;pdu;rack-a1,physical,,1,1,dc-rack-a1,42,false,false,,1805,2845,50,APC Switched PDU|Per-outlet metering, PDU Rack A2,192.168.200.22,Power Distribution,rectangle,power;pdu;rack-a2,physical,,1,1,dc-rack-a2,42,false,false,,1742,2845,50,APC Switched PDU|Per-outlet metering, CRAC Unit 1,192.168.200.30,Cooling,rectangle,cooling;hvac;datacenter,physical,,,1,,42,false,false,,246,626,50,Liebert CRV|Row-based cooling, CRAC Unit 2,192.168.200.31,Cooling,rectangle,cooling;hvac;datacenter,physical,,,1,,42,false,false,,1603,981,50,Liebert CRV|N+1 redundancy, camera A,0.0.0.0,,camera,,physical,,,1,,,false,false,,167,145,45,, camera B,0.0.0.0,,camera,,physical,,,1,,,false,false,,1041,738,45,, ================================================ FILE: demos/csv-exports/the-one-file-networkening-homelab.csv ================================================ #THEONEFILE_CONFIG:{"nodeData":{"internet":{"shape":"square","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}},"edgeData":{"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":[]}]},"rectData":{"list":[{"id":"rect-1765238219615","x":2680.053955078125,"y":251.44879150390625,"width":814.10400390625,"height":389.26678466796875,"color":"#ec0999","style":"filled","lineStyle":"solid","notes":[]}]},"textData":{"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}]},"edgeLegend":{"#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"},"nodePositions":{"internet":{"x":2103.968290880771,"y":268},"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}},"nodeSizes":{"core-router-1":36,"internet":168,"phone":121,"desktop":147,"racked":137,"docker-copy-2":82},"nodeStyles":{"internet":{"all":{"icon":{"library":"selfhst","name":"amazon-web-services"},"circleColor":"#ffffff","circleBorder":"#ffffff"}},"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"}}},"iconCache":{"selfhst-borg":"","selfhst-actual-budget":"","selfhst-anonaddy":"","selfhst-adguard-home":"","selfhst-ansible":"","selfhst-wikidocs":"","selfhst-alist":"","simple-amazonwebservices":"Amazon Web Services","simple-apple":"Apple","selfhst-amazon-web-services":"","selfhst-opnsense":"","selfhst-portainer":"","selfhst-jotty":"","selfhst-authportal":"","selfhst-docker":"","selfhst-opnsense-v1":"","mdi-server-security":""},"page":{"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"viewOnly":false,"defaultEdgeRouting":"curved","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":1.5},"autoPingEnabled":false,"autoPingInterval":30,"canvas":{"zoom":0.9921985961590549,"panX":-5.584863670202822,"panY":-99.90831573327841},"savedTopologyView":{"zoom":0.9325110211947125,"panX":-563.7108933103631,"panY":-561.6887674556383},"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":"globe","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},"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":"hexagon","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},"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"},{"id":"custom-1765239355462","type":"custom","color":"#f97316","width":4,"lineStyle":"solid","direction":"forward","points":[{"x":2467.182861328125,"y":156.12173461914062},{"x":2146.36376953125,"y":146.32574462890625},{"x":2305.548828125,"y":244.28573608398438}],"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":2702.3789772348055,"y":467.890869140625},"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":2566.9100352578575,"y":885.2827758789062},"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":148,"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"}}},"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-1765239331126","x":2454.5615234375,"y":160.73322105407715,"content":"Google is live!","fontSize":56,"color":"#e2e8f0","fontWeight":"bold","fontStyle":"normal","textAlign":"start","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}]},"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"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":"square","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}},"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":2103.968290880771,"y":268},"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}},"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":"#ffffff","circleBorder":"#ffffff"}},"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","rackFrameStroke":"#4fd1c5","rackLineColor":"#475569","rackTextColor":"#4fd1c5","rackGridEnabled":true,"viewOnly":false,"defaultEdgeRouting":"curved","animateConnections":false,"animationStyle":"arrows","animationDirection":"all","animationSpeed":1.5}}],"currentTabIndex":1,"encryptedSections":{},"auditLog":[{"timestamp":1766459518367,"type":"export","description":"Exported Markdown: the-one-file.md","details":{},"tab":"Homelab 2"},{"timestamp":1766459511746,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766459504374,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766459500911,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766459497380,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766459491436,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766459483682,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766459477676,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766457578277,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766457564726,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766457564253,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766457560309,"type":"import","description":"Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766455847368,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455844054,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843762,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843560,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843371,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455843162,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842852,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842747,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842601,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842449,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842348,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455842098,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841678,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455841053,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840901,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455840650,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839427,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839234,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455839061,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837247,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455837081,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836893,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836377,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455836198,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455835455,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455834630,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831880,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831676,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455831451,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830817,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830687,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830176,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455830048,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829944,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455829816,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378795,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378693,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378459,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378316,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378180,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455378069,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377956,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377677,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377558,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377448,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377318,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766455377209,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090534,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090317,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090213,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090112,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453090009,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453089903,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088895,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088793,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088689,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088584,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088480,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453088250,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453087236,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086485,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086373,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086142,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453086043,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453072857,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453070975,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453054439,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453053127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052450,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453052106,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051948,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051806,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453051334,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453050207,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042725,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453042179,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041797,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453041570,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039703,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039291,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039168,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453039065,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038481,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038365,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038237,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038105,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453038001,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037850,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037745,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037495,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037378,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037182,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453037078,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036972,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036860,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453036147,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035945,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035825,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035720,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035443,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035337,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035233,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035127,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453035026,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453034917,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453031063,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030955,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030833,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030732,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030225,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453030104,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029968,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029796,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453029474,"type":"edit","description":"rotate text","details":{},"tab":"Corporate Site B"},{"timestamp":1766453024797,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766451118553,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450929324,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450817210,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450257424,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450255024,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450254395,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450253241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450251598,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450250392,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450248756,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450244072,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450242166,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450240998,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450236492,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450233672,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450232384,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450231012,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450230254,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450229302,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766450228132,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766446610211,"type":"text","description":"paste text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604404,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604305,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446604099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603952,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603849,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603599,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603348,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603202,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446603099,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602953,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602850,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602600,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602453,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602349,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602204,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602101,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446602000,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601848,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601702,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601601,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601452,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601301,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601154,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446601049,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600948,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600802,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446600550,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598595,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598461,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598171,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446598017,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446597219,"type":"text","description":"edit text","details":{},"tab":"Corporate Site B"},{"timestamp":1766446595278,"type":"text","description":"add text","details":{},"tab":"Corporate Site B"},{"timestamp":1766445633355,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445632515,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445631735,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445630757,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445627846,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445625085,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445618645,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445617784,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608998,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608720,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608540,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608376,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608204,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445608038,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607852,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607678,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607506,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607319,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445607154,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604410,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604244,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445604066,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603900,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603743,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603563,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603406,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603226,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445603052,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602880,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445602641,"type":"edit","description":"edit zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766445576567,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445570290,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766445567192,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445566766,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445565520,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766445398115,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445390895,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445385694,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766445383241,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445382911,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445381695,"type":"edit","description":"edit node name","details":{},"tab":"Corporate Site B"},{"timestamp":1766445375383,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445374665,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766445373273,"type":"node","description":"paste node","details":{},"tab":"Corporate Site B"},{"timestamp":1766445372205,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157980,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438157430,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438152691,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151948,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438151286,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438146174,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438145649,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438144555,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438143655,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438142504,"type":"edit","description":"edit edge animation speed","details":{},"tab":"Corporate Site B"},{"timestamp":1766438130077,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438129561,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128772,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438128398,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122820,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438122062,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119836,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438119588,"type":"edit","description":"edit edge animate","details":{},"tab":"Corporate Site B"},{"timestamp":1766438095045,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438093965,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438062827,"type":"edit","description":"toggle fov animation","details":{},"tab":"Corporate Site B"},{"timestamp":1766438047679,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438044161,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438041852,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039668,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039562,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039421,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039260,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039150,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438039039,"type":"edit","description":"resize node","details":{},"tab":"Corporate Site B"},{"timestamp":1766438028508,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438021410,"type":"edit","description":"toggle fov","details":{},"tab":"Corporate Site B"},{"timestamp":1766438019234,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438017562,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766438014356,"type":"node","description":"add node","details":{},"tab":"Corporate Site B"},{"timestamp":1766437981696,"type":"edit","description":"apply routing to all","details":{},"tab":"Corporate Site B"},{"timestamp":1766437966551,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437964879,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437963627,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961813,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437961193,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437957989,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437956467,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437953437,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437952239,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437950807,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437944990,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437943699,"type":"node","description":"move nodes","details":{},"tab":"Corporate Site B"},{"timestamp":1766437935414,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437919019,"type":"zone","description":"delete zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437917758,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437913740,"type":"zone","description":"draw zone","details":{},"tab":"Corporate Site B"},{"timestamp":1766437882832,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766263279163,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766263270414,"type":"export","description":"Exported JSON: the-one-file.json","details":{},"tab":"Homelab 2"},{"timestamp":1766263260682,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766263259518,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766263249401,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766263246362,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1766190721141,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190717499,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1766190710946,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190705273,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1766190703463,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1766190695709,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1766190688417,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"},{"timestamp":1765402888416,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402884873,"type":"tab","description":"Switched to tab: Corporate Site B","details":{},"tab":"Corporate Site B"},{"timestamp":1765402878108,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402866440,"type":"save","description":"File saved: the-one-file.html","details":{},"tab":"Homelab 2"},{"timestamp":1765402865008,"type":"tab","description":"Switched to tab: Homelab 2","details":{},"tab":"Homelab 2"},{"timestamp":1765402860428,"type":"save","description":"File saved: the-one-file-corporate.html","details":{},"tab":"Corporate Site B"},{"timestamp":1765402858103,"type":"import","description":"Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)","details":{},"tab":"Corporate Site B"}],"savedStyleSets":[]} # # The One File - Node List # Exported from The One File on 2025-12-23T03:12:05.614Z name,ip,role,shape,tags,layer,mac,rackUnit,uHeight,assignedRack,rackCapacity,isRack,locked,groupId,x,y,size,notes,styles Internet,0.0.0.0,,square,,physical,,,1,,42,false,false,,2104,268,168,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""amazon-web-services""},""circleColor"":""#ffffff"",""circleBorder"":""#ffffff""}}" OPNSENSE,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2067,473,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""opnsense""}}}" Docker,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,1774,667,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""portainer""}}}" Docker2,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,1931,782,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""jotty""}}}" Docker3,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2158,768,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""authportal""}}}" Docker 4,0.0.0.0,,firewall,[object Object];[object Object];[object Object],physical,,,1,,42,false,false,,2342,632,82,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""docker""}}}" OPNSENSE GUEST,0.0.0.0,,firewall,,physical,,,1,,42,false,false,,2758,308,50,,"{""all"":{""icon"":{""library"":""selfhst"",""name"":""opnsense-v1""}}}" Phone,0.0.0.0,,phone,,physical,,,1,,42,false,false,,3313,503,121,, Desktop,0.0.0.0,,pc,,physical,,,1,,42,false,false,,2972,481,147,, DNS,0.0.0.0,,cloud,,physical,,,1,,42,false,false,,3200,320,50,, Racked,,Rack,server,,physical,,,1,,42,true,false,,2646,971,137,,"{""all"":{""icon"":{""library"":""mdi"",""name"":""server-security""},""circleColor"":""#010813"",""circleBorder"":""#ffffff""}}" ================================================ FILE: demos/index.html ================================================ The One File : Demo Browser

The One File : Demo Browser

Select a version and demo to load

Loading demo...
View on GitHub
================================================ FILE: demos/json-exports/the-one-file-corporate-demo.json ================================================ { "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": 1766459410068, "type": "export", "description": "Exported Markdown: the-one-file-corporate.md", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459403229, "type": "export", "description": "Exported CSV: the-one-file-corporate.csv", "details": {}, "tab": "Corporate Site B" }, { "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": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459318363, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459318258, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317846, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317742, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317464, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317314, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459313457, "type": "node", "description": "change shape", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459310142, "type": "node", "description": "change shape", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459306160, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459305289, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459305132, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304675, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304530, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304396, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304290, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304157, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303660, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303534, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303414, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303247, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303144, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303002, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302875, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302725, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302613, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302507, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459301997, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459301893, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458459721, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458438687, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438583, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438437, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438333, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438187, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438083, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437937, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437833, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437687, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437583, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437437, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437333, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437187, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458436932, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458435139, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434986, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434840, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434736, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434590, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434486, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434340, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434236, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434090, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433986, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433840, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433736, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433590, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433334, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458429157, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458429053, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458428947, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426794, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426691, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426584, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426481, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458423513, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458421278, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458416555, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458404891, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458392272, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458378068, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458367460, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458356226, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458338198, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458258865, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458249051, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248926, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248793, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248683, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248556, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248451, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248325, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248221, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248092, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247989, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247885, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247784, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247284, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246701, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246523, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246410, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246129, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245955, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245737, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245627, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245425, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245247, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245133, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244923, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244741, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244313, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244198, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244055, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243873, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243637, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243399, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243218, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458241018, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458237254, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458235033, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234835, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234694, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234425, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227773, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227623, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227441, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227279, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227155, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226967, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226847, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226733, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226563, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226421, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458222326, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458213989, "type": "connection", "description": "delete edge", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458209437, "type": "text", "description": "delete text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458195427, "type": "import", "description": "Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455847368, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844054, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843762, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843560, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843371, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843162, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842852, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842747, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842601, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842449, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842348, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842098, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841678, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841053, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840901, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840650, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839427, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839234, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839061, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837247, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837081, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836893, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836377, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836198, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455835455, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455834630, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831880, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831676, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831451, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830817, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830687, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830176, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830048, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829944, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829816, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378795, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378693, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378459, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378316, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378180, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378069, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377956, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377677, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377558, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377448, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377318, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377209, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090317, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090213, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090112, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090009, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453089903, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088895, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088793, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088689, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088584, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088480, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088250, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453087236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086485, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086373, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086142, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086043, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453072857, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453070975, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453054439, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453053127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052450, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052106, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051948, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051806, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051334, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453050207, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042179, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041797, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041570, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039703, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039291, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039168, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039065, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038481, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038365, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038237, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038105, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038001, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037850, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037745, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037495, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037378, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037182, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037078, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036972, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036860, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036147, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035945, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035825, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035720, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035443, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035337, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035233, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035026, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453034917, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453031063, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030955, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030833, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030732, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030225, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030104, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029968, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029796, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029474, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453024797, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766451118553, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450929324, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450817210, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450257424, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450255024, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450254395, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450253241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450251598, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450250392, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450248756, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450244072, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450242166, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450240998, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450236492, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450233672, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450232384, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450231012, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450230254, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450229302, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450228132, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446610211, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604404, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604305, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603952, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603599, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603348, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603202, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602953, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602850, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602600, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602453, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602349, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602101, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602000, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601848, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601601, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601301, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601154, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601049, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600948, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600802, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598595, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598461, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598171, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598017, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446597219, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446595278, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445633355, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445632515, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445631735, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445630757, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445627846, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445625085, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445618645, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445617784, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608998, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608720, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608540, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608376, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608204, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608038, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607852, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607678, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607506, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607319, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607154, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604410, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604244, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604066, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603900, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603743, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603563, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603406, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603226, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603052, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602880, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602641, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445576567, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445570290, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445567192, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445566766, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445565520, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445398115, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445390895, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445385694, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445383241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445382911, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445381695, "type": "edit", "description": "edit node name", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445375383, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445374665, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445373273, "type": "node", "description": "paste node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445372205, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157980, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157430, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438152691, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151948, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151286, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438146174, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438145649, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438144555, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438143655, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438142504, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438130077, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438129561, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128772, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128398, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122820, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122062, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119836, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119588, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438095045, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438093965, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438062827, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438047679, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438044161, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438041852, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039668, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039562, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039421, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039260, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039150, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039039, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438028508, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438021410, "type": "edit", "description": "toggle fov", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438019234, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438017562, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438014356, "type": "node", "description": "add node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437981696, "type": "edit", "description": "apply routing to all", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437966551, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437964879, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437963627, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961813, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961193, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437957989, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437956467, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437953437, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437952239, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437950807, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437944990, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437943699, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437935414, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437919019, "type": "zone", "description": "delete zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437917758, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437913740, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437882832, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263279163, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263270414, "type": "export", "description": "Exported JSON: the-one-file.json", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263260682, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263259518, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263249401, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263246362, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190721141, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190717499, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190710946, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190705273, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190703463, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190695709, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190688417, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402888416, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402884873, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402878108, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402866440, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402865008, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402860428, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402858103, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" } ], "savedStyleSets": [] } ================================================ FILE: demos/json-exports/the-one-file-homelab-demo.json ================================================ { "nodeData": { "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 } }, "edgeData": { "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": [] } ] }, "rectData": { "list": [ { "id": "rect-1765238219615", "x": 2680.053955078125, "y": 251.44879150390625, "width": 814.10400390625, "height": 389.26678466796875, "color": "#ec0999", "style": "filled", "lineStyle": "solid", "notes": [] } ] }, "textData": { "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 } ] }, "edgeLegend": { "#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" }, "nodePositions": { "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 } }, "nodeSizes": { "core-router-1": 36, "internet": 168, "phone": 121, "desktop": 147, "racked": 137, "docker-copy-2": 82 }, "nodeStyles": { "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" } } }, "page": { "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 }, "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": 1, "encryptedSections": {}, "auditLog": [ { "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": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459318363, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459318258, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317846, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317742, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317464, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459317314, "type": "style", "description": "style change", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459313457, "type": "node", "description": "change shape", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459310142, "type": "node", "description": "change shape", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459306160, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459305289, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459305132, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304675, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304530, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304396, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304290, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459304157, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303660, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303534, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303414, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303247, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303144, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459303002, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302875, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302725, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302613, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459302507, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459301997, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459301893, "type": "node", "description": "rotate node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458459721, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458438687, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438583, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438437, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438333, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438187, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458438083, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437937, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437833, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437687, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437583, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437437, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437333, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458437187, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458436932, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458435139, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434986, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434840, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434736, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434590, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434486, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434340, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434236, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458434090, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433986, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433840, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433736, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433590, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458433334, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458429157, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458429053, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458428947, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426794, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426691, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426584, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458426481, "type": "style", "description": "style change", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458423513, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458421278, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458416555, "type": "node", "description": "change shape", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458404891, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458392272, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458378068, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458367460, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458356226, "type": "node", "description": "add node", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458338198, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766458258865, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458249051, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248926, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248793, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248683, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248556, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248451, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248325, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248221, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458248092, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247989, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247885, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247784, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458247284, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246701, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246523, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246410, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458246129, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245955, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245737, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245627, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245425, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245247, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458245133, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244923, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244741, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244313, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244198, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458244055, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243873, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243637, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243399, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458243218, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458241018, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458237254, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458235033, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234835, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234694, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458234425, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227773, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227623, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227441, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227279, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458227155, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226967, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226847, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226733, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226563, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458226421, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458222326, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458213989, "type": "connection", "description": "delete edge", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458209437, "type": "text", "description": "delete text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766458195427, "type": "import", "description": "Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455847368, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844054, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843762, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843560, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843371, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843162, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842852, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842747, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842601, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842449, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842348, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842098, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841678, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841053, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840901, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840650, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839427, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839234, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839061, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837247, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837081, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836893, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836377, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836198, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455835455, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455834630, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831880, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831676, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831451, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830817, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830687, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830176, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830048, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829944, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829816, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378795, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378693, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378459, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378316, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378180, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378069, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377956, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377677, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377558, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377448, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377318, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377209, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090317, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090213, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090112, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090009, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453089903, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088895, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088793, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088689, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088584, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088480, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088250, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453087236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086485, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086373, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086142, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086043, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453072857, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453070975, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453054439, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453053127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052450, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052106, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051948, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051806, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051334, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453050207, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042179, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041797, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041570, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039703, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039291, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039168, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039065, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038481, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038365, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038237, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038105, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038001, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037850, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037745, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037495, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037378, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037182, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037078, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036972, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036860, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036147, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035945, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035825, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035720, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035443, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035337, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035233, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035026, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453034917, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453031063, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030955, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030833, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030732, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030225, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030104, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029968, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029796, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029474, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453024797, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766451118553, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450929324, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450817210, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450257424, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450255024, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450254395, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450253241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450251598, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450250392, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450248756, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450244072, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450242166, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450240998, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450236492, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450233672, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450232384, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450231012, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450230254, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450229302, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450228132, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446610211, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604404, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604305, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603952, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603599, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603348, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603202, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602953, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602850, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602600, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602453, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602349, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602101, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602000, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601848, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601601, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601301, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601154, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601049, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600948, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600802, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598595, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598461, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598171, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598017, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446597219, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446595278, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445633355, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445632515, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445631735, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445630757, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445627846, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445625085, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445618645, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445617784, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608998, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608720, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608540, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608376, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608204, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608038, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607852, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607678, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607506, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607319, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607154, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604410, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604244, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604066, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603900, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603743, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603563, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603406, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603226, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603052, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602880, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602641, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445576567, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445570290, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445567192, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445566766, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445565520, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445398115, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445390895, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445385694, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445383241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445382911, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445381695, "type": "edit", "description": "edit node name", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445375383, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445374665, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445373273, "type": "node", "description": "paste node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445372205, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157980, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157430, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438152691, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151948, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151286, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438146174, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438145649, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438144555, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438143655, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438142504, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438130077, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438129561, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128772, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128398, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122820, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122062, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119836, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119588, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438095045, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438093965, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438062827, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438047679, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438044161, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438041852, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039668, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039562, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039421, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039260, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039150, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039039, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438028508, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438021410, "type": "edit", "description": "toggle fov", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438019234, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438017562, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438014356, "type": "node", "description": "add node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437981696, "type": "edit", "description": "apply routing to all", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437966551, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437964879, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437963627, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961813, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961193, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437957989, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437956467, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437953437, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437952239, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437950807, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437944990, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437943699, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437935414, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437919019, "type": "zone", "description": "delete zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437917758, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437913740, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437882832, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263279163, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263270414, "type": "export", "description": "Exported JSON: the-one-file.json", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263260682, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263259518, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263249401, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263246362, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190721141, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190717499, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190710946, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190705273, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190703463, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190695709, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190688417, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402888416, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402884873, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402878108, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402866440, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402865008, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402860428, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402858103, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" } ], "savedStyleSets": [] } ================================================ FILE: demos/json-exports/theonefile-networkening-corporate-demo.json ================================================ { "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": "globe", "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 }, "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": "hexagon", "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 }, "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" }, { "id": "custom-1765239355462", "type": "custom", "color": "#f97316", "width": 4, "lineStyle": "solid", "direction": "forward", "points": [ { "x": 2467.182861328125, "y": 156.12173461914062 }, { "x": 2146.36376953125, "y": 146.32574462890625 }, { "x": 2305.548828125, "y": 244.28573608398438 } ], "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-1765239331126", "x": 2454.5615234375, "y": 160.73322105407715, "content": "Google is live!", "fontSize": 56, "color": "#e2e8f0", "fontWeight": "bold", "fontStyle": "normal", "textAlign": "start", "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 } ] }, "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": 2702.3789772348055, "y": 467.890869140625 }, "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": 2566.9100352578575, "y": 885.2827758789062 }, "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": 148, "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" } } }, "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" } } } }, "iconCache": { "selfhst-borg": "", "selfhst-actual-budget": "", "selfhst-anonaddy": "", "selfhst-adguard-home": "", "selfhst-ansible": "", "selfhst-wikidocs": "", "selfhst-alist": "", "simple-amazonwebservices": "Amazon Web Services", "simple-apple": "Apple", "selfhst-amazon-web-services": "", "selfhst-opnsense": "", "selfhst-portainer": "", "selfhst-jotty": "", "selfhst-authportal": "", "selfhst-docker": "", "selfhst-opnsense-v1": "", "mdi-server-security": "" }, "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "viewOnly": false, "defaultEdgeRouting": "orthogonal", "animateConnections": false, "animationStyle": "arrows", "animationDirection": "all", "animationSpeed": 4, "autoPingEnabled": false, "autoPingInterval": 30 }, "autoPingEnabled": false, "autoPingInterval": 30, "canvas": { "zoom": 0.9921985961590549, "panX": -5.584863670202822, "panY": -99.90831573327841 }, "savedTopologyView": { "zoom": 0.9325110211947125, "panX": -563.7108933103631, "panY": -561.6887674556383 }, "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": "globe", "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 }, "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": "hexagon", "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 }, "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" }, { "id": "custom-1765239355462", "type": "custom", "color": "#f97316", "width": 4, "lineStyle": "solid", "direction": "forward", "points": [ { "x": 2467.182861328125, "y": 156.12173461914062 }, { "x": 2146.36376953125, "y": 146.32574462890625 }, { "x": 2305.548828125, "y": 244.28573608398438 } ], "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": 2702.3789772348055, "y": 467.890869140625 }, "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": 2566.9100352578575, "y": 885.2827758789062 }, "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": 148, "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" } } }, "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-1765239331126", "x": 2454.5615234375, "y": 160.73322105407715, "content": "Google is live!", "fontSize": 56, "color": "#e2e8f0", "fontWeight": "bold", "fontStyle": "normal", "textAlign": "start", "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 } ] }, "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "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": "square", "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 } }, "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": 2103.968290880771, "y": 268 }, "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 } }, "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": "#ffffff", "circleBorder": "#ffffff" } }, "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "viewOnly": false, "defaultEdgeRouting": "curved", "animateConnections": false, "animationStyle": "arrows", "animationDirection": "all", "animationSpeed": 1.5 } } ], "currentTabIndex": 0, "encryptedSections": {}, "auditLog": [ { "timestamp": 1766459550267, "type": "export", "description": "Exported JSON: the-one-file-corporate.json", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459544255, "type": "export", "description": "Exported Markdown: the-one-file-corporate.md", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459540242, "type": "export", "description": "Exported CSV: the-one-file-corporate.csv", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459536815, "type": "export", "description": "Exported JSON: the-one-file-corporate.json", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459534490, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459525616, "type": "export", "description": "Exported CSV: the-one-file.csv", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459518367, "type": "export", "description": "Exported Markdown: the-one-file.md", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459511746, "type": "export", "description": "Exported JSON: the-one-file.json", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459504374, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459500911, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459497380, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459491436, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459483682, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459477676, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457578277, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457564726, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457564253, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766457560309, "type": "import", "description": "Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455847368, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844054, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843762, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843560, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843371, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843162, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842852, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842747, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842601, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842449, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842348, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842098, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841678, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841053, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840901, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840650, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839427, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839234, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839061, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837247, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837081, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836893, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836377, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836198, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455835455, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455834630, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831880, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831676, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831451, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830817, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830687, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830176, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830048, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829944, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829816, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378795, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378693, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378459, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378316, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378180, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378069, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377956, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377677, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377558, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377448, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377318, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377209, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090317, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090213, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090112, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090009, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453089903, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088895, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088793, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088689, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088584, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088480, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088250, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453087236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086485, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086373, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086142, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086043, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453072857, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453070975, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453054439, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453053127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052450, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052106, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051948, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051806, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051334, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453050207, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042179, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041797, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041570, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039703, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039291, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039168, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039065, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038481, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038365, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038237, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038105, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038001, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037850, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037745, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037495, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037378, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037182, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037078, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036972, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036860, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036147, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035945, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035825, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035720, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035443, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035337, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035233, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035026, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453034917, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453031063, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030955, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030833, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030732, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030225, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030104, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029968, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029796, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029474, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453024797, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766451118553, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450929324, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450817210, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450257424, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450255024, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450254395, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450253241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450251598, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450250392, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450248756, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450244072, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450242166, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450240998, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450236492, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450233672, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450232384, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450231012, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450230254, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450229302, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450228132, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446610211, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604404, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604305, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603952, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603599, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603348, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603202, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602953, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602850, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602600, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602453, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602349, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602101, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602000, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601848, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601601, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601301, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601154, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601049, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600948, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600802, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598595, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598461, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598171, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598017, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446597219, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446595278, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445633355, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445632515, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445631735, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445630757, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445627846, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445625085, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445618645, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445617784, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608998, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608720, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608540, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608376, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608204, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608038, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607852, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607678, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607506, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607319, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607154, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604410, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604244, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604066, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603900, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603743, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603563, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603406, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603226, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603052, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602880, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602641, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445576567, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445570290, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445567192, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445566766, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445565520, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445398115, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445390895, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445385694, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445383241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445382911, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445381695, "type": "edit", "description": "edit node name", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445375383, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445374665, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445373273, "type": "node", "description": "paste node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445372205, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157980, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157430, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438152691, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151948, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151286, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438146174, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438145649, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438144555, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438143655, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438142504, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438130077, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438129561, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128772, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128398, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122820, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122062, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119836, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119588, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438095045, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438093965, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438062827, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438047679, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438044161, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438041852, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039668, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039562, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039421, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039260, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039150, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039039, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438028508, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438021410, "type": "edit", "description": "toggle fov", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438019234, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438017562, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438014356, "type": "node", "description": "add node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437981696, "type": "edit", "description": "apply routing to all", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437966551, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437964879, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437963627, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961813, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961193, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437957989, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437956467, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437953437, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437952239, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437950807, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437944990, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437943699, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437935414, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437919019, "type": "zone", "description": "delete zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437917758, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437913740, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437882832, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263279163, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263270414, "type": "export", "description": "Exported JSON: the-one-file.json", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263260682, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263259518, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263249401, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263246362, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190721141, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190717499, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190710946, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190705273, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190703463, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190695709, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190688417, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402888416, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402884873, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402878108, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402866440, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402865008, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402860428, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402858103, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" } ], "savedStyleSets": [] } ================================================ FILE: demos/json-exports/theonefile-networkening-homelab-demo.json ================================================ { "nodeData": { "internet": { "shape": "square", "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 } }, "edgeData": { "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": [] } ] }, "rectData": { "list": [ { "id": "rect-1765238219615", "x": 2680.053955078125, "y": 251.44879150390625, "width": 814.10400390625, "height": 389.26678466796875, "color": "#ec0999", "style": "filled", "lineStyle": "solid", "notes": [] } ] }, "textData": { "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 } ] }, "edgeLegend": { "#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" }, "nodePositions": { "internet": { "x": 2103.968290880771, "y": 268 }, "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 } }, "nodeSizes": { "core-router-1": 36, "internet": 168, "phone": 121, "desktop": 147, "racked": 137, "docker-copy-2": 82 }, "nodeStyles": { "internet": { "all": { "icon": { "library": "selfhst", "name": "amazon-web-services" }, "circleColor": "#ffffff", "circleBorder": "#ffffff" } }, "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" } } }, "iconCache": { "selfhst-borg": "", "selfhst-actual-budget": "", "selfhst-anonaddy": "", "selfhst-adguard-home": "", "selfhst-ansible": "", "selfhst-wikidocs": "", "selfhst-alist": "", "simple-amazonwebservices": "Amazon Web Services", "simple-apple": "Apple", "selfhst-amazon-web-services": "", "selfhst-opnsense": "", "selfhst-portainer": "", "selfhst-jotty": "", "selfhst-authportal": "", "selfhst-docker": "", "selfhst-opnsense-v1": "", "mdi-server-security": "" }, "page": { "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "viewOnly": false, "defaultEdgeRouting": "curved", "animateConnections": false, "animationStyle": "arrows", "animationDirection": "all", "animationSpeed": 1.5 }, "autoPingEnabled": false, "autoPingInterval": 30, "canvas": { "zoom": 0.9921985961590549, "panX": -5.584863670202822, "panY": -99.90831573327841 }, "savedTopologyView": { "zoom": 0.9325110211947125, "panX": -563.7108933103631, "panY": -561.6887674556383 }, "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": "globe", "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 }, "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": "hexagon", "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 }, "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" }, { "id": "custom-1765239355462", "type": "custom", "color": "#f97316", "width": 4, "lineStyle": "solid", "direction": "forward", "points": [ { "x": 2467.182861328125, "y": 156.12173461914062 }, { "x": 2146.36376953125, "y": 146.32574462890625 }, { "x": 2305.548828125, "y": 244.28573608398438 } ], "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": 2702.3789772348055, "y": 467.890869140625 }, "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": 2566.9100352578575, "y": 885.2827758789062 }, "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": 148, "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" } } }, "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-1765239331126", "x": 2454.5615234375, "y": 160.73322105407715, "content": "Google is live!", "fontSize": 56, "color": "#e2e8f0", "fontWeight": "bold", "fontStyle": "normal", "textAlign": "start", "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 } ] }, "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "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": "square", "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 } }, "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": 2103.968290880771, "y": 268 }, "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 } }, "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": "#ffffff", "circleBorder": "#ffffff" } }, "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", "rackFrameStroke": "#4fd1c5", "rackLineColor": "#475569", "rackTextColor": "#4fd1c5", "rackGridEnabled": true, "viewOnly": false, "defaultEdgeRouting": "curved", "animateConnections": false, "animationStyle": "arrows", "animationDirection": "all", "animationSpeed": 1.5 } } ], "currentTabIndex": 1, "encryptedSections": {}, "auditLog": [ { "timestamp": 1766459504374, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459500911, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459497380, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766459491436, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459483682, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766459477676, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457578277, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457564726, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766457564253, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766457560309, "type": "import", "description": "Imported JSON: the-one-file-corporate.json (107 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455847368, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455844054, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843762, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843560, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843371, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455843162, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842852, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842747, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842601, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842449, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842348, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455842098, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841678, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455841053, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840901, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455840650, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839427, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839234, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455839061, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837247, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455837081, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836893, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836377, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455836198, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455835455, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455834630, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831880, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831676, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455831451, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830817, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830687, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830176, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455830048, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829944, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455829816, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378795, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378693, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378459, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378316, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378180, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455378069, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377956, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377677, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377558, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377448, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377318, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766455377209, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090534, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090317, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090213, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090112, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453090009, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453089903, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088895, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088793, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088689, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088584, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088480, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453088250, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453087236, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086485, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086373, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086142, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453086043, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453072857, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453070975, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453054439, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453053127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052450, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453052106, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051948, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051806, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453051334, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453050207, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042725, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453042179, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041797, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453041570, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039703, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039291, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039168, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453039065, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038481, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038365, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038237, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038105, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453038001, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037850, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037745, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037495, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037378, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037182, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453037078, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036972, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036860, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453036147, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035945, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035825, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035720, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035443, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035337, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035233, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035127, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453035026, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453034917, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453031063, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030955, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030833, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030732, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030225, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453030104, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029968, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029796, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453029474, "type": "edit", "description": "rotate text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766453024797, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766451118553, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450929324, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450817210, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450257424, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450255024, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450254395, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450253241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450251598, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450250392, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450248756, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450244072, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450242166, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450240998, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450236492, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450233672, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450232384, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450231012, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450230254, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450229302, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766450228132, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446610211, "type": "text", "description": "paste text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604404, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604305, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446604099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603952, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603849, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603599, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603348, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603202, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446603099, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602953, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602850, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602600, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602453, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602349, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602204, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602101, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446602000, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601848, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601702, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601601, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601452, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601301, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601154, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446601049, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600948, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600802, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446600550, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598595, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598461, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598171, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446598017, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446597219, "type": "text", "description": "edit text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766446595278, "type": "text", "description": "add text", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445633355, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445632515, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445631735, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445630757, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445627846, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445625085, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445618645, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445617784, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608998, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608720, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608540, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608376, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608204, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445608038, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607852, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607678, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607506, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607319, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445607154, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604410, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604244, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445604066, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603900, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603743, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603563, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603406, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603226, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445603052, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602880, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445602641, "type": "edit", "description": "edit zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445576567, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445570290, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445567192, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445566766, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445565520, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445398115, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445390895, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445385694, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445383241, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445382911, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445381695, "type": "edit", "description": "edit node name", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445375383, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445374665, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445373273, "type": "node", "description": "paste node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766445372205, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157980, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438157430, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438152691, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151948, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438151286, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438146174, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438145649, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438144555, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438143655, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438142504, "type": "edit", "description": "edit edge animation speed", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438130077, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438129561, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128772, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438128398, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122820, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438122062, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119836, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438119588, "type": "edit", "description": "edit edge animate", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438095045, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438093965, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438062827, "type": "edit", "description": "toggle fov animation", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438047679, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438044161, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438041852, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039668, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039562, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039421, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039260, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039150, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438039039, "type": "edit", "description": "resize node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438028508, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438021410, "type": "edit", "description": "toggle fov", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438019234, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438017562, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766438014356, "type": "node", "description": "add node", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437981696, "type": "edit", "description": "apply routing to all", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437966551, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437964879, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437963627, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961813, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437961193, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437957989, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437956467, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437953437, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437952239, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437950807, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437944990, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437943699, "type": "node", "description": "move nodes", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437935414, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437919019, "type": "zone", "description": "delete zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437917758, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437913740, "type": "zone", "description": "draw zone", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766437882832, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263279163, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263270414, "type": "export", "description": "Exported JSON: the-one-file.json", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263260682, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263259518, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766263249401, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766263246362, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190721141, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190717499, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190710946, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190705273, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190703463, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1766190695709, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1766190688417, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402888416, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402884873, "type": "tab", "description": "Switched to tab: Corporate Site B", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402878108, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402866440, "type": "save", "description": "File saved: the-one-file.html", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402865008, "type": "tab", "description": "Switched to tab: Homelab 2", "details": {}, "tab": "Homelab 2" }, { "timestamp": 1765402860428, "type": "save", "description": "File saved: the-one-file-corporate.html", "details": {}, "tab": "Corporate Site B" }, { "timestamp": 1765402858103, "type": "import", "description": "Imported JSON: theonefile-networkening-corporate-demo.json (105 nodes, 65 connections)", "details": {}, "tab": "Corporate Site B" } ], "savedStyleSets": [] } ================================================ FILE: demos/markdown-exports/the-one-file-corporate.md ================================================ # The One File Corporate > Exported from The One File on 2025-12-23T03:10:10.065Z ## 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 ## Nodes ### core-router-1 - **Name:** Core Router 1 - **IP:** 10.0.0.1 - **Role:** Core Routing - **Shape:** router - **Tags:** core; tier-1; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3720, 246 - **Size:** 50 - **Notes:** - Primary core router - BGP peering enabled - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"borg"}}}` ### core-router-2 - **Name:** Core Router 2 - **IP:** 10.0.0.2 - **Role:** Core Routing - **Shape:** router - **Tags:** core; tier-1; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2500, 330 - **Size:** 120 - **Notes:** - Secondary core router - HSRP standby - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"actual-budget"},"pingOffsetX":-15,"pingOffsetY":-38}}` ### fw-external-1 - **Name:** External FW 1 - **IP:** 10.0.1.1 - **Role:** Perimeter Security - **Shape:** firewall - **Tags:** security; perimeter; ha-pair - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:10 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3222, 1016 - **Size:** 50 - **Notes:** - Palo Alto PA-5250 - Active node - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"anonaddy"}}}` ### fw-external-2 - **Name:** External FW 2 - **IP:** 10.0.1.2 - **Role:** Perimeter Security - **Shape:** firewall - **Tags:** security; perimeter; ha-pair - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:11 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1916, 224 - **Size:** 50 - **Notes:** - Palo Alto PA-5250 - Passive node ### fw-internal - **Name:** Internal FW - **IP:** 10.0.2.1 - **Role:** Internal Segmentation - **Shape:** firewall - **Tags:** security; internal - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:12 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1747, 478 - **Size:** 50 - **Notes:** - East-West traffic inspection ### core-switch-1 - **Name:** Core Switch 1 - **IP:** 10.0.10.1 - **Role:** Core Switching - **Shape:** switch - **Tags:** core; layer3; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:20 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 449, 384 - **Size:** 50 - **Notes:** - Cisco Nexus 9000 - VPC Domain 1 ### core-switch-2 - **Name:** Core Switch 2 - **IP:** 10.0.10.2 - **Role:** Core Switching - **Shape:** switch - **Tags:** core; layer3; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:21 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 761, 181 - **Size:** 50 - **Notes:** - Cisco Nexus 9000 - VPC Domain 1 ### dc-rack-a1 - **Name:** DC Rack A1 - **IP:** 10.10.0.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-a; production - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 784, 647 - **Size:** 50 - **Notes:** - Row A, Position 1 - Primary compute - **Styles:** `{"all":{"circleColor":"#ff0000"}}` ### dc-rack-a2 - **Name:** DC Rack A2 - **IP:** 10.10.1.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-a; production - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 209, 228 - **Size:** 50 - **Notes:** - Row A, Position 2 - Primary compute ### dc-rack-b1 - **Name:** DC Rack B1 - **IP:** 10.10.2.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-b; storage - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 3184, 1627 - **Size:** 50 - **Notes:** - Row B, Position 1 - Storage systems - **Styles:** `{"all":{"circleColor":"#ff0000","titleSize":59}}` ### dc-rack-b2 - **Name:** DC Rack B2 - **IP:** 10.10.3.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-b; storage - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 245, 500 - **Size:** 50 - **Notes:** - Row B, Position 2 - Storage systems - **Styles:** `{"all":{"circleColor":"#ff0000"}}` ### dmz-rack - **Name:** DMZ Rack - **IP:** 172.16.0.0/24 - **Role:** DMZ Infrastructure - **Shape:** server - **Tags:** dmz; security; public-facing; [object Object]; [object Object] - **Layer:** security - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 24 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 2176, 611 - **Size:** 50 - **Notes:** - Isolated DMZ zone - Public-facing services ### mgmt-rack - **Name:** Management Rack - **IP:** 192.168.100.0/24 - **Role:** Management Infrastructure - **Shape:** server - **Tags:** management; oob; noc - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 24 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 1601, 1281 - **Size:** 50 - **Notes:** - Out-of-band management - NOC equipment ### esxi-host-01 - **Name:** ESXi Host 01 - **IP:** 10.10.0.11 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:01 - **Rack Unit:** 38 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2162, 2608 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-02 - **Name:** ESXi Host 02 - **IP:** 10.10.0.12 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:02 - **Rack Unit:** 35 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2206, 2690 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-03 - **Name:** ESXi Host 03 - **IP:** 10.10.0.13 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:03 - **Rack Unit:** 32 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2155, 2771 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-04 - **Name:** ESXi Host 04 - **IP:** 10.10.0.14 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:04 - **Rack Unit:** 29 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2196, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### tor-switch-a1 - **Name:** ToR Switch A1 - **IP:** 10.10.0.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-a1 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:01 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2147, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX - 48x25G ports ### esxi-host-05 - **Name:** ESXi Host 05 - **IP:** 10.10.1.11 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:01 - **Rack Unit:** 38 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2186, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-06 - **Name:** ESXi Host 06 - **IP:** 10.10.1.12 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:02 - **Rack Unit:** 35 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2139, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-07 - **Name:** ESXi Host 07 - **IP:** 10.10.1.13 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:03 - **Rack Unit:** 32 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2176, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-08 - **Name:** ESXi Host 08 - **IP:** 10.10.1.14 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:04 - **Rack Unit:** 29 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2131, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### tor-switch-a2 - **Name:** ToR Switch A2 - **IP:** 10.10.1.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-a2 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:02 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2165, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX - 48x25G ports ### san-primary - **Name:** SAN Primary - **IP:** 10.10.2.10 - **Role:** Primary Storage - **Shape:** database - **Tags:** storage; san; netapp - **Layer:** physical - **MAC:** 00:A0:98:AA:01:01 - **Rack Unit:** 36 - **U Height:** 6 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2123, 2845 - **Size:** 50 - **Notes:** - NetApp AFF A400 - 500TB Raw - FC 32Gb ### san-secondary - **Name:** SAN Secondary - **IP:** 10.10.2.11 - **Role:** Secondary Storage - **Shape:** database - **Tags:** storage; san; netapp - **Layer:** physical - **MAC:** 00:A0:98:AA:01:02 - **Rack Unit:** 28 - **U Height:** 6 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2155, 2845 - **Size:** 50 - **Notes:** - NetApp AFF A400 - 500TB Raw - FC 32Gb ### fc-switch-1 - **Name:** FC Switch 1 - **IP:** 10.10.2.1 - **Role:** Fibre Channel - **Shape:** switch - **Tags:** storage; fc; fabric-a - **Layer:** physical - **MAC:** 00:1A:2B:FC:01:01 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2115, 2845 - **Size:** 50 - **Notes:** - Brocade G620 - Fabric A ### fc-switch-2 - **Name:** FC Switch 2 - **IP:** 10.10.2.2 - **Role:** Fibre Channel - **Shape:** switch - **Tags:** storage; fc; fabric-b - **Layer:** physical - **MAC:** 00:1A:2B:FC:01:02 - **Rack Unit:** 41 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2145, 2845 - **Size:** 50 - **Notes:** - Brocade G620 - Fabric B ### backup-server-1 - **Name:** Backup Server 1 - **IP:** 10.10.3.10 - **Role:** Backup Infrastructure - **Shape:** server - **Tags:** backup; veeam; protection - **Layer:** physical - **MAC:** 00:50:56:BB:01:01 - **Rack Unit:** 36 - **U Height:** 2 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2107, 2845 - **Size:** 50 - **Notes:** - Veeam Backup Server - Dell R740xd - 200TB ### backup-server-2 - **Name:** Backup Server 2 - **IP:** 10.10.3.11 - **Role:** Backup Infrastructure - **Shape:** server - **Tags:** backup; veeam; protection - **Layer:** physical - **MAC:** 00:50:56:BB:01:02 - **Rack Unit:** 33 - **U Height:** 2 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2134, 2845 - **Size:** 50 - **Notes:** - Veeam Backup Server - Dell R740xd - 200TB ### tape-library - **Name:** Tape Library - **IP:** 10.10.3.20 - **Role:** Archival Storage - **Shape:** database - **Tags:** backup; tape; lto9 - **Layer:** physical - **MAC:** 00:50:56:BB:02:01 - **Rack Unit:** 20 - **U Height:** 10 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2099, 2845 - **Size:** 50 - **Notes:** - IBM TS4500 - LTO-9 - Long-term archive ### tor-switch-b1 - **Name:** ToR Switch B1 - **IP:** 10.10.2.3 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-b1 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:03 - **Rack Unit:** 40 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2123, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX ### tor-switch-b2 - **Name:** ToR Switch B2 - **IP:** 10.10.3.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-b2 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:04 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2091, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX ### web-server-1 - **Name:** Web Server 1 - **IP:** 172.16.0.11 - **Role:** Web Frontend - **Shape:** server - **Tags:** dmz; web; nginx - **Layer:** security - **MAC:** 00:50:56:CC:01:01 - **Rack Unit:** 20 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2113, 2845 - **Size:** 50 - **Notes:** - NGINX reverse proxy - Public facing ### web-server-2 - **Name:** Web Server 2 - **IP:** 172.16.0.12 - **Role:** Web Frontend - **Shape:** server - **Tags:** dmz; web; nginx - **Layer:** security - **MAC:** 00:50:56:CC:01:02 - **Rack Unit:** 18 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2082, 2845 - **Size:** 50 - **Notes:** - NGINX reverse proxy - Public facing ### waf-1 - **Name:** WAF Appliance - **IP:** 172.16.0.5 - **Role:** Web Application Firewall - **Shape:** firewall - **Tags:** dmz; security; waf - **Layer:** security - **MAC:** 00:50:56:CC:02:01 - **Rack Unit:** 22 - **U Height:** 2 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2102, 2845 - **Size:** 50 - **Notes:** - F5 BIG-IP ASM - OWASP protection ### load-balancer-dmz - **Name:** DMZ Load Balancer - **IP:** 172.16.0.3 - **Role:** Load Balancing - **Shape:** switch - **Tags:** dmz; lb; f5 - **Layer:** security - **MAC:** 00:50:56:CC:03:01 - **Rack Unit:** 16 - **U Height:** 2 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2074, 2845 - **Size:** 50 - **Notes:** - F5 BIG-IP LTM - VIP: 172.16.0.100 ### mail-gateway - **Name:** Mail Gateway - **IP:** 172.16.0.25 - **Role:** Email Security - **Shape:** server - **Tags:** dmz; email; security - **Layer:** security - **MAC:** 00:50:56:CC:04:01 - **Rack Unit:** 14 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2091, 2845 - **Size:** 50 - **Notes:** - Proofpoint Email Gateway - Spam/malware filtering ### dns-external-1 - **Name:** External DNS 1 - **IP:** 172.16.0.53 - **Role:** External DNS - **Shape:** circle - **Tags:** dmz; dns; public - **Layer:** security - **MAC:** 00:50:56:CC:05:01 - **Rack Unit:** 12 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2066, 2845 - **Size:** 50 - **Notes:** - BIND DNS - Authoritative for corp.com ### dns-external-2 - **Name:** External DNS 2 - **IP:** 172.16.0.54 - **Role:** External DNS - **Shape:** circle - **Tags:** dmz; dns; public - **Layer:** security - **MAC:** 00:50:56:CC:05:02 - **Rack Unit:** 10 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2080, 2845 - **Size:** 50 - **Notes:** - BIND DNS - Secondary for corp.com ### vcenter - **Name:** vCenter Server - **IP:** 192.168.100.10 - **Role:** Virtualization Management - **Shape:** server - **Tags:** management; vmware; vcsa - **Layer:** logical - **MAC:** 00:50:56:DD:01:01 - **Rack Unit:** 20 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2057, 2845 - **Size:** 50 - **Notes:** - vCenter Server Appliance 8.0 - Single SSO domain ### nsx-manager - **Name:** NSX Manager - **IP:** 192.168.100.15 - **Role:** Network Virtualization - **Shape:** server - **Tags:** management; vmware; nsx - **Layer:** logical - **MAC:** 00:50:56:DD:02:01 - **Rack Unit:** 17 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2069, 2845 - **Size:** 50 - **Notes:** - NSX-T 4.1 Manager Cluster ### siem-server - **Name:** SIEM Server - **IP:** 192.168.100.50 - **Role:** Security Monitoring - **Shape:** server - **Tags:** management; security; splunk - **Layer:** logical - **MAC:** 00:50:56:DD:03:01 - **Rack Unit:** 14 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2049, 2845 - **Size:** 50 - **Notes:** - Splunk Enterprise - Security monitoring ### nms-server - **Name:** Network Monitoring - **IP:** 192.168.100.60 - **Role:** Network Management - **Shape:** server - **Tags:** management; monitoring; prtg - **Layer:** logical - **MAC:** 00:50:56:DD:04:01 - **Rack Unit:** 11 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2058, 2845 - **Size:** 50 - **Notes:** - PRTG Network Monitor - 5000 sensors ### jump-server - **Name:** Jump Server - **IP:** 192.168.100.100 - **Role:** Bastion Host - **Shape:** server - **Tags:** management; security; bastion - **Layer:** logical - **MAC:** 00:50:56:DD:05:01 - **Rack Unit:** 9 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2040, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - MFA enabled ### ipam-server - **Name:** IPAM/DDI - **IP:** 192.168.100.70 - **Role:** IP Management - **Shape:** server - **Tags:** management; dns; dhcp - **Layer:** logical - **MAC:** 00:50:56:DD:06:01 - **Rack Unit:** 7 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2047, 2845 - **Size:** 50 - **Notes:** - Infoblox DDI - DNS/DHCP/IPAM ### wlc-primary - **Name:** WLC Primary - **IP:** 10.20.0.1 - **Role:** Wireless Controller - **Shape:** wifi - **Tags:** wireless; cisco; 9800 - **Layer:** physical - **MAC:** 00:1A:2B:WL:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1576, 2306 - **Size:** 50 - **Notes:** - Cisco C9800-40 - Primary controller ### wlc-secondary - **Name:** WLC Secondary - **IP:** 10.20.0.2 - **Role:** Wireless Controller - **Shape:** wifi - **Tags:** wireless; cisco; 9800 - **Layer:** physical - **MAC:** 00:1A:2B:WL:01:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1468, 1564 - **Size:** 50 - **Notes:** - Cisco C9800-40 - HA Secondary ### mobile-zone-hq - **Name:** HQ Mobile Zone - **IP:** 10.20.10.0/24 - **Role:** Mobile Device Zone - **Shape:** phone - **Tags:** wireless; byod; mobile - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2355, 2806 - **Size:** 50 - **Notes:** - Corporate BYOD - MDM enrolled devices ### mobile-zone-guest - **Name:** Guest WiFi Zone - **IP:** 10.30.0.0/24 - **Role:** Guest Network - **Shape:** phone - **Tags:** wireless; guest; isolated - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2308, 2611 - **Size:** 50 - **Notes:** - Captive portal - Internet only ### mobile-zone-iot - **Name:** IoT Device Zone - **IP:** 10.40.0.0/24 - **Role:** IoT Network - **Shape:** phone - **Tags:** wireless; iot; building - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2229, 2299 - **Size:** 50 - **Notes:** - Building automation - Smart devices ### branch-router-ny - **Name:** NYC Branch Router - **IP:** 10.100.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; nyc; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3152, 634 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-la - **Name:** LA Branch Router - **IP:** 10.101.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; la; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3084, 507 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-chi - **Name:** Chicago Branch Router - **IP:** 10.102.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; chicago; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3355, 393 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-lon - **Name:** London Branch Router - **IP:** 10.200.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; london; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3114, 260 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - EMEA region ### branch-router-tokyo - **Name:** Tokyo Branch Router - **IP:** 10.201.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; tokyo; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:05:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3699, 471 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - APAC region - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"adguard-home"}}}` ### cloud-aws - **Name:** AWS Cloud - **IP:** vpc-0a1b2c3d - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; aws; hybrid - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3437, 546 - **Size:** 50 - **Notes:** - AWS US-East-1 - VPC peering to HQ - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"ansible"}}}` ### cloud-azure - **Name:** Azure Cloud - **IP:** vnet-corp-prod - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; azure; hybrid - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2593, 2724 - **Size:** 50 - **Notes:** - Azure East US 2 - ExpressRoute ### cloud-gcp - **Name:** GCP Cloud - **IP:** vpc-gcp-corp - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; gcp; dev - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2827, 2731 - **Size:** 50 - **Notes:** - GCP us-central1 - Dev/Test workloads ### isp-primary - **Name:** ISP Primary - **IP:** 203.0.113.1 - **Role:** Internet Uplink - **Shape:** globe - **Tags:** wan; internet; primary - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3712, 616 - **Size:** 50 - **Notes:** - AT&T MPLS - 1 Gbps dedicated - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"wikidocs"}}}` ### isp-secondary - **Name:** ISP Secondary - **IP:** 198.51.100.1 - **Role:** Internet Uplink - **Shape:** vm - **Tags:** wan; internet; backup - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3254, 1993 - **Size:** 139 - **Notes:** - Verizon Business - 500 Mbps backup - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"alist"},"circleColor":"#4d2c58","circleBorder":"#000000","titleColor":"#006eff"}}` ### dc-internal-1 - **Name:** DC1 Int DNS - **IP:** 10.10.0.53 - **Role:** Internal DNS/AD - **Shape:** circle - **Tags:** dns; ad; dc1 - **Layer:** physical - **MAC:** 00:50:56:AD:01:01 - **Rack Unit:** 26 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1958, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - Primary DC ### dc-internal-2 - **Name:** DC2 Int DNS - **IP:** 10.10.1.53 - **Role:** Internal DNS/AD - **Shape:** circle - **Tags:** dns; ad; dc2 - **Layer:** physical - **MAC:** 00:50:56:AD:01:02 - **Rack Unit:** 26 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1964, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - Secondary DC ### app-server-1 - **Name:** App Server 01 - **IP:** 10.10.0.101 - **Role:** Application - **Shape:** server - **Tags:** app; iis; web - **Layer:** physical - **MAC:** 00:50:56:AP:01:01 - **Rack Unit:** 24 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1947, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - IIS Application ### app-server-2 - **Name:** App Server 02 - **IP:** 10.10.0.102 - **Role:** Application - **Shape:** server - **Tags:** app; iis; web - **Layer:** physical - **MAC:** 00:50:56:AP:01:02 - **Rack Unit:** 22 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1955, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - IIS Application ### db-server-1 - **Name:** SQL Server 01 - **IP:** 10.10.0.201 - **Role:** Database - **Shape:** database - **Tags:** db; sql; primary - **Layer:** physical - **MAC:** 00:50:56:DB:01:01 - **Rack Unit:** 20 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1936, 2845 - **Size:** 50 - **Notes:** - SQL Server 2022 Enterprise - AlwaysOn Primary ### db-server-2 - **Name:** SQL Server 02 - **IP:** 10.10.1.201 - **Role:** Database - **Shape:** database - **Tags:** db; sql; secondary - **Layer:** physical - **MAC:** 00:50:56:DB:01:02 - **Rack Unit:** 24 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1947, 2845 - **Size:** 50 - **Notes:** - SQL Server 2022 Enterprise - AlwaysOn Secondary ### k8s-master-1 - **Name:** K8s Master 1 - **IP:** 10.10.1.50 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:01 - **Rack Unit:** 21 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1925, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-master-2 - **Name:** K8s Master 2 - **IP:** 10.10.1.51 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:02 - **Rack Unit:** 19 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1938, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-master-3 - **Name:** K8s Master 3 - **IP:** 10.10.1.52 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:03 - **Rack Unit:** 17 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1914, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-worker-1 - **Name:** K8s Worker 1 - **IP:** 10.10.1.60 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:01 - **Rack Unit:** 15 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1930, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-2 - **Name:** K8s Worker 2 - **IP:** 10.10.1.61 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:02 - **Rack Unit:** 13 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1904, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-3 - **Name:** K8s Worker 3 - **IP:** 10.10.1.62 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:03 - **Rack Unit:** 11 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1922, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-4 - **Name:** K8s Worker 4 - **IP:** 10.10.1.63 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:04 - **Rack Unit:** 9 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1893, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### proxy-server-1 - **Name:** Proxy Server 1 - **IP:** 10.5.0.10 - **Role:** Web Proxy - **Shape:** server - **Tags:** proxy; squid; filtering - **Layer:** security - **MAC:** 00:50:56:PX:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1806, 654 - **Size:** 50 - **Notes:** - Squid Proxy - Content filtering ### proxy-server-2 - **Name:** Proxy Server 2 - **IP:** 10.5.0.11 - **Role:** Web Proxy - **Shape:** server - **Tags:** proxy; squid; filtering - **Layer:** security - **MAC:** 00:50:56:PX:01:02 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2937, 2629 - **Size:** 50 - **Notes:** - Squid Proxy - HA pair ### vpn-concentrator - **Name:** VPN Concentrator - **IP:** 10.0.5.1 - **Role:** Remote Access VPN - **Shape:** firewall - **Tags:** vpn; remote; security - **Layer:** security - **MAC:** 00:1A:2B:VP:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3642, 947 - **Size:** 50 - **Notes:** - Cisco ASA 5555-X - AnyConnect SSL VPN ### nac-server - **Name:** NAC Server - **IP:** 10.5.5.10 - **Role:** Network Access Control - **Shape:** server - **Tags:** nac; ise; 802.1x - **Layer:** security - **MAC:** 00:50:56:NA:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1153, 1172 - **Size:** 50 - **Notes:** - Cisco ISE 3.1 - RADIUS/TACACS+ ### print-server - **Name:** Print Server - **IP:** 10.10.0.150 - **Role:** Print Services - **Shape:** server - **Tags:** print; windows; services - **Layer:** physical - **MAC:** 00:50:56:PR:01:01 - **Rack Unit:** 18 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1897, 2845 - **Size:** 50 - **Notes:** - Windows Print Server - 50+ printers ### file-server - **Name:** File Server - **IP:** 10.10.0.160 - **Role:** File Services - **Shape:** database - **Tags:** file; smb; dfs - **Layer:** physical - **MAC:** 00:50:56:FS:01:01 - **Rack Unit:** 16 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1861, 2845 - **Size:** 50 - **Notes:** - Windows File Server - DFS namespace ### ca-server - **Name:** Certificate Authority - **IP:** 192.168.100.80 - **Role:** PKI Infrastructure - **Shape:** server - **Tags:** pki; ca; security - **Layer:** logical - **MAC:** 00:50:56:CA:01:01 - **Rack Unit:** 5 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1889, 2845 - **Size:** 50 - **Notes:** - Windows CA - Enterprise Root CA ### sccm-server - **Name:** SCCM Server - **IP:** 192.168.100.90 - **Role:** Endpoint Management - **Shape:** server - **Tags:** sccm; patching; software - **Layer:** logical - **MAC:** 00:50:56:SC:01:01 - **Rack Unit:** 3 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1850, 2845 - **Size:** 50 - **Notes:** - MECM Primary Site - Software deployment ### voip-cluster - **Name:** VoIP Cluster - **IP:** 10.50.0.0/24 - **Role:** Voice Services - **Shape:** phone - **Tags:** voip; cisco; ucm - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1777, 1617 - **Size:** 50 - **Notes:** - Cisco UCM Cluster - 3000 endpoints ### video-conf - **Name:** Video Conference - **IP:** 10.51.0.0/24 - **Role:** Video Services - **Shape:** laptop - **Tags:** video; webex; teams - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1994, 2245 - **Size:** 50 - **Notes:** - Webex/Teams integration - Meeting rooms ### security-cameras - **Name:** Security Cameras - **IP:** 10.60.0.0/24 - **Role:** Physical Security - **Shape:** camera - **Tags:** cctv; surveillance; security - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1674, 2046 - **Size:** 50 - **Notes:** - 150+ IP cameras - 30-day retention ### nvr-cluster - **Name:** NVR Cluster - **IP:** 10.60.0.10 - **Role:** Video Recording - **Shape:** server - **Tags:** nvr; surveillance; storage - **Layer:** physical - **MAC:** 00:50:56:NV:01:01 - **Rack Unit:** 15 - **U Height:** 4 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1829, 2845 - **Size:** 50 - **Notes:** - Milestone XProtect - 500TB storage ### dev-server-1 - **Name:** Dev Server 1 - **IP:** 10.80.0.10 - **Role:** Development - **Shape:** server - **Tags:** dev; gitlab; ci-cd; [object Object] - **Layer:** application - **MAC:** 00:50:56:DV:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2801, 1176 - **Size:** 128 - **Notes:** - GitLab Server - CI/CD pipelines - **Styles:** `{"all":{"icon":{"library":"simple","name":"amazonwebservices"}}}` ### dev-server-2 - **Name:** Dev Server 2 - **IP:** 10.80.0.11 - **Role:** Development - **Shape:** server - **Tags:** dev; jenkins; ci-cd - **Layer:** application - **MAC:** 00:50:56:DV:01:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1945, 1165 - **Size:** 50 - **Notes:** - Jenkins Server - Build automation ### test-environment - **Name:** Test Environment - **IP:** 10.81.0.0/24 - **Role:** QA/Testing - **Shape:** shield - **Tags:** test; qa; staging - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2932, 862 - **Size:** 121 - **Notes:** - Staging environment - Pre-prod validation - **Styles:** `{"all":{"icon":{"library":"simple","name":"apple"}}}` ### erp-system - **Name:** ERP System - **IP:** 10.90.0.10 - **Role:** Business Application - **Shape:** database - **Tags:** erp; sap; business - **Layer:** application - **MAC:** 00:50:56:ER:01:01 - **Rack Unit:** - **U Height:** 4 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 790, 474 - **Size:** 50 - **Notes:** - SAP S/4HANA - Financial/HR systems ### crm-system - **Name:** CRM System - **IP:** 10.91.0.10 - **Role:** Business Application - **Shape:** database - **Tags:** crm; salesforce; business - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3515, 1138 - **Size:** 50 - **Notes:** - Salesforce integration - Sales/Marketing ### endpoint-1000 - **Name:** Corporate Endpoints - **IP:** 10.70.0.0/22 - **Role:** User Workstations - **Shape:** laptop - **Tags:** endpoints; workstations; users - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 992, 2284 - **Size:** 50 - **Notes:** - ~1000 corporate laptops - Windows 11 ### dist-switch-floor1 - **Name:** Floor 1 Switch - **IP:** 10.1.1.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-1; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 654, 2020 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor2 - **Name:** Floor 2 Switch - **IP:** 10.1.2.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-2; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 854, 1843 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor3 - **Name:** Floor 3 Switch - **IP:** 10.1.3.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-3; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1899, 1457 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor4 - **Name:** Floor 4 Switch - **IP:** 10.1.4.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-4; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 489, 181 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### ap-floor1-zone1 - **Name:** AP Floor 1 Zone 1 - **IP:** 10.20.1.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-1 - **Layer:** physical - **MAC:** 00:1A:2B:AP:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1140, 2070 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor2-zone1 - **Name:** AP Floor 2 Zone 1 - **IP:** 10.20.2.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-2 - **Layer:** physical - **MAC:** 00:1A:2B:AP:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 688, 2384 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor3-zone1 - **Name:** AP Floor 3 Zone 1 - **IP:** 10.20.3.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-3 - **Layer:** physical - **MAC:** 00:1A:2B:AP:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2145, 1890 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor4-zone1 - **Name:** AP Floor 4 Zone 1 - **IP:** 10.20.4.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-4 - **Layer:** physical - **MAC:** 00:1A:2B:AP:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 518, 566 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ups-dc-1 - **Name:** UPS DC-1 - **IP:** 192.168.200.10 - **Role:** Power Management - **Shape:** rectangle - **Tags:** power; ups; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 771, 296 - **Size:** 50 - **Notes:** - APC Symmetra - 80kVA - 30 min runtime ### ups-dc-2 - **Name:** UPS DC-2 - **IP:** 192.168.200.11 - **Role:** Power Management - **Shape:** rectangle - **Tags:** power; ups; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 216, 330 - **Size:** 50 - **Notes:** - APC Symmetra - 80kVA - Redundant ### pdu-rack-a1 - **Name:** PDU Rack A1 - **IP:** 192.168.200.21 - **Role:** Power Distribution - **Shape:** rectangle - **Tags:** power; pdu; rack-a1 - **Layer:** physical - **MAC:** - **Rack Unit:** 1 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1805, 2845 - **Size:** 50 - **Notes:** - APC Switched PDU - Per-outlet metering ### pdu-rack-a2 - **Name:** PDU Rack A2 - **IP:** 192.168.200.22 - **Role:** Power Distribution - **Shape:** rectangle - **Tags:** power; pdu; rack-a2 - **Layer:** physical - **MAC:** - **Rack Unit:** 1 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1742, 2845 - **Size:** 50 - **Notes:** - APC Switched PDU - Per-outlet metering ### cooling-1 - **Name:** CRAC Unit 1 - **IP:** 192.168.200.30 - **Role:** Cooling - **Shape:** rectangle - **Tags:** cooling; hvac; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 246, 626 - **Size:** 50 - **Notes:** - Liebert CRV - Row-based cooling ### cooling-2 - **Name:** CRAC Unit 2 - **IP:** 192.168.200.31 - **Role:** Cooling - **Shape:** rectangle - **Tags:** cooling; hvac; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1603, 981 - **Size:** 50 - **Notes:** - Liebert CRV - N+1 redundancy ### camera-a - **Name:** camera A - **IP:** 0.0.0.0 - **Role:** - **Shape:** camera - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 167, 145 - **Size:** 45 ### camera-a-copy - **Name:** camera B - **IP:** 0.0.0.0 - **Role:** - **Shape:** camera - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1041, 738 - **Size:** 45 ## Connections - isp-primary (Gi0/0) --> core-router-1 (Gi1/0/1) - **ID:** isp1-router1 - **Label:** - **Color:** #10b981 - **Width:** 6 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Primary WAN link - isp-secondary (Gi0/0) --> core-router-2 (Gi1/0/1) - **ID:** isp2-router2 - **Label:** - **Color:** #10b981 - **Width:** 6 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Backup WAN link - core-router-1 (Gi1/0/24) --> core-router-2 (Gi1/0/24) - **ID:** router1-router2 - **Label:** - **Color:** #f59e0b - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - HSRP Peering - core-router-1 --> fw-external-1 - **ID:** router1-fw1 - **Label:** - **Color:** #ef4444 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-router-2 --> fw-external-2 - **ID:** router2-fw2 - **Label:** - **Color:** #ef4444 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> fw-external-2 - **ID:** fw1-fw2 - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - HA heartbeat - fw-external-1 --> core-switch-1 - **ID:** fw1-coresw1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-2 --> core-switch-2 - **ID:** fw2-coresw2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> core-switch-2 - **ID:** coresw1-coresw2 - **Label:** - **Color:** #3b82f6 - **Width:** 5 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - VPC peer-link - core-switch-1 --> fw-internal - **ID:** coresw1-fwint - **Label:** - **Color:** #ef4444 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> fw-internal - **ID:** coresw2-fwint - **Label:** - **Color:** #ef4444 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-a1 - **ID:** coresw1-racka1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-a1 - **ID:** coresw2-racka1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-a2 - **ID:** coresw1-racka2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-a2 - **ID:** coresw2-racka2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-b1 - **ID:** coresw1-rackb1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-b1 - **ID:** coresw2-rackb1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-b2 - **ID:** coresw1-rackb2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-b2 - **ID:** coresw2-rackb2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> dmz-rack - **ID:** fw1-dmz - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - DMZ segment - fw-external-2 --> dmz-rack - **ID:** fw2-dmz - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - DMZ segment - core-switch-1 --> mgmt-rack - **ID:** coresw1-mgmt - **Label:** - **Color:** #8b5cf6 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - OOB management - core-switch-1 --> wlc-primary - **ID:** coresw1-wlc1 - **Label:** - **Color:** #06b6d4 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> wlc-secondary - **ID:** coresw2-wlc2 - **Label:** - **Color:** #06b6d4 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> wlc-secondary - **ID:** wlc1-wlc2 - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - HA pair - wlc-primary --> mobile-zone-hq - **ID:** wlc1-mobile-hq - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> mobile-zone-guest - **ID:** wlc1-mobile-guest - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> mobile-zone-iot - **ID:** wlc1-mobile-iot - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-router-1 --> branch-router-ny - **ID:** router1-branch-ny - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-la - **ID:** router1-branch-la - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-chi - **ID:** router1-branch-chi - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-lon - **ID:** router1-branch-lon - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-tokyo - **ID:** router1-branch-tokyo - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> cloud-aws - **ID:** router1-aws - **Label:** - **Color:** #f97316 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - Direct Connect - core-router-2 --> cloud-azure - **ID:** router2-azure - **Label:** - **Color:** #0ea5e9 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - ExpressRoute - fw-internal --> cloud-gcp - **ID:** fwint-gcp - **Label:** - **Color:** #22c55e - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - VPN tunnel - core-switch-1 --> dist-switch-floor1 - **ID:** coresw1-floor1 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dist-switch-floor2 - **ID:** coresw1-floor2 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dist-switch-floor3 - **ID:** coresw2-floor3 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dist-switch-floor4 - **ID:** coresw2-floor4 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor1 --> endpoint-1000 - **ID:** floor1-endpoints - **Label:** - **Color:** #94a3b8 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor1 --> ap-floor1-zone1 - **ID:** floor1-ap1 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor2 --> ap-floor2-zone1 - **ID:** floor2-ap2 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor3 --> ap-floor3-zone1 - **ID:** floor3-ap3 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor4 --> ap-floor4-zone1 - **ID:** floor4-ap4 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> proxy-server-1 - **ID:** fwint-proxy1 - **Label:** - **Color:** #ef4444 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> proxy-server-2 - **ID:** fwint-proxy2 - **Label:** - **Color:** #ef4444 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> vpn-concentrator - **ID:** fwext1-vpn - **Label:** - **Color:** #8b5cf6 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> nac-server - **ID:** coresw1-nac - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> voip-cluster - **ID:** coresw1-voip - **Label:** - **Color:** #22c55e - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> video-conf - **ID:** coresw2-video - **Label:** - **Color:** #22c55e - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> security-cameras - **ID:** coresw1-cameras - **Label:** - **Color:** #94a3b8 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> dev-server-1 - **ID:** fwint-dev1 - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> dev-server-2 - **ID:** fwint-dev2 - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> test-environment - **ID:** fwint-test - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> erp-system - **ID:** coresw1-erp - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> crm-system - **ID:** fwext1-crm - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - Salesforce cloud - ups-dc-1 --> dc-rack-a1 - **ID:** ups1-racka1 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed A - ups-dc-2 --> dc-rack-a2 - **ID:** ups2-racka2 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed B - ups-dc-1 --> dc-rack-b1 - **ID:** ups1-rackb1 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed A - ups-dc-2 --> dc-rack-b2 - **ID:** ups2-rackb2 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed B - cooling-1 --> dc-rack-a1 - **ID:** cooling1-racka1 - **Label:** - **Color:** #38bdf8 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** dotted - **Group ID:** - **Notes:** - Cooling zone - cooling-2 --> dc-rack-b1 - **ID:** cooling2-rackb1 - **Label:** - **Color:** #38bdf8 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** dotted - **Group ID:** - **Notes:** - Cooling zone - undefined --> undefined - **ID:** custom-1765237881452 - **Label:** - **Color:** #c800ff - **Width:** 4 - **Direction:** forward - **Routing:** orthogonal - **Type:** custom - **Line Style:** solid - **Group ID:** - **Points:** 3492,1527 3501,1831 3304,1732 ## Zones ### rect-1765237540610 - **Position:** 2879, 160 - **Size:** 992 x 539 - **Color:** #f97316 - **Style:** filled - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ### rect-1765237681216 - **Position:** 448, 1672 - **Size:** 916 x 924 - **Color:** #c800ff - **Style:** outlined - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ### rect-1766437913740 - **Position:** 905, 115 - **Size:** 111 x 920 - **Color:** #5215f9 - **Style:** filled - **Line Style:** wall - **Border Color:** - **Border Width:** 13 ### rect-1766437935414 - **Position:** 131, 1072 - **Size:** 873 x 99 - **Color:** #5215f9 - **Style:** filled - **Line Style:** wall - **Border Color:** - **Border Width:** 13 ## Text Labels ### text-1765237828167 - **Content:** Double click on desktop
or long press on mobile
to enter rack canvas view - **Position:** 3411, 1390 - **Font Size:** 46 - **Color:** #e2e8f0 - **Font Weight:** bold - **Font Style:** italic - **Text Align:** middle - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766446595277 - **Content:** SITE A - **Position:** 654, 1368 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766446610211 - **Content:** SITE A - **Position:** 181, 1129 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453024797 - **Content:** SITE A - **Position:** 969, 1029 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453070975 - **Content:** SITE A - **Position:** 613, 1140 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453072857 - **Content:** SITE A - **Position:** 969, 474 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766458222326 - **Content:** - **Position:** 3168, 2191 - **Font Size:** 18 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ================================================ FILE: demos/markdown-exports/the-one-file-homelab.md ================================================ # The One File > Exported from The One File on 2025-12-23T03:09:46.367Z ## 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 ## Nodes ### internet - **Name:** Internet - **IP:** 0.0.0.0 - **Role:** - **Shape:** stop-sign - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1758, 299 - **Size:** 168 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"amazon-web-services"},"circleColor":"#db0000","circleBorder":"#000000","titleSize":52,"subSize":46}}` ### internet-copy - **Name:** OPNSENSE - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2067, 473 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"opnsense"}}}` ### opnsense-copy - **Name:** Docker - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1774, 667 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"portainer"}}}` ### docker-copy - **Name:** Docker2 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1931, 782 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"jotty"}}}` ### docker-copy-1 - **Name:** Docker3 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2158, 768 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"authportal"}}}` ### docker-copy-2 - **Name:** Docker 4 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** [object Object]; [object Object]; [object Object] - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2342, 632 - **Size:** 82 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"docker"}}}` ### opnsense-copy-1 - **Name:** OPNSENSE GUEST - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2758, 308 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"opnsense-v1"}}}` ### phone - **Name:** Phone - **IP:** 0.0.0.0 - **Role:** - **Shape:** phone - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3313, 503 - **Size:** 121 ### desktop - **Name:** Desktop - **IP:** 0.0.0.0 - **Role:** - **Shape:** pc - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2972, 481 - **Size:** 147 ### dns - **Name:** DNS - **IP:** 0.0.0.0 - **Role:** - **Shape:** cloud - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3200, 320 - **Size:** 50 ### racked - **Name:** Racked - **IP:** - **Role:** Rack - **Shape:** server - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 2646, 971 - **Size:** 137 - **Styles:** `{"all":{"icon":{"library":"mdi","name":"server-security"},"circleColor":"#010813","circleBorder":"#ffffff"}}` ### thermostat - **Name:** Thermostat - **IP:** 0.0.0.0 - **Role:** - **Shape:** thermostat - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1323, 575 - **Size:** 50 ### video-doorbell - **Name:** Video Doorbell - **IP:** 0.0.0.0 - **Role:** - **Shape:** doorbell - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1188, 455 - **Size:** 50 ### smart-lock - **Name:** Smart Lock - **IP:** 0.0.0.0 - **Role:** - **Shape:** smart-lock - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1292, 790 - **Size:** 50 ### smart-bulb - **Name:** Smart Bulb - **IP:** 0.0.0.0 - **Role:** - **Shape:** smart-bulb - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1496, 717 - **Size:** 50 ### robot-vacuum - **Name:** Robot Vacuum - **IP:** 0.0.0.0 - **Role:** - **Shape:** vacuum - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2289, 979 - **Size:** 50 ## Connections - internet --> internet-copy - **ID:** internet-internet-copy-1765238145151 - **Label:** - **Color:** #55e208 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> opnsense-copy - **ID:** internet-copy-opnsense-copy-1765238187451 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy - **ID:** internet-copy-docker-copy-1765238242477 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy-1 - **ID:** internet-copy-docker-copy-1-1765238244637 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy-2 - **ID:** internet-copy-docker-copy-2-1765238246233 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet --> opnsense-copy-1 - **ID:** internet-opnsense-copy-1-1765238266117 - **Label:** - **Color:** #80ff00 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - opnsense-copy-1 --> dns - **ID:** opnsense-copy-1-dns-1765238347996 - **Label:** - **Color:** #fb00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - dns --> desktop - **ID:** dns-desktop-1765238386101 - **Label:** - **Color:** #ff00d0 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - phone --> dns - **ID:** phone-dns-1765238391156 - **Label:** - **Color:** #ff00d0 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - undefined --> undefined - **ID:** custom-1765239449323 - **Label:** - **Color:** #f97316 - **Width:** 4 - **Direction:** forward - **Routing:** curved - **Type:** custom - **Line Style:** solid - **Group ID:** - **Points:** 2936,786 3184,888 2763,982 ## Zones ### rect-1765238219615 - **Position:** 2680, 251 - **Size:** 814 x 389 - **Color:** #ec0999 - **Style:** filled - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ## Text Labels ### text-1765238422602 - **Content:** Double click on desktop
or long press on mobile
to enter rack canvas view - **Position:** 2466, 742 - **Font Size:** 40 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ================================================ FILE: demos/markdown-exports/the-one-file-networkening-corporate.md ================================================ # The One File Corporate > Exported from The One File on 2025-12-23T03:12:24.252Z ## 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 ## Nodes ### core-router-1 - **Name:** Core Router 1 - **IP:** 10.0.0.1 - **Role:** Core Routing - **Shape:** router - **Tags:** core; tier-1; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3720, 246 - **Size:** 50 - **Notes:** - Primary core router - BGP peering enabled - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"borg"}}}` ### core-router-2 - **Name:** Core Router 2 - **IP:** 10.0.0.2 - **Role:** Core Routing - **Shape:** router - **Tags:** core; tier-1; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2500, 330 - **Size:** 120 - **Notes:** - Secondary core router - HSRP standby - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"actual-budget"},"pingOffsetX":-15,"pingOffsetY":-38}}` ### fw-external-1 - **Name:** External FW 1 - **IP:** 10.0.1.1 - **Role:** Perimeter Security - **Shape:** firewall - **Tags:** security; perimeter; ha-pair - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:10 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3222, 1016 - **Size:** 50 - **Notes:** - Palo Alto PA-5250 - Active node - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"anonaddy"}}}` ### fw-external-2 - **Name:** External FW 2 - **IP:** 10.0.1.2 - **Role:** Perimeter Security - **Shape:** firewall - **Tags:** security; perimeter; ha-pair - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:11 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1916, 224 - **Size:** 50 - **Notes:** - Palo Alto PA-5250 - Passive node ### fw-internal - **Name:** Internal FW - **IP:** 10.0.2.1 - **Role:** Internal Segmentation - **Shape:** firewall - **Tags:** security; internal - **Layer:** security - **MAC:** 00:1A:2B:3C:4D:12 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1747, 478 - **Size:** 50 - **Notes:** - East-West traffic inspection ### core-switch-1 - **Name:** Core Switch 1 - **IP:** 10.0.10.1 - **Role:** Core Switching - **Shape:** switch - **Tags:** core; layer3; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:20 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 449, 384 - **Size:** 50 - **Notes:** - Cisco Nexus 9000 - VPC Domain 1 ### core-switch-2 - **Name:** Core Switch 2 - **IP:** 10.0.10.2 - **Role:** Core Switching - **Shape:** switch - **Tags:** core; layer3; redundant - **Layer:** physical - **MAC:** 00:1A:2B:3C:4D:21 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 761, 181 - **Size:** 50 - **Notes:** - Cisco Nexus 9000 - VPC Domain 1 ### dc-rack-a1 - **Name:** DC Rack A1 - **IP:** 10.10.0.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-a; production - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 784, 647 - **Size:** 50 - **Notes:** - Row A, Position 1 - Primary compute - **Styles:** `{"all":{"circleColor":"#ff0000"}}` ### dc-rack-a2 - **Name:** DC Rack A2 - **IP:** 10.10.1.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-a; production - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 209, 228 - **Size:** 50 - **Notes:** - Row A, Position 2 - Primary compute ### dc-rack-b1 - **Name:** DC Rack B1 - **IP:** 10.10.2.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-b; storage - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 3184, 1627 - **Size:** 50 - **Notes:** - Row B, Position 1 - Storage systems - **Styles:** `{"all":{"circleColor":"#ff0000","titleSize":59}}` ### dc-rack-b2 - **Name:** DC Rack B2 - **IP:** 10.10.3.0/24 - **Role:** Data Center Rack - **Shape:** server - **Tags:** datacenter; row-b; storage - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 245, 500 - **Size:** 50 - **Notes:** - Row B, Position 2 - Storage systems - **Styles:** `{"all":{"circleColor":"#ff0000"}}` ### dmz-rack - **Name:** DMZ Rack - **IP:** 172.16.0.0/24 - **Role:** DMZ Infrastructure - **Shape:** server - **Tags:** dmz; security; public-facing; [object Object]; [object Object] - **Layer:** security - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 24 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 2176, 611 - **Size:** 50 - **Notes:** - Isolated DMZ zone - Public-facing services ### mgmt-rack - **Name:** Management Rack - **IP:** 192.168.100.0/24 - **Role:** Management Infrastructure - **Shape:** server - **Tags:** management; oob; noc - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 24 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 1601, 1281 - **Size:** 50 - **Notes:** - Out-of-band management - NOC equipment ### esxi-host-01 - **Name:** ESXi Host 01 - **IP:** 10.10.0.11 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:01 - **Rack Unit:** 38 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2162, 2608 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-02 - **Name:** ESXi Host 02 - **IP:** 10.10.0.12 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:02 - **Rack Unit:** 35 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2206, 2690 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-03 - **Name:** ESXi Host 03 - **IP:** 10.10.0.13 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:03 - **Rack Unit:** 32 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2155, 2771 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### esxi-host-04 - **Name:** ESXi Host 04 - **IP:** 10.10.0.14 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-a - **Layer:** physical - **MAC:** 00:50:56:AA:01:04 - **Rack Unit:** 29 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2196, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 512GB RAM - vSphere 8.0 ### tor-switch-a1 - **Name:** ToR Switch A1 - **IP:** 10.10.0.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-a1 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:01 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2147, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX - 48x25G ports ### esxi-host-05 - **Name:** ESXi Host 05 - **IP:** 10.10.1.11 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:01 - **Rack Unit:** 38 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2186, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-06 - **Name:** ESXi Host 06 - **IP:** 10.10.1.12 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:02 - **Rack Unit:** 35 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2139, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-07 - **Name:** ESXi Host 07 - **IP:** 10.10.1.13 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:03 - **Rack Unit:** 32 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2176, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### esxi-host-08 - **Name:** ESXi Host 08 - **IP:** 10.10.1.14 - **Role:** Hypervisor - **Shape:** server - **Tags:** vmware; compute; cluster-b - **Layer:** physical - **MAC:** 00:50:56:AA:02:04 - **Rack Unit:** 29 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2131, 2845 - **Size:** 50 - **Notes:** - Dell PowerEdge R750 - 768GB RAM - vSphere 8.0 ### tor-switch-a2 - **Name:** ToR Switch A2 - **IP:** 10.10.1.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-a2 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:02 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2165, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX - 48x25G ports ### san-primary - **Name:** SAN Primary - **IP:** 10.10.2.10 - **Role:** Primary Storage - **Shape:** database - **Tags:** storage; san; netapp - **Layer:** physical - **MAC:** 00:A0:98:AA:01:01 - **Rack Unit:** 36 - **U Height:** 6 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2123, 2845 - **Size:** 50 - **Notes:** - NetApp AFF A400 - 500TB Raw - FC 32Gb ### san-secondary - **Name:** SAN Secondary - **IP:** 10.10.2.11 - **Role:** Secondary Storage - **Shape:** database - **Tags:** storage; san; netapp - **Layer:** physical - **MAC:** 00:A0:98:AA:01:02 - **Rack Unit:** 28 - **U Height:** 6 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2155, 2845 - **Size:** 50 - **Notes:** - NetApp AFF A400 - 500TB Raw - FC 32Gb ### fc-switch-1 - **Name:** FC Switch 1 - **IP:** 10.10.2.1 - **Role:** Fibre Channel - **Shape:** switch - **Tags:** storage; fc; fabric-a - **Layer:** physical - **MAC:** 00:1A:2B:FC:01:01 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2115, 2845 - **Size:** 50 - **Notes:** - Brocade G620 - Fabric A ### fc-switch-2 - **Name:** FC Switch 2 - **IP:** 10.10.2.2 - **Role:** Fibre Channel - **Shape:** switch - **Tags:** storage; fc; fabric-b - **Layer:** physical - **MAC:** 00:1A:2B:FC:01:02 - **Rack Unit:** 41 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2145, 2845 - **Size:** 50 - **Notes:** - Brocade G620 - Fabric B ### backup-server-1 - **Name:** Backup Server 1 - **IP:** 10.10.3.10 - **Role:** Backup Infrastructure - **Shape:** server - **Tags:** backup; veeam; protection - **Layer:** physical - **MAC:** 00:50:56:BB:01:01 - **Rack Unit:** 36 - **U Height:** 2 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2107, 2845 - **Size:** 50 - **Notes:** - Veeam Backup Server - Dell R740xd - 200TB ### backup-server-2 - **Name:** Backup Server 2 - **IP:** 10.10.3.11 - **Role:** Backup Infrastructure - **Shape:** server - **Tags:** backup; veeam; protection - **Layer:** physical - **MAC:** 00:50:56:BB:01:02 - **Rack Unit:** 33 - **U Height:** 2 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2134, 2845 - **Size:** 50 - **Notes:** - Veeam Backup Server - Dell R740xd - 200TB ### tape-library - **Name:** Tape Library - **IP:** 10.10.3.20 - **Role:** Archival Storage - **Shape:** database - **Tags:** backup; tape; lto9 - **Layer:** physical - **MAC:** 00:50:56:BB:02:01 - **Rack Unit:** 20 - **U Height:** 10 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2099, 2845 - **Size:** 50 - **Notes:** - IBM TS4500 - LTO-9 - Long-term archive ### tor-switch-b1 - **Name:** ToR Switch B1 - **IP:** 10.10.2.3 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-b1 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:03 - **Rack Unit:** 40 - **U Height:** 1 - **Assigned Rack:** dc-rack-b1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2123, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX ### tor-switch-b2 - **Name:** ToR Switch B2 - **IP:** 10.10.3.1 - **Role:** Top of Rack - **Shape:** switch - **Tags:** tor; access; rack-b2 - **Layer:** physical - **MAC:** 00:1A:2B:3C:5D:04 - **Rack Unit:** 42 - **U Height:** 1 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2091, 2845 - **Size:** 50 - **Notes:** - Cisco Nexus 93180YC-FX ### web-server-1 - **Name:** Web Server 1 - **IP:** 172.16.0.11 - **Role:** Web Frontend - **Shape:** server - **Tags:** dmz; web; nginx - **Layer:** security - **MAC:** 00:50:56:CC:01:01 - **Rack Unit:** 20 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2113, 2845 - **Size:** 50 - **Notes:** - NGINX reverse proxy - Public facing ### web-server-2 - **Name:** Web Server 2 - **IP:** 172.16.0.12 - **Role:** Web Frontend - **Shape:** server - **Tags:** dmz; web; nginx - **Layer:** security - **MAC:** 00:50:56:CC:01:02 - **Rack Unit:** 18 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2082, 2845 - **Size:** 50 - **Notes:** - NGINX reverse proxy - Public facing ### waf-1 - **Name:** WAF Appliance - **IP:** 172.16.0.5 - **Role:** Web Application Firewall - **Shape:** firewall - **Tags:** dmz; security; waf - **Layer:** security - **MAC:** 00:50:56:CC:02:01 - **Rack Unit:** 22 - **U Height:** 2 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2102, 2845 - **Size:** 50 - **Notes:** - F5 BIG-IP ASM - OWASP protection ### load-balancer-dmz - **Name:** DMZ Load Balancer - **IP:** 172.16.0.3 - **Role:** Load Balancing - **Shape:** switch - **Tags:** dmz; lb; f5 - **Layer:** security - **MAC:** 00:50:56:CC:03:01 - **Rack Unit:** 16 - **U Height:** 2 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2074, 2845 - **Size:** 50 - **Notes:** - F5 BIG-IP LTM - VIP: 172.16.0.100 ### mail-gateway - **Name:** Mail Gateway - **IP:** 172.16.0.25 - **Role:** Email Security - **Shape:** server - **Tags:** dmz; email; security - **Layer:** security - **MAC:** 00:50:56:CC:04:01 - **Rack Unit:** 14 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2091, 2845 - **Size:** 50 - **Notes:** - Proofpoint Email Gateway - Spam/malware filtering ### dns-external-1 - **Name:** External DNS 1 - **IP:** 172.16.0.53 - **Role:** External DNS - **Shape:** circle - **Tags:** dmz; dns; public - **Layer:** security - **MAC:** 00:50:56:CC:05:01 - **Rack Unit:** 12 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2066, 2845 - **Size:** 50 - **Notes:** - BIND DNS - Authoritative for corp.com ### dns-external-2 - **Name:** External DNS 2 - **IP:** 172.16.0.54 - **Role:** External DNS - **Shape:** circle - **Tags:** dmz; dns; public - **Layer:** security - **MAC:** 00:50:56:CC:05:02 - **Rack Unit:** 10 - **U Height:** 1 - **Assigned Rack:** dmz-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2080, 2845 - **Size:** 50 - **Notes:** - BIND DNS - Secondary for corp.com ### vcenter - **Name:** vCenter Server - **IP:** 192.168.100.10 - **Role:** Virtualization Management - **Shape:** server - **Tags:** management; vmware; vcsa - **Layer:** logical - **MAC:** 00:50:56:DD:01:01 - **Rack Unit:** 20 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2057, 2845 - **Size:** 50 - **Notes:** - vCenter Server Appliance 8.0 - Single SSO domain ### nsx-manager - **Name:** NSX Manager - **IP:** 192.168.100.15 - **Role:** Network Virtualization - **Shape:** server - **Tags:** management; vmware; nsx - **Layer:** logical - **MAC:** 00:50:56:DD:02:01 - **Rack Unit:** 17 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2069, 2845 - **Size:** 50 - **Notes:** - NSX-T 4.1 Manager Cluster ### siem-server - **Name:** SIEM Server - **IP:** 192.168.100.50 - **Role:** Security Monitoring - **Shape:** server - **Tags:** management; security; splunk - **Layer:** logical - **MAC:** 00:50:56:DD:03:01 - **Rack Unit:** 14 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2049, 2845 - **Size:** 50 - **Notes:** - Splunk Enterprise - Security monitoring ### nms-server - **Name:** Network Monitoring - **IP:** 192.168.100.60 - **Role:** Network Management - **Shape:** server - **Tags:** management; monitoring; prtg - **Layer:** logical - **MAC:** 00:50:56:DD:04:01 - **Rack Unit:** 11 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2058, 2845 - **Size:** 50 - **Notes:** - PRTG Network Monitor - 5000 sensors ### jump-server - **Name:** Jump Server - **IP:** 192.168.100.100 - **Role:** Bastion Host - **Shape:** server - **Tags:** management; security; bastion - **Layer:** logical - **MAC:** 00:50:56:DD:05:01 - **Rack Unit:** 9 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2040, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - MFA enabled ### ipam-server - **Name:** IPAM/DDI - **IP:** 192.168.100.70 - **Role:** IP Management - **Shape:** server - **Tags:** management; dns; dhcp - **Layer:** logical - **MAC:** 00:50:56:DD:06:01 - **Rack Unit:** 7 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2047, 2845 - **Size:** 50 - **Notes:** - Infoblox DDI - DNS/DHCP/IPAM ### wlc-primary - **Name:** WLC Primary - **IP:** 10.20.0.1 - **Role:** Wireless Controller - **Shape:** wifi - **Tags:** wireless; cisco; 9800 - **Layer:** physical - **MAC:** 00:1A:2B:WL:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1576, 2306 - **Size:** 50 - **Notes:** - Cisco C9800-40 - Primary controller ### wlc-secondary - **Name:** WLC Secondary - **IP:** 10.20.0.2 - **Role:** Wireless Controller - **Shape:** wifi - **Tags:** wireless; cisco; 9800 - **Layer:** physical - **MAC:** 00:1A:2B:WL:01:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1468, 1564 - **Size:** 50 - **Notes:** - Cisco C9800-40 - HA Secondary ### mobile-zone-hq - **Name:** HQ Mobile Zone - **IP:** 10.20.10.0/24 - **Role:** Mobile Device Zone - **Shape:** phone - **Tags:** wireless; byod; mobile - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2355, 2806 - **Size:** 50 - **Notes:** - Corporate BYOD - MDM enrolled devices ### mobile-zone-guest - **Name:** Guest WiFi Zone - **IP:** 10.30.0.0/24 - **Role:** Guest Network - **Shape:** phone - **Tags:** wireless; guest; isolated - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2308, 2611 - **Size:** 50 - **Notes:** - Captive portal - Internet only ### mobile-zone-iot - **Name:** IoT Device Zone - **IP:** 10.40.0.0/24 - **Role:** IoT Network - **Shape:** phone - **Tags:** wireless; iot; building - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2229, 2299 - **Size:** 50 - **Notes:** - Building automation - Smart devices ### branch-router-ny - **Name:** NYC Branch Router - **IP:** 10.100.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; nyc; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3152, 634 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-la - **Name:** LA Branch Router - **IP:** 10.101.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; la; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3084, 507 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-chi - **Name:** Chicago Branch Router - **IP:** 10.102.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; chicago; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3355, 393 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - SD-WAN enabled ### branch-router-lon - **Name:** London Branch Router - **IP:** 10.200.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; london; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3114, 260 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - EMEA region ### branch-router-tokyo - **Name:** Tokyo Branch Router - **IP:** 10.201.0.1 - **Role:** Branch Gateway - **Shape:** router - **Tags:** branch; tokyo; sd-wan - **Layer:** physical - **MAC:** 00:1A:2B:BR:05:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3699, 471 - **Size:** 50 - **Notes:** - Cisco Viptela vEdge - APAC region - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"adguard-home"}}}` ### cloud-aws - **Name:** AWS Cloud - **IP:** vpc-0a1b2c3d - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; aws; hybrid - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3437, 546 - **Size:** 50 - **Notes:** - AWS US-East-1 - VPC peering to HQ - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"ansible"}}}` ### cloud-azure - **Name:** Azure Cloud - **IP:** vnet-corp-prod - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; azure; hybrid - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2593, 2724 - **Size:** 50 - **Notes:** - Azure East US 2 - ExpressRoute ### cloud-gcp - **Name:** GCP Cloud - **IP:** vpc-gcp-corp - **Role:** Public Cloud - **Shape:** cloud - **Tags:** cloud; gcp; dev - **Layer:** logical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2827, 2731 - **Size:** 50 - **Notes:** - GCP us-central1 - Dev/Test workloads ### isp-primary - **Name:** ISP Primary - **IP:** 203.0.113.1 - **Role:** Internet Uplink - **Shape:** globe - **Tags:** wan; internet; primary - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3712, 616 - **Size:** 50 - **Notes:** - AT&T MPLS - 1 Gbps dedicated - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"wikidocs"}}}` ### isp-secondary - **Name:** ISP Secondary - **IP:** 198.51.100.1 - **Role:** Internet Uplink - **Shape:** globe - **Tags:** wan; internet; backup - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2702, 468 - **Size:** 139 - **Notes:** - Verizon Business - 500 Mbps backup - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"alist"}}}` ### dc-internal-1 - **Name:** DC1 Int DNS - **IP:** 10.10.0.53 - **Role:** Internal DNS/AD - **Shape:** circle - **Tags:** dns; ad; dc1 - **Layer:** physical - **MAC:** 00:50:56:AD:01:01 - **Rack Unit:** 26 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1958, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - Primary DC ### dc-internal-2 - **Name:** DC2 Int DNS - **IP:** 10.10.1.53 - **Role:** Internal DNS/AD - **Shape:** circle - **Tags:** dns; ad; dc2 - **Layer:** physical - **MAC:** 00:50:56:AD:01:02 - **Rack Unit:** 26 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1964, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - Secondary DC ### app-server-1 - **Name:** App Server 01 - **IP:** 10.10.0.101 - **Role:** Application - **Shape:** server - **Tags:** app; iis; web - **Layer:** physical - **MAC:** 00:50:56:AP:01:01 - **Rack Unit:** 24 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1947, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - IIS Application ### app-server-2 - **Name:** App Server 02 - **IP:** 10.10.0.102 - **Role:** Application - **Shape:** server - **Tags:** app; iis; web - **Layer:** physical - **MAC:** 00:50:56:AP:01:02 - **Rack Unit:** 22 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1955, 2845 - **Size:** 50 - **Notes:** - Windows Server 2022 - IIS Application ### db-server-1 - **Name:** SQL Server 01 - **IP:** 10.10.0.201 - **Role:** Database - **Shape:** database - **Tags:** db; sql; primary - **Layer:** physical - **MAC:** 00:50:56:DB:01:01 - **Rack Unit:** 20 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1936, 2845 - **Size:** 50 - **Notes:** - SQL Server 2022 Enterprise - AlwaysOn Primary ### db-server-2 - **Name:** SQL Server 02 - **IP:** 10.10.1.201 - **Role:** Database - **Shape:** database - **Tags:** db; sql; secondary - **Layer:** physical - **MAC:** 00:50:56:DB:01:02 - **Rack Unit:** 24 - **U Height:** 2 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1947, 2845 - **Size:** 50 - **Notes:** - SQL Server 2022 Enterprise - AlwaysOn Secondary ### k8s-master-1 - **Name:** K8s Master 1 - **IP:** 10.10.1.50 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:01 - **Rack Unit:** 21 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1925, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-master-2 - **Name:** K8s Master 2 - **IP:** 10.10.1.51 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:02 - **Rack Unit:** 19 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1938, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-master-3 - **Name:** K8s Master 3 - **IP:** 10.10.1.52 - **Role:** Container Orchestration - **Shape:** hexagon - **Tags:** kubernetes; master; container - **Layer:** physical - **MAC:** 00:50:56:K8:01:03 - **Rack Unit:** 17 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1914, 2845 - **Size:** 50 - **Notes:** - K8s Control Plane - etcd member ### k8s-worker-1 - **Name:** K8s Worker 1 - **IP:** 10.10.1.60 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:01 - **Rack Unit:** 15 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1930, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-2 - **Name:** K8s Worker 2 - **IP:** 10.10.1.61 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:02 - **Rack Unit:** 13 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1904, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-3 - **Name:** K8s Worker 3 - **IP:** 10.10.1.62 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:03 - **Rack Unit:** 11 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1922, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### k8s-worker-4 - **Name:** K8s Worker 4 - **IP:** 10.10.1.63 - **Role:** Container Workload - **Shape:** server - **Tags:** kubernetes; worker; container - **Layer:** physical - **MAC:** 00:50:56:K8:02:04 - **Rack Unit:** 9 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1893, 2845 - **Size:** 50 - **Notes:** - K8s Worker Node - 64GB RAM ### proxy-server-1 - **Name:** Proxy Server 1 - **IP:** 10.5.0.10 - **Role:** Web Proxy - **Shape:** server - **Tags:** proxy; squid; filtering - **Layer:** security - **MAC:** 00:50:56:PX:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1806, 654 - **Size:** 50 - **Notes:** - Squid Proxy - Content filtering ### proxy-server-2 - **Name:** Proxy Server 2 - **IP:** 10.5.0.11 - **Role:** Web Proxy - **Shape:** server - **Tags:** proxy; squid; filtering - **Layer:** security - **MAC:** 00:50:56:PX:01:02 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2937, 2629 - **Size:** 50 - **Notes:** - Squid Proxy - HA pair ### vpn-concentrator - **Name:** VPN Concentrator - **IP:** 10.0.5.1 - **Role:** Remote Access VPN - **Shape:** firewall - **Tags:** vpn; remote; security - **Layer:** security - **MAC:** 00:1A:2B:VP:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3642, 947 - **Size:** 50 - **Notes:** - Cisco ASA 5555-X - AnyConnect SSL VPN ### nac-server - **Name:** NAC Server - **IP:** 10.5.5.10 - **Role:** Network Access Control - **Shape:** server - **Tags:** nac; ise; 802.1x - **Layer:** security - **MAC:** 00:50:56:NA:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1153, 1172 - **Size:** 50 - **Notes:** - Cisco ISE 3.1 - RADIUS/TACACS+ ### print-server - **Name:** Print Server - **IP:** 10.10.0.150 - **Role:** Print Services - **Shape:** server - **Tags:** print; windows; services - **Layer:** physical - **MAC:** 00:50:56:PR:01:01 - **Rack Unit:** 18 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1897, 2845 - **Size:** 50 - **Notes:** - Windows Print Server - 50+ printers ### file-server - **Name:** File Server - **IP:** 10.10.0.160 - **Role:** File Services - **Shape:** database - **Tags:** file; smb; dfs - **Layer:** physical - **MAC:** 00:50:56:FS:01:01 - **Rack Unit:** 16 - **U Height:** 2 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1861, 2845 - **Size:** 50 - **Notes:** - Windows File Server - DFS namespace ### ca-server - **Name:** Certificate Authority - **IP:** 192.168.100.80 - **Role:** PKI Infrastructure - **Shape:** server - **Tags:** pki; ca; security - **Layer:** logical - **MAC:** 00:50:56:CA:01:01 - **Rack Unit:** 5 - **U Height:** 1 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1889, 2845 - **Size:** 50 - **Notes:** - Windows CA - Enterprise Root CA ### sccm-server - **Name:** SCCM Server - **IP:** 192.168.100.90 - **Role:** Endpoint Management - **Shape:** server - **Tags:** sccm; patching; software - **Layer:** logical - **MAC:** 00:50:56:SC:01:01 - **Rack Unit:** 3 - **U Height:** 2 - **Assigned Rack:** mgmt-rack - **Rack Capacity:** 24 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1850, 2845 - **Size:** 50 - **Notes:** - MECM Primary Site - Software deployment ### voip-cluster - **Name:** VoIP Cluster - **IP:** 10.50.0.0/24 - **Role:** Voice Services - **Shape:** phone - **Tags:** voip; cisco; ucm - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1777, 1617 - **Size:** 50 - **Notes:** - Cisco UCM Cluster - 3000 endpoints ### video-conf - **Name:** Video Conference - **IP:** 10.51.0.0/24 - **Role:** Video Services - **Shape:** laptop - **Tags:** video; webex; teams - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1994, 2245 - **Size:** 50 - **Notes:** - Webex/Teams integration - Meeting rooms ### security-cameras - **Name:** Security Cameras - **IP:** 10.60.0.0/24 - **Role:** Physical Security - **Shape:** camera - **Tags:** cctv; surveillance; security - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1674, 2046 - **Size:** 50 - **Notes:** - 150+ IP cameras - 30-day retention ### nvr-cluster - **Name:** NVR Cluster - **IP:** 10.60.0.10 - **Role:** Video Recording - **Shape:** server - **Tags:** nvr; surveillance; storage - **Layer:** physical - **MAC:** 00:50:56:NV:01:01 - **Rack Unit:** 15 - **U Height:** 4 - **Assigned Rack:** dc-rack-b2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1829, 2845 - **Size:** 50 - **Notes:** - Milestone XProtect - 500TB storage ### dev-server-1 - **Name:** Dev Server 1 - **IP:** 10.80.0.10 - **Role:** Development - **Shape:** server - **Tags:** dev; gitlab; ci-cd; [object Object] - **Layer:** application - **MAC:** 00:50:56:DV:01:01 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2801, 1176 - **Size:** 128 - **Notes:** - GitLab Server - CI/CD pipelines - **Styles:** `{"all":{"icon":{"library":"simple","name":"amazonwebservices"}}}` ### dev-server-2 - **Name:** Dev Server 2 - **IP:** 10.80.0.11 - **Role:** Development - **Shape:** server - **Tags:** dev; jenkins; ci-cd - **Layer:** application - **MAC:** 00:50:56:DV:01:02 - **Rack Unit:** - **U Height:** 2 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1945, 1165 - **Size:** 50 - **Notes:** - Jenkins Server - Build automation ### test-environment - **Name:** Test Environment - **IP:** 10.81.0.0/24 - **Role:** QA/Testing - **Shape:** hexagon - **Tags:** test; qa; staging - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2567, 885 - **Size:** 148 - **Notes:** - Staging environment - Pre-prod validation - **Styles:** `{"all":{"icon":{"library":"simple","name":"apple"}}}` ### erp-system - **Name:** ERP System - **IP:** 10.90.0.10 - **Role:** Business Application - **Shape:** database - **Tags:** erp; sap; business - **Layer:** application - **MAC:** 00:50:56:ER:01:01 - **Rack Unit:** - **U Height:** 4 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 790, 474 - **Size:** 50 - **Notes:** - SAP S/4HANA - Financial/HR systems ### crm-system - **Name:** CRM System - **IP:** 10.91.0.10 - **Role:** Business Application - **Shape:** database - **Tags:** crm; salesforce; business - **Layer:** application - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3515, 1138 - **Size:** 50 - **Notes:** - Salesforce integration - Sales/Marketing ### endpoint-1000 - **Name:** Corporate Endpoints - **IP:** 10.70.0.0/22 - **Role:** User Workstations - **Shape:** laptop - **Tags:** endpoints; workstations; users - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 992, 2284 - **Size:** 50 - **Notes:** - ~1000 corporate laptops - Windows 11 ### dist-switch-floor1 - **Name:** Floor 1 Switch - **IP:** 10.1.1.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-1; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 654, 2020 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor2 - **Name:** Floor 2 Switch - **IP:** 10.1.2.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-2; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 854, 1843 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor3 - **Name:** Floor 3 Switch - **IP:** 10.1.3.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-3; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1899, 1457 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### dist-switch-floor4 - **Name:** Floor 4 Switch - **IP:** 10.1.4.1 - **Role:** Distribution - **Shape:** switch - **Tags:** distribution; floor-4; access - **Layer:** physical - **MAC:** 00:1A:2B:FL:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 489, 181 - **Size:** 50 - **Notes:** - Cisco C9300-48P - PoE+ enabled ### ap-floor1-zone1 - **Name:** AP Floor 1 Zone 1 - **IP:** 10.20.1.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-1 - **Layer:** physical - **MAC:** 00:1A:2B:AP:01:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1140, 2070 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor2-zone1 - **Name:** AP Floor 2 Zone 1 - **IP:** 10.20.2.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-2 - **Layer:** physical - **MAC:** 00:1A:2B:AP:02:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 688, 2384 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor3-zone1 - **Name:** AP Floor 3 Zone 1 - **IP:** 10.20.3.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-3 - **Layer:** physical - **MAC:** 00:1A:2B:AP:03:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2145, 1890 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ap-floor4-zone1 - **Name:** AP Floor 4 Zone 1 - **IP:** 10.20.4.10 - **Role:** Wireless Access - **Shape:** wifi - **Tags:** wifi; ap; floor-4 - **Layer:** physical - **MAC:** 00:1A:2B:AP:04:01 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 518, 566 - **Size:** 50 - **Notes:** - Cisco 9120AX - Wi-Fi 6 ### ups-dc-1 - **Name:** UPS DC-1 - **IP:** 192.168.200.10 - **Role:** Power Management - **Shape:** rectangle - **Tags:** power; ups; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 771, 296 - **Size:** 50 - **Notes:** - APC Symmetra - 80kVA - 30 min runtime ### ups-dc-2 - **Name:** UPS DC-2 - **IP:** 192.168.200.11 - **Role:** Power Management - **Shape:** rectangle - **Tags:** power; ups; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 216, 330 - **Size:** 50 - **Notes:** - APC Symmetra - 80kVA - Redundant ### pdu-rack-a1 - **Name:** PDU Rack A1 - **IP:** 192.168.200.21 - **Role:** Power Distribution - **Shape:** rectangle - **Tags:** power; pdu; rack-a1 - **Layer:** physical - **MAC:** - **Rack Unit:** 1 - **U Height:** 1 - **Assigned Rack:** dc-rack-a1 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1805, 2845 - **Size:** 50 - **Notes:** - APC Switched PDU - Per-outlet metering ### pdu-rack-a2 - **Name:** PDU Rack A2 - **IP:** 192.168.200.22 - **Role:** Power Distribution - **Shape:** rectangle - **Tags:** power; pdu; rack-a2 - **Layer:** physical - **MAC:** - **Rack Unit:** 1 - **U Height:** 1 - **Assigned Rack:** dc-rack-a2 - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1742, 2845 - **Size:** 50 - **Notes:** - APC Switched PDU - Per-outlet metering ### cooling-1 - **Name:** CRAC Unit 1 - **IP:** 192.168.200.30 - **Role:** Cooling - **Shape:** rectangle - **Tags:** cooling; hvac; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 246, 626 - **Size:** 50 - **Notes:** - Liebert CRV - Row-based cooling ### cooling-2 - **Name:** CRAC Unit 2 - **IP:** 192.168.200.31 - **Role:** Cooling - **Shape:** rectangle - **Tags:** cooling; hvac; datacenter - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1603, 981 - **Size:** 50 - **Notes:** - Liebert CRV - N+1 redundancy ### camera-a - **Name:** camera A - **IP:** 0.0.0.0 - **Role:** - **Shape:** camera - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 167, 145 - **Size:** 45 ### camera-a-copy - **Name:** camera B - **IP:** 0.0.0.0 - **Role:** - **Shape:** camera - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1041, 738 - **Size:** 45 ## Connections - isp-primary (Gi0/0) --> core-router-1 (Gi1/0/1) - **ID:** isp1-router1 - **Label:** - **Color:** #10b981 - **Width:** 6 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Primary WAN link - isp-secondary (Gi0/0) --> core-router-2 (Gi1/0/1) - **ID:** isp2-router2 - **Label:** - **Color:** #10b981 - **Width:** 6 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Backup WAN link - core-router-1 (Gi1/0/24) --> core-router-2 (Gi1/0/24) - **ID:** router1-router2 - **Label:** - **Color:** #f59e0b - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - HSRP Peering - core-router-1 --> fw-external-1 - **ID:** router1-fw1 - **Label:** - **Color:** #ef4444 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-router-2 --> fw-external-2 - **ID:** router2-fw2 - **Label:** - **Color:** #ef4444 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> fw-external-2 - **ID:** fw1-fw2 - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - HA heartbeat - fw-external-1 --> core-switch-1 - **ID:** fw1-coresw1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-2 --> core-switch-2 - **ID:** fw2-coresw2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> core-switch-2 - **ID:** coresw1-coresw2 - **Label:** - **Color:** #3b82f6 - **Width:** 5 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - VPC peer-link - core-switch-1 --> fw-internal - **ID:** coresw1-fwint - **Label:** - **Color:** #ef4444 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> fw-internal - **ID:** coresw2-fwint - **Label:** - **Color:** #ef4444 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-a1 - **ID:** coresw1-racka1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-a1 - **ID:** coresw2-racka1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-a2 - **ID:** coresw1-racka2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-a2 - **ID:** coresw2-racka2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-b1 - **ID:** coresw1-rackb1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-b1 - **ID:** coresw2-rackb1 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dc-rack-b2 - **ID:** coresw1-rackb2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dc-rack-b2 - **ID:** coresw2-rackb2 - **Label:** - **Color:** #475569 - **Width:** 4 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> dmz-rack - **ID:** fw1-dmz - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - DMZ segment - fw-external-2 --> dmz-rack - **ID:** fw2-dmz - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - DMZ segment - core-switch-1 --> mgmt-rack - **ID:** coresw1-mgmt - **Label:** - **Color:** #8b5cf6 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - OOB management - core-switch-1 --> wlc-primary - **ID:** coresw1-wlc1 - **Label:** - **Color:** #06b6d4 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> wlc-secondary - **ID:** coresw2-wlc2 - **Label:** - **Color:** #06b6d4 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> wlc-secondary - **ID:** wlc1-wlc2 - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - HA pair - wlc-primary --> mobile-zone-hq - **ID:** wlc1-mobile-hq - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> mobile-zone-guest - **ID:** wlc1-mobile-guest - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - wlc-primary --> mobile-zone-iot - **ID:** wlc1-mobile-iot - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-router-1 --> branch-router-ny - **ID:** router1-branch-ny - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-la - **ID:** router1-branch-la - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-chi - **ID:** router1-branch-chi - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-lon - **ID:** router1-branch-lon - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> branch-router-tokyo - **ID:** router1-branch-tokyo - **Label:** - **Color:** #a855f7 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - SD-WAN tunnel - core-router-1 --> cloud-aws - **ID:** router1-aws - **Label:** - **Color:** #f97316 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - Direct Connect - core-router-2 --> cloud-azure - **ID:** router2-azure - **Label:** - **Color:** #0ea5e9 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - ExpressRoute - fw-internal --> cloud-gcp - **ID:** fwint-gcp - **Label:** - **Color:** #22c55e - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - VPN tunnel - core-switch-1 --> dist-switch-floor1 - **ID:** coresw1-floor1 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> dist-switch-floor2 - **ID:** coresw1-floor2 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dist-switch-floor3 - **ID:** coresw2-floor3 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> dist-switch-floor4 - **ID:** coresw2-floor4 - **Label:** - **Color:** #475569 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor1 --> endpoint-1000 - **ID:** floor1-endpoints - **Label:** - **Color:** #94a3b8 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor1 --> ap-floor1-zone1 - **ID:** floor1-ap1 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor2 --> ap-floor2-zone1 - **ID:** floor2-ap2 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor3 --> ap-floor3-zone1 - **ID:** floor3-ap3 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - dist-switch-floor4 --> ap-floor4-zone1 - **ID:** floor4-ap4 - **Label:** - **Color:** #06b6d4 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> proxy-server-1 - **ID:** fwint-proxy1 - **Label:** - **Color:** #ef4444 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> proxy-server-2 - **ID:** fwint-proxy2 - **Label:** - **Color:** #ef4444 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> vpn-concentrator - **ID:** fwext1-vpn - **Label:** - **Color:** #8b5cf6 - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> nac-server - **ID:** coresw1-nac - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> voip-cluster - **ID:** coresw1-voip - **Label:** - **Color:** #22c55e - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-2 --> video-conf - **ID:** coresw2-video - **Label:** - **Color:** #22c55e - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> security-cameras - **ID:** coresw1-cameras - **Label:** - **Color:** #94a3b8 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> dev-server-1 - **ID:** fwint-dev1 - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> dev-server-2 - **ID:** fwint-dev2 - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-internal --> test-environment - **ID:** fwint-test - **Label:** - **Color:** #a855f7 - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - core-switch-1 --> erp-system - **ID:** coresw1-erp - **Label:** - **Color:** #f59e0b - **Width:** 3 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - fw-external-1 --> crm-system - **ID:** fwext1-crm - **Label:** - **Color:** #f59e0b - **Width:** 2 - **Direction:** both - **Routing:** orthogonal - **Type:** main - **Line Style:** dashed - **Group ID:** - **Notes:** - Salesforce cloud - ups-dc-1 --> dc-rack-a1 - **ID:** ups1-racka1 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed A - ups-dc-2 --> dc-rack-a2 - **ID:** ups2-racka2 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed B - ups-dc-1 --> dc-rack-b1 - **ID:** ups1-rackb1 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed A - ups-dc-2 --> dc-rack-b2 - **ID:** ups2-rackb2 - **Label:** - **Color:** #fbbf24 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** solid - **Group ID:** - **Notes:** - Power feed B - cooling-1 --> dc-rack-a1 - **ID:** cooling1-racka1 - **Label:** - **Color:** #38bdf8 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** dotted - **Group ID:** - **Notes:** - Cooling zone - cooling-2 --> dc-rack-b1 - **ID:** cooling2-rackb1 - **Label:** - **Color:** #38bdf8 - **Width:** 2 - **Direction:** forward - **Routing:** orthogonal - **Type:** main - **Line Style:** dotted - **Group ID:** - **Notes:** - Cooling zone - undefined --> undefined - **ID:** custom-1765237881452 - **Label:** - **Color:** #c800ff - **Width:** 4 - **Direction:** forward - **Routing:** orthogonal - **Type:** custom - **Line Style:** solid - **Group ID:** - **Points:** 3492,1527 3501,1831 3304,1732 - undefined --> undefined - **ID:** custom-1765239355462 - **Label:** - **Color:** #f97316 - **Width:** 4 - **Direction:** forward - **Routing:** orthogonal - **Type:** custom - **Line Style:** solid - **Group ID:** - **Points:** 2467,156 2146,146 2306,244 ## Zones ### rect-1765237540610 - **Position:** 2879, 160 - **Size:** 992 x 539 - **Color:** #f97316 - **Style:** filled - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ### rect-1765237681216 - **Position:** 448, 1672 - **Size:** 916 x 924 - **Color:** #c800ff - **Style:** outlined - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ### rect-1766437913740 - **Position:** 905, 115 - **Size:** 111 x 920 - **Color:** #5215f9 - **Style:** filled - **Line Style:** wall - **Border Color:** - **Border Width:** 13 ### rect-1766437935414 - **Position:** 131, 1072 - **Size:** 873 x 99 - **Color:** #5215f9 - **Style:** filled - **Line Style:** wall - **Border Color:** - **Border Width:** 13 ## Text Labels ### text-1765237828167 - **Content:** Double click on desktop
or long press on mobile
to enter rack canvas view - **Position:** 3411, 1390 - **Font Size:** 46 - **Color:** #e2e8f0 - **Font Weight:** bold - **Font Style:** italic - **Text Align:** middle - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1765239331126 - **Content:** Google is live! - **Position:** 2455, 161 - **Font Size:** 56 - **Color:** #e2e8f0 - **Font Weight:** bold - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766446595277 - **Content:** SITE A - **Position:** 654, 1368 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766446610211 - **Content:** SITE A - **Position:** 181, 1129 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453024797 - **Content:** SITE A - **Position:** 969, 1029 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453070975 - **Content:** SITE A - **Position:** 613, 1140 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ### text-1766453072857 - **Content:** SITE A - **Position:** 969, 474 - **Font Size:** 101 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ================================================ FILE: demos/markdown-exports/the-one-file-networkening-homelab.md ================================================ # The One File > Exported from The One File on 2025-12-23T03:11:58.364Z ## 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 ## Nodes ### internet - **Name:** Internet - **IP:** 0.0.0.0 - **Role:** - **Shape:** square - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2104, 268 - **Size:** 168 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"amazon-web-services"},"circleColor":"#ffffff","circleBorder":"#ffffff"}}` ### internet-copy - **Name:** OPNSENSE - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2067, 473 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"opnsense"}}}` ### opnsense-copy - **Name:** Docker - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1774, 667 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"portainer"}}}` ### docker-copy - **Name:** Docker2 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 1931, 782 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"jotty"}}}` ### docker-copy-1 - **Name:** Docker3 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2158, 768 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"authportal"}}}` ### docker-copy-2 - **Name:** Docker 4 - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** [object Object]; [object Object]; [object Object] - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2342, 632 - **Size:** 82 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"docker"}}}` ### opnsense-copy-1 - **Name:** OPNSENSE GUEST - **IP:** 0.0.0.0 - **Role:** - **Shape:** firewall - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2758, 308 - **Size:** 50 - **Styles:** `{"all":{"icon":{"library":"selfhst","name":"opnsense-v1"}}}` ### phone - **Name:** Phone - **IP:** 0.0.0.0 - **Role:** - **Shape:** phone - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3313, 503 - **Size:** 121 ### desktop - **Name:** Desktop - **IP:** 0.0.0.0 - **Role:** - **Shape:** pc - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 2972, 481 - **Size:** 147 ### dns - **Name:** DNS - **IP:** 0.0.0.0 - **Role:** - **Shape:** cloud - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 3200, 320 - **Size:** 50 ### racked - **Name:** Racked - **IP:** - **Role:** Rack - **Shape:** server - **Tags:** _none_ - **Layer:** physical - **MAC:** - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** 42 - **Is Rack:** true - **Locked:** false - **Group ID:** - **Position:** 2646, 971 - **Size:** 137 - **Styles:** `{"all":{"icon":{"library":"mdi","name":"server-security"},"circleColor":"#010813","circleBorder":"#ffffff"}}` ## Connections - internet --> internet-copy - **ID:** internet-internet-copy-1765238145151 - **Label:** - **Color:** #55e208 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> opnsense-copy - **ID:** internet-copy-opnsense-copy-1765238187451 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy - **ID:** internet-copy-docker-copy-1765238242477 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy-1 - **ID:** internet-copy-docker-copy-1-1765238244637 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet-copy --> docker-copy-2 - **ID:** internet-copy-docker-copy-2-1765238246233 - **Label:** - **Color:** #4c00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - internet --> opnsense-copy-1 - **ID:** internet-opnsense-copy-1-1765238266117 - **Label:** - **Color:** #80ff00 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - opnsense-copy-1 --> dns - **ID:** opnsense-copy-1-dns-1765238347996 - **Label:** - **Color:** #fb00ff - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - dns --> desktop - **ID:** dns-desktop-1765238386101 - **Label:** - **Color:** #ff00d0 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - phone --> dns - **ID:** phone-dns-1765238391156 - **Label:** - **Color:** #ff00d0 - **Width:** 4 - **Direction:** both - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - undefined --> undefined - **ID:** custom-1765239449323 - **Label:** - **Color:** #f97316 - **Width:** 4 - **Direction:** forward - **Routing:** curved - **Type:** custom - **Line Style:** solid - **Group ID:** - **Points:** 2936,786 3184,888 2763,982 ## Zones ### rect-1765238219615 - **Position:** 2680, 251 - **Size:** 814 x 389 - **Color:** #ec0999 - **Style:** filled - **Line Style:** solid - **Border Color:** - **Border Width:** 2 ## Text Labels ### text-1765238422602 - **Content:** Double click on desktop
or long press on mobile
to enter rack canvas view - **Position:** 2466, 742 - **Font Size:** 40 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ================================================ FILE: demos/password-protected/password.txt ================================================ lambert ================================================ FILE: demos/password-protected/the-one-file-corporate-demo.html ================================================ The One File Corporate

The One File Corporate

?
  • Scroll to zoom
  • Drag to pan
  • Right click to clone and align
  • Right click to select multiple
  • Hold Shift + drag mouse for marquee selection
  • You have the power
  • Your time is NOW!
Line Legend
Trusted Lan
Secure Lan
DMZ
Main ISP
Alternate ISP
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
88%
================================================ FILE: demos/password-protected/the-one-file-homelab-demo.html ================================================ The One File

The One File

?
  • Scroll to zoom
  • Drag to pan
  • Right click to clone and align
  • Right click to select multiple
  • Hold Shift + drag mouse for marquee selection
  • You have the power
  • Your time is NOW!
Line Legend
ISP LINE
MY Guest NETWORK
you can edit me too
you can edit me too
iPhone (always guest iPhone)
you can edit me too
88%
================================================ FILE: demos/password-protected/theonefile-networkening-corporate-demo.html ================================================ The One File Corporate

Select Icon

The One File Corporate

?
Line Legend
Trusted Lan
Secure Lan
DMZ
Main ISP
Alternate ISP
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
you can edit me too
99%
================================================ FILE: demos/password-protected/theonefile-networkening-homelab-demo.html ================================================ The One File

Select Icon

The One File

?
Line Legend
ISP LINE
MY Guest NETWORK
you can edit me too
you can edit me too
iPhone (always guest iPhone)
you can edit me too
99%
================================================ FILE: import-export-save.md ================================================ # Export and Import | Format | Export | Import | Full Backup | Editable | |--------|--------|--------|-------------|---------------------| | **HTML/Default** | Yes | Yes | Yes | Yes | | **JSON** | Yes | Yes | Yes | Yes | | **Markdown** | Yes | Yes | Yes | Yes | | **CSV** | Yes | Yes | Yes | Yes | | **PNG** | Yes | No | No | No | | **SVG** | Yes | No | No | Yes | ## HTML (Save File) ### Use Cases | Scenario | Recommendation | |----------|----------------| | Daily work and saving progress | Save HTML | | Sharing with others | Save HTML | | Offline use | Save HTML | | Archival backup | Save HTML plus JSON | ## JSON Format ### Structure ``` { "nodeData": { ... }, "edgeData": { "list": [ ... ] }, "rectData": { "list": [ ... ] }, "textData": { "list": [ ... ] }, "edgeLegend": { ... }, "nodePositions": { ... }, "nodeSizes": { ... }, "nodeStyles": { ... }, "page": { ... }, "canvas": { "zoom": 1, "panX": 0, "panY": 0 }, "savedTopologyView": { ... }, "documentTabs": [ ... ], "currentTabIndex": 0, "encryptedSections": { ... }, "auditLog": [ ... ] } ``` ### Use Cases | Scenario | Recommendation | |----------|----------------| | Full backup | JSON | | Transfer between files | JSON | | Programmatic access | JSON | | API integration | JSON | ## Markdown Format ### Structure ``` # Topology Title > Exported from The One File on 2025-01-15T10:30:00.000Z ## Legend - #4fd1c5: Primary Links - #f97316: Secondary Links ## Nodes ### node-id-here - **Name:** Display Name - **IP:** 10.0.0.1 - **Role:** Core Router - **Shape:** router - **Tags:** network; critical - **Layer:** physical - **MAC:** 00:11:22:33:44:55 - **Rack Unit:** - **U Height:** 1 - **Assigned Rack:** - **Rack Capacity:** - **Is Rack:** false - **Locked:** false - **Group ID:** - **Position:** 500, 300 - **Size:** 55 - **Notes:** - First note here - Second note here - **Styles:** `{"all":{"circleColor":"#1e293b"}}` ## Connections - source-node (port1) --> target-node (port2) - **ID:** edge-1234567890 - **Label:** Connection Label - **Color:** #4fd1c5 - **Width:** 4 - **Direction:** none - **Routing:** curved - **Type:** main - **Line Style:** solid - **Group ID:** - **Points:** 100,200 150,250 200,300 - **Notes:** - Edge note here ## Zones ### rect-1234567890 - **Position:** 100, 100 - **Size:** 400 x 300 - **Color:** #f97316 - **Style:** filled - **Line Style:** solid - **Border Color:** - **Border Width:** 2 - **Notes:** - Zone note here ## Text Labels ### text-1234567890 - **Content:** Label text here - **Position:** 500, 200 - **Font Size:** 18 - **Color:** #e2e8f0 - **Font Weight:** normal - **Font Style:** normal - **Text Align:** start - **Text Decoration:** none - **Background Color:** #000000 - **Background Enabled:** false - **Opacity:** 1 ``` ### Special Characters | Character | Export Format | Import Conversion | |-----------|---------------|-------------------| | Newline in text | `
` | Converted back to newline | | Tags separator | Semicolon | Split into array | | Notes separator | Indented list | Array of strings | ### Use Cases | Scenario | Recommendation | |----------|----------------| | Version control (git) | Markdown | | Text editor viewing | Markdown | | Manual editing of topology | Markdown | | Documentation generation | Markdown | | Diff comparison between versions | Markdown | ## CSV ### Structure ``` #THEONEFILE_CONFIG:{ ... complete JSON backup ... } # # Topology Title - Node List # Exported from The One File on 2025-01-15T10:30:00.000Z # NOTE: CSV contains nodes only. Use Markdown or JSON for full topology. # name,ip,role,shape,tags,layer,mac,rackUnit,uHeight,assignedRack,rackCapacity,isRack,locked,groupId,x,y,size,notes,styles Core Router,10.0.0.1,Router,router,network;critical,physical,00:11:22:33:44:55,,,,,false,false,,500,300,55,Note 1|Note 2,"{...}" Web Server,10.0.1.10,Web Server,server,production,physical,,,,,,false,false,,700,400,50,, ``` ### Columns | Column | Required | Description | Format | |--------|----------|-------------|--------| | name | Yes | Display name of node | Text | | ip | No | IP address | Text | | role | No | Role or description | Text | | shape | No | Node shape | circle, server, router, switch, firewall, cloud, database | | tags | No | Tags for filtering | Semicolon separated | | layer | No | Network layer | physical, logical, security, application | | mac | No | MAC address | Text | | rackUnit | No | Rack unit position | Text | | uHeight | No | Height in rack units | Number | | assignedRack | No | Rack node ID | Text | | rackCapacity | No | Rack capacity | Number | | isRack | No | Is this a rack node | true or false | | locked | No | Movement locked | true or false | | groupId | No | Group identifier | Text | | x | No | Horizontal position | Number | | y | No | Vertical position | Number | | size | No | Node size | Number | | notes | No | Node notes | Pipe separated | | styles | No | Custom styles | JSON string | ### Use Cases | Scenario | Recommendation | |----------|----------------| | Bulk node creation | CSV | | Spreadsheet editing of nodes | CSV | | Import from asset database | CSV | | Quick node list for editing | CSV | | Full backup with editable nodes | CSV | ### Minimal CSV Example ``` name,ip,role,shape Router 1,10.0.0.1,Core Router,router Switch 1,10.0.0.2,Distribution,switch Server 1,10.0.1.10,Web Server,server Firewall,10.0.0.254,Edge Firewall,firewall ``` ### CSV with Positions ``` name,ip,shape,x,y,size Router 1,10.0.0.1,router,500,200,60 Switch 1,10.0.0.2,switch,500,400,50 Server 1,10.0.1.10,server,300,600,50 Server 2,10.0.1.11,server,500,600,50 Server 3,10.0.1.12,server,700,600,50 ``` ### CSV with Tags and Notes ``` name,ip,role,shape,tags,layer,notes Core Router,10.0.0.1,Primary Router,router,network;critical;core,physical,Main gateway|Managed by NetOps Web Server 1,10.0.1.10,Production Web,server,production;web;critical,application,Apache 2.4|Ubuntu 22.04 DB Server,10.0.2.10,Primary Database,database,production;database,application,PostgreSQL 15 Dev Server,10.0.3.10,Development,server,development;non-critical,application, ``` ## PNG Export ### Use Cases | Scenario | Recommendation | |----------|----------------| | Documentation screenshots | PNG | | Presentations | PNG | | Email attachments | PNG | | Quick sharing | PNG | ## SVG Export ### Use Cases | Scenario | Recommendation | |----------|----------------| | Design tool editing | SVG | | Large format printing | SVG | | Scalable documentation | SVG | | Custom styling | SVG | ## Print Optimized print layout for physical documentation. ### Use Cases | Scenario | Recommendation | |----------|----------------| | Physical documentation | Print | | Meeting handouts | Print | | Wall diagrams | Print | | Offline reference | Print | ================================================ FILE: keyboard-shortcuts.md ================================================ # Keyboard Shortcuts ## Navigation & Movement | Shortcut | Action | |----------|--------| | `Arrow Keys` | Move selected node(s) 1 pixel in arrow direction | | `Shift + Arrow Keys` | Move selected node(s) 10 pixels for faster positioning | | `Tab` | Cycle to next node in current view | | `Shift + Tab` | Cycle to previous node in current view | | `F` | Focus camera on selected node(s) with auto zoom | | `Shift + Click/Drag` | Multiple Select (marquee selection) | ## Node Management | Shortcut | Action | |----------|--------| | `L` | Lock or unlock selected node(s) to prevent movement | | `G` | Group or ungroup selected nodes (requires 2+ nodes selected) | | `Ctrl/Cmd + C` | Copy selected node | | `Ctrl/Cmd + V` | Paste node at center of view | | `Ctrl/Cmd + D` | Duplicate selected node | | `Ctrl/Cmd + A` | Select all nodes in current view | | `Delete` | Delete selected item(s) | | `Escape` | Clear selection | ## Editing | Shortcut | Action | |----------|--------| | `Ctrl/Cmd + Z` | Undo last action | | `Ctrl/Cmd + Y` | Redo last undone action | | `Ctrl/Cmd + Shift + Z` | Redo (alternative) | ## View Controls | Shortcut | Action | |----------|--------| | `Ctrl/Cmd + Plus` | Zoom in | | `Ctrl/Cmd + Minus` | Zoom out | | `Ctrl/Cmd + 0` | Reset view to default zoom and position | | `Space + Drag` | Pan canvas (hold space and drag with mouse) | | `Scroll` | Zoom in/out at cursor position | ## 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 | ================================================ FILE: mobile-gestures.md ================================================ # Mobile Gestures & Touch Controls | Gesture | Action | Context | |---------|--------|---------| | **Tap node** | Select node and open properties panel | Any view | | **Tap empty space** | Deselect all nodes | Any view | | **Drag node** | Move node to new position | Any view (unless locked) | | **Drag empty space** | Pan canvas | Any view | | **Pinch** | Zoom in/out | Any view | | **Triple Tap** | Undo | Any view | | **Long Press** | Add Waypoint to line | Any view | ## Multi-Selection | Gesture | Action | Context | |---------|--------|---------| | **Double tap node** | Add node to multi selection | Any view | | **Double tap selected node** | Remove node from multi selection | Any view | | **Tap "Multi Select" button** | Open bulk operations menu | When 2+ nodes selected | ## Rack View Navigation | Gesture | Action | Context | |---------|--------|---------| | **Long press rack node** | Enter rack view to see devices inside | Topology view | | **Double tap empty space** | Exit rack view and return to topology | Rack view only | | **Tap "Back to Topology" button** | Exit rack view (alternative to double tap) | Rack view only | ## Bulk Operations Menu When you have multiple nodes selected, tap the bottom button to open the mobile menu with these actions: | Button | Action | |--------|--------| | **Align Left** | Align all selected nodes to leftmost position | | **Align Right** | Align all selected nodes to rightmost position | | **Align Top** | Align all selected nodes to topmost position | | **Align Bottom** | Align all selected nodes to bottommost position | | **Distribute H** | Evenly space selected nodes horizontally | | **Distribute V** | Evenly space selected nodes vertically | | **Lock Toggle** | Lock or unlock all selected nodes (prevents movement) | | **Group Toggle** | Create or dissolve a group from selected nodes | | **Clone All** | Duplicate all selected nodes | | **Delete All** | Remove all selected nodes | | **Clear Selection** | Deselect all nodes and close menu | ## Panel Controls | Gesture | Action | |---------|--------| | **Drag footer handle** | Resize mobile footer panel (bottom panel on phones/tablets) | | **Swipe up on handle** | Maximize footer panel | | **Swipe down on handle** | Minimize footer panel | ================================================ FILE: the-one-file.html ================================================ The One File

The One File

🔒
?
  • Scroll to zoom
  • Drag to pan
  • Right click to clone and align
  • Right click to select multiple
  • Hold Shift + drag mouse for marquee selection
  • You have the power
  • Your time is NOW!
100%
================================================ FILE: theonefile-networkening.html ================================================ The One File: The Networkening

Select Icon

The One File: The Networkening

🔒
?
100%
================================================ FILE: theonefile_verse/.dockerignore ================================================ node_modules .git .gitignore *.md data .env .env.* docker-compose.yml .dockerignore demo-admin.html ================================================ FILE: theonefile_verse/.gitattributes ================================================ *.sh text eol=lf Dockerfile text eol=lf ================================================ FILE: theonefile_verse/Dockerfile ================================================ FROM oven/bun:alpine WORKDIR /app RUN apk add --no-cache su-exec iputils bind-tools samba-client avahi-tools net-snmp-tools COPY package.json ./ RUN bun install --production COPY src ./src COPY public/index.html public/theonefile.html public/collab.js public/collab.css public/collab-init.js public/collab-save-hook.js public/landing.js public/admin-dashboard.js public/admin-auth.js public/admin-pages.js public/qrcode.min.js ./public/ COPY entrypoint.sh ./ RUN mkdir -p /app/data/rooms /app/data/backups /app/public && \ addgroup -S appgroup && adduser -S appuser -G appgroup && \ chown -R appuser:appgroup /app && \ chmod +x /app/entrypoint.sh EXPOSE 10101 ENTRYPOINT ["/app/entrypoint.sh"] ================================================ FILE: theonefile_verse/README.md ================================================ ### TheOneFile_Verse

License: Unlicense TheOneFile 4.1.5 Docker Version 1.9.0

*As it turns out, there can be more than one (in 3d soon :) )* ![The One File Verse Mutli User Collaboration](https://raw.githubusercontent.com/gelatinescreams/The-One-File/refs/heads/main/assets/collab-preview.gif) An easily deployable, Docker based, real time collaboration server with mutli network device discovery, auto service & selfh.st/icons tagging, user accounts, email authentication, SSO, role based access control and more. All configurable via a robust admin panel. When you're done collaborating, each person can save their own portable copy. That file works exactly like the original TheOneFile: fully offline, self contained, editable anywhere. Import it back into the TheOneFile_Verse anytime to continue collaborating. **AND/OR** Rooms auto save your work, no manual exports required. Admins can run as many rooms as needed, a multiOneFileverse of parallel diagrams. Host it privately or open it to the internet (use tons of caution and a secure reverse proxy). * [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) ### Option 1: Easiest ```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` ## Configuration All settings are configured via the admin panel at `/admin`. On first run, you'll set up an admin account. ### .env | Variable | Default | Description | |----------|---------|-------------| | `PORT` | `10101` | Server port | | `DATA_DIR` | `./data` | Where settings and room data are stored | | `REDIS_URL` | | Optional Redis connection for scaling | | `CORS_ORIGIN` | | Comma separated list of allowed origins | | `REQUIRE_WS_TOKEN` | `false` | Require WebSocket session tokens | | `TRUSTED_PROXY_COUNT` | | Number of trusted reverse proxies for X Forwarded For | | `TRUSTED_PROXIES` | | Comma separated list of trusted proxy IPs | | `DEBUG_OIDC` | `false` | Enable OIDC debug logging (dev only) | ### TheOneFile_Verse Features * **Current Version 1.9.0 BETA 2** **Production ready hierarchical architecture + fixes** * See [changelog](changelog.md) for full 1.9.0 list of changes #### Core Collaboration * Realtime sync via WebSocket * Realtime chat per room with message persistence * Typing indicators, message replies, @mentions * Emoji picker and sound notifications * Real time multi user cursor engine with smooth transitions * Room based sessions with optional passwords * Auto destruct rooms (time based or when empty) with countdown display * Guest access controls per room * All the functions of TheOneFile_Networkening #### Full User Account System * User registration with email verification * Secure password login with Argon2id hashing * Two factor authentication (TOTP) with backup codes **NEW 1.7** * Email change with verification **NEW 1.7** * Magic link login (passwordless authentication) * Session management with device tracking * Multiple active sessions per user * Account lockout protection #### Single Sign On (SSO/OIDC) * Sign in with Authentik, Google, GitHub, Microsoft, or any OIDC provider * Link multiple SSO providers to one account * Auto account linking by email * Configurable per provider settings * Full OIDC spec compliance (JWT algorithm mapping, discovery validation, sub claim enforcement) * Post login redirect persistence across SSO flows * Secure account linking re verification #### Real PING * Overrides built in TheOneFileNetworkening "HTTP PING" with real server side methods * New probe types: ICMP ping, TCP port check, HTTP/HTTPS, DNS and Multi Probe (all combined) * Custom user ports #### etwork Discovery * Added "Discover Network Hosts" button to settings panel under Auto Status Checking section (at the bottom) * Full subnet discovery with CIDR range input and preset common ranges * Multiple range support * Port scanning on discovered hosts across 70+ common ports covering infrastructure and self hosted services (more soon) * Custom user ports * Export hosts to canvas as nodes and racks with all scanned and edited information * Admin only mode and public range restrictions available in Admin settings #### Popular Service + selfh.st/icons Detection * Reverse DNS hostname resolution * NetBIOS name resolution (Windows network names) * mDNS / Avahi multicast DNS resolution * HTTP server header detection (Server and X Powered By) * SNMPv2c system name and description queries with configurable community string * Automatic port to service mapping for 70+ common ports * Automatic icon detection and assignment for 70+ services via selfh.st icons * Smart icon tagging via popular ports * Self hosted media: Plex, Jellyfin, Emby, Sonarr, Radarr, Lidarr, Prowlarr, Bazarr, Overseerr, Tautulli, Ombi, Navidrome, Audiobookshelf, Komga, Jackett, Calibre web * Automation and IoT: Home Assistant, Node RED, ESPHome, n8n * +tons more #### DNS Detection * Hosts running port 53 are probed further:) to identify the DNS software * AdGuard Home detected via /control/status endpoint (should work with password protected instances) * Pi-hole detected via /admin/api.php (v5) and /api/ (v6), (should work with password protected instances) * Technitium detected via port 5380 presence #### Docker Detection * Looks for docker api, dockge, portainer etc * "Deep Scan" button will popup next to host * This will scan the host more indepth for containers running though docker IF api is not available * Docker container names from "Deep Scan" are also added as tags #### Automated Service Tagging * Services column in Network Discovery table shows tags that will be saved with the host * Named services (Jellyfin, Grafana, Dockge, etc.) automatic detection * Generic port detection (Port 3003, Port 8810, etc.) * Docker container names from "Deep Scan" are also added as tags #### Email System * SMTP configuration with TLS/STARTTLS support * Email verification on signup * Password reset via email * Magic link authentication * Room invitation emails * Customizable email templates * Email delivery logging * Multiple SMTP configurations supported #### Admin Dashboard * Full user management (create, edit, deactivate, delete) * Role based access control (admin, user, guest) * OIDC provider configuration * SMTP configuration management * Email template customization * Comprehensive audit logging * Activity logs per room * Email delivery logs * System settings management #### Security & Protection * AES 256 GCM encryption for all secrets (including TOTP secrets and backup codes) * PBKDF2 key derivation (600,000 iterations) **Enhanced 1.7** * Argon2id password hashing * TOTP two factor authentication (RFC 6238 compliant) **NEW 1.7** * Secure HTTP only cookies with proper autocomplete attributes * SameSite cookie policy * HSTS headers on all responses * WebSocket session tokens * WebSocket connection rate limiting per IP * IP based rate limiting * Email rate limiting * Configurable trusted proxy support with environment variable overrides **NEW 1.7** * Custom admin path (security through obscurity but not everyone likes the default) * Constant time token comparison with length padding * SSRF protection on webhook URLs * Automatic admin token cleanup * Full HTML entity escaping on all user generated content * CRLF injection prevention in email headers * STARTTLS downgrade protection * File upload size limits * Generic error messages to prevent user enumeration #### Responsive & Mobile * Full responsive design across all pages (landing, auth, admin dashboard) #### Rate Limiting * Endpoint rate limiting (configurable window and max attempts) * Email action rate limiting (signup, password reset, magic link) * WebSocket token bucket rate limiting per message type #### Authentication Modes * Open registration * Email verification required * OIDC only (SSO required) * Invite only (admin must create accounts) * Closed (no new registrations) * Guest room access controls #### Full Api System [api.md](api.md) * REST API with authentication * API key management * Webhook notifications for events #### Backup & Recovery * Manual and automatic backups * Configurable backup intervals * Backup retention policies * One click restore ## How It Works 1. Server fetches the latest TheOneFile Networkening HTML from GitHub on startup or upload your own custom template. 2. When users create or join rooms, the HTML is served with collaboration scripts injected. 3. All edits sync in realtime via WebSocket. 4. Data can be saved in the room and can be export into a fully editable and portable version of The One File. 5. Or data can be exported in all popular editing formats. 6. Bring it back later and import the HTML, CSV, JSON, or MD right back into your TheOneFile_Verse room. ================================================ FILE: theonefile_verse/api.md ================================================ # TheOneFile Verse API Documentation Base URL: `http://localhost:10101` (or your deployed instance) ## Authentication ### API Key Authentication ``` Authorization: Bearer yourapikey ``` API keys have granular permissions: - `read`: View rooms and data - `write`: Create and modify rooms - `admin`: Full administrative access --- ## Public Endpoints ### Check Room Exists ``` GET /api/room/{roomId}/exists ``` **Response** ```json { "exists": true, "hasPassword": false, "created": "2024-01-15T10:30:00.000Z", "destruct": { "mode": "time", "value": 86400000 } } ``` ### Create Room ``` POST /api/room Content-Type: application/json { "creatorId": "optional uuid", "password": "optional room password", "destructMode": "time", "destructValue": 86400000, "topology": null } ``` **Parameters** | Field | Type | Description | |-------|------|-------------| | creatorId | string (UUID) | Optional. Auto generated if not provided | | password | string | Optional. Minimum 4 characters | | destructMode | string | `time`, `empty`, or `never` | | destructValue | number | Milliseconds until destruction (max 30 days) | | topology | object | Optional initial state | **Response** ```json { "id": "550e8400-e29b-41d4-a716-446655440000", "url": "/s/550e8400-e29b-41d4-a716-446655440000", "hasPassword": false } ``` ### Verify Room Password ``` POST /api/room/{roomId}/verify Content-Type: application/json { "password": "room password" } ``` **Response** ```json { "valid": true } ``` ### Delete Room (Creator Only) ``` DELETE /api/room/{roomId} Content-Type: application/json { "creatorId": "creator uuid" } ``` **Response** ```json { "deleted": true } ``` ### Get Theme Settings ``` GET /api/theme ``` **Response** ```json { "forcedTheme": "user", "chatEnabled": true, "cursorSharingEnabled": true, "nameChangeEnabled": true } ``` --- ### Rooms **List All Rooms** ``` GET /api/admin/rooms GET /api/admin/rooms?q=searchterm ``` **Response** ```json { "rooms": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "created": "2024-01-15T10:30:00.000Z", "lastActivity": "2024-01-15T12:00:00.000Z", "hasPassword": false, "connectedUsers": 2, "destruct": { "mode": "time", "value": 86400000 } } ], "total": 1 } ``` **Delete Room** ``` DELETE /api/admin/rooms/{roomId} ``` **Response** ```json { "deleted": true } ``` ### Settings **Get Settings** ``` GET /api/admin/settings ``` **Response** ```json { "instancePasswordEnabled": false, "instancePasswordSet": false, "updateIntervalHours": 24, "skipUpdates": false, "allowPublicRoomCreation": true, "maxRoomsPerInstance": 0, "defaultDestructMode": "time", "defaultDestructHours": 24, "forcedTheme": "user", "rateLimitEnabled": true, "rateLimitWindow": 60, "rateLimitMaxAttempts": 10, "chatEnabled": true, "cursorSharingEnabled": true, "nameChangeEnabled": true, "webhookEnabled": false, "webhookUrl": null, "backupEnabled": false, "backupIntervalHours": 24, "backupRetentionCount": 7 } ``` **Update Settings** ``` POST /api/admin/settings Content-Type: application/json { "chatEnabled": false, "webhookEnabled": true, "webhookUrl": "https://example.com/webhook" } ``` Only include fields you want to update. ### Activity Logs **Get Activity Logs** ``` GET /api/admin/activity-logs GET /api/admin/activity-logs?room={roomId} ``` **Response** ```json { "logs": [ { "id": 1, "timestamp": "2024-01-15T10:30:00.000Z", "roomId": "550e8400-e29b-41d4-a716-446655440000", "userId": "user uuid", "userName": "Connor MacLeod", "eventType": "join", "ipAddress": "192.168.1.1" } ] } ``` ### Audit Logs **Get Audit Logs** ``` GET /api/admin/audit-logs GET /api/admin/audit-logs?q=searchterm ``` **Response** ```json { "logs": [ { "id": 1, "timestamp": "2024-01-15T10:30:00.000Z", "action": "room_deleted", "actor": "admin", "actorIp": "192.168.1.1", "targetType": "room", "targetId": "550e8400-e29b-41d4-a716-446655440000", "details": null } ] } ``` ### Backups **List Backups** ``` GET /api/admin/backups ``` **Response** ```json { "backups": [ { "id": "backup uuid", "filename": "backup_2024-01-15T10-30-00.json", "createdAt": "2024-01-15T10:30:00.000Z", "sizeBytes": 15234, "roomCount": 5, "autoGenerated": false } ] } ``` **Create Backup** ``` POST /api/admin/backups ``` **Response** ```json { "success": true, "backup": { "id": "backup uuid", "filename": "backup_2024-01-15T10-30-00.json", "sizeBytes": 15234, "roomCount": 5 } } ``` **Download Backup** ``` GET /api/admin/backups/{backupId}/download ``` Returns the backup file as JSON download. **Restore Backup** ``` POST /api/admin/backups/{backupId}/restore ``` **Response** ```json { "success": true, "roomsRestored": 3 } ``` **Delete Backup** ``` DELETE /api/admin/backups/{backupId} ``` **Response** ```json { "deleted": true } ``` ### Export **Export All Data** ``` GET /api/admin/export ``` Returns a JSON file containing all rooms and settings. **Response Structure** ```json { "version": 1, "exportedAt": "2024-01-15T10:30:00.000Z", "rooms": [...], "settings": {...} } ``` ### API Keys **List API Keys** ``` GET /api/admin/api-keys ``` **Response** ```json { "keys": [ { "id": "key uuid", "name": "My Integration", "permissions": ["read", "write"], "createdAt": "2024-01-15T10:30:00.000Z", "lastUsed": "2024-01-15T12:00:00.000Z", "expiresAt": null, "active": true } ] } ``` **Create API Key** ``` POST /api/admin/api-keys Content-Type: application/json { "name": "My Integration", "permissions": ["read", "write"], "expiresInDays": 30 } ``` **Parameters** | Field | Type | Description | |-------|------|-------------| | name | string | Required. Display name for the key | | permissions | array | `read`, `write`, `admin` | | expiresInDays | number | Optional. 0 or null for no expiration | **Response** ```json { "id": "key uuid", "key": "tof_a1b2c3d4e5f6...", "name": "My Integration", "permissions": ["read", "write"] } ``` > **Important**: The `key` value is only returned once at creation. Store it securely. **Revoke API Key** ``` DELETE /api/admin/api-keys/{keyId} ``` **Response** ```json { "revoked": true } ``` ### Source Management **Change Source Mode** ``` POST /api/admin/source-mode Content-Type: application/json { "mode": "github" } ``` Modes: `github` (auto update from GitHub) or `local` (manual upload) **Trigger GitHub Update** ``` POST /api/admin/update ``` **Response** ```json { "success": true, "size": 245678 } ``` **Upload Local HTML** ``` POST /api/admin/upload-html Content-Type: multipart/form-data file: [HTML file] ``` **Response** ```json { "success": true, "size": 245678, "edition": "networkening" } ``` --- ## WebSocket API ``` ws://localhost:10101/ws/{roomId} ``` ### Message Types **Join Room** ```json { "type": "join", "user": { "id": "user uuid", "name": "Connor MacLeod", "color": "#e63946" } } ``` **Leave Room** ```json { "type": "leave", "userId": "user uuid" } ``` **Presence Update** ```json { "type": "presence", "userId": "user uuid", "selectedNodes": ["node-1", "node-2"], "editingNode": "node-1", "currentTab": "Main" } ``` **State Sync** ```json { "type": "state", "state": { "nodeData": {...}, "edgeData": {...}, "imageData": {...}, ... } } ``` **Cursor Position** ```json { "type": "cursor", "userId": "user uuid", "x": 1500, "y": 1200, "isCanvasCoords": true } ``` **Chat Message** ```json { "type": "chat", "userId": "user uuid", "userName": "Connor MacLeod", "userColor": "#e63946", "text": "Hello everyone!", "timestamp": 1705312200000 } ``` ### Server Messages **Initial State** ```json { "type": "initial-state", "state": {...} } ``` **User List** ```json { "type": "users", "users": [...] } ``` **Name Rejected** ```json { "type": "name-rejected", "reason": "Name already taken in this room" } ``` --- ## Rate Limiting When rate limiting is enabled, endpoints return `429 Too Many Requests` if limits are exceeded. Default limits: - 10 attempts per 60 seconds per IP per endpoint Response: ```json { "error": "Too many attempts. Try again later." } ``` --- ## Error Responses All errors follow this format: ```json { "error": "Error message description" } ``` Common HTTP status codes: - `400` Bad Request (invalid input) - `401` Unauthorized (missing or invalid auth) - `403` Forbidden (insufficient permissions) - `404` Not Found - `429` Too Many Requests (rate limited) - `500` Internal Server Error --- ## Webhook Events When webhooks are enabled, POST requests are sent to your configured URL. **Room Created** ```json { "event": "room_created", "timestamp": "2024-01-15T10:30:00.000Z", "data": { "roomId": "550e8400-e29b-41d4-a716-446655440000", "hasPassword": false, "destructMode": "time", "creatorId": "creator uuid" } } ``` ================================================ FILE: theonefile_verse/changelog.md ================================================ ### TheOneFile_Verse changelog **4/6/26 Theonefile_verse 1.9.0 Beta 2** : **Production ready hierarchical architecture + fixes** *Now that most of the core TheOneFile_Verse development is done, I have begun breaking the code into a more production friendly hierarchical structure. This will be completed by 2.0 Stable.* * **Complete index.ts Refactoring** * Broke the monolithic index.ts into a hierarchical module structure * 14 route handler files organized by domain (auth, admin, rooms, network, public) * Dedicated WebSocket handler * **Further Production Hardening** * Graceful shutdown with SIGTERM/SIGINT handlers * Global error handling for uncaught exceptions and unhandled rejections * Enhanced /api/health endpoint with database, Redis, and uptime status * Database healthCheck() and Redis ping() for component level monitoring * Proper cleanup of WebSocket connections, timers, and database on shutdown * **Reverse Proxy Fixes + Hardening** * Fixed all OIDC callback, email verification, and password reset URLs * Added a helper to prevent internal origin leakage behind reverse proxy * CORS origins now parsed once at startup instead of per request * Pre compiled cookie regex for room access checks * **API Key Authentication + fixes** * Fixed validateApiKey() for programmatic access. * Bearer token auth with tof_ prefix routes to API key validation, all other Bearer tokens route to session validation * Permission enforcement: read, write, and admin permissions checked per endpoint * CSRF validation are now skipped for API key requests * Audit logs track API key identity for all actions * **Bug Fixes** * Fixed a settings bug where partial settings changes were visible to concurrent requests before validation completed * Fixed initializeTheOneFile() not being awaited on startup, which caused first room requests to fail with "room unavailable" before the HTML file finished loading * Fixed XSS vulnerability in network discovery icon alt attributes where icon names were not escaped with escapeHtml() * Fixed hardcoded /admin redirect in setup and migration pages that broke custom admin path configurations * Fixed OIDC email matching not normalizing case before database lookup * Static file serving simplified with lookup table * All innerHTML usage audited and verified safe with escapeHtml() **3/26/26 Theonefile_verse 1.8.6** : **Further improvements to Network Auto Discovery scanner/editor one page setup** *Now that most of the core TheOneFile_Verse development is done, I have begun breaking the code into a more production friendly hierarchical structure. This will be completed by 2.0 Stable.* * **Network Discovery : Connections** * Thanks to [ahmaddxb](https://github.com/ahmaddxb) [#44](https://github.com/gelatinescreams/The-One-File/issues/44) * Added connections section to host editor cards * Connect discovered hosts to each other or to existing canvas nodes * From port and To port added to host editor cards * Icon syling added to host editor cards * Layer added to host editor cards * Notes added to host editor cards **3/11/26 Theonefile_verse 1.8.5** : **Real ping, mutli network host discovery with selfh.st/icons matching and various other tidbits** *Now that most of the core TheOneFile_Verse development is done, I have begun breaking the code into a more production friendly hierarchical structure. This will be completed by 2.0 Stable.* * **Real PING** * Overrides built in TheOneFileNetworkening "HTTP PING" with real server side methods * New probe types: ICMP ping, TCP port check, HTTP/HTTPS, DNS and Multi Probe (all combined) * Custom user ports * **Network Discovery** * Added "Discover Network Hosts" button to settings panel under Auto Status Checking section (at the bottom) * Full subnet discovery with CIDR range input and preset common ranges * Multiple range support * Port scanning on discovered hosts across 70+ common ports covering infrastructure and self hosted services (more soon) * Custom user ports * Export hosts to canvas as nodes and racks with all scanned and edited information * Admin only mode and public range restrictions available in Admin settings * **Popular Service + selfh.st/icons Detection** * Reverse DNS hostname resolution * NetBIOS name resolution (Windows network names) * mDNS / Avahi multicast DNS resolution * HTTP server header detection (Server and X Powered By) * SNMPv2c system name and description queries with configurable community string * Automatic port to service mapping for 70+ common ports * Automatic icon detection and assignment for 70+ services via selfh.st icons * Smart icon tagging via popular ports * Self hosted media: Plex, Jellyfin, Emby, Sonarr, Radarr, Lidarr, Prowlarr, Bazarr, Overseerr, Tautulli, Ombi, Navidrome, Audiobookshelf, Komga, Jackett, Calibre web * Automation and IoT: Home Assistant, Node RED, ESPHome, n8n * +tons more * **DNS Detection** * Hosts running port 53 are probed further:) to identify the DNS software * AdGuard Home detected via /control/status endpoint (should work with password protected instances) * Pi-hole detected via /admin/api.php (v5) and /api/ (v6), (should work with password protected instances) * Technitium detected via port 5380 presence * **Docker Detection** * Looks for docker api, dockge, portainer etc * "Deep Scan" button will popup next to host * This will scan the host more indepth for containers running though docker IF api is not available * Docker container names from "Deep Scan" are also added as tags * **Automated Service Tagging** * Services column in Network Discovery table shows tags that will be saved with the host * Named services (Jellyfin, Grafana, Dockge, etc.) automatic detection * Generic port detection (Port 3003, Port 8810, etc.) * Docker container names from "Deep Scan" are also added as tags **3/4/26 Theonefile_verse 1.8.0** : **Added a few settings, fixed some bugs, annoyances, security and production friendly hierarchical structure** *Now that most of the core TheOneFile_Verse development is done, I have begun breaking the code into a more production friendly hierarchical structure. This will be completed by 2.0 Stable.* * **New admin settings.** * Added admin setting to set room themes as default. Custom themes from imported versions will also be able to set as default. Thanks to [ahmaddxb](https://github.com/ahmaddxb) [#45](https://github.com/gelatinescreams/The-One-File/issues/45) * Added admin setting to show hide admin login link on homepage * Added admin setting to force welcome modal to all users even if custom data present * **Changes + Bug Fixes** * Fixed an issue where custom styles were not being applied after leaving the room * Changed QR code library to local library * Changed crypto.randomUUID() to oidc.generateSecureToken(32) for room ID creation * Backup code login as fallback (single use) * Password required to disable 2FA * AES 256 GCM encrypted secret and backup code storage * Removed all remaining innerHTML references * XSS audit passed * Added futher error logging to docker logs * Tons of security + performance fixes * **OIDC Fixes** * Fixed an admin promotion issue when OIDC is the first user registered * **Redis Fixes** * Changed Redis KEYS to SCAN. * Added redis.conf with safe limits * **Docker Fixes** * Added docker resource limits to default compose file **3/2/26 Theonefile_verse 1.7.0** : *2FA, responsive overhaul, email change, path to stable, further security improvements* *Now that most of the core TheOneFile_Verse development is done, I have begun breaking the code into a more production friendly hierarchical structure. This will be completed by 2.0 Stable.* * **Two Factor Authentication (TOTP)** * Full TOTP implementation (RFC 6238, HMAC SHA1, 30 second window with ±1 tolerance) * QR code setup flow with manual secret entry fallback * 10 encrypted backup codes generated on enable * 2FA verification on login for both user and admin login pages * Backup code login as fallback (single use) * Password required to disable 2FA * AES 256 GCM encrypted secret and backup code storage * 5 minute expiry on pending 2FA tokens with replay prevention * **Email Change** * Request email change with password confirmation * Verification email sent to new address * Token hash verification pattern (raw token to user, SHA 256 hash stored) * Uniqueness check on both request and confirmation * 24 hour token expiry * **Responsive & Mobile Overhaul** * Full responsive design on landing page, all 9 auth page templates, and admin dashboard * **User Settings Modal** * New account settings modal accessible from user menu * 2FA setup and disable UI with QR code display * Backup codes display after 2FA enable * Email change form with password confirmation * Verification status feedback * **Security Hardening** * Per token 2FA attempt limit (3 maximum) prevents brute force on TOTP codes * PBKDF2 key derivation iterations increased from 100,000 to 600,000 * OIDC email matching defaults to disabled (requires explicit opt in) * typeof input validation on all authentication API endpoints * typeof validation on profile update fields * CSRF validation added to all authenticated endpoints * OIDC token values redacted from debug logs * Proper autocomplete attributes on all auth inputs (email, current password, new password, one time code) * HSTS header now sent unconditionally (removed production mode guard) * WebSocket per message deflate compression enabled * Trusted proxy count and trusted proxy list configurable via TRUSTED_PROXY_COUNT and TRUSTED_PROXIES env vars * **Bug Fixes** * Fixed registration failing with "Invalid security token" in some instances. (CSRF token was never fetched on landing page) * Fixed closeModal throwing error on modals without error elements (settings modal) * Fixed error text elements not showing when set via textContent (added not empty CSS rule) * Chat input alignment changed from flex end to center * Chat emoji changed from text entity to actual emoji character * Room creator_id database index added for search optimization **2/15/26 Theonefile_verse 1.6.0** : **Security hardening, chat overhaul, UX improvements** * **Security Hardening** * Timing safe comparison for legacy password hashes using crypto.timingSafeEqual * Length padded admin password comparison to prevent length oracle attacks * Full HTML entity escaping on chat messages and usernames (& < > " ') * Content Security Policy headers applied to all pages * OIDC provider name/type XSS protection with esc() in admin panel * PUT method added to CORS allowed methods * 50MB file upload size limit enforced before processing * Generic error messages on registration and disabled accounts to prevent user enumeration * CRLF injection prevention in all email headers (from, to, subject) * STARTTLS downgrade now throws error instead of continuing in plaintext * Template subject variable CRLF sanitization * **Chat System Overhaul** * Chat message persistence sffrf * Typing indicators with "user is typing" display * Message replies with quoted reference * @mention highlighting with notification sound * 500 character counter with visual warning * Emoji picker with most common emojis * Relative timestamps (2m ago, 1h ago) * **UX Improvements** * iOS safe area inset support on collab bar, modals, toasts * User avatars with colored initials in user list * Connection status indicator (green/yellow/red dot with pulse) * Offline/reconnecting banner with manual reconnect button * Stacking notification toasts with slide animations * Full screen mobile chat at 640px breakpoint * Smooth CSS transitions on remote cursors * Room expiry countdown display for auto destruct rooms * **Server** * Typing message type with dedicated rate limit (5 bucket, 1/sec refill) * Chat history cleanup on room deletion **2/14/26 Theonefile_verse 1.5.2** : **Auth flow fixes, error logging, version tracking** * **Auth Flow Fixes** * Fixed setup page JavaScript SyntaxError that prevented form submission * Fixed missing SetCookie header on /api/setup route * Fixed password reset form variable shadowing window.confirm * Added defensive semicolons to OIDC button rendering across all forms * **Error Logging** * All server side catch blocks now log errors with tagged prefixes * Tags: [Setup], [Login], [Register], [AdminLogin], [API], [Backup], [Update], etc. * **Infrastructure** * Docker entrypoint now handles volume permissions automatically via su exec * Database migrations use safe column existence check before ALTER TABLE (BUN FIX) * Added /api/version endpoint for build verification * Version displayed in startup logs * CSRF cookie now includes HttpOnly flag **2/14/26 Theonefile_verse 1.5.1** : **Fixes and further security hardening** * **OIDC/SSO** * JWT signature verification now correctly maps hash algorithms (SHA 256/384/512) per token header * Discovery document validation ensures authorization and token endpoints exist and issuer matches * Sub claim enforcement on all ID tokens per OIDC spec * Openid scope automatically enforced on all provider configurations * Token type validation on token exchange responses * Post login redirect persistence across SSO flows * Account linking reverification ensures session is still valid before linking * Increased entropy in random string generation for required values * **Security Hardening** * Added CSRF token protection on password reset endpoint * Constant time token comparison using crypto.timingSafeEqual * SSRF protection on webhook URLs (blocks private/internal IP ranges) * WebSocket connection rate limiting per IP address * IP validation on all rate limited endpoints * Automatic admin token cleanup on startup * Rate limit store memory management improvements * Token revocation on session termination * Docker Redis password security via --requirepass * Dockerfile now uses non root USER directive **1/26/26 Theonefile_verse 1.5.0** *The Identity Update* * **Full User Account System** * User registration with email verification * Magic link login for passwordless authentication * Session management with device tracking (browser, OS, IP) * Multiple active sessions per user * Account lockout protection * User profile management (display name, avatar) * User preferences (theme, email notifications) * Self service account deletion * **Single Sign On (SSO/OIDC)** * Sign in with Authentik, Google, GitHub, Microsoft, or any OpenID Connect provider * Link multiple SSO providers to a single account * Auto account linking by email * Configurable provider settings (scopes, display order, icons) * Secure encrypted token storage * **Email System** * SMTP configuration with TLS/STARTTLS support * Email verification on signup * Password reset via email * Magic link authentication * Room invitation emails * Customizable email templates with variables * Email delivery logging with status tracking * Multiple SMTP configurations supported * **Enhanced Security** * AES 256 GCM encryption for all stored secrets * PBKDF2 key derivation (100,000 iterations) * CSRF token protection on all forms * Secure HTTP only cookies * SameSite cookie policy * Production mode with HSTS headers * WebSocket session tokens for authenticated connections * Custom admin path option * Configurable trusted proxy support * Content Security Policy headers * **Rate Limiting** * Endpoint rate limiting (configurable window and max attempts) * Email action rate limiting (signup, password reset, magic link) * WebSocket token bucket rate limiting per message type * Brute force protection on login attempts * **Authentication Modes** * Open registration * Email verification required mode * OIDC only * Invite only * Closed * Guest room join controls * **Admin Dashboard Enhancements** * Full user management (create, edit, deactivate, delete) * Role based access control (admin, user, guest) * OIDC provider configuration UI * SMTP configuration management * Email template customization * Email delivery logs * Auth settings configuration * **Bug Fixes** * Many bug and security fixes. As above and so below **1/18/26 Theonefile_verse 1.4.0** *From Alpha to Beta status* * **New Features** * **Database & Storage Migration** * Migrated from flat JSON files to SQLite with WAL mode for better performance * **Redis Integration** * Added Redis support for data with graceful fallback to in memory * Rate limiting via Redis with automatic expiration * Session token storage with TTL * User presence tracking per room * Room state caching * Pub/sub messaging infrastructure for future scaling * Admin Dashboard Enhancements * **Full Api System** [api.md](api.md) * **New Tabs** * Logs tab: View activity logs (joins/leaves) and audit logs (admin actions) * Backups tab: Create, download, restore, and delete backups * API Keys tab: Create and revoke API keys with granular permissions * **New Admin Settings** * Toggle chat * Toggle cursor sharing * Toggle name changes globally * Webhooks: Enable webhook notifications with configurable URL * Automatic Backups: Enable scheduled backups with interval and retention settings * Room search/filter by ID or creator * Activity logging (who joined which room, when) * Audit logging for all admin actions * Backup & Recovery System * Manual backup creation via admin panel * Automatic scheduled backups with configurable interval (hours) * Backup retention policy (keeps N most recent auto backups) * One click restore from any backup * Export all rooms as JSON with settings * API Key System * Create API keys with custom names * Granular permissions: read, write, admin * Optional expiration (days) * Last used tracking * Revoke keys instantly * Webhook Notifications * POST notifications to configured URL * Events: room creation (with room ID, password status, destruct mode) * JSON payload with timestamp * **Bug Fixes** * Fixed a rare bug affecting custom image persistence * Fixed rare instances where images would not be restored on tab change * Further Cursor Precision Improvements * Polling every 100ms detects canvas state changes * Reduced throttle from 50ms to 25ms (20Hz → 40Hz) * Various performance and security improvements **1/17/26 Theonefile_verse 1.3.1** Updated for Image and Notes update **1/12/26 Theonefile_verse 1.3** Its all coming together now * Completely rewrote the cross user mouse logic. It is much more reliable now. * Fixed an issue where styles and some variables were not saving across user instances * Various bug fixes **1/6/26 Theonefile_verse 1.2** Flip it and reverse it * Fixed an issue where revere proxies did not pick us WSS correctly * Fixed an issue where username did not persist in some rare cases * various fixes **1/6/26 Theonefile_verse 1.1** Getting chatty * 1.1 gitea bleeding edge version main lined * adds instant message chat per room * adds duplciate name detection * adds real time mutli user cursor engine * adds current tab to the users top bar name plate * various fixes **1/6/26 Theonefile_verse intitial upload 1.0** * initial upload ================================================ FILE: theonefile_verse/demo-admin.html ================================================ Admin Demo | TheOneFile_Verse

Admin Dashboard Demo Mode

Back to App
This is a demo admin panel with sample data. All buttons are non functional for security.
12
Total Rooms
5
Active
8
Protected
23
Users Online

All Rooms

0 selected
Room Users Created Password Actions
Room
a1b2c3d4-e5f6-7890-abcd-ef1234567890
4
Jan 15, 2026
Yes
Room
b208667b-7a9e-4a18-ac98-5cb6e73bb669
7
Jan 18, 2026
Yes
Room
c3d4e5f6-7890-abcd-ef12-345678901234
2
Jan 20, 2026
No
Room
d4e5f678-90ab-cdef-1234-567890123456
5
Jan 22, 2026
Yes
Room
e5f67890-abcd-ef12-3456-789012345678
5
Jan 24, 2026
Yes
Room
f6789012-cdef-3456-7890-abcdef123456
0
Jan 25, 2026
Yes

User Management

User Role Status Created Actions
Administrator
admin@example.com
Admin
Active
Jan 1, 2026
John Doe
john.doe@company.com
User
Active
Jan 5, 2026
Jane Smith
jane.smith@company.com
User
Active
Jan 8, 2026
Bob Wilson
bob.wilson@external.org
User
Active Unverified
Jan 12, 2026
Sarah Connor
sarah@skynet.io
Admin
Active
Jan 15, 2026
Mike Chen
mike.chen@startup.co
User
Inactive
Jan 18, 2026

Authentication Mode

Default Auth Mode
How users can access the system
Require Email Verification
Users must verify email before accessing
Allow Magic Link Login
Users can login via email link
Match OIDC Emails
Auto link OIDC accounts with matching email. Only enable with trusted providers

Security

Production Mode
Enable HTTPS secure cookies. Required for production
ID Token Max Age (hours)
Maximum age for OIDC ID tokens before they are considered too old
Email Rate Limit Window (seconds)
Time window for email rate limiting
Email Rate Limit Max Attempts
Maximum email requests per address within window

Guest Access

Allow Guest Room Creation
Unregistered users can create rooms
Allow Guest Room Join
Unregistered users can join rooms
Room Creator Guest Setting
Let room creators choose guest access per room
Share Button
Show share button in rooms

OIDC Providers

Configure OpenID Connect providers for SSO

Google
generic | Active
Authentik (Internal)
authentik | Active
GitHub
generic | Inactive

SMTP Configuration

Configure email delivery for verification and notifications

Primary SMTP Default
smtp.sendgrid.net:587 (starttls) | Active
Backup SMTP
smtp.mailgun.org:465 (tls) | Active

Email Templates

Email Verification
Subject: Verify your email | TheOneFile_Verse
Password Reset
Subject: Reset your password | TheOneFile_Verse
Magic Link
Subject: Your login link | TheOneFile_Verse
Room Invitation
Subject: You've been invited to collaborate | TheOneFile_Verse

Email Logs

1/26/2026, 10:32 AM sent john.doe@company.com Verify your email | TheOneFile_Verse
1/26/2026, 9:15 AM sent jane.smith@company.com Your login link | TheOneFile_Verse
1/25/2026, 4:45 PM sent bob.wilson@external.org Verify your email | TheOneFile_Verse
1/25/2026, 2:20 PM failed invalid@nowhere.xyz Verify your email | TheOneFile_Verse Recipient rejected
1/24/2026, 11:00 AM sent sarah@skynet.io You've been invited to collaborate | TheOneFile_Verse

Instance Access

Password Lock
Require password to access the entire instance
Instance Password
Set a password for instance access
Admin Panel Path
Custom URL path for the admin panel (default: admin)
/
Current path: /admin
Show Admin Link
Show admin panel link in the landing page footer

TheOneFile Source

Source Mode
Choose where to load TheOneFile from
Update Interval
Hours between auto updates (0 = manual only)
Upload Local File
Upload your own TheOneFile HTML
v2.4.1 networkening edition
Up to date
Last updated: Jan 26, 2026, 11:00 AM 245 KB
Changelog

Appearance

Theme
Force a theme for all users or let them choose

Room Defaults

Default Self Destruct
Default expiration for new rooms
hours
Max Rooms
Maximum rooms allowed (0 = unlimited)
Default Room Theme
Theme preset for new rooms (from loaded file)
Public Room Creation
Allow anyone to create rooms

Network Probing

Server-Side Probing
Enable real ICMP/TCP/HTTP/DNS probes from server
Network Discovery
Allow subnet scanning to discover hosts
Discovery Admin Only
Restrict network discovery to admin users
Allow Public Ranges
Allow scanning non-private (public) IP ranges
Max Scan Size
Minimum CIDR prefix (larger = smaller range)
/

Rate Limiting

Enable Rate Limiting
Protect against brute force attacks
Limit Settings
Max attempts per time window
attempts per seconds

Collaboration Features

Chat
Enable chat in rooms
Cursor Sharing
Show other users cursors
Name Changes
Allow users to change name after joining
Welcome Modal
Always show welcome setup when joining rooms

Webhooks

Enable Webhooks
Send notifications for events
Webhook URL
POST endpoint for notifications

Automatic Backups

Enable Auto Backup
Automatically backup data
Backup Settings
Interval and retention
Every hours, keep backups

Activity Log

1/26/2026, 11:45 AM join John Doe a1b2c3d4
1/26/2026, 11:42 AM leave Jane Smith b208667b
1/26/2026, 11:30 AM join Guest_7842 c3d4e5f6
1/26/2026, 11:15 AM join Sarah Connor a1b2c3d4
1/26/2026, 10:58 AM leave Bob Wilson d4e5f678
1/26/2026, 10:45 AM join Mike Chen e5f67890

Audit Log

1/26/2026, 11:30 AM settings_update admin@example.com
1/26/2026, 11:15 AM user_create admin@example.com abc123de
1/26/2026, 10:45 AM backup_create system
1/26/2026, 9:30 AM oidc_update admin@example.com google_01
1/26/2026, 8:00 AM admin_login admin@example.com

Backups

backup_2026-01-26_110000.json
1/26/2026, 11:00:00 AM | 156KB | 12 rooms | Auto
backup_2026-01-25_110000.json
1/25/2026, 11:00:00 AM | 148KB | 11 rooms | Auto
backup_2026-01-24_143022.json
1/24/2026, 2:30:22 PM | 142KB | 10 rooms
backup_2026-01-23_110000.json
1/23/2026, 11:00:00 AM | 128KB | 8 rooms | Auto

API Keys

Production API
read, write | Created: 1/15/2026 | Last used: 1/26/2026
Monitoring Service
read | Created: 1/10/2026 | Last used: 1/26/2026
Admin CLI Tool
read, write, admin | Created: 1/1/2026 | Expires: 2/1/2026
================================================ FILE: theonefile_verse/docker-compose.yml ================================================ services: theonefile_verse: image: ghcr.io/gelatinescreams/theonefile_verse:latest ports: - "10101:10101" volumes: - ./data:/app/data environment: - PORT=10101 - DATA_DIR=/app/data - UPDATE_INTERVAL=24 - REDIS_URL=redis://redis:6379 depends_on: redis: condition: service_healthy restart: unless-stopped healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:10101/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: limits: cpus: "2" memory: 512M pids: 256 logging: driver: json-file options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true cap_drop: - ALL cap_add: - CHOWN - SETUID - SETGID - NET_RAW networks: - internal redis: image: redis:7-alpine volumes: - redis_data:/data - ./redis.conf:/usr/local/etc/redis/redis.conf:ro command: redis-server /usr/local/etc/redis/redis.conf restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 3 deploy: resources: limits: cpus: "2" memory: 512M pids: 64 logging: driver: json-file options: max-size: "10m" max-file: "3" networks: - internal volumes: redis_data: networks: internal: driver: bridge ================================================ FILE: theonefile_verse/entrypoint.sh ================================================ #!/bin/sh set -e chown -R appuser:appgroup /app/data if ! su-exec appuser test -w /app/data; then echo "FATAL: /app/data is not writable by appuser" >&2 exit 1 fi exec su-exec appuser bun run src/index.ts ================================================ FILE: theonefile_verse/package.json ================================================ { "name": "theonefile_verse", "version": "1.9.0", "type": "module", "scripts": { "dev": "bun run --watch src/index.ts", "start": "bun run src/index.ts" }, "dependencies": { "redis": "^4.6.13" } } ================================================ FILE: theonefile_verse/public/admin-auth.js ================================================ (function() { 'use strict'; var forcedTheme = null; function getTheme() { if (forcedTheme && forcedTheme !== 'user') return forcedTheme; return localStorage.getItem('theme') || 'dark'; } function setTheme(t) { document.documentElement.setAttribute('data-theme', t); } setTheme(getTheme()); fetch('/api/theme').then(function(r) { return r.json(); }).then(function(d) { if (d.forcedTheme && d.forcedTheme !== 'user') { forcedTheme = d.forcedTheme; setTheme(forcedTheme); } }).catch(function() {}); window.__authCsrfToken = ''; window.__authCsrfRefresh = function() { return fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { window.__authCsrfToken = d.token; }).catch(function() {}); }; window.__authRenderOidcProviders = function(containerId, dividerId, redirectSuffix) { fetch('/api/auth/providers').then(function(r) { return r.json(); }).then(function(providers) { if (providers.length > 0) { var divider = document.getElementById(dividerId); if (divider) divider.style.display = 'flex'; var container = document.getElementById(containerId); providers.forEach(function(p) { var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'oidc-btn'; if (p.iconUrl && (p.iconUrl.startsWith('http://') || p.iconUrl.startsWith('https://'))) { var img = document.createElement('img'); img.src = p.iconUrl; img.width = 20; img.height = 20; btn.appendChild(img); } btn.appendChild(document.createTextNode(' Continue with ' + (p.name || ''))); btn.addEventListener('click', function() { window.location.href = '/api/auth/oidc/' + p.id + '/login' + (redirectSuffix || ''); }); container.appendChild(btn); }); } }).catch(function() {}); }; })(); ================================================ FILE: theonefile_verse/public/admin-dashboard.js ================================================ (function() { 'use strict'; var pageData = JSON.parse((document.getElementById('page-data') || {}).textContent || '{}'); var ADMIN_PATH = pageData.adminPath || 'admin'; var csrfToken = ''; function refreshCsrf() { return fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { if (d.token) csrfToken = d.token; }).catch(function() {}); } refreshCsrf(); function csrfHeaders(extra) { var h = { 'x-csrf-token': csrfToken }; if (extra) { for (var k in extra) { if (extra.hasOwnProperty(k)) h[k] = extra[k]; } } setTimeout(refreshCsrf, 0); return h; } var forcedTheme = null; function getTheme() { if (forcedTheme && forcedTheme !== 'user') return forcedTheme; return localStorage.getItem('theme') || 'dark'; } function setTheme(theme) { if (!forcedTheme || forcedTheme === 'user') { localStorage.setItem('theme', theme); } document.documentElement.setAttribute('data-theme', theme); document.getElementById('theme-icon').textContent = theme === 'dark' ? '\u2600' : '\u263E'; } function toggleTheme() { if (forcedTheme && forcedTheme !== 'user') return; setTheme(getTheme() === 'dark' ? 'light' : 'dark'); } function updateThemeToggleVisibility() { var btn = document.getElementById('theme-toggle'); if (forcedTheme && forcedTheme !== 'user') { btn.style.display = 'none'; } else { btn.style.display = 'block'; } } setTheme(getTheme()); fetch('/api/theme') .then(function(r) { return r.json(); }) .then(function(data) { if (data.forcedTheme && data.forcedTheme !== 'user') { forcedTheme = data.forcedTheme; setTheme(forcedTheme); } updateThemeToggleVisibility(); }) .catch(function() { updateThemeToggleVisibility(); }); function h(tag, props) { var node = document.createElement(tag); if (props) { for (var key in props) { if (!props.hasOwnProperty(key)) continue; if (key === 'className') node.className = props[key]; else if (key === 'style') node.setAttribute('style', props[key]); else if (key === 'textContent') node.textContent = props[key]; else if (key.slice(0, 5) === 'data-') node.setAttribute(key, props[key]); else if (key === 'checked') { if (props[key]) node.checked = true; } else node[key] = props[key]; } } for (var i = 2; i < arguments.length; i++) _append(node, arguments[i]); return node; } function _append(parent, child) { if (child == null || child === false) return; if (typeof child === 'string' || typeof child === 'number') { parent.appendChild(document.createTextNode(String(child))); } else if (Array.isArray(child)) { for (var j = 0; j < child.length; j++) _append(parent, child[j]); } else { parent.appendChild(child); } } function clearNode(el) { while (el.firstChild) el.removeChild(el.firstChild); } function setContent(container, children) { clearNode(container); var frag = document.createDocumentFragment(); _append(frag, children); container.appendChild(frag); } var rooms = []; var selected = new Set(); var settings = {}; var totalRooms = 0; var searchTimeout = null; var users = []; var authSettings = {}; var oidcProviders = []; var smtpConfigs = []; var emailLogs = []; function showTab(name) { document.querySelectorAll('.tab').forEach(function(t) { t.classList.remove('active'); }); document.querySelectorAll('.tab-content').forEach(function(t) { t.classList.remove('active'); }); document.querySelector('.tab-content#tab-' + name).classList.add('active'); document.querySelector('.tab[data-tab="' + name + '"]').classList.add('active'); if (name === 'settings') loadSettings(); if (name === 'logs') { loadActivityLogs(); loadAuditLogs(); } if (name === 'backups') loadBackups(); if (name === 'apikeys') loadApiKeys(); if (name === 'users') loadUsers(); if (name === 'auth') { loadAuthSettings(); loadOidcProviders(); loadSmtpConfigs(); loadEmailTemplates(); loadEmailLogs(); } } async function loadData(query) { query = query || ''; try { var url = query ? '/api/admin/rooms?q=' + encodeURIComponent(query) : '/api/admin/rooms'; var res = await fetch(url); if (!res.ok) { if (res.status === 401) { window.location.href = '/' + ADMIN_PATH + '/login'; } return; } var data = await res.json(); rooms = data.rooms || data; totalRooms = data.total || rooms.length; renderStats(); renderRooms(); updateBulkUI(); } catch (e) { console.error(e); } } function searchRooms(q) { if (searchTimeout) clearTimeout(searchTimeout); searchTimeout = setTimeout(function() { loadData(q); }, 300); } async function loadSettings() { try { var res = await fetch('/api/admin/settings'); if (!res.ok) return; settings = await res.json(); renderSettings(); } catch (e) { console.error(e); } } function renderSettings() { document.getElementById('toggle-instance-lock').classList.toggle('active', settings.instancePasswordEnabled); document.getElementById('toggle-public-rooms').classList.toggle('active', settings.allowPublicRoomCreation); document.getElementById('toggle-rate-limit').classList.toggle('active', settings.rateLimitEnabled !== false); document.getElementById('update-interval').value = settings.updateIntervalHours || 0; document.getElementById('default-destruct-mode').value = settings.defaultDestructMode || 'time'; document.getElementById('default-destruct-hours').value = settings.defaultDestructHours || 24; document.getElementById('max-rooms').value = settings.maxRoomsPerInstance || 0; document.getElementById('forced-theme').value = settings.forcedTheme || 'user'; var themeSelect = document.getElementById('default-room-theme'); if (themeSelect) { themeSelect.innerHTML = ''; if (settings.availableThemes) { settings.availableThemes.forEach(function(t) { var opt = document.createElement('option'); opt.value = t.key; opt.textContent = t.label; themeSelect.appendChild(opt); }); } themeSelect.value = settings.defaultRoomTheme || ''; } document.getElementById('rate-limit-attempts').value = settings.rateLimitMaxAttempts || 10; document.getElementById('rate-limit-window').value = settings.rateLimitWindow || 60; document.getElementById('rate-limit-options').style.display = settings.rateLimitEnabled !== false ? 'flex' : 'none'; document.getElementById('instance-pwd-row').style.display = settings.instancePasswordEnabled ? 'flex' : 'none'; document.getElementById('instance-pwd-status').textContent = settings.instancePasswordSet ? 'Password is set' : 'No password set'; if (settings.envAdminPasswordSet) { document.getElementById('toggle-instance-lock').style.opacity = '0.5'; document.getElementById('toggle-instance-lock').setAttribute('data-disabled', 'true'); } document.getElementById('toggle-chat').classList.toggle('active', settings.chatEnabled !== false); document.getElementById('toggle-cursor').classList.toggle('active', settings.cursorSharingEnabled !== false); document.getElementById('toggle-namechange').classList.toggle('active', settings.nameChangeEnabled !== false); document.getElementById('toggle-welcome-modal').classList.toggle('active', settings.forceWelcomeModal); document.getElementById('toggle-probe').classList.toggle('active', settings.probeEnabled !== false); document.getElementById('toggle-discovery').classList.toggle('active', settings.discoveryEnabled !== false); document.getElementById('toggle-discovery-admin').classList.toggle('active', settings.discoveryAdminOnly !== false); document.getElementById('toggle-discovery-public').classList.toggle('active', settings.discoveryAllowPublicRanges); document.getElementById('discovery-max-prefix').value = settings.discoveryMaxPrefix || 20; document.getElementById('toggle-webhook').classList.toggle('active', settings.webhookEnabled); document.getElementById('webhook-url').value = settings.webhookUrl || ''; document.getElementById('webhook-url-row').style.display = settings.webhookEnabled ? 'flex' : 'none'; document.getElementById('toggle-backup').classList.toggle('active', settings.backupEnabled); document.getElementById('backup-interval').value = settings.backupIntervalHours || 24; document.getElementById('backup-retention').value = settings.backupRetentionCount || 7; document.getElementById('backup-options').style.display = settings.backupEnabled ? 'flex' : 'none'; document.getElementById('admin-path').value = settings.adminPath || 'admin'; document.getElementById('admin-path-info').style.display = 'flex'; document.getElementById('admin-path-current').textContent = 'Current path: /' + (settings.adminPath || 'admin'); document.getElementById('toggle-show-admin-link').classList.toggle('active', settings.showAdminLink !== false); updateSourceUI(); } async function saveAdminPath() { var newPath = document.getElementById('admin-path').value.trim(); if (!newPath) { showStatus('Admin path cannot be empty', 'error'); return; } if (!/^[a-zA-Z0-9_-]+$/.test(newPath)) { showStatus('Admin path can only contain letters, numbers, hyphens, and underscores', 'error'); return; } if (newPath.length < 2) { showStatus('Admin path must be at least 2 characters', 'error'); return; } var reserved = ['api', 's', 'ws', 'auth', 'public', 'static', 'assets']; if (reserved.includes(newPath.toLowerCase())) { showStatus('This path is reserved', 'error'); return; } try { var res = await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ adminPath: newPath }) }); var data = await res.json(); if (!res.ok) { showStatus(data.error || 'Failed to save', 'error'); return; } document.getElementById('admin-path-current').textContent = 'Current path: /' + newPath; showStatus('Admin path saved! Redirecting to new path...', 'success'); setTimeout(function() { window.location.href = '/' + newPath; }, 1500); } catch (e) { showStatus('Error saving admin path', 'error'); } } async function saveRateLimitSettings() { var attempts = parseInt(document.getElementById('rate-limit-attempts').value) || 10; var windowVal = parseInt(document.getElementById('rate-limit-window').value) || 60; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ rateLimitMaxAttempts: attempts, rateLimitWindow: windowVal }) }); showStatus('Rate limit settings saved', 'success'); } async function saveForcedTheme() { var val = document.getElementById('forced-theme').value; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ forcedTheme: val }) }); showStatus('Theme setting saved', 'success'); } async function toggleSetting(key) { if (key === 'instancePasswordEnabled' && settings.envAdminPasswordSet) return; settings[key] = !settings[key]; renderSettings(); await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ [key]: settings[key] }) }); showStatus('Setting updated', 'success'); } async function setInstancePassword() { var pwd = document.getElementById('instance-password').value; if (pwd.length < 10) { showStatus('Password must be at least 10 characters', 'error'); return; } await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ instancePassword: pwd }) }); document.getElementById('instance-password').value = ''; showStatus('Password updated', 'success'); loadSettings(); } async function saveUpdateInterval() { var val = parseInt(document.getElementById('update-interval').value) || 0; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ updateIntervalHours: val }) }); showStatus('Update interval saved', 'success'); } async function triggerUpdate() { var btn = document.getElementById('update-btn'); btn.disabled = true; btn.textContent = 'Updating...'; try { var res = await fetch('/api/admin/update', { method: 'POST', headers: csrfHeaders() }); var data = await res.json(); if (data.success) { var msg = 'Updated to v' + (data.version || '?') + ' (' + Math.round(data.size / 1024) + 'KB)'; if (data.previousVersion && data.previousVersion !== data.version) msg = 'Updated v' + data.previousVersion + ' → v' + data.version + ' (' + Math.round(data.size / 1024) + 'KB)'; showStatus(msg, 'success'); loadSettings(); } else { showStatus(data.error || 'Update failed', 'error'); } } catch (e) { showStatus('Update failed', 'error'); } btn.disabled = false; btn.textContent = 'Update Now'; } async function checkForUpdates() { var btn = document.getElementById('check-update-btn'); btn.disabled = true; btn.textContent = 'Checking...'; try { var res = await fetch('/api/admin/version-check'); var data = await res.json(); if (data.error) { showStatus(data.error, 'error'); } else if (data.updateAvailable) { showStatus('Update available: v' + data.latestVersion + ' (current: v' + data.currentVersion + ')', 'success'); var updateBtn = document.getElementById('update-btn'); if (updateBtn) updateBtn.style.background = '#22c55e'; } else { showStatus('Up to date (v' + data.currentVersion + ')', 'success'); } settings.latestGitHubVersion = data.latestVersion; settings.lastVersionCheck = data.lastChecked; updateSourceUI(); } catch (e) { showStatus('Version check failed', 'error'); } btn.disabled = false; btn.textContent = 'Check for Updates'; } async function changeSourceMode() { var mode = document.getElementById('source-mode').value; try { var res = await fetch('/api/admin/source-mode', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ mode: mode }) }); var data = await res.json(); if (data.success) { showStatus('Source mode changed to ' + mode, 'success'); loadSettings(); } else { showStatus(data.error || 'Failed to change mode', 'error'); } } catch (e) { showStatus('Failed to change mode', 'error'); } } async function uploadFile() { var input = document.getElementById('upload-file'); if (!input.files || !input.files[0]) return; var file = input.files[0]; var formData = new FormData(); formData.append('file', file); try { var res = await fetch('/api/admin/upload-html', { method: 'POST', headers: csrfHeaders(), body: formData }); var data = await res.json(); if (data.success) { showStatus('Uploaded successfully (' + Math.round(data.size / 1024) + 'KB), ' + data.edition + ' edition', 'success'); loadSettings(); } else { showStatus(data.error || 'Upload failed', 'error'); } } catch (e) { showStatus('Upload failed', 'error'); } input.value = ''; } function updateSourceUI() { var isLocal = settings.skipUpdates; document.getElementById('source-mode').value = isLocal ? 'local' : 'github'; document.getElementById('github-settings').style.display = isLocal ? 'none' : 'flex'; document.getElementById('github-update-row').style.display = isLocal ? 'none' : 'flex'; document.getElementById('upload-row').style.display = isLocal ? 'flex' : 'none'; var ver = settings.currentFileVersion || 'unknown'; var edition = settings.currentFileEdition || 'unknown'; var sizeKB = settings.currentFileSize ? Math.round(settings.currentFileSize / 1024) : 0; var versionEl = document.getElementById('current-version-badge'); var editionEl = document.getElementById('current-edition-badge'); var sizeEl = document.getElementById('file-size-info'); var lastUpdateEl = document.getElementById('last-update-info'); var statusBadge = document.getElementById('version-status-badge'); if (versionEl) versionEl.textContent = 'v' + ver; if (editionEl) editionEl.textContent = edition.charAt(0).toUpperCase() + edition.slice(1) + ' edition'; if (sizeEl) sizeEl.textContent = sizeKB + 'KB'; if (lastUpdateEl) { if (settings.lastUpdateTimestamp) { var d = new Date(settings.lastUpdateTimestamp); lastUpdateEl.textContent = 'Last updated: ' + d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) + ' at ' + d.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' }); } else { lastUpdateEl.textContent = 'Never updated from GitHub'; } } if (statusBadge) { var latest = settings.latestGitHubVersion; if (latest) latest = latest.replace(/^["']+|["']+$/g, ''); if (latest && latest !== 'unknown' && ver !== 'unknown') { var isNewer = (function(a, b) { var pa = a.replace(/^v/i, '').split('.').map(Number); var pb = b.replace(/^v/i, '').split('.').map(Number); for (var i = 0; i < Math.max(pa.length, pb.length); i++) { if ((pa[i] || 0) > (pb[i] || 0)) return true; if ((pa[i] || 0) < (pb[i] || 0)) return false; } return false; })(latest, ver); if (isNewer) { statusBadge.textContent = 'v' + latest + ' available'; statusBadge.style.background = '#854d0e'; statusBadge.style.color = '#fbbf24'; } else { statusBadge.textContent = 'Up to date'; statusBadge.style.background = '#166534'; statusBadge.style.color = '#4ade80'; } } else { statusBadge.textContent = ''; } } } async function saveRoomDefaults() { await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ defaultDestructMode: document.getElementById('default-destruct-mode').value, defaultDestructHours: parseInt(document.getElementById('default-destruct-hours').value) || 24, maxRoomsPerInstance: parseInt(document.getElementById('max-rooms').value) || 0, defaultRoomTheme: document.getElementById('default-room-theme').value }) }); showStatus('Room defaults saved', 'success'); } function showStatus(msg, type) { var container = document.getElementById('settings-status'); setContent(container, h('div', {className: 'status-msg ' + type}, msg)); setTimeout(function() { clearNode(container); }, 3000); } function showAuthStatus(msg, type) { var container = document.getElementById('auth-status'); setContent(container, h('div', {className: 'status-msg ' + type}, msg)); setTimeout(function() { clearNode(container); }, 3000); } function renderStats() { var active = rooms.filter(function(r) { return r.connectedUsers > 0; }).length; var withPwd = rooms.filter(function(r) { return r.hasPassword; }).length; var totalUsers = rooms.reduce(function(a, r) { return a + r.connectedUsers; }, 0); function statCard(value, label) { return h('div', {className: 'stat-card'}, h('div', {className: 'stat-value'}, String(value)), h('div', {className: 'stat-label'}, label) ); } setContent(document.getElementById('stats'), [ statCard(rooms.length, 'Total Rooms'), statCard(active, 'Active'), statCard(withPwd, 'Protected'), statCard(totalUsers, 'Users Online') ]); } function renderRooms() { var container = document.getElementById('room-list'); if (rooms.length === 0) { setContent(container, h('div', {className: 'empty-state'}, h('h3', null, 'No rooms yet'), h('p', null, 'Rooms will appear here when created') )); return; } var header = h('div', {className: 'room-header'}, h('input', {type: 'checkbox', className: 'room-checkbox', 'data-action': 'toggleAll', checked: selected.size === rooms.length && rooms.length > 0}), h('span', null, 'Room'), h('span', null, 'Users'), h('span', null, 'Created'), h('span', null, 'Password'), h('span', null, 'Actions') ); var rows = rooms.map(function(r) { var isSelected = selected.has(r.id); return h('div', {className: 'room-row' + (isSelected ? ' selected' : '')}, h('input', {type: 'checkbox', className: 'room-checkbox', checked: isSelected, 'data-action': 'toggleSelect', 'data-id': r.id}), h('div', null, h('div', {className: 'room-name'}, 'Room'), h('div', {className: 'room-id'}, r.id) ), h('div', null, h('span', {className: 'badge badge-' + (r.connectedUsers > 0 ? 'green' : 'gray')}, String(r.connectedUsers))), h('div', null, new Date(r.created).toLocaleDateString()), h('div', null, h('span', {className: 'badge badge-' + (r.hasPassword ? 'yellow' : 'gray')}, r.hasPassword ? 'Yes' : 'No')), h('div', {className: 'room-actions'}, h('button', {className: 'btn btn-secondary btn-sm', 'data-action': 'viewRoom', 'data-id': r.id}, 'View'), h('button', {className: 'btn btn-primary btn-sm', 'data-action': 'joinRoom', 'data-id': r.id}, 'Join'), h('button', {className: 'btn btn-danger btn-sm', 'data-action': 'deleteRoom', 'data-id': r.id}, 'Del') ) ); }); setContent(container, [header].concat(rows)); } function toggleSelect(id, checked) { if (checked) { selected.add(id); } else { selected.delete(id); } updateBulkUI(); renderRooms(); } function toggleAll(checked) { if (checked) { rooms.forEach(function(r) { selected.add(r.id); }); } else { selected.clear(); } updateBulkUI(); renderRooms(); } function clearSelection() { selected.clear(); updateBulkUI(); renderRooms(); } function updateBulkUI() { var bulk = document.getElementById('bulk-actions'); var count = document.getElementById('selected-count'); if (selected.size > 0) { bulk.classList.add('active'); count.textContent = selected.size + ' selected'; } else { bulk.classList.remove('active'); } } async function deleteSelected() { if (selected.size === 0) return; if (!confirm('Delete ' + selected.size + ' room(s) permanently?')) return; for (var id of selected) { try { await fetch('/api/admin/rooms/' + id, { method: 'DELETE', headers: csrfHeaders() }); } catch (e) { } } selected.clear(); loadData(); } function viewRoom(id) { var room = rooms.find(function(r) { return r.id === id; }); if (!room) return; var destruct = 'Never'; if (room.destruct.mode === 'time') { var hours = room.destruct.value / 3600000; destruct = hours < 1 ? Math.round(hours * 60) + ' min' : hours < 24 ? hours + ' hours' : Math.round(hours / 24) + ' days'; } else if (room.destruct.mode === 'empty') { destruct = 'When empty'; } document.getElementById('modal-title').textContent = 'Room Details'; function infoRow(label, value, extraStyle) { return h('div', {className: 'info-row'}, h('span', {className: 'info-label'}, label), h('span', {className: 'info-value', style: extraStyle || ''}, value) ); } setContent(document.getElementById('modal-body'), [ infoRow('Room ID', room.id, 'font-family:monospace;font-size:12px'), infoRow('Created', new Date(room.created).toLocaleString()), infoRow('Last Activity', new Date(room.lastActivity).toLocaleString()), infoRow('Connected Users', String(room.connectedUsers)), infoRow('Password Protected', room.hasPassword ? 'Yes' : 'No'), infoRow('Self-Destruct', destruct), h('div', {style: 'margin-top:20px;display:flex;gap:12px;flex-wrap:wrap'}, h('button', {className: 'btn btn-primary', 'data-action': 'joinRoom', 'data-id': room.id}, 'Join Room'), h('button', {className: 'btn btn-danger', 'data-action': 'deleteRoom', 'data-id': room.id}, 'Delete Room') ) ]); document.getElementById('room-modal').classList.add('active'); } function closeModal() { document.getElementById('room-modal').classList.remove('active'); } function joinRoom(id) { window.open('/s/' + id, '_blank'); } async function deleteRoom(id) { if (!confirm('Delete this room permanently?')) return; try { var res = await fetch('/api/admin/rooms/' + id, { method: 'DELETE', headers: csrfHeaders() }); if (res.ok) { selected.delete(id); loadData(); } else { showStatus('Failed to delete room', 'error'); } } catch (e) { showStatus('Error deleting room', 'error'); } } async function logout() { await fetch('/api/logout', { method: 'POST', credentials: 'include', headers: csrfHeaders() }); window.location.href = '/'; } document.getElementById('room-modal').addEventListener('click', function(e) { if (e.target.id === 'room-modal') closeModal(); }); document.getElementById('apikey-modal').addEventListener('click', function(e) { if (e.target.id === 'apikey-modal') closeApiKeyModal(); }); async function saveWebhookUrl() { var url = document.getElementById('webhook-url').value; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ webhookUrl: url }) }); showStatus('Webhook URL saved', 'success'); } async function saveDiscoveryPrefix() { var prefix = parseInt(document.getElementById('discovery-max-prefix').value) || 20; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ discoveryMaxPrefix: prefix }) }); showStatus('Discovery prefix saved', 'success'); } async function saveBackupSettings() { var interval = parseInt(document.getElementById('backup-interval').value) || 24; var retention = parseInt(document.getElementById('backup-retention').value) || 7; await fetch('/api/admin/settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ backupIntervalHours: interval, backupRetentionCount: retention }) }); showStatus('Backup settings saved', 'success'); } async function loadActivityLogs() { try { var room = document.getElementById('activity-search').value; var url = room ? '/api/admin/activity-logs?room=' + encodeURIComponent(room) : '/api/admin/activity-logs'; var res = await fetch(url); if (!res.ok) return; var data = await res.json(); renderActivityLogs(data.logs); } catch (e) { } } async function loadAuditLogs() { try { var q = document.getElementById('audit-search').value; var url = q ? '/api/admin/audit-logs?q=' + encodeURIComponent(q) : '/api/admin/audit-logs'; var res = await fetch(url); if (!res.ok) return; var data = await res.json(); renderAuditLogs(data.logs); } catch (e) { } } function renderActivityLogs(logs) { var container = document.getElementById('activity-log-list'); if (!logs || logs.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No activity logs')); return; } setContent(container, logs.map(function(l) { return h('div', {style: 'padding:8px 0;border-bottom:1px solid var(--border);font-size:13px'}, h('span', {style: 'color:var(--text-soft)'}, new Date(l.timestamp).toLocaleString()), ' ', h('span', {className: 'badge badge-' + (l.eventType === 'join' ? 'green' : 'gray')}, l.eventType), ' ', l.userName || 'Unknown', ' ', h('span', {style: 'color:var(--text-soft);font-size:11px'}, l.roomId.slice(0, 8)) ); })); } function renderAuditLogs(logs) { var container = document.getElementById('audit-log-list'); if (!logs || logs.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No audit logs')); return; } setContent(container, logs.map(function(l) { return h('div', {style: 'padding:8px 0;border-bottom:1px solid var(--border);font-size:13px'}, h('span', {style: 'color:var(--text-soft)'}, new Date(l.timestamp).toLocaleString()), ' ', h('span', {className: 'badge badge-yellow'}, l.action), ' ', l.actor || 'system', l.targetId ? [' ', h('span', {style: 'color:var(--text-soft);font-size:11px'}, l.targetId.slice(0, 8))] : null ); })); } async function loadBackups() { try { var res = await fetch('/api/admin/backups'); if (!res.ok) return; var data = await res.json(); renderBackups(data.backups); } catch (e) { } } function renderBackups(backups) { var container = document.getElementById('backup-list'); if (!backups || backups.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No backups')); return; } setContent(container, backups.map(function(b) { return h('div', {style: 'display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)'}, h('div', null, h('div', {style: 'font-weight:500'}, b.filename), h('div', {style: 'font-size:12px;color:var(--text-soft)'}, new Date(b.createdAt).toLocaleString() + ' | ' + Math.round(b.sizeBytes / 1024) + 'KB | ' + b.roomCount + ' rooms' + (b.autoGenerated ? ' | Auto' : '') ) ), h('div', {style: 'display:flex;gap:6px'}, h('button', {className: 'btn btn-sm btn-secondary', 'data-action': 'downloadBackup', 'data-id': b.id}, 'Download'), h('button', {className: 'btn btn-sm btn-success', 'data-action': 'restoreBackup', 'data-id': b.id}, 'Restore'), h('button', {className: 'btn btn-sm btn-danger', 'data-action': 'deleteBackup', 'data-id': b.id}, 'Delete') ) ); })); } async function createBackup() { try { var res = await fetch('/api/admin/backups', { method: 'POST', headers: csrfHeaders() }); var data = await res.json(); if (data.success) { showStatus('Backup created', 'success'); loadBackups(); } else { showStatus(data.error || 'Failed', 'error'); } } catch (e) { showStatus('Failed to create backup', 'error'); } } async function downloadBackup(id) { window.open('/api/admin/backups/' + id + '/download', '_blank'); } async function restoreBackup(id) { if (!confirm('Restore this backup? This will add missing rooms.')) return; try { var res = await fetch('/api/admin/backups/' + id + '/restore', { method: 'POST', headers: csrfHeaders() }); var data = await res.json(); if (data.success) { showStatus('Restored ' + data.roomsRestored + ' rooms', 'success'); loadData(); } else { showStatus(data.error || 'Failed', 'error'); } } catch (e) { showStatus('Failed to restore', 'error'); } } async function deleteBackup(id) { if (!confirm('Delete this backup?')) return; try { await fetch('/api/admin/backups/' + id, { method: 'DELETE', headers: csrfHeaders() }); loadBackups(); } catch (e) { } } async function exportAll() { window.open('/api/admin/export', '_blank'); } async function loadApiKeys() { try { var res = await fetch('/api/admin/api-keys'); if (!res.ok) return; var data = await res.json(); renderApiKeys(data.keys); } catch (e) { } } function renderApiKeys(keys) { var container = document.getElementById('apikey-list'); if (!keys || keys.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No API keys')); return; } setContent(container, keys.map(function(k) { return h('div', {style: 'display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)'}, h('div', null, h('div', {style: 'font-weight:500'}, k.name), h('div', {style: 'font-size:12px;color:var(--text-soft)'}, k.permissions.join(', ') + ' | Created: ' + new Date(k.createdAt).toLocaleDateString() + (k.lastUsed ? ' | Last used: ' + new Date(k.lastUsed).toLocaleDateString() : '') + (k.expiresAt ? ' | Expires: ' + new Date(k.expiresAt).toLocaleDateString() : '') ) ), h('button', {className: 'btn btn-sm btn-danger', 'data-action': 'revokeApiKey', 'data-id': k.id}, 'Revoke') ); })); } function showCreateApiKey() { document.getElementById('apikey-modal').classList.add('active'); document.getElementById('new-key-display').style.display = 'none'; } function closeApiKeyModal() { document.getElementById('apikey-modal').classList.remove('active'); } async function createApiKey() { var name = document.getElementById('apikey-name').value; if (!name) { showStatus('Name required', 'error'); return; } var perms = []; if (document.getElementById('perm-read').checked) perms.push('read'); if (document.getElementById('perm-write').checked) perms.push('write'); if (document.getElementById('perm-admin').checked) perms.push('admin'); var expires = parseInt(document.getElementById('apikey-expires').value) || 0; try { var res = await fetch('/api/admin/api-keys', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ name: name, permissions: perms, expiresInDays: expires || null }) }); var data = await res.json(); if (data.key) { closeApiKeyModal(); document.getElementById('new-key-display').style.display = 'block'; document.getElementById('new-key-value').textContent = data.key; loadApiKeys(); } else { showStatus(data.error || 'Failed to create key', 'error'); } } catch (e) { showStatus('Failed to create key', 'error'); } } async function revokeApiKey(id) { if (!confirm('Revoke this API key?')) return; try { await fetch('/api/admin/api-keys/' + id, { method: 'DELETE', headers: csrfHeaders() }); loadApiKeys(); } catch (e) { } } async function loadUsers(q) { q = q || ''; try { var url = q ? '/api/admin/users?q=' + encodeURIComponent(q) : '/api/admin/users'; var res = await fetch(url); if (!res.ok) return; var data = await res.json(); users = data.users || []; renderUsers(); } catch (e) { } } function searchUsers(q) { if (searchTimeout) clearTimeout(searchTimeout); searchTimeout = setTimeout(function() { loadUsers(q); }, 300); } function renderUsers() { var container = document.getElementById('user-list'); if (!users || users.length === 0) { setContent(container, h('div', {className: 'empty-state'}, h('h3', null, 'No users yet'), h('p', null, 'Users will appear here when registered') )); return; } var header = h('div', {className: 'room-header'}, h('span', null, 'User'), h('span', null, 'Role'), h('span', null, 'Status'), h('span', null, 'Created'), h('span', null, 'Actions') ); var rows = users.map(function(u) { return h('div', {className: 'room-row'}, h('div', null, h('div', {className: 'room-name'}, u.displayName || 'No name'), h('div', {className: 'room-id'}, u.email) ), h('div', null, h('span', {className: 'badge badge-' + (u.role === 'admin' ? 'yellow' : 'gray')}, u.role === 'admin' ? 'Admin' : 'User')), h('div', null, h('span', {className: 'badge badge-' + (u.isActive ? 'green' : 'gray')}, u.isActive ? 'Active' : 'Inactive'), u.emailVerified ? null : h('span', {className: 'badge badge-yellow'}, 'Unverified') ), h('div', null, new Date(u.createdAt).toLocaleDateString()), h('div', {className: 'room-actions'}, h('button', {className: 'btn btn-secondary btn-sm', 'data-action': 'editUser', 'data-id': u.id}, 'Edit'), h('button', {className: 'btn btn-danger btn-sm', 'data-action': 'deleteUser', 'data-id': u.id}, 'Del') ) ); }); setContent(container, [header].concat(rows)); } function showCreateUser() { document.getElementById('user-modal').classList.add('active'); } function closeUserModal() { document.getElementById('user-modal').classList.remove('active'); document.getElementById('user-email').value = ''; document.getElementById('user-displayname').value = ''; document.getElementById('user-password').value = ''; document.getElementById('user-role').value = 'user'; } async function createUser() { var email = document.getElementById('user-email').value; var displayName = document.getElementById('user-displayname').value; var password = document.getElementById('user-password').value || null; var role = document.getElementById('user-role').value; if (!email) { showAuthStatus('Email required', 'error'); return; } try { var res = await fetch('/api/admin/users', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ email: email, displayName: displayName, password: password, role: role }) }); var data = await res.json(); if (data.success) { closeUserModal(); loadUsers(); showAuthStatus('User created', 'success'); } else { showAuthStatus(data.error || 'Failed to create user', 'error'); } } catch (e) { showAuthStatus('Failed to create user', 'error'); } } async function deleteUser(id) { if (!confirm('Delete this user permanently?')) return; try { await fetch('/api/admin/users/' + id, { method: 'DELETE', headers: csrfHeaders() }); loadUsers(); } catch (e) { showAuthStatus('Error deleting user', 'error'); } } function editUser(id) { var u = users.find(function(x) { return x.id === id; }); if (!u) return; document.getElementById('edit-user-id').value = id; document.getElementById('edit-user-email').value = u.email; document.getElementById('edit-user-displayname').value = u.displayName || ''; document.getElementById('edit-user-password').value = ''; document.getElementById('edit-user-role').value = u.role || 'user'; document.getElementById('edit-user-active').checked = u.isActive !== false; document.getElementById('edit-user-verified').checked = u.emailVerified === true; document.getElementById('edit-user-modal').classList.add('active'); } function closeEditUserModal() { document.getElementById('edit-user-modal').classList.remove('active'); } async function saveUserEdit() { var id = document.getElementById('edit-user-id').value; var data = { displayName: document.getElementById('edit-user-displayname').value, role: document.getElementById('edit-user-role').value, isActive: document.getElementById('edit-user-active').checked, emailVerified: document.getElementById('edit-user-verified').checked }; var password = document.getElementById('edit-user-password').value; if (password) data.password = password; try { var res = await fetch('/api/admin/users/' + id, { method: 'PUT', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(data) }); var result = await res.json(); if (result.success) { closeEditUserModal(); loadUsers(); showAuthStatus('User updated', 'success'); } else { showAuthStatus(result.error || 'Failed to update user', 'error'); } } catch (e) { showAuthStatus('Failed to update user', 'error'); } } async function resetUserPassword() { var id = document.getElementById('edit-user-id').value; var email = document.getElementById('edit-user-email').value; if (!confirm('Send password reset email to ' + email + '?')) return; try { var res = await fetch('/api/admin/users/' + id + '/reset-password', { method: 'POST', headers: csrfHeaders() }); var result = await res.json(); if (result.success) { showAuthStatus('Password reset email sent!', 'success'); } else { showAuthStatus(result.error || 'Failed to send reset email', 'error'); } } catch (e) { showAuthStatus('Failed to send reset email', 'error'); } } document.getElementById('user-modal').addEventListener('click', function(e) { if (e.target.id === 'user-modal') closeUserModal(); }); document.getElementById('edit-user-modal').addEventListener('click', function(e) { if (e.target.id === 'edit-user-modal') closeEditUserModal(); }); async function loadAuthSettings() { try { var res = await fetch('/api/admin/auth-settings'); if (!res.ok) return; authSettings = await res.json(); renderAuthSettings(); } catch (e) { } } function renderAuthSettings() { document.getElementById('auth-mode').value = authSettings.authMode || 'open'; document.getElementById('toggle-require-email-verify').classList.toggle('active', authSettings.requireEmailVerification); document.getElementById('toggle-magic-link').classList.toggle('active', authSettings.allowMagicLinkLogin); document.getElementById('toggle-oidc-email-match').classList.toggle('active', authSettings.oidcEmailMatching); document.getElementById('toggle-production-mode').classList.toggle('active', authSettings.productionMode); document.getElementById('toggle-guest-room-create').classList.toggle('active', authSettings.allowGuestRoomCreation !== false); document.getElementById('toggle-guest-room-join').classList.toggle('active', authSettings.allowGuestRoomJoin !== false); document.getElementById('toggle-room-creator-guest').classList.toggle('active', authSettings.allowRoomCreatorGuestSetting !== false); document.getElementById('toggle-share-button').classList.toggle('active', authSettings.shareButtonEnabled !== false); document.getElementById('input-id-token-max-age').value = authSettings.idTokenMaxAgeHours || 2; document.getElementById('input-email-rate-window').value = authSettings.emailRateLimitWindowSeconds || 300; document.getElementById('input-email-rate-max').value = authSettings.emailRateLimitMaxAttempts || 3; } async function saveAuthSettings() { var mode = document.getElementById('auth-mode').value; await fetch('/api/admin/auth-settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ authMode: mode }) }); showAuthStatus('Auth mode saved', 'success'); } async function toggleAuthSetting(key) { authSettings[key] = !authSettings[key]; renderAuthSettings(); await fetch('/api/admin/auth-settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ [key]: authSettings[key] }) }); showAuthStatus('Setting updated', 'success'); } async function updateAuthNumber(key, value) { var num = parseInt(value); if (isNaN(num)) return; authSettings[key] = num; await fetch('/api/admin/auth-settings', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ [key]: num }) }); showAuthStatus('Setting updated', 'success'); } async function loadOidcProviders() { try { var res = await fetch('/api/admin/oidc-providers'); if (!res.ok) return; var data = await res.json(); oidcProviders = data.providers || []; renderOidcProviders(); } catch (e) { } } function renderOidcProviders() { var container = document.getElementById('oidc-provider-list'); if (!oidcProviders || oidcProviders.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No OIDC providers configured')); return; } setContent(container, oidcProviders.map(function(p) { return h('div', {style: 'display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)'}, h('div', null, h('div', {style: 'font-weight:500'}, p.name), h('div', {style: 'font-size:12px;color:var(--text-soft)'}, p.providerType, ' | ', h('span', {style: 'color:' + (p.isActive ? '#22c55e' : '#94a3b8')}, p.isActive ? 'Active' : 'Inactive') ) ), h('div', {style: 'display:flex;gap:6px'}, h('button', {className: 'btn btn-sm btn-secondary', 'data-action': 'editOidcProvider', 'data-id': p.id}, 'Edit'), h('button', {className: 'btn btn-sm btn-danger', 'data-action': 'deleteOidcProvider', 'data-id': p.id}, 'Delete') ) ); })); } function showAddOidcProvider() { document.getElementById('oidc-modal-title').textContent = 'Add OIDC Provider'; document.getElementById('oidc-edit-id').value = ''; document.getElementById('oidc-name').value = ''; document.getElementById('oidc-type').value = 'generic'; document.getElementById('oidc-client-id').value = ''; document.getElementById('oidc-client-secret').value = ''; document.getElementById('oidc-issuer').value = ''; document.getElementById('oidc-auth-url').value = ''; document.getElementById('oidc-token-url').value = ''; document.getElementById('oidc-userinfo-url').value = ''; document.getElementById('oidc-scopes').value = 'openid email profile'; document.getElementById('oidc-active').checked = true; document.getElementById('oidc-modal').classList.add('active'); } function editOidcProvider(id) { var p = oidcProviders.find(function(x) { return x.id === id; }); if (!p) return; document.getElementById('oidc-modal-title').textContent = 'Edit OIDC Provider'; document.getElementById('oidc-edit-id').value = id; document.getElementById('oidc-name').value = p.name; document.getElementById('oidc-type').value = p.providerType; document.getElementById('oidc-client-id').value = p.clientId; document.getElementById('oidc-client-secret').value = ''; document.getElementById('oidc-issuer').value = p.issuerUrl || ''; document.getElementById('oidc-auth-url').value = p.authorizationUrl || ''; document.getElementById('oidc-token-url').value = p.tokenUrl || ''; document.getElementById('oidc-userinfo-url').value = p.userinfoUrl || ''; document.getElementById('oidc-scopes').value = p.scopes || 'openid email profile'; document.getElementById('oidc-active').checked = p.isActive; document.getElementById('oidc-modal').classList.add('active'); } function closeOidcModal() { document.getElementById('oidc-modal').classList.remove('active'); } async function saveOidcProvider() { var id = document.getElementById('oidc-edit-id').value; var data = { name: document.getElementById('oidc-name').value, providerType: document.getElementById('oidc-type').value, clientId: document.getElementById('oidc-client-id').value, clientSecret: document.getElementById('oidc-client-secret').value || undefined, issuerUrl: document.getElementById('oidc-issuer').value, authorizationUrl: document.getElementById('oidc-auth-url').value, tokenUrl: document.getElementById('oidc-token-url').value, userinfoUrl: document.getElementById('oidc-userinfo-url').value, scopes: document.getElementById('oidc-scopes').value, isActive: document.getElementById('oidc-active').checked }; if (!data.name || !data.clientId) { showAuthStatus('Name and Client ID required', 'error'); return; } try { var url = id ? '/api/admin/oidc-providers/' + id : '/api/admin/oidc-providers'; var method = id ? 'PUT' : 'POST'; var res = await fetch(url, { method: method, headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(data) }); var result = await res.json(); if (result.success) { closeOidcModal(); loadOidcProviders(); showAuthStatus('Provider saved', 'success'); } else { showAuthStatus(result.error || 'Failed to save provider', 'error'); } } catch (e) { showAuthStatus('Failed to save provider', 'error'); } } async function deleteOidcProvider(id) { if (!confirm('Delete this OIDC provider?')) return; try { await fetch('/api/admin/oidc-providers/' + id, { method: 'DELETE', headers: csrfHeaders() }); loadOidcProviders(); } catch (e) { } } document.getElementById('oidc-modal').addEventListener('click', function(e) { if (e.target.id === 'oidc-modal') closeOidcModal(); }); async function loadSmtpConfigs() { try { var res = await fetch('/api/admin/smtp-configs'); if (!res.ok) return; var data = await res.json(); smtpConfigs = data.configs || []; renderSmtpConfigs(); } catch (e) { } } function renderSmtpConfigs() { var container = document.getElementById('smtp-config-list'); if (!smtpConfigs || smtpConfigs.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No SMTP configurations')); return; } setContent(container, smtpConfigs.map(function(s) { return h('div', {style: 'display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)'}, h('div', null, h('div', {style: 'font-weight:500'}, s.name, s.isDefault ? [' ', h('span', {className: 'badge badge-green'}, 'Default')] : null ), h('div', {style: 'font-size:12px;color:var(--text-soft)'}, s.host, ':', String(s.port), ' (', s.secureMode, ') | ', h('span', {style: 'color:' + (s.isActive ? '#22c55e' : '#94a3b8')}, s.isActive ? 'Active' : 'Inactive') ) ), h('div', {style: 'display:flex;gap:6px'}, h('button', {className: 'btn btn-sm btn-secondary', 'data-action': 'editSmtpConfig', 'data-id': s.id}, 'Edit'), h('button', {className: 'btn btn-sm btn-danger', 'data-action': 'deleteSmtpConfig', 'data-id': s.id}, 'Delete') ) ); })); } function showAddSmtpConfig() { document.getElementById('smtp-modal-title').textContent = 'Add SMTP Configuration'; document.getElementById('smtp-edit-id').value = ''; document.getElementById('smtp-name').value = ''; document.getElementById('smtp-host').value = ''; document.getElementById('smtp-port').value = '587'; document.getElementById('smtp-secure-mode').value = 'starttls'; document.getElementById('smtp-username').value = ''; document.getElementById('smtp-password').value = ''; document.getElementById('smtp-from-email').value = ''; document.getElementById('smtp-from-name').value = ''; document.getElementById('smtp-default').checked = false; document.getElementById('smtp-active').checked = true; document.getElementById('smtp-modal').classList.add('active'); } function editSmtpConfig(id) { var s = smtpConfigs.find(function(x) { return x.id === id; }); if (!s) return; document.getElementById('smtp-modal-title').textContent = 'Edit SMTP Configuration'; document.getElementById('smtp-edit-id').value = id; document.getElementById('smtp-name').value = s.name; document.getElementById('smtp-host').value = s.host || ''; document.getElementById('smtp-port').value = s.port || 587; document.getElementById('smtp-secure-mode').value = s.secureMode || 'starttls'; document.getElementById('smtp-username').value = s.username || ''; document.getElementById('smtp-password').value = ''; document.getElementById('smtp-from-email').value = s.fromEmail || ''; document.getElementById('smtp-from-name').value = s.fromName || ''; document.getElementById('smtp-default').checked = s.isDefault; document.getElementById('smtp-active').checked = s.isActive; document.getElementById('smtp-modal').classList.add('active'); } function closeSmtpModal() { document.getElementById('smtp-modal').classList.remove('active'); } async function saveSmtpConfig() { var id = document.getElementById('smtp-edit-id').value; var data = { name: document.getElementById('smtp-name').value, host: document.getElementById('smtp-host').value, port: parseInt(document.getElementById('smtp-port').value), secureMode: document.getElementById('smtp-secure-mode').value, username: document.getElementById('smtp-username').value, password: document.getElementById('smtp-password').value || undefined, fromEmail: document.getElementById('smtp-from-email').value, fromName: document.getElementById('smtp-from-name').value, isDefault: document.getElementById('smtp-default').checked, isActive: document.getElementById('smtp-active').checked }; if (!data.name || !data.host) { showAuthStatus('Name and Host required', 'error'); return; } try { var url = id ? '/api/admin/smtp-configs/' + id : '/api/admin/smtp-configs'; var method = id ? 'PUT' : 'POST'; var res = await fetch(url, { method: method, headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(data) }); var result = await res.json(); if (result.success) { closeSmtpModal(); loadSmtpConfigs(); showAuthStatus('SMTP config saved', 'success'); } else { showAuthStatus(result.error || 'Failed to save config', 'error'); } } catch (e) { showAuthStatus('Failed to save config', 'error'); } } async function testSmtpConfig() { var data = { name: document.getElementById('smtp-name').value, host: document.getElementById('smtp-host').value, port: parseInt(document.getElementById('smtp-port').value), secureMode: document.getElementById('smtp-secure-mode').value, username: document.getElementById('smtp-username').value, password: document.getElementById('smtp-password').value, fromEmail: document.getElementById('smtp-from-email').value, fromName: document.getElementById('smtp-from-name').value }; try { var res = await fetch('/api/admin/smtp-configs/test', { method: 'POST', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(data) }); var result = await res.json(); if (result.success) { showAuthStatus('Test email sent successfully!', 'success'); } else { showAuthStatus('Test failed: ' + (result.error || 'Unknown error'), 'error'); } } catch (e) { showAuthStatus('Test failed', 'error'); } } async function deleteSmtpConfig(id) { if (!confirm('Delete this SMTP configuration?')) return; try { await fetch('/api/admin/smtp-configs/' + id, { method: 'DELETE', headers: csrfHeaders() }); loadSmtpConfigs(); } catch (e) { } } document.getElementById('smtp-modal').addEventListener('click', function(e) { if (e.target.id === 'smtp-modal') closeSmtpModal(); }); var emailTemplates = []; var currentEditTemplate = null; var isHtmlSourceView = false; async function loadEmailTemplates() { try { var res = await fetch('/api/admin/email-templates'); if (!res.ok) return; var data = await res.json(); emailTemplates = data.templates || []; renderEmailTemplates(emailTemplates); } catch (e) { } } function renderEmailTemplates(templates) { var container = document.getElementById('email-template-list'); if (!templates || templates.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No email templates. Default templates will be used.')); return; } setContent(container, templates.map(function(t) { return h('div', {style: 'display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--border)'}, h('div', null, h('div', {style: 'font-weight:500'}, t.name), h('div', {style: 'font-size:12px;color:var(--text-soft)'}, 'Subject: ', t.subject) ), h('button', {className: 'btn btn-sm btn-secondary', 'data-action': 'editTemplate', 'data-id': t.id}, 'Edit') ); })); } function sanitizeTemplateHtml(html) { var doc = new DOMParser().parseFromString(html, 'text/html'); doc.querySelectorAll('script,iframe,object,embed,form').forEach(function(el) { el.remove(); }); doc.querySelectorAll('*').forEach(function(el) { Array.from(el.attributes).forEach(function(attr) { if (attr.name.startsWith('on') || (typeof attr.value === 'string' && attr.value.trim().toLowerCase().startsWith('javascript:'))) { el.removeAttribute(attr.name); } }); if (el.hasAttribute('href') && el.getAttribute('href').trim().toLowerCase().startsWith('javascript:')) { el.removeAttribute('href'); } if (el.hasAttribute('src') && el.getAttribute('src').trim().toLowerCase().startsWith('javascript:')) { el.removeAttribute('src'); } }); return doc.body.innerHTML; } function editTemplate(id) { var t = emailTemplates.find(function(x) { return x.id === id; }); if (!t) return; currentEditTemplate = t; document.getElementById('template-edit-id').value = id; document.getElementById('template-name').value = t.name; document.getElementById('template-subject').value = t.subject || ''; var safeHtml = sanitizeTemplateHtml(t.bodyHtml || ''); document.getElementById('template-editor').innerHTML = safeHtml; document.getElementById('template-html-source').value = t.bodyHtml || ''; document.getElementById('template-text').value = t.bodyText || ''; isHtmlSourceView = false; showWysiwygView(); document.getElementById('template-modal').classList.add('active'); } function closeTemplateModal() { document.getElementById('template-modal').classList.remove('active'); currentEditTemplate = null; } function showWysiwygView() { document.getElementById('template-editor').style.display = 'block'; document.getElementById('template-editor-toolbar').style.display = 'flex'; document.getElementById('template-html-source').style.display = 'none'; } function showHtmlSourceView() { document.getElementById('template-html-source').value = document.getElementById('template-editor').innerHTML; document.getElementById('template-editor').style.display = 'none'; document.getElementById('template-editor-toolbar').style.display = 'none'; document.getElementById('template-html-source').style.display = 'block'; } function toggleTemplateView() { if (isHtmlSourceView) { document.getElementById('template-editor').innerHTML = sanitizeTemplateHtml(document.getElementById('template-html-source').value); showWysiwygView(); } else { showHtmlSourceView(); } isHtmlSourceView = !isHtmlSourceView; } function execCmd(cmd) { document.execCommand(cmd, false, null); document.getElementById('template-editor').focus(); } function execCmdArg(cmd, arg) { if (!arg) return; document.execCommand(cmd, false, arg); document.getElementById('template-editor').focus(); } function insertTemplateVar(varName) { var editor = document.getElementById('template-editor'); editor.focus(); document.execCommand('insertText', false, '{{' + varName + '}}'); } function insertLink() { var url = prompt('Enter URL:'); if (url) { document.execCommand('createLink', false, url); } } function insertImage() { var url = prompt('Enter image URL:'); if (url) { document.execCommand('insertImage', false, url); } } function insertButton() { var url = prompt('Enter button URL:'); var text = prompt('Enter button text:', 'Click Here'); if (url && text) { var safeUrl = url.replace(/&/g, '&').replace(/"/g, '"').replace(//g, '>'); var safeText = text.replace(/&/g, '&').replace(//g, '>'); if (/^javascript:/i.test(safeUrl.trim())) return; var btn = '' + safeText + ''; document.execCommand('insertHTML', false, btn); } } async function saveTemplate() { var id = document.getElementById('template-edit-id').value; if (!id) { showAuthStatus('No template selected', 'error'); return; } var html = isHtmlSourceView ? document.getElementById('template-html-source').value : document.getElementById('template-editor').innerHTML; var data = { subject: document.getElementById('template-subject').value, bodyHtml: html, bodyText: document.getElementById('template-text').value }; try { var res = await fetch('/api/admin/email-templates/' + id, { method: 'PUT', headers: csrfHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify(data) }); var result = await res.json(); if (result.success) { closeTemplateModal(); loadEmailTemplates(); showAuthStatus('Template saved', 'success'); } else { showAuthStatus(result.error || 'Failed to save template', 'error'); } } catch (e) { showAuthStatus('Failed to save template', 'error'); } } function previewTemplate() { var subject = document.getElementById('template-subject').value .replace(/\{\{displayName\}\}/g, 'John Doe') .replace(/\{\{actionUrl\}\}/g, 'https://example.com/action') .replace(/\{\{appName\}\}/g, 'TheOneFile_Verse'); var html = (isHtmlSourceView ? document.getElementById('template-html-source').value : document.getElementById('template-editor').innerHTML) .replace(/\{\{displayName\}\}/g, 'John Doe') .replace(/\{\{actionUrl\}\}/g, 'https://example.com/action') .replace(/\{\{appName\}\}/g, 'TheOneFile_Verse'); document.getElementById('preview-subject').textContent = subject; var frame = document.getElementById('preview-frame'); frame.sandbox = ''; frame.srcdoc = '' + html + ''; document.getElementById('template-preview-modal').classList.add('active'); } function closeTemplatePreview() { document.getElementById('template-preview-modal').classList.remove('active'); } document.getElementById('template-modal').addEventListener('click', function(e) { if (e.target.id === 'template-modal') closeTemplateModal(); }); document.getElementById('template-preview-modal').addEventListener('click', function(e) { if (e.target.id === 'template-preview-modal') closeTemplatePreview(); }); async function loadEmailLogs() { try { var email = document.getElementById('email-log-search').value; var url = email ? '/api/admin/email-logs?email=' + encodeURIComponent(email) : '/api/admin/email-logs'; var res = await fetch(url); if (!res.ok) return; var data = await res.json(); emailLogs = data.logs || []; renderEmailLogs(); } catch (e) { } } function renderEmailLogs() { var container = document.getElementById('email-log-list'); if (!emailLogs || emailLogs.length === 0) { setContent(container, h('p', {style: 'color:var(--text-soft);padding:12px'}, 'No email logs')); return; } setContent(container, emailLogs.map(function(l) { return h('div', {style: 'padding:8px 0;border-bottom:1px solid var(--border);font-size:13px'}, h('span', {style: 'color:var(--text-soft)'}, new Date(l.sentAt).toLocaleString()), ' ', h('span', {className: 'badge badge-' + (l.status === 'sent' ? 'green' : 'gray')}, l.status), ' ', l.toEmail, ' ', h('span', {style: 'color:var(--text-soft)'}, l.subject), l.errorMessage ? [' ', h('span', {style: 'color:#ef4444'}, l.errorMessage)] : null ); })); } async function clearEmailLogs() { if (!confirm('Clear all email logs? This cannot be undone.')) return; try { var res = await fetch('/api/admin/email-logs', { method: 'DELETE', headers: csrfHeaders() }); if (res.ok) { loadEmailLogs(); showAuthStatus('Email logs cleared', 'success'); } } catch (e) { } } async function clearActivityLogs() { if (!confirm('Clear all activity logs? This cannot be undone.')) return; try { var res = await fetch('/api/admin/activity-logs', { method: 'DELETE', headers: csrfHeaders() }); if (res.ok) { loadActivityLogs(); showAuthStatus('Activity logs cleared', 'success'); } } catch (e) { } } async function clearAuditLogs() { if (!confirm('Clear all audit logs? This cannot be undone.')) return; try { var res = await fetch('/api/admin/audit-logs', { method: 'DELETE', headers: csrfHeaders() }); if (res.ok) { loadAuditLogs(); showAuthStatus('Audit logs cleared', 'success'); } } catch (e) { } } document.addEventListener('click', function(e) { var target = e.target.closest('[data-action]'); if (!target) return; if (target.getAttribute('data-disabled') === 'true') return; var action = target.dataset.action; var handlers = { toggleTheme: toggleTheme, logout: logout, showTab: function() { showTab(target.dataset.tab); }, deleteSelected: deleteSelected, clearSelection: clearSelection, viewRoom: function() { viewRoom(target.dataset.id); }, joinRoom: function() { joinRoom(target.dataset.id); }, deleteRoom: function() { deleteRoom(target.dataset.id); }, toggleSetting: function() { toggleSetting(target.dataset.setting); }, toggleAuthSetting: function() { toggleAuthSetting(target.dataset.setting); }, showAddOidcProvider: showAddOidcProvider, showAddSmtpConfig: showAddSmtpConfig, editOidcProvider: function() { editOidcProvider(target.dataset.id); }, deleteOidcProvider: function() { deleteOidcProvider(target.dataset.id); }, editSmtpConfig: function() { editSmtpConfig(target.dataset.id); }, deleteSmtpConfig: function() { deleteSmtpConfig(target.dataset.id); }, saveOidcProvider: saveOidcProvider, saveSmtpConfig: saveSmtpConfig, testSmtpConfig: testSmtpConfig, closeModal: closeModal, closeApiKeyModal: closeApiKeyModal, closeUserModal: closeUserModal, closeEditUserModal: closeEditUserModal, closeOidcModal: closeOidcModal, closeSmtpModal: closeSmtpModal, closeTemplateModal: closeTemplateModal, closeTemplatePreview: closeTemplatePreview, showCreateApiKey: showCreateApiKey, createApiKey: createApiKey, showCreateUser: showCreateUser, createUser: createUser, editUser: function() { editUser(target.dataset.id); }, deleteUser: function() { deleteUser(target.dataset.id); }, saveUserEdit: saveUserEdit, resetUserPassword: resetUserPassword, revokeApiKey: function() { revokeApiKey(target.dataset.id); }, setInstancePassword: setInstancePassword, saveAdminPath: saveAdminPath, saveUpdateInterval: saveUpdateInterval, triggerUpdate: triggerUpdate, checkForUpdates: checkForUpdates, saveForcedTheme: saveForcedTheme, saveRoomDefaults: saveRoomDefaults, saveRateLimitSettings: saveRateLimitSettings, saveDiscoveryPrefix: saveDiscoveryPrefix, saveWebhookUrl: saveWebhookUrl, saveBackupSettings: saveBackupSettings, createBackup: createBackup, exportAll: exportAll, downloadBackup: function() { downloadBackup(target.dataset.id); }, restoreBackup: function() { restoreBackup(target.dataset.id); }, deleteBackup: function() { deleteBackup(target.dataset.id); }, editTemplate: function() { editTemplate(target.dataset.id); }, saveTemplate: saveTemplate, previewTemplate: previewTemplate, insertTemplateVar: function() { insertTemplateVar(target.dataset.varname); }, toggleTemplateView: toggleTemplateView, execCmd: function() { execCmd(target.dataset.cmd); }, insertLink: insertLink, insertImage: insertImage, insertButton: insertButton, uploadFileClick: function() { document.getElementById('upload-file').click(); }, clearEmailLogs: clearEmailLogs, clearActivityLogs: clearActivityLogs, clearAuditLogs: clearAuditLogs }; if (handlers[action]) handlers[action](); }); document.addEventListener('change', function(e) { var target = e.target.closest('[data-action]'); if (!target) return; var action = target.dataset.action; if (action === 'saveAuthSettings') saveAuthSettings(); else if (action === 'changeSourceMode') changeSourceMode(); else if (action === 'saveForcedTheme') saveForcedTheme(); else if (action === 'updateAuthNumber') updateAuthNumber(target.dataset.setting, target.value); else if (action === 'execCmdArg') { execCmdArg(target.dataset.cmd, target.value); target.selectedIndex = 0; } else if (action === 'uploadFile') uploadFile(); else if (action === 'toggleAll') toggleAll(target.checked); else if (action === 'toggleSelect') toggleSelect(target.dataset.id, target.checked); else if (action === 'templateColor') execCmdArg('foreColor', target.value); }); document.addEventListener('keyup', function(e) { var target = e.target.closest('[data-action]'); if (!target) return; var action = target.dataset.action; if (action === 'searchRooms') searchRooms(target.value); else if (action === 'searchUsers') searchUsers(target.value); else if (action === 'loadActivityLogs') loadActivityLogs(); else if (action === 'loadAuditLogs') loadAuditLogs(); else if (action === 'loadEmailLogs') loadEmailLogs(); }); loadData(); setInterval(loadData, 10000); })(); ================================================ FILE: theonefile_verse/public/admin-pages.js ================================================ (function() { 'use strict'; function withFormLoading(form, fn) { return async function(e) { e.preventDefault(); var btn = form.querySelector('button[type="submit"], button:not([type])'); if (btn) btn.disabled = true; try { await fn.call(this, e); } finally { if (btn) btn.disabled = false; } }; } var pageData = JSON.parse( (document.getElementById('page-data') || {}).textContent || '{}' ); var page = document.body.dataset.page; function build2FAForm(form) { while (form.firstChild) form.removeChild(form.firstChild); var label = document.createElement('label'); label.setAttribute('for', '2fa-code'); label.textContent = 'Authentication Code'; var input = document.createElement('input'); input.type = 'text'; input.id = '2fa-code'; input.placeholder = '000000'; input.maxLength = 8; input.autocomplete = 'one-time-code'; input.inputMode = 'numeric'; input.setAttribute('style', 'text-align:center;font-size:24px;letter-spacing:8px'); input.autofocus = true; var btn = document.createElement('button'); btn.type = 'submit'; btn.textContent = 'Verify'; form.appendChild(label); form.appendChild(input); form.appendChild(btn); } if (page === 'setup') { window.__authRenderOidcProviders('oidc-buttons', 'divider', ''); var setupForm = document.getElementById('setup-form'); setupForm.addEventListener('submit', withFormLoading(setupForm, async function() { var error = document.getElementById('error'); error.classList.remove('active'); var email = document.getElementById('email').value; var pwd = document.getElementById('password').value; var confirmVal = document.getElementById('confirm').value; if (!email || !email.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (pwd.length < 8) { error.textContent = 'Password must be at least 8 characters'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (pwd !== confirmVal) { error.textContent = 'Passwords do not match'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/setup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: pwd }) }); var d = await res.json(); if (res.ok && d.success) { window.location.href = '/' + (pageData.adminPath || 'admin'); } else { error.textContent = d.error || 'Setup failed'; error.setAttribute('role', 'alert'); error.classList.add('active'); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'migration') { var migrateForm = document.getElementById('migrate-form'); migrateForm.addEventListener('submit', withFormLoading(migrateForm, async function() { var oldPwd = document.getElementById('old-password'); var email = document.getElementById('email'); var newPwd = document.getElementById('new-password'); var error = document.getElementById('error'); error.classList.remove('active'); if (!oldPwd.value) { error.textContent = 'Please enter your current admin password'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (!email.value || !email.value.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/admin/migrate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ oldPassword: oldPwd.value, email: email.value, newPassword: newPwd.value || null }) }); var d = await res.json(); if (res.ok && d.success) { window.location.href = '/' + (pageData.adminPath || 'admin'); } else { error.textContent = d.error || 'Migration failed'; error.setAttribute('role', 'alert'); error.classList.add('active'); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'login') { var loginForm = document.getElementById('login-form'); loginForm.addEventListener('submit', withFormLoading(loginForm, async function() { var password = document.getElementById('password').value; try { var res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password: password }) }); if (res.ok) window.location.reload(); else { document.getElementById('error').setAttribute('role', 'alert'); document.getElementById('error').classList.add('active'); document.getElementById('password').value = ''; } } catch(ex) { document.getElementById('error').textContent = 'Connection error'; document.getElementById('error').setAttribute('role', 'alert'); document.getElementById('error').classList.add('active'); } })); } else if (page === 'instance-login') { var instanceForm = document.getElementById('login-form'); instanceForm.addEventListener('submit', withFormLoading(instanceForm, async function() { try { var res = await fetch('/api/instance-login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password: document.getElementById('password').value }) }); if (res.ok) window.location.reload(); else { document.getElementById('error').setAttribute('role', 'alert'); document.getElementById('error').classList.add('active'); document.getElementById('password').value = ''; } } catch(ex) { document.getElementById('error').textContent = 'Connection error'; document.getElementById('error').setAttribute('role', 'alert'); document.getElementById('error').classList.add('active'); } })); } else if (page === 'user-login') { var csrfToken = ''; var pendingToken = null; window.__authCsrfRefresh().then(function() { csrfToken = window.__authCsrfToken; }); window.__authRenderOidcProviders('oidc-buttons', 'divider', ''); var userLoginForm = document.getElementById('login-form'); userLoginForm.addEventListener('submit', withFormLoading(userLoginForm, async function() { var error = document.getElementById('error'); error.classList.remove('active'); if (pendingToken) { var code = document.getElementById('2fa-code').value.trim(); if (!code) { error.textContent = 'Please enter your 2FA code'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/auth/2fa/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pendingToken: pendingToken, code: code }) }); var d = await res.json(); if (res.ok && d.success) { var redirect = new URLSearchParams(window.location.search).get('redirect') || '/'; if (redirect.startsWith('/') && !redirect.startsWith('//')) { window.location.href = redirect; } else { window.location.href = '/'; } } else { error.textContent = d.error || 'Invalid code'; error.setAttribute('role', 'alert'); error.classList.add('active'); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } return; } var email = document.getElementById('email').value; var password = document.getElementById('password').value; if (!email || !email.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (!password) { error.textContent = 'Please enter your password'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: password, csrfToken: csrfToken }) }); var d = await res.json(); if (d.requires2FA) { pendingToken = d.pendingToken; build2FAForm(userLoginForm); document.querySelector('h1').textContent = 'Two Factor Authentication'; document.querySelector('p').textContent = 'Enter the 6 digit code from your authenticator app'; return; } if (res.ok && d.success) { var redirect = new URLSearchParams(window.location.search).get('redirect') || '/'; if (redirect.startsWith('/') && !redirect.startsWith('//')) { window.location.href = redirect; } else { window.location.href = '/'; } } else { error.textContent = d.error || 'Invalid credentials'; error.setAttribute('role', 'alert'); error.classList.add('active'); document.getElementById('password').value = ''; fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(c) { csrfToken = c.token; }).catch(function() {}); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'user-register') { var csrfToken = ''; window.__authCsrfRefresh().then(function() { csrfToken = window.__authCsrfToken; }); window.__authRenderOidcProviders('oidc-buttons', 'divider', ''); function checkPasswordStrength(pwd) { if (!pwd) return { strength: '', text: '' }; var score = 0; if (pwd.length >= 8) score++; if (pwd.length >= 12) score++; if (/[a-z]/.test(pwd) && /[A-Z]/.test(pwd)) score++; if (/[0-9]/.test(pwd)) score++; if (/[^a-zA-Z0-9]/.test(pwd)) score++; if (score <= 2) return { strength: 'weak', text: 'Weak: Add more characters, numbers, or symbols' }; if (score <= 3) return { strength: 'medium', text: 'Medium: Getting better, add more variety' }; return { strength: 'strong', text: 'Strong password' }; } document.getElementById('password').addEventListener('input', function(e) { var result = checkPasswordStrength(e.target.value); var bar = document.getElementById('strength-bar'); var txt = document.getElementById('strength-text'); bar.className = 'password-strength-bar' + (result.strength ? ' ' + result.strength : ''); txt.className = 'password-strength-text' + (result.strength ? ' ' + result.strength : ''); txt.textContent = result.text; }); var registerForm = document.getElementById('register-form'); registerForm.addEventListener('submit', withFormLoading(registerForm, async function() { var error = document.getElementById('error'); var success = document.getElementById('success'); error.classList.remove('active'); success.classList.remove('active'); var email = document.getElementById('email').value; var displayName = document.getElementById('displayName').value; var password = document.getElementById('password').value; var confirmPassword = document.getElementById('confirmPassword').value; if (!email || !email.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (!password) { error.textContent = 'Please enter a password'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (password !== confirmPassword) { error.textContent = 'Passwords do not match'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: password, displayName: displayName || null, csrfToken: csrfToken }) }); var d = await res.json(); if (res.ok) { if (d.requiresVerification) { success.textContent = 'Account created! Please check your email to verify your account.'; success.classList.add('active'); registerForm.reset(); } else { window.location.href = '/'; } } else { error.textContent = d.error || 'Registration failed'; error.setAttribute('role', 'alert'); error.classList.add('active'); fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(c) { csrfToken = c.token; }).catch(function() {}); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'user-forgot-password') { var forgotForm = document.getElementById('forgot-form'); forgotForm.addEventListener('submit', withFormLoading(forgotForm, async function() { var error = document.getElementById('error'); var success = document.getElementById('success'); error.classList.remove('active'); success.classList.remove('active'); var email = document.getElementById('email').value; if (!email || !email.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/auth/forgot-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email }) }); var d = await res.json(); if (res.ok) { success.textContent = 'If an account exists with this email, a reset link has been sent.'; success.classList.add('active'); document.getElementById('email').value = ''; } else { error.textContent = d.error || 'Failed to send reset email'; error.setAttribute('role', 'alert'); error.classList.add('active'); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'admin-login') { var adminPath = pageData.adminPath || 'admin'; window.__authRenderOidcProviders('oidc-buttons', 'divider', '?redirect=/' + adminPath); var pendingToken = null; var adminLoginForm = document.getElementById('login-form'); adminLoginForm.addEventListener('submit', withFormLoading(adminLoginForm, async function() { var error = document.getElementById('error'); error.classList.remove('active'); if (pendingToken) { var code = document.getElementById('2fa-code').value.trim(); if (!code) { error.textContent = 'Please enter your 2FA code'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/auth/2fa/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pendingToken: pendingToken, code: code }) }); var d = await res.json(); if (res.ok && d.success) { window.location.href = '/' + adminPath; } else { error.textContent = d.error || 'Invalid code'; error.setAttribute('role', 'alert'); error.classList.add('active'); } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } return; } var email = document.getElementById('email').value; var password = document.getElementById('password').value; if (!email || !email.includes('@')) { error.textContent = 'Please enter a valid email'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } if (!password) { error.textContent = 'Please enter your password'; error.setAttribute('role', 'alert'); error.classList.add('active'); return; } try { var res = await fetch('/api/admin/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: email, password: password }) }); var d = await res.json(); if (d.requires2FA) { pendingToken = d.pendingToken; build2FAForm(adminLoginForm); document.querySelector('h1').textContent = 'Two Factor Authentication'; document.querySelector('p').textContent = 'Enter the 6 digit code from your authenticator app'; return; } if (res.ok && d.success) { window.location.href = '/' + adminPath; } else { error.textContent = d.error || 'Invalid credentials'; error.setAttribute('role', 'alert'); error.classList.add('active'); document.getElementById('password').value = ''; } } catch(ex) { error.textContent = 'Connection error'; error.setAttribute('role', 'alert'); error.classList.add('active'); } })); } else if (page === 'password-reset') { var resetForm = document.getElementById('form'); resetForm.addEventListener('submit', withFormLoading(resetForm, async function() { var pw = document.getElementById('password').value; var confirmVal = document.getElementById('confirm').value; var err = document.getElementById('error'); err.classList.remove('active'); if (pw !== confirmVal) { err.textContent = 'Passwords do not match'; err.setAttribute('role', 'alert'); err.classList.add('active'); return; } if (pw.length < 8) { err.textContent = 'Password must be at least 8 characters'; err.setAttribute('role', 'alert'); err.classList.add('active'); return; } try { var csrfRes = await fetch('/api/auth/csrf'); var csrfData = await csrfRes.json(); var res = await fetch('/api/auth/reset-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: pageData.token, password: pw, csrfToken: csrfData.token }) }); var data = await res.json(); if (data.success) { resetForm.style.display = 'none'; document.getElementById('success').classList.add('active'); } else { err.textContent = data.error || 'Failed to reset password'; err.setAttribute('role', 'alert'); err.classList.add('active'); } } catch(ex) { err.textContent = 'Connection error'; err.setAttribute('role', 'alert'); err.classList.add('active'); } })); } })(); ================================================ FILE: theonefile_verse/public/collab-init.js ================================================ (function(){ window.COLLAB_MODE = true; var origGetItem = localStorage.getItem.bind(localStorage); var origSetItem = localStorage.setItem.bind(localStorage); var origRemoveItem = localStorage.removeItem.bind(localStorage); var blockedKeys = ['topology', 'autosave', 'savedState', 'nodeData', 'edgeData', 'canvasState', 'lastState', 'PAGE_STATE', 'theonefile']; function isBlockedKey(key) { if (!key) return false; var lk = key.toLowerCase(); for (var i = 0; i < blockedKeys.length; i++) { if (lk.indexOf(blockedKeys[i].toLowerCase()) !== -1) return true; } return false; } localStorage.getItem = function(key) { if (window.COLLAB_MODE && isBlockedKey(key)) { return null; } return origGetItem(key); }; localStorage.setItem = function(key, value) { if (window.COLLAB_MODE && isBlockedKey(key)) { return; } return origSetItem(key, value); }; localStorage.removeItem = function(key) { if (window.COLLAB_MODE && isBlockedKey(key)) return; return origRemoveItem(key); }; var origOpen = indexedDB.open.bind(indexedDB); indexedDB.open = function(name) { if (window.COLLAB_MODE && name && name.toLowerCase().indexOf('theonefile') !== -1) { var fakeRequest = { result: null, error: null, onsuccess: null, onerror: null, onupgradeneeded: null, onblocked: null, readyState: 'done', transaction: null, source: null }; setTimeout(function() { if (fakeRequest.onerror) fakeRequest.onerror(new Event('error')); }, 0); return fakeRequest; } return origOpen.apply(indexedDB, arguments); }; window.__collabSuppressWelcome = true; new MutationObserver(function(mutations) { if (!window.__collabSuppressWelcome) return; for (var i = 0; i < mutations.length; i++) { var el = mutations[i].target; if (el.id === 'welcome-modal' && el.classList.contains('active')) { el.classList.remove('active'); } } }).observe(document.documentElement, { subtree: true, attributes: true, attributeFilter: ['class'] }); })(); (function(){ var checkInterval = setInterval(function(){ if(typeof NODE_DATA !== 'undefined'){ clearInterval(checkInterval); window.__collabGetVar = function(name) { try { switch(name) { case 'NODE_DATA': return NODE_DATA; case 'EDGE_DATA': return EDGE_DATA; case 'RECT_DATA': return RECT_DATA; case 'TEXT_DATA': return TEXT_DATA; case 'EDGE_LEGEND': return EDGE_LEGEND; case 'ZONE_LEGEND': return typeof ZONE_LEGEND !== 'undefined' ? ZONE_LEGEND : {}; case 'ZONE_PRESETS': return typeof ZONE_PRESETS !== 'undefined' ? ZONE_PRESETS : {}; case 'PAGE_STATE': return PAGE_STATE; case 'savedPositions': return savedPositions; case 'savedSizes': return savedSizes; case 'savedStyles': return savedStyles; case 'savedStyleSets': return typeof savedStyleSets !== 'undefined' ? savedStyleSets : {}; case 'canvasState': return canvasState; case 'documentTabs': return documentTabs; case 'currentTabIndex': return currentTabIndex; case 'auditLog': return auditLog; case 'autoPingEnabled': return typeof autoPingEnabled !== 'undefined' ? autoPingEnabled : false; case 'autoPingInterval': return typeof autoPingInterval !== 'undefined' ? autoPingInterval : 5000; case 'savedTopologyView': return typeof savedTopologyView !== 'undefined' ? savedTopologyView : null; case 'encryptedSections': return typeof encryptedSections !== 'undefined' ? encryptedSections : {}; case 'iconCache': return typeof IconLibrary !== 'undefined' ? IconLibrary.iconCache : {}; case 'ANIM_SETTINGS': return typeof ANIM_SETTINGS !== 'undefined' ? ANIM_SETTINGS : null; case 'rollbackVersions': return typeof rollbackVersions !== 'undefined' ? rollbackVersions : []; case 'CUSTOM_LANG': return typeof CUSTOM_LANG !== 'undefined' ? CUSTOM_LANG : null; case 'IMAGE_DATA': return typeof IMAGE_DATA !== 'undefined' ? IMAGE_DATA : { list: [] }; case 'checkNodeStatus': return typeof checkNodeStatus !== 'undefined' ? checkNodeStatus : undefined; case 'checkAllNodesStatus': return typeof checkAllNodesStatus !== 'undefined' ? checkAllNodesStatus : undefined; case 'updatePingIndicator': return typeof updatePingIndicator !== 'undefined' ? updatePingIndicator : undefined; case 'updatePingStatusDisplay': return typeof updatePingStatusDisplay !== 'undefined' ? updatePingStatusDisplay : undefined; case 'forgeTheTopology': return typeof forgeTheTopology !== 'undefined' ? forgeTheTopology : undefined; case 'currentNodeId': return typeof currentNodeId !== 'undefined' ? currentNodeId : undefined; case 'pushUndo': return typeof pushUndo !== 'undefined' ? pushUndo : undefined; default: return undefined; } } catch(e) { return undefined; } }; window.__collabSetVar = function(name, value) { try { switch(name) { case 'NODE_DATA': NODE_DATA = value; return true; case 'EDGE_DATA': EDGE_DATA = value; return true; case 'RECT_DATA': RECT_DATA = value; return true; case 'TEXT_DATA': TEXT_DATA = value; return true; case 'EDGE_LEGEND': EDGE_LEGEND = value; return true; case 'ZONE_LEGEND': if(typeof ZONE_LEGEND !== 'undefined') ZONE_LEGEND = value; return true; case 'ZONE_PRESETS': if(typeof ZONE_PRESETS !== 'undefined') ZONE_PRESETS = value; return true; case 'savedPositions': savedPositions = value; return true; case 'savedSizes': savedSizes = value; return true; case 'savedStyles': savedStyles = value; return true; case 'savedStyleSets': if(typeof savedStyleSets !== 'undefined') savedStyleSets = value; return true; case 'auditLog': auditLog = value; return true; case 'documentTabs': documentTabs = value; return true; case 'currentTabIndex': currentTabIndex = value; return true; case 'autoPingEnabled': if(typeof autoPingEnabled !== 'undefined') autoPingEnabled = value; return true; case 'autoPingInterval': if(typeof autoPingInterval !== 'undefined') autoPingInterval = value; return true; case 'savedTopologyView': if(typeof savedTopologyView !== 'undefined') savedTopologyView = value; return true; case 'encryptedSections': if(typeof encryptedSections !== 'undefined') encryptedSections = value; return true; case 'iconCache': if(typeof IconLibrary !== 'undefined') IconLibrary.iconCache = value; return true; case 'ANIM_SETTINGS': if(typeof ANIM_SETTINGS !== 'undefined') { Object.assign(ANIM_SETTINGS, value); return true; } return false; case 'rollbackVersions': if(typeof rollbackVersions !== 'undefined') { rollbackVersions = value; return true; } return false; case 'CUSTOM_LANG': CUSTOM_LANG = value; if(typeof LANG !== 'undefined' && typeof DEFAULT_LANG !== 'undefined' && value) { LANG = deepMerge(DEFAULT_LANG, value); } return true; case 'PAGE_STATE': if(typeof PAGE_STATE !== 'undefined') { Object.assign(PAGE_STATE, value); return true; } return false; case 'IMAGE_DATA': if(typeof IMAGE_DATA !== 'undefined') { IMAGE_DATA = value; if(typeof renderCanvasImages === 'function') renderCanvasImages(); return true; } return false; default: return false; } } catch(e) { return false; } }; } }, 50); })(); ================================================ FILE: theonefile_verse/public/collab-save-hook.js ================================================ (function(){ var pendingHtmlBlobs = new Map(); var origCreateObjectURL = URL.createObjectURL; var origRevokeObjectURL = URL.revokeObjectURL; URL.createObjectURL = function(blob) { var url = origCreateObjectURL.apply(URL, arguments); if (blob && blob.type && blob.type.indexOf('text/html') !== -1) { pendingHtmlBlobs.set(url, blob); } return url; }; URL.revokeObjectURL = function(url) { pendingHtmlBlobs.delete(url); return origRevokeObjectURL.apply(URL, arguments); }; document.addEventListener('click', function(e) { var anchor = e.target; if (!anchor.download) { anchor = e.target.closest ? e.target.closest('a[download]') : null; } if (!anchor || !anchor.download || !anchor.href) return; if (!anchor.download.endsWith('.html')) return; if (!anchor.href.startsWith('blob:')) return; if (typeof window.__collabStripHTML !== 'function') return; var blob = pendingHtmlBlobs.get(anchor.href); if (!blob) return; e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); var reader = new FileReader(); reader.onload = function() { var cleanHtml = window.__collabStripHTML(reader.result); var cleanBlob = new Blob([cleanHtml], {type: 'text/html'}); var cleanUrl = origCreateObjectURL.call(URL, cleanBlob); var a = document.createElement('a'); a.href = cleanUrl; a.download = anchor.download; a.style.display = 'none'; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); origRevokeObjectURL.call(URL, cleanUrl); }, 100); }; reader.readAsText(blob); }, true); })(); ================================================ FILE: theonefile_verse/public/collab.css ================================================ #collab-bar { position: fixed; top: 0; left: 0; right: 0; top: env(safe-area-inset-top, 0); height: 48px; background: linear-gradient(to bottom, #0f1419 0%, #0a0e14 100%); border-bottom: 1px solid #1e2530; display: flex; align-items: center; justify-content: space-between; padding: 0 max(16px, env(safe-area-inset-left, 16px)); padding-right: max(16px, env(safe-area-inset-right, 16px)); z-index: 99999; font-family: Inter, system-ui, -apple-system, sans-serif; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); } #collab-bar * { box-sizing: border-box; } .collab-users { display: flex; align-items: center; gap: 8px; flex: 1; overflow-x: auto; padding: 4px 0; -webkit-overflow-scrolling: touch; scrollbar-width: none; } .collab-users::-webkit-scrollbar { display: none; } .collab-user { display: flex; align-items: center; gap: 6px; padding: 6px 12px; background: rgba(255, 255, 255, 0.05); border-radius: 20px; font-size: 13px; color: #e2e8f0; white-space: nowrap; border: 1px solid transparent; } .collab-user.me { background: rgba(59, 130, 246, 0.15); border-color: rgba(59, 130, 246, 0.3); } .collab-user-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; } .collab-user-avatar { width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: white; text-transform: uppercase; } .collab-user-name { max-width: 150px; overflow: hidden; text-overflow: ellipsis; } .collab-user-editing { font-size: 11px; color: #22c55e; margin-left: 4px; padding: 2px 6px; background: rgba(34, 197, 94, 0.15); border-radius: 8px; } .collab-actions { display: flex; align-items: center; gap: 8px; } .collab-btn { padding: 8px 16px; min-height: 44px; min-width: 44px; background: #1e2530; border: 1px solid #2d3748; border-radius: 8px; color: #e2e8f0; font-size: 13px; font-weight: 500; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 6px; transition: all 0.15s; -webkit-tap-highlight-color: transparent; } .collab-btn:hover { background: #2d3748; border-color: #3b82f6; } .collab-btn:active { transform: scale(0.96); } .collab-btn-icon { font-size: 16px; } .collab-modal-overlay { display: none; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.85); z-index: 999999; align-items: center; justify-content: center; padding: 20px; padding-bottom: max(20px, env(safe-area-inset-bottom, 20px)); } .collab-modal-overlay.active { display: flex; } #collab-name-modal.collab-modal-overlay { z-index: 99999999; } .collab-modal { background: #0f1419; border: 1px solid #1e2530; border-radius: 16px; width: 100%; max-width: 420px; font-family: Inter, system-ui, sans-serif; animation: collabModalIn 0.2s ease; } @keyframes collabModalIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .collab-modal-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid #1e2530; } .collab-modal-header h3 { font-size: 18px; font-weight: 600; color: #e2e8f0; margin: 0; } .collab-modal-close { background: none; border: none; color: #8892a0; font-size: 24px; cursor: pointer; padding: 4px; line-height: 1; min-width: 44px; min-height: 44px; display: flex; align-items: center; justify-content: center; -webkit-tap-highlight-color: transparent; } .collab-modal-close:hover { color: #e2e8f0; } .collab-modal-body { padding: 20px; } .collab-share-url { display: flex; gap: 8px; margin-bottom: 20px; } .collab-share-url input { flex: 1; padding: 12px; background: #0a0e14; border: 1px solid #1e2530; border-radius: 8px; color: #e2e8f0; font-size: 13px; font-family: monospace; } .collab-share-url button { padding: 12px 16px; min-height: 44px; background: #3b82f6; border: none; border-radius: 8px; color: white; font-size: 18px; cursor: pointer; -webkit-tap-highlight-color: transparent; } .collab-share-url button:hover { background: #2563eb; } .collab-qr { display: flex; justify-content: center; padding: 20px; background: white; border-radius: 12px; margin-bottom: 16px; } .collab-qr svg { max-width: 180px; max-height: 180px; } .collab-share-note { font-size: 13px; color: #8892a0; text-align: center; margin: 0; } #collab-menu-dropdown { display: none; position: fixed; background: #0f1419; border: 1px solid #1e2530; border-radius: 12px; min-width: 180px; z-index: 999999; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); overflow: hidden; } #collab-menu-dropdown.active { display: block; } .collab-menu-item { display: flex; align-items: center; gap: 10px; padding: 12px 16px; min-height: 44px; color: #e2e8f0; font-size: 14px; cursor: pointer; border: none; background: none; width: 100%; text-align: left; font-family: inherit; -webkit-tap-highlight-color: transparent; } .collab-menu-item:hover { background: #1e2530; } .collab-menu-item.danger { color: #ef4444; } .collab-menu-item.danger:hover { background: rgba(239, 68, 68, 0.1); } .collab-menu-divider { height: 1px; background: #1e2530; margin: 4px 0; } .collab-info-row { display: flex; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid #1e2530; } .collab-info-row:last-child { border-bottom: none; } .collab-info-label { color: #8892a0; font-size: 14px; } .collab-info-value { color: #e2e8f0; font-size: 14px; font-weight: 500; } .collab-info-id { font-family: monospace; font-size: 11px; word-break: break-all; } .collab-input { width: 100%; padding: 14px 16px; background: #0a0e14; border: 1px solid #1e2530; border-radius: 8px; color: #e2e8f0; font-size: 16px; outline: none; font-family: inherit; } .collab-input:focus { border-color: #3b82f6; } .collab-input::placeholder { color: #4a5568; } .collab-name-actions { display: flex; gap: 12px; margin-top: 16px; } .collab-btn-secondary { flex: 1; padding: 12px; min-height: 44px; background: #1e2530; border: 1px solid #2d3748; border-radius: 8px; color: #e2e8f0; font-size: 14px; font-weight: 500; cursor: pointer; font-family: inherit; -webkit-tap-highlight-color: transparent; } .collab-btn-secondary:hover { background: #2d3748; } .collab-btn-primary { flex: 1; padding: 12px; min-height: 44px; background: #3b82f6; border: none; border-radius: 8px; color: white; font-size: 14px; font-weight: 600; cursor: pointer; font-family: inherit; -webkit-tap-highlight-color: transparent; } .collab-btn-primary:hover { background: #2563eb; } .collab-pwd-error, .collab-name-error { color: #ef4444; font-size: 13px; margin-top: 8px; display: none; } .collab-pwd-error.active, .collab-name-error.active { display: block; } .collab-node-indicator { position: absolute; bottom: -20px; left: 50%; transform: translateX(-50%); padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 500; white-space: nowrap; pointer-events: none; z-index: 1000; font-family: Inter, system-ui, sans-serif; } .collab-selection-ring { position: absolute; inset: -4px; border: 3px solid; border-radius: inherit; pointer-events: none; animation: collab-pulse 2s infinite; } @keyframes collab-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } body.collab-active { padding-top: calc(48px + env(safe-area-inset-top, 0px)) !important; } @media (max-width: 640px) { #collab-bar { padding: 0 12px; } .collab-user { padding: 4px 8px; font-size: 12px; } .collab-user-name { max-width: 80px; } .collab-user-editing { display: none; } .collab-btn { padding: 8px 12px; font-size: 12px; min-height: 44px; } .collab-btn span:not(.collab-btn-icon) { display: none; } } #collab-sync-overlay { position: fixed; inset: 0; background: rgba(10, 14, 20, 0.95); z-index: 9999999; display: flex; align-items: center; justify-content: center; font-family: Inter, system-ui, -apple-system, sans-serif; animation: syncFadeIn 0.3s ease; } #collab-sync-overlay.fade-out { animation: syncFadeOut 0.3s ease forwards; } @keyframes syncFadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes syncFadeOut { from { opacity: 1; } to { opacity: 0; } } .collab-sync-content { text-align: center; position: relative; } .collab-sync-sword { width: 80px; height: 200px; margin: 0 auto 30px; position: relative; animation: swordFloat 2s ease-in-out infinite; } .collab-sync-sword::before { content: ''; position: absolute; left: 50%; top: 0; transform: translateX(-50%); width: 8px; height: 140px; background: linear-gradient(to bottom, #e2e8f0 0%, #94a3b8 50%, #64748b 100%); border-radius: 2px 2px 0 0; box-shadow: 0 0 20px rgba(226, 232, 240, 0.5); } .collab-sync-sword::after { content: ''; position: absolute; left: 50%; top: 130px; transform: translateX(-50%); width: 50px; height: 12px; background: linear-gradient(to bottom, #92400e, #78350f); border-radius: 3px; box-shadow: 0 4px 0 #451a03; } @keyframes swordFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-15px); } } .collab-sync-lightning { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 200px; height: 200px; pointer-events: none; } .collab-sync-lightning::before, .collab-sync-lightning::after { content: ''; position: absolute; background: linear-gradient(180deg, transparent 0%, #3b82f6 50%, transparent 100%); animation: lightning 1.5s ease-in-out infinite; } .collab-sync-lightning::before { left: 20%; top: 0; width: 3px; height: 100%; animation-delay: 0s; } .collab-sync-lightning::after { right: 20%; top: 0; width: 3px; height: 100%; animation-delay: 0.3s; } @keyframes lightning { 0%, 100% { opacity: 0; transform: scaleY(0); } 10%, 30% { opacity: 1; transform: scaleY(1); } 40% { opacity: 0; transform: scaleY(0); } } .collab-sync-text { font-size: 24px; font-weight: 700; color: #e2e8f0; margin-bottom: 12px; text-shadow: 0 0 30px rgba(59, 130, 246, 0.5); animation: textPulse 2s ease-in-out infinite; } @keyframes textPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } } .collab-sync-subtext { font-size: 14px; color: #8892a0; animation: dotDotDot 1.5s steps(4, end) infinite; } .collab-sync-subtext::after { content: ''; animation: dots 1.5s steps(4, end) infinite; } @keyframes dots { 0% { content: ''; } 25% { content: '.'; } 50% { content: '..'; } 75% { content: '...'; } 100% { content: ''; } } #collab-chat-panel { display: none; position: fixed; top: 56px; right: 16px; width: 360px; max-width: calc(100vw - 32px); height: 440px; max-height: calc(100vh - 100px); background: #0f1419; border: 1px solid #1e2530; border-radius: 12px; z-index: 999998; flex-direction: column; font-family: Inter, system-ui, -apple-system, sans-serif; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); animation: collabModalIn 0.2s ease; } #collab-chat-panel.active { display: flex; } .collab-chat-header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid #1e2530; color: #e2e8f0; font-weight: 600; font-size: 14px; flex-shrink: 0; } .collab-chat-close { background: none; border: none; color: #8892a0; font-size: 20px; cursor: pointer; padding: 0; line-height: 1; min-width: 44px; min-height: 44px; display: flex; align-items: center; justify-content: center; -webkit-tap-highlight-color: transparent; } .collab-chat-close:hover { color: #e2e8f0; } .collab-chat-messages { flex: 1; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px; -webkit-overflow-scrolling: touch; } .collab-chat-msg { padding: 8px 10px; background: rgba(255, 255, 255, 0.03); border-radius: 8px; position: relative; } .collab-chat-msg.mentioned { background: rgba(59, 130, 246, 0.1); border-left: 3px solid #3b82f6; } .collab-chat-reply-ref { font-size: 11px; color: #64748b; padding: 4px 8px; margin-bottom: 4px; border-left: 2px solid #2d3748; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; } .collab-chat-reply-ref:hover { color: #8892a0; } .collab-chat-reply-btn { display: none; position: absolute; right: 6px; top: 6px; background: #1e2530; border: 1px solid #2d3748; border-radius: 4px; color: #8892a0; font-size: 11px; cursor: pointer; padding: 2px 6px; line-height: 1; } .collab-chat-msg:hover .collab-chat-reply-btn { display: block; } .collab-chat-reply-btn:hover { color: #e2e8f0; background: #2d3748; } .collab-chat-name { font-weight: 600; font-size: 12px; margin-right: 8px; } .collab-chat-time { font-size: 10px; color: #64748b; } .collab-chat-text { font-size: 13px; color: #e2e8f0; margin-top: 4px; line-height: 1.4; word-break: break-word; } .collab-chat-mention { color: #3b82f6; font-weight: 600; } .collab-chat-input-area { flex-shrink: 0; border-top: 1px solid #1e2530; } .collab-chat-reply-preview { display: none; padding: 8px 12px; background: rgba(255, 255, 255, 0.02); font-size: 12px; color: #8892a0; border-bottom: 1px solid #1e2530; align-items: center; gap: 8px; } .collab-chat-reply-preview.active { display: flex; } .collab-chat-reply-preview span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .collab-chat-reply-cancel { background: none; border: none; color: #8892a0; cursor: pointer; font-size: 16px; padding: 0; line-height: 1; min-width: 28px; min-height: 28px; display: flex; align-items: center; justify-content: center; } .collab-chat-reply-cancel:hover { color: #e2e8f0; } .collab-chat-input-wrap { display: flex; gap: 8px; padding: 8px 12px; align-items: center; } .collab-chat-input-inner { flex: 1; display: flex; flex-direction: column; gap: 4px; } .collab-chat-input-wrap input { flex: 1; padding: 8px 12px; background: #0a0e14; border: 1px solid #1e2530; border-radius: 8px; color: #e2e8f0; font-size: 13px; outline: none; font-family: inherit; height: 40px; box-sizing: border-box; } .collab-chat-input-wrap input:focus { border-color: #3b82f6; } .collab-chat-input-wrap input::placeholder { color: #4a5568; } .collab-chat-char-count { font-size: 10px; color: #4a5568; text-align: right; padding-right: 4px; height: 14px; transition: color 0.15s; } .collab-chat-char-count.warning { color: #f59e0b; } .collab-chat-char-count.danger { color: #ef4444; } #collab-chat-send { padding: 10px 16px; min-height: 40px; background: #3b82f6; border: none; border-radius: 8px; color: white; font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit; -webkit-tap-highlight-color: transparent; flex-shrink: 0; } #collab-chat-send:hover { background: #2563eb; } .collab-typing-indicator { display: none; padding: 4px 12px; font-size: 11px; color: #64748b; font-style: italic; flex-shrink: 0; } .collab-typing-indicator.active { display: block; } .collab-chat-badge { display: none; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; background: #ef4444; color: white; font-size: 11px; font-weight: 700; border-radius: 10px; margin-left: 4px; } #collab-chat-btn { position: relative; } .collab-user-info { display: flex; flex-direction: column; gap: 2px; } .collab-user-tab { font-size: 10px; color: #64748b; } .collab-remote-cursor { position: fixed; pointer-events: none; z-index: 999997; transform: translate(-2px, -2px); transition: left 100ms ease-out, top 100ms ease-out; } .collab-remote-cursor svg { display: block; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.5)); } .collab-cursor-name { position: absolute; left: 14px; top: 12px; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: 500; color: white; white-space: nowrap; font-family: Inter, system-ui, -apple-system, sans-serif; } .collab-conn-status { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; margin-right: 4px; transition: background 0.3s; } .collab-conn-status.connected { background: #22c55e; box-shadow: 0 0 6px rgba(34, 197, 94, 0.5); } .collab-conn-status.reconnecting { background: #f59e0b; animation: connPulse 1s infinite; } .collab-conn-status.disconnected { background: #ef4444; } @keyframes connPulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } .collab-reconnect-banner { display: none; position: fixed; top: 48px; left: 0; right: 0; background: rgba(245, 158, 11, 0.95); color: #000; font-size: 13px; font-weight: 500; text-align: center; padding: 8px 16px; z-index: 99998; font-family: Inter, system-ui, -apple-system, sans-serif; align-items: center; justify-content: center; gap: 12px; } .collab-reconnect-banner.active { display: flex; } .collab-reconnect-banner.offline { background: rgba(239, 68, 68, 0.95); color: white; } .collab-reconnect-btn { background: rgba(0, 0, 0, 0.2); border: none; border-radius: 6px; color: inherit; padding: 4px 12px; font-size: 12px; font-weight: 600; cursor: pointer; min-height: 32px; } .collab-reconnect-btn:hover { background: rgba(0, 0, 0, 0.3); } .collab-toast-stack { position: fixed; bottom: max(80px, calc(80px + env(safe-area-inset-bottom, 0px))); left: 50%; transform: translateX(-50%); display: flex; flex-direction: column-reverse; gap: 8px; z-index: 100001; pointer-events: none; } .collab-toast-item { background: #333; color: #fff; padding: 10px 20px; border-radius: 8px; font-size: 13px; font-family: Inter, system-ui, -apple-system, sans-serif; white-space: nowrap; opacity: 0; transform: translateY(10px); animation: toastIn 0.3s ease forwards; pointer-events: auto; } .collab-toast-item.fade-out { animation: toastOut 0.3s ease forwards; } @keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes toastOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-10px); } } .collab-room-expiry { font-size: 11px; color: #f59e0b; display: flex; align-items: center; gap: 4px; padding: 2px 8px; background: rgba(245, 158, 11, 0.1); border-radius: 12px; white-space: nowrap; } .collab-emoji-picker { display: none; position: absolute; bottom: 100%; left: 0; right: 0; background: #0f1419; border: 1px solid #1e2530; border-radius: 12px 12px 0 0; padding: 8px; max-height: 200px; overflow-y: auto; -webkit-overflow-scrolling: touch; } .collab-emoji-picker.active { display: block; } .collab-emoji-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; } .collab-emoji-btn { background: none; border: none; font-size: 20px; padding: 6px; cursor: pointer; border-radius: 6px; min-width: 36px; min-height: 36px; display: flex; align-items: center; justify-content: center; -webkit-tap-highlight-color: transparent; } .collab-emoji-btn:hover { background: rgba(255, 255, 255, 0.1); } .collab-emoji-toggle { background: none !important; border: none; color: #8892a0; font-size: 20px; cursor: pointer; padding: 4px; width: 36px; height: 40px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; -webkit-tap-highlight-color: transparent; border-radius: 8px; transition: background 0.15s; } .collab-emoji-toggle:hover { background: rgba(255, 255, 255, 0.08) !important; color: #e2e8f0; } @media (max-width: 640px) { #collab-chat-panel { position: fixed; top: 0; right: 0; left: 0; bottom: 0; width: 100%; max-width: none; height: 100%; max-height: none; border-radius: 0; border: none; padding-top: env(safe-area-inset-top, 0); padding-bottom: env(safe-area-inset-bottom, 0); } #collab-chat-panel .collab-chat-header { padding-top: max(12px, env(safe-area-inset-top, 12px)); } .collab-emoji-grid { grid-template-columns: repeat(7, 1fr); } } ================================================ FILE: theonefile_verse/public/collab.js ================================================ (function() { 'use strict'; const roomConfigEl = document.getElementById('room-config'); if (!roomConfigEl) return; let _rc; try { _rc = JSON.parse(roomConfigEl.textContent); } catch { return; } if (!_rc.roomId) return; const ROOM_ID = _rc.roomId; const WS_URL = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.host + '/ws/' + _rc.roomId; const HAS_PASSWORD = _rc.roomHasPassword; const IS_ADMIN = _rc.isAdmin || false; const IS_CREATOR = _rc.isCreator || IS_ADMIN; if (_rc.csrfToken) window.CSRF_TOKEN = _rc.csrfToken; function refreshCsrf() { fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { if (d.token) window.CSRF_TOKEN = d.token; }).catch(function() {}); } refreshCsrf(); if (_rc.defaultRoomTheme) window.DEFAULT_ROOM_THEME = _rc.defaultRoomTheme; let shareButtonEnabled = true; function h(tag, props, ...children) { const node = document.createElement(tag); if (props) { for (const key of Object.keys(props)) { if (key === 'className') node.className = props[key]; else if (key === 'style') node.setAttribute('style', props[key]); else if (key === 'textContent') node.textContent = props[key]; else if (key.startsWith('data-')) node.setAttribute(key, props[key]); else if (key === 'checked') { if (props[key]) node.checked = true; } else if (key === 'readonly') { if (props[key]) node.readOnly = true; } else node[key] = props[key]; } } for (const child of children) _append(node, child); return node; } function _append(parent, child) { if (child == null || child === false) return; if (typeof child === 'string' || typeof child === 'number') { parent.appendChild(document.createTextNode(String(child))); } else if (Array.isArray(child)) { for (const c of child) _append(parent, c); } else { parent.appendChild(child); } } function clearNode(el) { while (el.firstChild) el.removeChild(el.firstChild); } function setContent(container, children) { clearNode(container); const frag = document.createDocumentFragment(); _append(frag, Array.isArray(children) ? children : [children]); container.appendChild(frag); } function generateUUID() { if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID(); } return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } function getOrCreateUserId() { const globalKey = 'collab-global-user-id'; let userId = localStorage.getItem(globalKey); if (!userId) { userId = generateUUID(); localStorage.setItem(globalKey, userId); } return userId; } function getStoredUserName() { return localStorage.getItem(`collab-name-${ROOM_ID}`); } function setStoredUserName(name) { localStorage.setItem(`collab-name-${ROOM_ID}`, name); } const COLORS = [ '#e63946', '#f4a261', '#2a9d8f', '#264653', '#e9c46a', '#8338ec', '#ff006e', '#3b82ff', '#06d6a0', '#118ab2', '#ef476f', '#ffd166', '#073b4c', '#06aed5', '#f72585', '#7209b7' ]; const HIGHLANDER_NAMES = [ 'Connor MacLeod', 'Duncan MacLeod', 'Ramirez', 'The Kurgan', 'Methos', 'Amanda Darieux', 'Richie Ryan', 'Joe Dawson', 'Cassandra', 'Kronos', 'Silas', 'Caspian', 'Xavier St. Cloud', 'Kalas', 'Fitzcairn', 'Darius', 'Kenny', 'Ceirdwyn', 'Rebecca Horne', 'Grace Chandel', 'Nakano', 'Kastagir', 'Sean Burns', 'Grayson', 'Kern', 'Kell', 'Jacob Kell', 'Faith', 'Kane', 'Quentin MacLeod', 'Kortan', 'Arak', 'Asklepios', 'Hugh Fitzcairn', 'Carl Robinson', 'Annie Devlin' ]; const HIGHLANDER_SYNC_QUOTES = [ "There can be only one... state.", "I am immortal. Your data is eternal.", "The Quickening approaches...", "Gathering the power of all Immortals...", "From the dawn of time we came...", "In the end, there can be only one... source of truth.", "I have something to say! Syncing...", "It's better to burn out than to fade away... loading.", "The Prize awaits... synchronizing.", "Feel the Quickening!" ]; const EMOJI_LIST = [ '😀','😂','🤣','😊','😍','🤔','😎','🙄','😴','🤯', '👍','👎','👏','🙌','🤝','💪','🔥','❤️','💯','⭐', '✅','❌','⚡','💡','🎉','🚀','👀','🤷','😭','🥳' ]; function getRandomSyncQuote() { return HIGHLANDER_SYNC_QUOTES[Math.floor(Math.random() * HIGHLANDER_SYNC_QUOTES.length)]; } let syncOverlayTimeout = null; function showSyncingOverlay() { if (document.getElementById('collab-sync-overlay')) return; const overlay = document.createElement('div'); overlay.id = 'collab-sync-overlay'; overlay.appendChild( h('div', {className: 'collab-sync-content'}, h('div', {className: 'collab-sync-sword'}), h('div', {className: 'collab-sync-lightning'}), h('div', {className: 'collab-sync-text'}, getRandomSyncQuote()), h('div', {className: 'collab-sync-subtext'}, 'Synchronizing with the realm...') ) ); document.body.appendChild(overlay); syncOverlayTimeout = setTimeout(() => { hideSyncingOverlay(); showToast('Sync timed out. You may need to refresh.'); }, 30000); } function hideSyncingOverlay() { if (syncOverlayTimeout) { clearTimeout(syncOverlayTimeout); syncOverlayTimeout = null; } const overlay = document.getElementById('collab-sync-overlay'); if (overlay) { overlay.classList.add('fade-out'); setTimeout(() => overlay.remove(), 300); } } function leaveRoom() { if (ws) { sendMessage('leave', { userId: window.COLLAB_USER.id }); ws.close(); ws = null; } localStorage.removeItem(`collab-name-${ROOM_ID}`); localStorage.removeItem(`collab-color-${ROOM_ID}`); window.location.href = '/'; } function generateHighlanderName() { return HIGHLANDER_NAMES[Math.floor(Math.random() * HIGHLANDER_NAMES.length)]; } function isValidColor(color) { return typeof color === 'string' && /^#[0-9a-fA-F]{6}$/.test(color); } function sanitizeColor(color) { return isValidColor(color) ? color : COLORS[0]; } function getOrCreateUserColor() { const storageKey = `collab-color-${ROOM_ID}`; let color = localStorage.getItem(storageKey); if (!color || !isValidColor(color)) { color = pickUniqueColor(); localStorage.setItem(storageKey, color); } return color; } function pickUniqueColor() { const usedColors = new Set(); users.forEach(u => usedColors.add(u.color)); const available = COLORS.filter(c => !usedColors.has(c)); if (available.length > 0) { return available[Math.floor(Math.random() * available.length)]; } return COLORS[Math.floor(Math.random() * COLORS.length)]; } function getInitials(name) { if (!name) return '?'; const parts = name.trim().split(/\s+/); if (parts.length >= 2) return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase(); return name.substring(0, 2).toUpperCase(); } window.COLLAB_USER = { id: getOrCreateUserId(), name: null, color: null, selectedNodes: [], editingNode: null }; const users = new Map(); let ws = null; let reconnectAttempts = 0; let lastStateHash = null; let syncPaused = false; let hasReceivedInitialState = false; let chatMessages = []; let unreadCount = 0; let chatOpen = false; let replyingTo = null; let typingUsers = new Map(); let typingTimeout = null; let lastTypingSent = 0; let connectionState = 'disconnected'; let roomExpiryData = null; let expiryInterval = null; let chatSoundEnabled = localStorage.getItem('collab-chat-sound') !== 'false'; let emojiPickerOpen = false; let currentWsToken = null; async function fetchWsToken() { try { const res = await fetch(`/api/room/${ROOM_ID}/ws-token`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN || '' }, body: JSON.stringify({ collabUserId: window.COLLAB_USER.id }) }); refreshCsrf(); if (!res.ok) return null; const data = await res.json(); if (data.collabUserId && data.collabUserId !== window.COLLAB_USER.id) { window.COLLAB_USER.id = data.collabUserId; } return data.wsToken; } catch (e) { console.warn('[Collab] Failed to fetch WS token:', e); return null; } } function setConnectionState(state) { connectionState = state; const dot = document.getElementById('collab-conn-dot'); if (dot) { dot.className = 'collab-conn-status ' + state; } const banner = document.getElementById('collab-reconnect-banner'); if (banner) { if (state === 'connected') { banner.classList.remove('active', 'offline'); } else if (state === 'reconnecting') { banner.classList.add('active'); banner.classList.remove('offline'); banner.querySelector('span').textContent = 'Reconnecting...'; } else if (state === 'disconnected') { banner.classList.add('active', 'offline'); banner.querySelector('span').textContent = 'Connection lost'; } } } async function connect() { if (ws && ws.readyState === WebSocket.OPEN) return; setConnectionState('reconnecting'); currentWsToken = await fetchWsToken(); ws = new WebSocket(WS_URL); ws.onopen = () => { if (currentWsToken) { ws.send(JSON.stringify({ type: 'auth', token: currentWsToken })); } else { reconnectAttempts = 0; setConnectionState('connected'); window.COLLAB_USER.color = getOrCreateUserColor(); hasReceivedInitialState = false; showSyncingOverlay(); sendMessage('join', { user: window.COLLAB_USER }); } }; ws.onmessage = (event) => { try { const msg = JSON.parse(event.data); handleMessage(msg); } catch (e) {} }; ws.onclose = () => { setConnectionState('reconnecting'); scheduleReconnect(); }; ws.onerror = () => {}; } function scheduleReconnect() { if (reconnectAttempts >= 10) { setConnectionState('disconnected'); return; } const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), 30000); reconnectAttempts++; setTimeout(connect, delay); } function sendMessage(type, data) { if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type, ...data })); } } function sanitizeUser(user) { if (user && user.color) { user.color = sanitizeColor(user.color); } return user; } function handleMessage(msg) { switch (msg.type) { case 'auth-ok': reconnectAttempts = 0; setConnectionState('connected'); window.COLLAB_USER.color = getOrCreateUserColor(); hasReceivedInitialState = false; showSyncingOverlay(); sendMessage('join', { user: window.COLLAB_USER }); return; case 'auth-error': console.error('[Collab] Auth failed:', msg.error); return; case 'join': users.set(msg.user.id, sanitizeUser(msg.user)); renderUsers(); renderUserIndicators(); break; case 'leave': users.delete(msg.userId); removeUserIndicators(msg.userId); removeRemoteCursor(msg.userId); typingUsers.delete(msg.userId); updateTypingIndicator(); renderUsers(); break; case 'users': msg.users.forEach(u => { if (u.id !== window.COLLAB_USER.id) users.set(u.id, sanitizeUser(u)); }); renderUsers(); renderUserIndicators(); break; case 'presence': if (msg.userId !== window.COLLAB_USER.id) { const user = users.get(msg.userId); if (user) { user.selectedNodes = msg.selectedNodes || []; user.editingNode = msg.editingNode || null; user.currentTab = msg.currentTab || null; users.set(msg.userId, user); renderUserIndicators(); renderUsers(); } } break; case 'initial-state': hideSyncingOverlay(); hasReceivedInitialState = true; if (msg.state) { applyRemoteState(msg.state); if (!msg.state.themeState && window.DEFAULT_ROOM_THEME) { var dPresets = typeof THEME_PRESETS !== 'undefined' ? THEME_PRESETS : null; if (dPresets && dPresets[window.DEFAULT_ROOM_THEME]) { setGlobal('PAGE_STATE', dPresets[window.DEFAULT_ROOM_THEME]); if (typeof wieldThePower === 'function') try { wieldThePower(); } catch(e) {} var dSel = document.getElementById('welcome-theme-select'); if (dSel) dSel.value = window.DEFAULT_ROOM_THEME; } } } else { if (window.DEFAULT_ROOM_THEME) { var dPresets2 = typeof THEME_PRESETS !== 'undefined' ? THEME_PRESETS : null; if (dPresets2 && dPresets2[window.DEFAULT_ROOM_THEME]) { setGlobal('PAGE_STATE', dPresets2[window.DEFAULT_ROOM_THEME]); if (typeof wieldThePower === 'function') try { wieldThePower(); } catch(e) {} var dSel2 = document.getElementById('welcome-theme-select'); if (dSel2) dSel2.value = window.DEFAULT_ROOM_THEME; } } sendFullState(); } window.__collabSuppressWelcome = false; var _nd = getGlobal('NODE_DATA'); var _ed = getGlobal('EDGE_DATA'); var _roomEmpty = (!_nd || Object.keys(_nd).length === 0) && (!_ed || !_ed.list || _ed.list.length === 0); if (_roomEmpty || _rc.forceWelcomeModal) { if (typeof showWelcomeModal === 'function') showWelcomeModal(); } else { var _wm = document.getElementById('welcome-modal'); if (_wm) _wm.classList.remove('active'); } break; case 'state': if (!syncPaused && hasReceivedInitialState) applyRemoteState(msg.state); break; case 'patch': if (!syncPaused && hasReceivedInitialState) applyRemoteState(msg.patch); break; case 'chat': addChatMessage(msg); break; case 'chat-history': if (msg.messages && Array.isArray(msg.messages)) { msg.messages.forEach(m => { if (!chatMessages.some(existing => existing.timestamp === m.timestamp && existing.userId === m.userId)) { chatMessages.push(m); } }); chatMessages.sort((a, b) => a.timestamp - b.timestamp); if (chatMessages.length > 100) chatMessages = chatMessages.slice(-100); renderChatMessages(); } break; case 'typing': if (msg.userId !== window.COLLAB_USER.id) { typingUsers.set(msg.userId, { name: msg.userName, expires: Date.now() + 3000 }); updateTypingIndicator(); } break; case 'cursor': if (msg.userId !== window.COLLAB_USER.id) { const user = users.get(msg.userId); if (user) { user.cursorX = msg.x; user.cursorY = msg.y; user.isRatio = msg.isRatio || false; user.isCanvasCoords = msg.isCanvasCoords || false; users.set(msg.userId, user); updateRemoteCursor(msg.userId, user); renderUsers(); } } break; case 'name-rejected': handleNameRejected(msg.reason); break; case 'discovery-progress': updateDiscoveryProgress(msg.percent, msg.scanned, msg.total, msg.rangeIndex, msg.totalRanges); break; case 'discovery-found': addDiscoveryResult(msg.host); break; case 'discovery-complete': finalizeDiscovery(msg.totalFound); break; case 'deepscan-progress': handleDeepScanProgress(msg.scanId, msg.ip, msg.percent, msg.scanned, msg.total); break; case 'deepscan-update': handleDeepScanUpdate(msg.scanId, msg.ip, msg.newPorts, msg.newServices, msg.containers, msg.newIcons); break; case 'deepscan-complete': handleDeepScanComplete(msg.scanId, msg.ip); break; } } let nameRejectedRecovery = false; function handleNameRejected(reason) { hideSyncingOverlay(); localStorage.removeItem(`collab-name-${ROOM_ID}`); window.COLLAB_USER.name = null; nameRejectedRecovery = true; showNameModal(false, reason); } let msgIdCounter = 0; function addChatMessage(msg) { const chatMsg = { id: msg.id || (Date.now() + '-' + (msgIdCounter++)), userId: msg.userId, userName: msg.userName, userColor: msg.userColor, text: msg.text, timestamp: msg.timestamp || Date.now(), replyTo: msg.replyTo || null }; chatMessages.push(chatMsg); if (chatMessages.length > 100) chatMessages.shift(); const isMentioned = msg.text && window.COLLAB_USER.name && msg.text.toLowerCase().includes('@' + window.COLLAB_USER.name.toLowerCase()); if (!chatOpen && msg.userId !== window.COLLAB_USER.id) { unreadCount++; updateChatBadge(); if (chatSoundEnabled) playChatSound(isMentioned); } renderChatMessages(); } function playChatSound(isMention) { try { const ctx = new (window.AudioContext || window.webkitAudioContext)(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.connect(gain); gain.connect(ctx.destination); osc.type = 'sine'; osc.frequency.value = isMention ? 880 : 660; gain.gain.value = 0.08; gain.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.15); osc.start(ctx.currentTime); osc.stop(ctx.currentTime + 0.15); } catch (e) {} } function sendChatMessage(text) { if (!text.trim()) return; let trimmedText = text.trim(); if (trimmedText.length > 500) { trimmedText = trimmedText.substring(0, 500); showToast('Message truncated to 500 characters'); } const msg = { id: Date.now() + '-' + (msgIdCounter++), userId: window.COLLAB_USER.id, userName: window.COLLAB_USER.name, userColor: window.COLLAB_USER.color, text: trimmedText, timestamp: Date.now(), replyTo: replyingTo ? { id: replyingTo.id, userName: replyingTo.userName, text: replyingTo.text.substring(0, 80) } : null }; sendMessage('chat', msg); addChatMessage(msg); clearReply(); } function setReplyTo(msg) { replyingTo = msg; const preview = document.getElementById('collab-reply-preview'); if (preview) { preview.querySelector('span').textContent = `${msg.userName}: ${msg.text.substring(0, 60)}`; preview.classList.add('active'); } const input = document.getElementById('collab-chat-input'); if (input) input.focus(); } function clearReply() { replyingTo = null; const preview = document.getElementById('collab-reply-preview'); if (preview) preview.classList.remove('active'); } function sendTypingIndicator() { const now = Date.now(); if (now - lastTypingSent < 2000) return; lastTypingSent = now; sendMessage('typing', { userId: window.COLLAB_USER.id, userName: window.COLLAB_USER.name }); } function updateTypingIndicator() { const now = Date.now(); const active = []; typingUsers.forEach((data, userId) => { if (data.expires > now) active.push(data.name); else typingUsers.delete(userId); }); const el = document.getElementById('collab-typing'); if (!el) return; if (active.length === 0) { el.classList.remove('active'); } else { el.classList.add('active'); if (active.length === 1) el.textContent = active[0] + ' is typing...'; else if (active.length === 2) el.textContent = active[0] + ' and ' + active[1] + ' are typing...'; else el.textContent = active.length + ' people are typing...'; } } setInterval(updateTypingIndicator, 1000); function showToast(message) { let stack = document.getElementById('collab-toast-stack'); if (!stack) { stack = document.createElement('div'); stack.id = 'collab-toast-stack'; stack.className = 'collab-toast-stack'; document.body.appendChild(stack); } const toast = document.createElement('div'); toast.className = 'collab-toast-item'; toast.textContent = message; stack.appendChild(toast); setTimeout(() => { toast.classList.add('fade-out'); setTimeout(() => toast.remove(), 300); }, 3000); if (stack.children.length > 5) stack.firstChild.remove(); } function updateChatBadge() { const badge = document.getElementById('collab-chat-badge'); if (badge) { if (unreadCount > 0) { badge.textContent = unreadCount > 99 ? '99+' : unreadCount; badge.style.display = 'flex'; } else { badge.style.display = 'none'; } } } function highlightMentions(text) { const allNames = [window.COLLAB_USER.name]; users.forEach(u => { if (u.name) allNames.push(u.name); }); const validNames = allNames.filter(n => n); if (validNames.length === 0) return [text]; const escaped = validNames.map(n => n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); const regex = new RegExp('@(?:' + escaped.join('|') + ')', 'gi'); const children = []; let lastIndex = 0; let match; while ((match = regex.exec(text)) !== null) { if (match.index > lastIndex) children.push(text.slice(lastIndex, match.index)); children.push(h('span', {className: 'collab-chat-mention'}, match[0])); lastIndex = regex.lastIndex; } if (lastIndex < text.length) children.push(text.slice(lastIndex)); return children.length > 0 ? children : [text]; } function formatTimeAgo(timestamp) { const diff = Date.now() - timestamp; if (diff < 60000) return 'now'; if (diff < 3600000) return Math.floor(diff / 60000) + 'm ago'; if (diff < 86400000) return Math.floor(diff / 3600000) + 'h ago'; return new Date(timestamp).toLocaleDateString([], { month: 'short', day: 'numeric' }); } function renderChatMessages() { const container = document.getElementById('collab-chat-messages'); if (!container) return; clearNode(container); chatMessages.forEach(msg => { const time = formatTimeAgo(msg.timestamp); const safeColor = sanitizeColor(msg.userColor); const isMentioned = msg.text && window.COLLAB_USER.name && msg.text.toLowerCase().includes('@' + window.COLLAB_USER.name.toLowerCase()); const msgDiv = h('div', {className: 'collab-chat-msg' + (isMentioned ? ' mentioned' : ''), 'data-msg-id': msg.id}); if (msg.replyTo) { msgDiv.appendChild(h('div', {className: 'collab-chat-reply-ref'}, msg.replyTo.userName + ': ' + msg.replyTo.text)); } msgDiv.appendChild(h('span', {className: 'collab-chat-name', style: 'color: ' + safeColor}, msg.userName)); msgDiv.appendChild(h('span', {className: 'collab-chat-time'}, time)); const replyBtn = h('button', {className: 'collab-chat-reply-btn', 'data-reply-id': msg.id}, 'Reply'); replyBtn.addEventListener('click', () => { const m = chatMessages.find(x => x.id === msg.id); if (m) setReplyTo(m); }); msgDiv.appendChild(replyBtn); msgDiv.appendChild(h('div', {className: 'collab-chat-text'}, highlightMentions(msg.text))); container.appendChild(msgDiv); }); container.scrollTop = container.scrollHeight; } const CANVAS_WIDTH = 4000; const CANVAS_HEIGHT = 3000; function getCanvasState() { const state = getGlobal('canvasState'); return state || { zoom: 1, panX: 0, panY: 0 }; } function screenToCanvasCoords(screenX, screenY) { const viewport = document.getElementById('canvas-viewport'); if (!viewport) return null; const rect = viewport.getBoundingClientRect(); const cs = getCanvasState(); const viewportX = screenX - rect.left; const viewportY = screenY - rect.top; const viewWidth = CANVAS_WIDTH / cs.zoom; const viewHeight = CANVAS_HEIGHT / cs.zoom; const canvasX = cs.panX + (viewportX / rect.width) * viewWidth; const canvasY = cs.panY + (viewportY / rect.height) * viewHeight; return { x: canvasX, y: canvasY }; } function canvasToScreenCoords(canvasX, canvasY) { const viewport = document.getElementById('canvas-viewport'); if (!viewport) return null; const rect = viewport.getBoundingClientRect(); const cs = getCanvasState(); const viewWidth = CANVAS_WIDTH / cs.zoom; const viewHeight = CANVAS_HEIGHT / cs.zoom; const ratioX = (canvasX - cs.panX) / viewWidth; const ratioY = (canvasY - cs.panY) / viewHeight; const screenX = rect.left + ratioX * rect.width; const screenY = rect.top + ratioY * rect.height; return { x: screenX, y: screenY }; } function safeElementId(userId) { return typeof CSS !== 'undefined' && CSS.escape ? CSS.escape(userId) : userId.replace(/[^a-zA-Z0-9-_]/g, ''); } function updateRemoteCursor(userId, user) { const safeId = safeElementId(userId); let cursor = document.getElementById(`collab-cursor-${safeId}`); if (!cursor && user.cursorX !== undefined) { cursor = document.createElement('div'); cursor.id = `collab-cursor-${safeId}`; cursor.className = 'collab-remote-cursor'; const safeColor = sanitizeColor(user.color); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '16'); svg.setAttribute('height', '16'); svg.setAttribute('viewBox', '0 0 16 16'); const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', 'M0 0L16 12L8 12L4 16L0 0Z'); path.setAttribute('fill', safeColor); svg.appendChild(path); cursor.appendChild(svg); cursor.appendChild(h('span', {className: 'collab-cursor-name', style: 'background:' + safeColor}, user.name)); document.body.appendChild(cursor); } if (cursor && user.cursorX !== undefined) { const viewport = document.getElementById('canvas-viewport'); if (!viewport) { cursor.style.display = 'none'; return; } const rect = viewport.getBoundingClientRect(); let screenX, screenY; if (user.isCanvasCoords) { const screen = canvasToScreenCoords(user.cursorX, user.cursorY); if (!screen) { cursor.style.display = 'none'; return; } screenX = screen.x; screenY = screen.y; } else if (user.isRatio) { screenX = rect.left + user.cursorX * rect.width; screenY = rect.top + user.cursorY * rect.height; } else { screenX = user.cursorX; screenY = user.cursorY; } const margin = 100; if (screenX < rect.left - margin || screenX > rect.right + margin || screenY < rect.top - margin || screenY > rect.bottom + margin) { cursor.style.display = 'none'; return; } cursor.style.display = 'block'; cursor.style.left = screenX + 'px'; cursor.style.top = screenY + 'px'; } } function refreshAllRemoteCursors() { users.forEach((user, userId) => { if (user.cursorX !== undefined) { updateRemoteCursor(userId, user); } }); } function removeRemoteCursor(userId) { const cursor = document.getElementById(`collab-cursor-${safeElementId(userId)}`); if (cursor) cursor.remove(); } function trackCursor() { let lastSent = 0; let pendingPos = null; let rafId = null; function sendCursorUpdate() { if (!pendingPos) return; const canvas = screenToCanvasCoords(pendingPos.x, pendingPos.y); if (canvas) { sendMessage('cursor', { userId: window.COLLAB_USER.id, x: canvas.x, y: canvas.y, isCanvasCoords: true }); } pendingPos = null; rafId = null; } document.addEventListener('mousemove', (e) => { const now = Date.now(); if (now - lastSent < 25) return; lastSent = now; pendingPos = { x: e.clientX, y: e.clientY }; if (rafId === null) { rafId = requestAnimationFrame(sendCursorUpdate); } }); let lastZoom = null; let lastPanX = null; let lastPanY = null; setInterval(() => { const cs = getCanvasState(); if (cs.zoom !== lastZoom || cs.panX !== lastPanX || cs.panY !== lastPanY) { lastZoom = cs.zoom; lastPanX = cs.panX; lastPanY = cs.panY; refreshAllRemoteCursors(); } }, 100); } function getGlobal(name) { if (typeof window.__collabGetVar === 'function') return window.__collabGetVar(name); return undefined; } function setGlobal(name, value) { if (typeof window.__collabSetVar === 'function') return window.__collabSetVar(name, value); return false; } function captureState() { let state = null; if (typeof captureTheQuickening === 'function') { try { state = captureTheQuickening(); delete state.canvas; if (state.documentTabs) { state.documentTabs = state.documentTabs.map(tab => { const { pageState, ...rest } = tab; return rest; }); } } catch (e) { console.error('captureTheQuickening error:', e); } } if (!state) { const nodeData = getGlobal('NODE_DATA'); if (!nodeData) return null; state = { nodeData: nodeData, edgeData: getGlobal('EDGE_DATA'), rectData: getGlobal('RECT_DATA'), textData: getGlobal('TEXT_DATA'), imageData: getGlobal('IMAGE_DATA'), nodePositions: getGlobal('savedPositions'), nodeSizes: getGlobal('savedSizes'), nodeStyles: getGlobal('savedStyles'), edgeLegend: getGlobal('EDGE_LEGEND'), zoneLegend: getGlobal('ZONE_LEGEND'), zonePresets: getGlobal('ZONE_PRESETS'), documentTabs: getGlobal('documentTabs'), currentTabIndex: getGlobal('currentTabIndex'), iconCache: getGlobal('iconCache'), auditLog: getGlobal('auditLog'), savedStyleSets: getGlobal('savedStyleSets'), autoPingEnabled: getGlobal('autoPingEnabled'), autoPingInterval: getGlobal('autoPingInterval'), savedTopologyView: getGlobal('savedTopologyView'), encryptedSections: getGlobal('encryptedSections') }; } state.animSettings = getGlobal('ANIM_SETTINGS'); state.rollbackVersions = getGlobal('rollbackVersions'); state.customLang = getGlobal('CUSTOM_LANG'); const pageState = getGlobal('PAGE_STATE'); if (pageState) { state.themeState = {}; const themeKeys = ['panel','panelAlt','accent','danger','textMain','textSoft', 'background','canvasGrid','tagFill','tagText','tagBorder','sidebarBg', 'btnBg','btnText','inputBg','inputText','inputBorder','toolbarBg', 'toolbarBorder','toolbarText','toolbarBtnBg','toolbarBtnText']; for (const k of themeKeys) { if (pageState[k] !== undefined) state.themeState[k] = pageState[k]; } } if (window.COLLAB_DEBUG) { console.log('[Collab] Captured state keys:', Object.keys(state)); console.log('[Collab] nodeStyles count:', state.nodeStyles ? Object.keys(state.nodeStyles).length : 0); console.log('[Collab] savedStyleSets count:', state.savedStyleSets ? state.savedStyleSets.length : 0); } return state; } function hashState(state) { const str = JSON.stringify(state); let hash = 5381; for (let i = 0; i < str.length; i++) { hash = ((hash << 5) + hash) + str.charCodeAt(i); hash = hash & hash; } return hash.toString(36); } function sendFullState() { const state = captureState(); if (!state) return; lastStateHash = hashState(state); sendMessage('state', { state }); } function applyRemoteState(state) { if (!state) return; syncPaused = true; try { if (window.COLLAB_DEBUG) { console.log('[Collab] Applying remote state, keys:', Object.keys(state)); console.log('[Collab] Incoming nodeStyles:', state.nodeStyles ? Object.keys(state.nodeStyles).length : 'none'); } const localTabIndex = getGlobal('currentTabIndex') || 0; const senderTabIndex = state.currentTabIndex !== undefined ? state.currentTabIndex : 0; if (state.documentTabs) { const localTabs = getGlobal('documentTabs') || []; const mergedTabs = state.documentTabs.map((remoteTab, i) => { const localTab = localTabs[i]; return { ...remoteTab, pageState: localTab?.pageState || remoteTab.pageState || {} }; }); setGlobal('documentTabs', mergedTabs); } if (state.zoneLegend) setGlobal('ZONE_LEGEND', state.zoneLegend); if (state.zonePresets) setGlobal('ZONE_PRESETS', state.zonePresets); const tabs = getGlobal('documentTabs') || []; const myTab = tabs[localTabIndex]; if (localTabIndex === senderTabIndex) { if (window.COLLAB_DEBUG) console.log('[Collab] Same tab, applying directly'); if (state.nodeData) setGlobal('NODE_DATA', state.nodeData); if (state.edgeData) setGlobal('EDGE_DATA', state.edgeData); if (state.rectData) setGlobal('RECT_DATA', state.rectData); if (state.textData) setGlobal('TEXT_DATA', state.textData); if (state.imageData) setGlobal('IMAGE_DATA', state.imageData); if (state.nodePositions) setGlobal('savedPositions', state.nodePositions); if (state.nodeSizes) setGlobal('savedSizes', state.nodeSizes); if (state.nodeStyles) { if (window.COLLAB_DEBUG) console.log('[Collab] Setting savedStyles from nodeStyles'); setGlobal('savedStyles', state.nodeStyles); } if (state.edgeLegend) setGlobal('EDGE_LEGEND', state.edgeLegend); } else if (myTab) { if (myTab.nodes) setGlobal('NODE_DATA', myTab.nodes); if (myTab.edges) setGlobal('EDGE_DATA', myTab.edges); if (myTab.positions) setGlobal('savedPositions', myTab.positions); if (myTab.sizes) setGlobal('savedSizes', myTab.sizes); if (myTab.styles) setGlobal('savedStyles', myTab.styles); if (myTab.legend) setGlobal('EDGE_LEGEND', myTab.legend); if (myTab.rects) setGlobal('RECT_DATA', myTab.rects); if (myTab.texts) setGlobal('TEXT_DATA', myTab.texts); if (myTab.images) setGlobal('IMAGE_DATA', myTab.images); } if (state.iconCache) setGlobal('iconCache', state.iconCache); if (state.auditLog) setGlobal('auditLog', state.auditLog); if (state.savedStyleSets) setGlobal('savedStyleSets', state.savedStyleSets); if (state.autoPingEnabled !== undefined) setGlobal('autoPingEnabled', state.autoPingEnabled); if (state.autoPingInterval !== undefined) setGlobal('autoPingInterval', state.autoPingInterval); if (state.savedTopologyView) setGlobal('savedTopologyView', state.savedTopologyView); if (state.animSettings) setGlobal('ANIM_SETTINGS', state.animSettings); if (state.rollbackVersions) setGlobal('rollbackVersions', state.rollbackVersions); if (state.customLang) setGlobal('CUSTOM_LANG', state.customLang); if (state.encryptedSections) setGlobal('encryptedSections', state.encryptedSections); if (typeof forgeTheTopology === 'function') { try { forgeTheTopology(); } catch (e) {} } if (state.themeState) { setGlobal('PAGE_STATE', state.themeState); if (typeof wieldThePower === 'function') { try { wieldThePower(); } catch (e) {} } } } finally { setTimeout(() => { syncPaused = false; }, 200); } } const STATE_SYNC_MIN_INTERVAL = 500; const STATE_SYNC_DEBOUNCE = 300; let lastStateSyncTime = 0; let stateSyncTimeout = null; function syncStateIfChanged() { const state = captureState(); if (!state) return; const currentHash = hashState(state); if (currentHash === lastStateHash) return; lastStateHash = currentHash; sendMessage('state', { state }); lastStateSyncTime = Date.now(); } function startStatePolling() { setInterval(() => { if (syncPaused || !hasReceivedInitialState) return; const now = Date.now(); const timeSinceLastSync = now - lastStateSyncTime; if (timeSinceLastSync < STATE_SYNC_MIN_INTERVAL) { if (!stateSyncTimeout) { stateSyncTimeout = setTimeout(() => { stateSyncTimeout = null; syncStateIfChanged(); }, STATE_SYNC_DEBOUNCE); } return; } syncStateIfChanged(); }, 250); } function sendPresence() { sendMessage('presence', { userId: window.COLLAB_USER.id, selectedNodes: window.COLLAB_USER.selectedNodes || [], editingNode: window.COLLAB_USER.editingNode, currentTab: getCurrentTabName() }); } function trackSelection() { const map = document.getElementById('map'); if (!map) { setTimeout(trackSelection, 500); return; } let lastTab = getCurrentTabName(); setInterval(() => { const currentTab = getCurrentTabName(); if (currentTab !== lastTab) { lastTab = currentTab; sendPresence(); renderUsers(); } }, 500); const observer = new MutationObserver(() => { const selected = []; document.querySelectorAll('.node-group.selected, [data-id].selected').forEach(el => { const id = el.dataset?.id || el.getAttribute('data-id'); if (id) selected.push(id); }); if (JSON.stringify(selected) !== JSON.stringify(window.COLLAB_USER.selectedNodes)) { window.COLLAB_USER.selectedNodes = selected; sendPresence(); renderUsers(); } }); observer.observe(map, { subtree: true, attributes: true, attributeFilter: ['class'] }); } function setupAuditLogInjection() { if (typeof window.__collabGetVar !== 'function') return; if (typeof window.addAuditEntry === 'function') { window.__collabOriginalAddAudit = window.addAuditEntry; window.addAuditEntry = function(type, description, details) { const entry = { timestamp: Date.now(), type: type, description: description, details: details || {}, tab: window.__collabGetVar('documentTabs')?.[window.__collabGetVar('currentTabIndex')]?.name || 'Main', user: window.COLLAB_USER?.name || 'Unknown', userColor: window.COLLAB_USER?.color || '#888' }; const auditLog = window.__collabGetVar('auditLog') || []; auditLog.unshift(entry); if (auditLog.length > 1000) auditLog.pop(); window.__collabSetVar('auditLog', auditLog); return entry; }; } } function getCurrentTabName() { try { const tabs = getGlobal('documentTabs'); const idx = getGlobal('currentTabIndex') || 0; if (tabs && tabs[idx]) return tabs[idx].name || 'Main'; return 'Main'; } catch { return 'Main'; } } function renderUsers() { const container = document.querySelector('.collab-users'); if (!container) return; const myTab = getCurrentTabName(); const allUsers = [window.COLLAB_USER, ...users.values()]; clearNode(container); allUsers.forEach(user => { const isMe = user.id === window.COLLAB_USER.id; const tabName = isMe ? myTab : (user.currentTab || 'Main'); const safeColor = sanitizeColor(user.color); const initials = getInitials(user.name); container.appendChild( h('div', {className: 'collab-user' + (isMe ? ' me' : ''), 'data-user-id': user.id}, h('div', {className: 'collab-user-avatar', style: 'background: ' + safeColor}, initials), h('div', {className: 'collab-user-info'}, h('span', {className: 'collab-user-name'}, user.name), user.editingNode ? h('span', {className: 'collab-user-editing'}, 'editing') : null, h('span', {className: 'collab-user-tab'}, tabName) ) ) ); }); } function renderUserIndicators() { document.querySelectorAll('.collab-node-indicator, .collab-selection-ring').forEach(el => el.remove()); users.forEach(user => { if (!user.selectedNodes) return; user.selectedNodes.forEach(nodeId => { if (typeof nodeId !== 'string' || !/^[\w-]+$/.test(nodeId)) return; const nodeEl = document.querySelector(`[data-id="${nodeId}"]`); if (!nodeEl) return; const ring = document.createElement('div'); ring.className = 'collab-selection-ring'; ring.style.borderColor = user.color; ring.dataset.collabUserId = user.id; const nodeGroup = nodeEl.closest('.node-group') || nodeEl; nodeGroup.style.position = 'relative'; nodeGroup.appendChild(ring); const label = document.createElement('div'); label.className = 'collab-node-indicator'; label.style.background = user.color; label.style.color = '#fff'; label.textContent = user.name; label.dataset.collabUserId = user.id; nodeGroup.appendChild(label); }); }); } function removeUserIndicators(userId) { document.querySelectorAll(`[data-collab-user-id="${userId}"]`).forEach(el => el.remove()); } function updateCharCount() { const input = document.getElementById('collab-chat-input'); const counter = document.getElementById('collab-char-count'); if (!input || !counter) return; const len = input.value.length; const remaining = 500 - len; if (remaining <= 50) { counter.textContent = remaining; counter.className = 'collab-chat-char-count' + (remaining <= 20 ? ' danger' : ' warning'); } else { counter.textContent = ''; counter.className = 'collab-chat-char-count'; } } function toggleEmojiPicker() { emojiPickerOpen = !emojiPickerOpen; const picker = document.getElementById('collab-emoji-picker'); if (picker) picker.classList.toggle('active', emojiPickerOpen); } function insertEmoji(emoji) { const input = document.getElementById('collab-chat-input'); if (!input) return; const start = input.selectionStart || input.value.length; input.value = input.value.substring(0, start) + emoji + input.value.substring(input.selectionEnd || start); input.focus(); input.selectionStart = input.selectionEnd = start + emoji.length; updateCharCount(); emojiPickerOpen = false; const picker = document.getElementById('collab-emoji-picker'); if (picker) picker.classList.remove('active'); } function updateExpiryCountdown() { const el = document.getElementById('collab-expiry'); if (!el || !roomExpiryData) { if (el) el.style.display = 'none'; return; } if (!roomExpiryData.destruct || roomExpiryData.destruct.mode === 'none') { el.style.display = 'none'; return; } if (roomExpiryData.destruct.mode === 'empty') { el.style.display = 'flex'; el.textContent = 'Destroys when empty'; return; } if (roomExpiryData.destruct.mode === 'time') { const created = new Date(roomExpiryData.created).getTime(); const expiresAt = created + roomExpiryData.destruct.value; const remaining = expiresAt - Date.now(); if (remaining <= 0) { el.style.display = 'flex'; el.textContent = 'Expiring...'; return; } el.style.display = 'flex'; const hours = Math.floor(remaining / 3600000); const mins = Math.floor((remaining % 3600000) / 60000); if (hours > 24) el.textContent = Math.ceil(hours / 24) + 'd left'; else if (hours > 0) el.textContent = hours + 'h ' + mins + 'm left'; else el.textContent = mins + 'm left'; } } function injectCollabBar() { document.body.classList.add('collab-active'); const bar = document.createElement('div'); bar.id = 'collab-bar'; _append(bar, [ h('div', {id: 'collab-conn-dot', className: 'collab-conn-status connected'}), h('div', {className: 'collab-users'}), h('div', {id: 'collab-expiry', className: 'collab-room-expiry', style: 'display:none'}), h('div', {className: 'collab-actions'}, h('button', {className: 'collab-btn', id: 'collab-chat-btn'}, h('span', {className: 'collab-btn-icon'}, '\u2709'), h('span', null, 'Chat'), h('span', {className: 'collab-chat-badge', id: 'collab-chat-badge'}) ), h('button', {className: 'collab-btn', id: 'collab-share-btn', style: shareButtonEnabled ? '' : 'display:none'}, h('span', {className: 'collab-btn-icon'}, '+'), h('span', null, 'Share') ), h('button', {className: 'collab-btn', id: 'collab-menu-btn'}, h('span', {className: 'collab-btn-icon'}, '=') ) ) ]); document.body.prepend(bar); const reconnectBanner = document.createElement('div'); reconnectBanner.id = 'collab-reconnect-banner'; reconnectBanner.className = 'collab-reconnect-banner'; _append(reconnectBanner, [ h('span', null, 'Reconnecting...'), h('button', {className: 'collab-reconnect-btn', id: 'collab-reconnect-btn'}, 'Reconnect') ]); document.body.appendChild(reconnectBanner); document.getElementById('collab-reconnect-btn').addEventListener('click', () => { reconnectAttempts = 0; connect(); }); const chatPanel = document.createElement('div'); chatPanel.id = 'collab-chat-panel'; _append(chatPanel, [ h('div', {className: 'collab-chat-header'}, h('span', null, 'Chat'), h('button', {className: 'collab-chat-close', id: 'collab-chat-close'}, '\u00d7') ), h('div', {className: 'collab-chat-messages', id: 'collab-chat-messages'}), h('div', {id: 'collab-typing', className: 'collab-typing-indicator'}), h('div', {className: 'collab-chat-input-area', style: 'position:relative'}, h('div', {id: 'collab-reply-preview', className: 'collab-chat-reply-preview'}, h('span', null, ''), h('button', {className: 'collab-chat-reply-cancel', id: 'collab-reply-cancel'}, '\u00d7') ), h('div', {id: 'collab-emoji-picker', className: 'collab-emoji-picker'}, h('div', {className: 'collab-emoji-grid'}, EMOJI_LIST.map(e => h('button', {className: 'collab-emoji-btn', 'data-emoji': e}, e)) ) ), h('div', {className: 'collab-chat-input-wrap'}, h('button', {className: 'collab-emoji-toggle', id: 'collab-emoji-toggle'}, '\ud83d\ude0a'), h('div', {className: 'collab-chat-input-inner'}, h('input', {type: 'text', id: 'collab-chat-input', placeholder: 'Type a message...', maxLength: 500, autocomplete: 'off'}), h('div', {className: 'collab-chat-char-count', id: 'collab-char-count'}) ), h('button', {id: 'collab-chat-send'}, 'Send') ) ) ]); document.body.appendChild(chatPanel); const shareModal = document.createElement('div'); shareModal.id = 'collab-share-modal'; shareModal.className = 'collab-modal-overlay'; shareModal.appendChild( h('div', {className: 'collab-modal'}, h('div', {className: 'collab-modal-header'}, h('h3', null, 'Share Room'), h('button', {className: 'collab-modal-close'}, '\u00d7') ), h('div', {className: 'collab-modal-body'}, h('div', {className: 'collab-share-url'}, h('input', {type: 'text', readonly: true, value: window.location.href, id: 'collab-share-input'}), h('button', {id: 'collab-copy-btn'}, 'Copy') ), h('div', {className: 'collab-qr', id: 'collab-qr'}), h('p', {className: 'collab-share-note'}, HAS_PASSWORD ? 'Password protected. Share password separately.' : 'Anyone with this link can join.') ) ) ); document.body.appendChild(shareModal); const infoModal = document.createElement('div'); infoModal.id = 'collab-info-modal'; infoModal.className = 'collab-modal-overlay'; infoModal.appendChild( h('div', {className: 'collab-modal'}, h('div', {className: 'collab-modal-header'}, h('h3', null, 'Room Info'), h('button', {className: 'collab-modal-close'}, '\u00d7') ), h('div', {className: 'collab-modal-body'}, h('div', {id: 'collab-info-content'}) ) ) ); document.body.appendChild(infoModal); const menuDropdown = document.createElement('div'); menuDropdown.id = 'collab-menu-dropdown'; _append(menuDropdown, [ shareButtonEnabled ? h('button', {className: 'collab-menu-item', id: 'collab-menu-copy'}, 'Copy Link') : null, h('button', {className: 'collab-menu-item', id: 'collab-menu-info'}, 'Room Info'), h('button', {className: 'collab-menu-item', id: 'collab-menu-name'}, 'Change Name'), h('button', {className: 'collab-menu-item', id: 'collab-menu-sound'}, chatSoundEnabled ? 'Mute Sounds' : 'Unmute Sounds'), h('div', {className: 'collab-menu-divider'}), h('button', {className: 'collab-menu-item', id: 'collab-menu-leave'}, 'Leave Room'), IS_CREATOR ? h('button', {className: 'collab-menu-item danger', id: 'collab-menu-delete'}, 'Delete Room') : null ]); document.body.appendChild(menuDropdown); document.getElementById('collab-chat-btn').addEventListener('click', () => { chatOpen = !chatOpen; chatPanel.classList.toggle('active', chatOpen); if (chatOpen) { unreadCount = 0; updateChatBadge(); document.getElementById('collab-chat-input').focus(); } }); document.getElementById('collab-chat-close').addEventListener('click', () => { chatOpen = false; chatPanel.classList.remove('active'); emojiPickerOpen = false; const picker = document.getElementById('collab-emoji-picker'); if (picker) picker.classList.remove('active'); }); document.getElementById('collab-chat-send').addEventListener('click', () => { const input = document.getElementById('collab-chat-input'); sendChatMessage(input.value); input.value = ''; updateCharCount(); }); const chatInput = document.getElementById('collab-chat-input'); chatInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendChatMessage(e.target.value); e.target.value = ''; updateCharCount(); } }); chatInput.addEventListener('input', () => { updateCharCount(); sendTypingIndicator(); }); document.getElementById('collab-reply-cancel').addEventListener('click', clearReply); document.getElementById('collab-emoji-toggle').addEventListener('click', (e) => { e.stopPropagation(); toggleEmojiPicker(); }); document.getElementById('collab-emoji-picker').addEventListener('click', (e) => { e.stopPropagation(); const emoji = e.target.dataset?.emoji; if (emoji) insertEmoji(emoji); }); document.getElementById('collab-share-btn').addEventListener('click', () => { shareModal.classList.add('active'); generateQR(); }); shareModal.querySelector('.collab-modal-close').addEventListener('click', () => shareModal.classList.remove('active')); shareModal.addEventListener('click', (e) => { if (e.target === shareModal) shareModal.classList.remove('active'); }); infoModal.querySelector('.collab-modal-close').addEventListener('click', () => infoModal.classList.remove('active')); infoModal.addEventListener('click', (e) => { if (e.target === infoModal) infoModal.classList.remove('active'); }); document.getElementById('collab-copy-btn').addEventListener('click', () => { navigator.clipboard.writeText(document.getElementById('collab-share-input').value); const btn = document.getElementById('collab-copy-btn'); btn.textContent = 'OK'; setTimeout(() => { btn.textContent = 'Copy'; }, 2000); }); const menuBtn = document.getElementById('collab-menu-btn'); menuBtn.addEventListener('click', (e) => { e.stopPropagation(); const rect = menuBtn.getBoundingClientRect(); menuDropdown.style.top = `${rect.bottom + 8}px`; menuDropdown.style.right = `${window.innerWidth - rect.right}px`; menuDropdown.classList.toggle('active'); }); document.addEventListener('click', () => { menuDropdown.classList.remove('active'); if (emojiPickerOpen) { emojiPickerOpen = false; const picker = document.getElementById('collab-emoji-picker'); if (picker) picker.classList.remove('active'); } }); const copyBtn = document.getElementById('collab-menu-copy'); if (copyBtn) { copyBtn.addEventListener('click', () => { navigator.clipboard.writeText(window.location.href); showToast('Link copied'); }); } document.getElementById('collab-menu-sound').addEventListener('click', () => { chatSoundEnabled = !chatSoundEnabled; localStorage.setItem('collab-chat-sound', chatSoundEnabled); document.getElementById('collab-menu-sound').textContent = chatSoundEnabled ? 'Mute Sounds' : 'Unmute Sounds'; showToast(chatSoundEnabled ? 'Sound notifications on' : 'Sound notifications off'); }); document.getElementById('collab-menu-info').addEventListener('click', async () => { try { const res = await fetch(`/api/room/${ROOM_ID}/exists`); const data = await res.json(); roomExpiryData = data; updateExpiryCountdown(); let destructText = 'Never'; if (data.destruct) { if (data.destruct.mode === 'time') { const hours = data.destruct.value / 3600000; if (hours < 1) destructText = `${Math.round(hours * 60)} minutes after last activity`; else if (hours < 24) destructText = `${hours} hours after last activity`; else destructText = `${Math.round(hours / 24)} days after last activity`; } else if (data.destruct.mode === 'empty') { destructText = 'When everyone leaves'; } } function infoRow(label, value, extraClass) { return h('div', {className: 'collab-info-row'}, h('span', {className: 'collab-info-label'}, label), h('span', {className: 'collab-info-value' + (extraClass ? ' ' + extraClass : '')}, value) ); } setContent(document.getElementById('collab-info-content'), [ infoRow('Room ID', ROOM_ID, 'collab-info-id'), infoRow('Created', new Date(data.created).toLocaleString()), infoRow('Self Destruct', destructText), infoRow('Password', data.hasPassword ? 'Yes' : 'No'), infoRow('Connected', (users.size + 1) + ' users'), infoRow('You are', IS_CREATOR ? 'Room Creator' : 'Participant') ]); infoModal.classList.add('active'); } catch { setContent(document.getElementById('collab-info-content'), h('p', null, 'Failed to load room info')); infoModal.classList.add('active'); } }); document.getElementById('collab-menu-name').addEventListener('click', () => showNameModal(true)); document.getElementById('collab-menu-leave').addEventListener('click', () => { if (confirm('Leave this room? You will need to enter your name again to rejoin.')) { leaveRoom(); } }); const deleteBtn = document.getElementById('collab-menu-delete'); if (deleteBtn) { deleteBtn.addEventListener('click', async () => { if (!confirm('Delete this room permanently?')) return; try { const res = await fetch(`/api/room/${ROOM_ID}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN || '' }, body: JSON.stringify({ creatorId: localStorage.getItem('collab-user-' + ROOM_ID) }) }); refreshCsrf(); if (res.ok) window.location.href = '/'; else showToast((await res.json()).error || 'Failed to delete'); } catch { showToast('Failed to delete room'); } }); } document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { if (chatOpen) { chatOpen = false; chatPanel.classList.remove('active'); emojiPickerOpen = false; const picker = document.getElementById('collab-emoji-picker'); if (picker) picker.classList.remove('active'); } shareModal.classList.remove('active'); infoModal.classList.remove('active'); menuDropdown.classList.remove('active'); } }); renderUsers(); fetch(`/api/room/${ROOM_ID}/exists`).then(r => r.json()).then(data => { roomExpiryData = data; updateExpiryCountdown(); }).catch(() => {}); expiryInterval = setInterval(updateExpiryCountdown, 30000); } function generateQR() { const container = document.getElementById('collab-qr'); const url = window.location.href; if (typeof qrcode === 'undefined') { const script = document.createElement('script'); script.src = '/qrcode.min.js'; script.onload = () => renderQR(container, url); script.onerror = () => { setContent(container, h('p', {style: 'color:#888;font-size:12px'}, 'QR unavailable')); }; document.head.appendChild(script); } else { renderQR(container, url); } } function renderQR(container, url) { try { const qr = qrcode(0, 'M'); qr.addData(url); qr.make(); const svgHtml = qr.createSvgTag({ cellSize: 4, margin: 4 }); const parsed = new DOMParser().parseFromString(svgHtml, 'image/svg+xml'); clearNode(container); container.appendChild(document.importNode(parsed.documentElement, true)); } catch { setContent(container, h('p', {style: 'color:#888;font-size:12px'}, 'QR unavailable')); } } function showNameModal(isChange = false, errorMsg = null) { const existing = document.getElementById('collab-name-modal'); if (existing) existing.remove(); const modal = document.createElement('div'); modal.id = 'collab-name-modal'; modal.className = 'collab-modal-overlay active'; modal.appendChild( h('div', {className: 'collab-modal'}, h('div', {className: 'collab-modal-header'}, h('h3', null, isChange ? 'Change Name' : 'Enter Your Name'), isChange ? h('button', {className: 'collab-modal-close'}, '\u00d7') : null ), h('div', {className: 'collab-modal-body'}, h('input', {type: 'text', id: 'collab-name-input', className: 'collab-input', placeholder: 'Your name', maxLength: 30}), h('div', {className: 'collab-name-error', id: 'collab-name-error'}, errorMsg || ''), h('div', {className: 'collab-name-actions'}, h('button', {id: 'collab-name-random', className: 'collab-btn-secondary'}, 'Random'), h('button', {id: 'collab-name-submit', className: 'collab-btn-primary'}, isChange ? 'Update' : 'Join') ) ) ) ); document.body.appendChild(modal); const errorEl = document.getElementById('collab-name-error'); if (errorMsg) errorEl.classList.add('active'); const input = document.getElementById('collab-name-input'); if (isChange && window.COLLAB_USER.name) input.value = window.COLLAB_USER.name; input.focus(); input.addEventListener('input', () => { errorEl.classList.remove('active'); }); document.getElementById('collab-name-random').addEventListener('click', () => { input.value = generateHighlanderName(); errorEl.classList.remove('active'); }); document.getElementById('collab-name-submit').addEventListener('click', () => { const name = input.value.trim() || generateHighlanderName(); setStoredUserName(name); window.COLLAB_USER.name = name; modal.remove(); if (isChange || nameRejectedRecovery) { nameRejectedRecovery = false; sendMessage('join', { user: window.COLLAB_USER }); renderUsers(); } else { startCollab(); } }); input.addEventListener('keypress', (e) => { if (e.key === 'Enter') document.getElementById('collab-name-submit').click(); }); const closeBtn = modal.querySelector('.collab-modal-close'); if (closeBtn) closeBtn.addEventListener('click', () => modal.remove()); } async function checkPassword() { if (!HAS_PASSWORD) return true; try { const res = await fetch(`/api/room/${ROOM_ID}/access`, { credentials: 'include' }); if (res.ok && (await res.json()).authorized) return true; } catch {} return new Promise((resolve) => { const modal = document.createElement('div'); modal.id = 'collab-password-modal'; modal.className = 'collab-modal-overlay active'; modal.appendChild( h('div', {className: 'collab-modal'}, h('div', {className: 'collab-modal-header'}, h('h3', null, 'Password Required') ), h('div', {className: 'collab-modal-body'}, h('input', {type: 'password', id: 'collab-pwd-input', className: 'collab-input', placeholder: 'Room password'}), h('div', {className: 'collab-pwd-error', id: 'collab-pwd-error'}, 'Invalid password'), h('button', {id: 'collab-pwd-submit', className: 'collab-btn-primary', style: 'width:100%;margin-top:12px'}, 'Enter') ) ) ); document.body.appendChild(modal); const input = document.getElementById('collab-pwd-input'); const error = document.getElementById('collab-pwd-error'); input.focus(); async function tryPwd() { const res = await fetch(`/api/room/${ROOM_ID}/verify`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ password: input.value }) }); if ((await res.json()).valid) { modal.remove(); resolve(true); } else { error.classList.add('active'); input.value = ''; input.focus(); } } document.getElementById('collab-pwd-submit').addEventListener('click', tryPwd); input.addEventListener('keypress', (e) => { if (e.key === 'Enter') tryPwd(); }); }); } async function init() { const authorized = await checkPassword(); if (!authorized) { window.location.href = '/'; return; } try { const themeRes = await fetch('/api/theme'); if (themeRes.ok) { const themeData = await themeRes.json(); if (themeData.shareButtonEnabled !== undefined) { shareButtonEnabled = themeData.shareButtonEnabled; } } } catch (e) { console.error('[Collab] Failed to fetch theme settings:', e); } function waitForApp() { const hasForge = typeof forgeTheTopology === 'function'; const hasHelper = typeof window.__collabGetVar === 'function'; const hasNodeData = hasHelper ? window.__collabGetVar('NODE_DATA') !== undefined : false; if (hasForge && hasNodeData) { const storedName = getStoredUserName(); if (storedName) { window.COLLAB_USER.name = storedName; startCollab(); } else { if (window.DEFAULT_ROOM_THEME) { var drt = typeof THEME_PRESETS !== 'undefined' ? THEME_PRESETS : null; if (drt && drt[window.DEFAULT_ROOM_THEME]) { setGlobal('PAGE_STATE', drt[window.DEFAULT_ROOM_THEME]); if (typeof wieldThePower === 'function') try { wieldThePower(); } catch(e) {} var tsel = document.getElementById('welcome-theme-select'); if (tsel) tsel.value = window.DEFAULT_ROOM_THEME; } } showNameModal(false); } } else { setTimeout(waitForApp, 200); } } waitForApp(); } function stripCollabFromHTML(htmlString) { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const collabElements = [ '#collab-bar', '#collab-share-modal', '#collab-info-modal', '#collab-menu-dropdown', '#collab-name-modal', '#collab-password-modal', '#collab-sync-overlay', '#collab-chat-panel', '#collab-reconnect-banner', '#collab-toast-stack', '.collab-node-indicator', '.collab-selection-ring', '.collab-remote-cursor', '#verse-discovery-modal', '#verse-disc-edit-modal', '#verse-discover-btn', '.verse-probe-ui' ]; collabElements.forEach(sel => { doc.querySelectorAll(sel).forEach(el => el.remove()); }); const body = doc.querySelector('body'); if (body) { body.classList.remove('collab-active'); } doc.querySelectorAll('script[src*="collab"], link[href*="collab.css"], #room-config').forEach(el => el.remove()); var topoState = doc.querySelector('#topology-state'); if (topoState && topoState.textContent) { try { var topo = JSON.parse(topoState.textContent); function scrubProbeResults(nodeData) { if (!nodeData || typeof nodeData !== 'object') return; Object.keys(nodeData).forEach(function(nid) { if (nodeData[nid] && nodeData[nid].ping) { delete nodeData[nid].ping.probeResults; } }); } if (topo.nodeData) scrubProbeResults(topo.nodeData); if (topo.documentTabs && Array.isArray(topo.documentTabs)) { topo.documentTabs.forEach(function(tab) { if (tab && tab.nodes) scrubProbeResults(tab.nodes); }); } topoState.textContent = JSON.stringify(topo); } catch(e) {} } return '\n' + doc.documentElement.outerHTML; } function hookSaveFunction() { window.__collabStripHTML = stripCollabFromHTML; } function buildProbeList(ping) { if (ping.probeTypes && Array.isArray(ping.probeTypes) && ping.probeTypes.length > 0) { return ping.probeTypes; } var probes = [{ type: 'icmp' }]; if (ping.protocol === 'custom' && ping.customUrl) { probes.push({ type: 'http', url: ping.customUrl }); } else if (ping.protocol === 'https') { probes.push({ type: 'http' }); } else { probes.push({ type: 'http' }); } return probes; } function updateProbeResultsPanel(nodeId) { var panel = document.getElementById('verse-probe-results'); if (!panel) return; var nd = getGlobal('NODE_DATA'); var data = nd[nodeId]; if (!data || !data.ping || !data.ping.probeResults || data.ping.probeResults.length === 0) { panel.innerHTML = ''; return; } var html = ''; data.ping.probeResults.forEach(function(r) { var color = r.status === 'online' ? 'var(--accent)' : r.status === 'offline' ? 'var(--danger)' : 'var(--text-soft)'; var label = r.type.toUpperCase(); if (r.port) label += ':' + r.port; var detail = ''; if (r.responseTime !== null) detail = r.responseTime + 'ms'; if (r.detail) detail += (detail ? ' ' : '') + r.detail; html += '
'; html += '' + label + ''; html += '● ' + (detail || r.status) + ''; html += '
'; }); panel.innerHTML = html; } function overridePingFunctions() { if (!window.COLLAB_MODE || !_rc.probeEnabled) return; window.checkNodeStatus = async function(nodeId) { var nd = getGlobal('NODE_DATA'); var data = nd[nodeId]; if (!data || !data.ping || !data.ping.enabled) return; data.ping.status = 'checking'; data.ping.lastCheck = new Date().toISOString(); data.ping.responseTime = null; var updateIndicator = window.__collabGetVar('updatePingIndicator'); var updateDisplay = window.__collabGetVar('updatePingStatusDisplay'); if (updateIndicator) updateIndicator(nodeId); var curId = window.__collabGetVar('currentNodeId'); if (curId === nodeId && updateDisplay) updateDisplay(nodeId); var target = data.ip || ''; if (!target && data.ping.protocol === 'custom') target = data.ping.customUrl; if (!target) { data.ping.status = 'unknown'; return; } var probes = buildProbeList(data.ping); try { var resp = await fetch('/api/probe', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ target: target, probes: probes, timeout: data.ping.timeout || 3000 }) }); refreshCsrf(); var result = await resp.json(); if (resp.ok) { data.ping.status = result.status; data.ping.responseTime = result.rtt || null; data.ping.probeResults = result.results || []; } else { data.ping.status = 'offline'; data.ping.responseTime = null; } } catch(e) { data.ping.status = 'offline'; data.ping.responseTime = null; } data.ping.lastCheck = new Date().toISOString(); if (updateIndicator) updateIndicator(nodeId); curId = window.__collabGetVar('currentNodeId'); if (curId === nodeId && updateDisplay) updateDisplay(nodeId); updateProbeResultsPanel(nodeId); }; window.checkAllNodesStatus = async function() { var nd = getGlobal('NODE_DATA'); var targets = []; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].ping && nd[nid].ping.enabled) { var t = nd[nid].ip || ''; if (!t && nd[nid].ping.protocol === 'custom') t = nd[nid].ping.customUrl; if (t) targets.push({ nodeId: nid, target: t, probes: buildProbeList(nd[nid].ping), timeout: nd[nid].ping.timeout || 3000 }); } }); if (!targets.length) return; var btn = document.getElementById('check-all-ping-btn'); if (btn) { btn.disabled = true; btn.textContent = 'Checking...'; btn.style.opacity = '0.7'; } var checked = 0; try { for (var i = 0; i < targets.length; i += 50) { var batch = targets.slice(i, i + 50); try { var resp = await fetch('/api/probe/batch', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ targets: batch }) }); refreshCsrf(); if (!resp.ok) { checked += batch.length; continue; } var result = await resp.json(); var updateIndicator = window.__collabGetVar('updatePingIndicator'); Object.keys(result.results).forEach(function(nid) { var r = result.results[nid]; if (!nd[nid] || !nd[nid].ping) return; nd[nid].ping.status = r.status; nd[nid].ping.responseTime = r.rtt || null; nd[nid].ping.probeResults = r.results || []; nd[nid].ping.lastCheck = new Date().toISOString(); if (updateIndicator) updateIndicator(nid); }); checked += batch.length; if (btn) btn.textContent = 'Checking ' + Math.min(checked, targets.length) + '/' + targets.length; } catch(e) { checked += batch.length; } } } finally { if (btn) { btn.disabled = false; btn.textContent = 'Check Pings'; btn.style.opacity = ''; } } }; var checkAllBtn = document.getElementById('check-all-ping-btn'); if (checkAllBtn) { var newBtn = checkAllBtn.cloneNode(true); checkAllBtn.parentNode.replaceChild(newBtn, checkAllBtn); newBtn.addEventListener('click', window.checkAllNodesStatus); } } function injectProbeUI() { if (!_rc.probeEnabled) return; var observer = new MutationObserver(function() { var pingSection = document.getElementById('node-ping-options'); if (!pingSection || document.getElementById('verse-probe-type')) return; var protocolRow = document.getElementById('node-ping-protocol'); if (!protocolRow) return; var insertAfter = protocolRow.closest('.style-row') || protocolRow.parentElement; var probeRow = document.createElement('div'); probeRow.className = 'style-row verse-probe-ui'; probeRow.style.marginTop = '8px'; probeRow.innerHTML = '' + ''; insertAfter.parentNode.insertBefore(probeRow, insertAfter.nextSibling); var portsRow = document.createElement('div'); portsRow.className = 'verse-probe-ui'; portsRow.id = 'verse-tcp-ports-row'; portsRow.style.cssText = 'display:none;margin-top:8px'; portsRow.innerHTML = '' + ''; probeRow.parentNode.insertBefore(portsRow, probeRow.nextSibling); var resultsPanel = document.createElement('div'); resultsPanel.className = 'verse-probe-ui'; resultsPanel.id = 'verse-probe-results'; resultsPanel.style.cssText = 'margin-top:8px;padding:8px;background:var(--panel);border-radius:6px;border:1px solid var(--edge-main)'; portsRow.parentNode.insertBefore(resultsPanel, portsRow.nextSibling); var probeSelect = document.getElementById('verse-probe-type'); probeSelect.addEventListener('change', function() { var val = probeSelect.value; document.getElementById('verse-tcp-ports-row').style.display = (val === 'tcp' || val === 'multi') ? 'block' : 'none'; saveProbeConfig(); }); document.getElementById('verse-tcp-ports').addEventListener('change', function() { saveProbeConfig(); }); }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); var origNodePingable = null; document.addEventListener('change', function(e) { if (e.target && e.target.id === 'node-pingable') { setTimeout(loadProbeConfig, 50); } }); var lastSelectedNode = null; setInterval(function() { var curId = window.__collabGetVar('currentNodeId'); if (curId !== lastSelectedNode) { lastSelectedNode = curId; if (curId) setTimeout(function() { loadProbeConfig(); updateProbeResultsPanel(curId); }, 100); } }, 200); } function loadProbeConfig() { var curId = window.__collabGetVar('currentNodeId'); if (!curId) return; var nd = getGlobal('NODE_DATA'); var data = nd[curId]; if (!data || !data.ping) return; var probeSelect = document.getElementById('verse-probe-type'); var portsInput = document.getElementById('verse-tcp-ports'); if (!probeSelect) return; if (data.ping.probeTypes && data.ping.probeTypes.length > 0) { var types = data.ping.probeTypes.map(function(p) { return p.type; }); var hasTcp = types.indexOf('tcp') !== -1; var hasIcmp = types.indexOf('icmp') !== -1; var hasHttp = types.indexOf('http') !== -1; if (hasTcp && hasIcmp && hasHttp) probeSelect.value = 'multi'; else if (hasTcp && !hasHttp) probeSelect.value = 'tcp'; else if (hasIcmp && !hasHttp && !hasTcp) probeSelect.value = 'icmp'; else if (hasHttp && !hasTcp) probeSelect.value = 'http'; else probeSelect.value = 'auto'; if (hasTcp && portsInput) { var ports = data.ping.probeTypes.filter(function(p) { return p.type === 'tcp'; }).map(function(p) { return p.port; }); portsInput.value = ports.join(', '); } } else { probeSelect.value = 'auto'; if (portsInput) portsInput.value = ''; } var portsRow = document.getElementById('verse-tcp-ports-row'); if (portsRow) portsRow.style.display = (probeSelect.value === 'tcp' || probeSelect.value === 'multi') ? 'block' : 'none'; } function saveProbeConfig() { var curId = window.__collabGetVar('currentNodeId'); if (!curId) return; var nd = getGlobal('NODE_DATA'); var data = nd[curId]; if (!data || !data.ping) return; var probeSelect = document.getElementById('verse-probe-type'); var portsInput = document.getElementById('verse-tcp-ports'); if (!probeSelect) return; var val = probeSelect.value; var probes = []; if (val === 'auto') { probes = []; } else if (val === 'icmp') { probes = [{ type: 'icmp' }]; } else if (val === 'tcp') { probes = [{ type: 'icmp' }]; var ports = parsePorts(portsInput ? portsInput.value : ''); ports.forEach(function(p) { probes.push({ type: 'tcp', port: p }); }); } else if (val === 'http') { probes = [{ type: 'http' }]; } else if (val === 'multi') { probes = [{ type: 'icmp' }, { type: 'http' }]; var ports2 = parsePorts(portsInput ? portsInput.value : ''); ports2.forEach(function(p) { probes.push({ type: 'tcp', port: p }); }); probes.push({ type: 'dns' }); } data.ping.probeTypes = probes.length > 0 ? probes : undefined; } function parsePorts(str) { if (!str) return []; return str.split(',').map(function(s) { return parseInt(s.trim(), 10); }).filter(function(p) { return p >= 1 && p <= 65535; }); } var discoveryResults = []; var discoveryTaskId = null; var discoveryScanning = false; var discoveryOverrides = {}; var _renderEditModal = null; var DISC_SHAPES = { basic: ['circle','square','rectangle','triangle','hexagon','diamond','star','stop-sign','octagon','pentagon','cross','rounded-square','pill','parallelogram','trapezoid'], computers: ['server','pc','laptop','phone','printer','pi','sensor'], network: ['router','switch','firewall','access-point','load-balancer','gateway','vpn','nas'], cloud: ['cloud','database','docker','container','vm','kubernetes','api','queue','lambda','bucket'], security: ['shield','camera','monitor'], smarthome: ['thermostat','doorbell','smart-lock','smart-bulb','smart-plug','smart-speaker','smart-tv','hub','smoke-detector','motion-sensor','garage','sprinkler','vacuum'], sports: ['basketball-ball','football-ball','soccer-ball','hockey-puck','baseball-ball','tennis-ball','volleyball','rugby-ball','golf-ball','frisbee','cricket-ball','lacrosse-stick','golf-flag','tactical-x','tactical-o','tactical-star'], rack: ['patch-panel','ups','pdu','rack-shelf','blank-panel','cable-management','kvm'] }; var SHAPE_PREVIEW_SVGS = { 'circle': '', 'square': '', 'rectangle': '', 'triangle': '', 'hexagon': '', 'diamond': '', 'star': '', 'stop-sign': '', 'octagon': '', 'pentagon': '', 'cross': '', 'rounded-square': '', 'pill': '', 'parallelogram': '', 'trapezoid': '', 'server': '', 'pc': '', 'laptop': '', 'phone': '', 'printer': '', 'pi': '', 'sensor': '', 'router': '', 'switch': '', 'firewall': '', 'access-point': '', 'load-balancer': '', 'gateway': '', 'vpn': '', 'nas': '', 'cloud': '', 'database': '', 'docker': '', 'container': '', 'vm': '', 'kubernetes': '', 'api': '', 'queue': '', 'lambda': '', 'bucket': '', 'shield': '', 'camera': '', 'monitor': '', 'thermostat': '', 'doorbell': '', 'smart-lock': '', 'smart-bulb': '', 'smart-plug': '', 'smart-speaker': '', 'smart-tv': '', 'hub': '', 'smoke-detector': '', 'motion-sensor': '', 'garage': '', 'sprinkler': '', 'vacuum': '', 'basketball-ball': '', 'football-ball': '', 'soccer-ball': '', 'hockey-puck': '', 'baseball-ball': '', 'tennis-ball': '', 'volleyball': '', 'rugby-ball': '', 'golf-ball': '', 'frisbee': '', 'cricket-ball': '', 'lacrosse-stick': '', 'golf-flag': '', 'tactical-x': '', 'tactical-o': '', 'tactical-star': '', 'patch-panel': '', 'ups': '', 'pdu': '', 'rack-shelf': '', 'blank-panel': '', 'cable-management': '', 'kvm': '' }; function getLayerName(val) { var sel = document.getElementById('node-layer'); if (sel) { for (var i = 0; i < sel.options.length; i++) { if (sel.options[i].value === val) return sel.options[i].textContent; } } var fallback = { layer1: 'Physical Layer', layer2: 'Logical Layer', layer3: 'Security Layer', layer4: 'Application Layer' }; return fallback[val] || val; } var _iconCache = {}; function fetchDiscoveryIcon(library, name, el, size) { var sz = size || 20; var key = library + '/' + name; if (_iconCache[key] === false) return; var url = ''; if (library === 'selfhst') url = 'https://cdn.jsdelivr.net/gh/selfhst/icons@master/png/' + encodeURIComponent(name) + '.png'; else if (library === 'mdi') url = 'https://cdn.jsdelivr.net/npm/@mdi/svg@latest/svg/' + encodeURIComponent(name) + '.svg'; if (!url) return; if (_iconCache[key]) { el.innerHTML = '' + escapeHtml(name) + ''; return; } _iconCache[key] = url; el.innerHTML = '' + escapeHtml(name) + ''; var img = el.querySelector('img'); if (img) { img.onerror = function() { _iconCache[key] = false; el.innerHTML = ''; }; } } function getShapePreviewSVG(shape) { var svg = SHAPE_PREVIEW_SVGS[shape]; if (svg) return '' + svg + ''; return '' + escapeHtml(shape || 'circle') + ''; } function updateDiscoveryProgress(percent, scanned, total, rangeIndex, totalRanges) { var bar = document.getElementById('verse-discovery-progress-fill'); var text = document.getElementById('verse-discovery-progress-text'); if (bar) bar.style.width = percent + '%'; if (text) { var label = percent + '% (' + scanned + '/' + total + ')'; if (totalRanges > 1) label = 'Range ' + (rangeIndex + 1) + '/' + totalRanges + ' : ' + label; text.textContent = label; } } var _scanRenderInterval = null; function addDiscoveryResult(host) { discoveryResults.push(host); var countEl = document.getElementById('verse-discovery-count'); if (countEl) countEl.textContent = discoveryResults.length + ' hosts found'; if (!_scanRenderInterval) { _scanRenderInterval = setInterval(function() { renderDiscoveryResults(); }, 2000); } } function finalizeDiscovery(totalFound) { discoveryScanning = false; discoveryTaskId = null; if (_scanRenderInterval) { clearInterval(_scanRenderInterval); _scanRenderInterval = null; } var btn = document.getElementById('verse-discovery-start'); var cancelBtn = document.getElementById('verse-discovery-cancel'); if (btn) { btn.textContent = 'Start Scan'; btn.disabled = false; } if (cancelBtn) cancelBtn.style.display = 'none'; var text = document.getElementById('verse-discovery-progress-text'); if (text) text.textContent = 'Complete: ' + totalFound + ' hosts found'; renderDiscoveryResults(); } var activeDeepScans = {}; function handleDeepScanProgress(scanId, ip, percent) { activeDeepScans[ip] = { scanId: scanId, percent: percent }; var cell = document.querySelector('[data-deepscan-ip="' + ip + '"]'); if (cell) { var bar = cell.querySelector('.deepscan-bar-fill'); var text = cell.querySelector('.deepscan-text'); if (bar) bar.style.width = percent + '%'; if (text) text.textContent = percent + '%'; } } function handleDeepScanUpdate(scanId, ip, newPorts, newServices, containers, newIcons) { for (var i = 0; i < discoveryResults.length; i++) { if (discoveryResults[i].ip === ip) { var host = discoveryResults[i]; if (!host.ports) host.ports = []; if (!host.services) host.services = {}; newPorts.forEach(function(p) { if (host.ports.indexOf(p) === -1) host.ports.push(p); }); Object.keys(newServices).forEach(function(portStr) { host.services[parseInt(portStr, 10)] = newServices[portStr]; }); if (containers) host.dockerContainers = containers; if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; var ov = discoveryOverrides[ip]; var existing = ov.tags ? ov.tags.split(',').map(function(t) { return t.trim(); }).filter(function(t) { return t; }) : []; Object.values(newServices).forEach(function(s) { if (s && s.indexOf('Port ') !== 0 && existing.indexOf(s) === -1) existing.push(s); }); if (containers && containers.length > 0) { containers.forEach(function(c) { var label = c.name || ''; if (label && existing.indexOf(label) === -1) existing.push(label); }); } ov.tags = existing.join(', '); ov._tagsSeeded = true; if (newIcons && newIcons.length > 0) { if (!ov.iconTags) ov.iconTags = []; newIcons.forEach(function(icon) { var exists = ov.iconTags.some(function(t) { return t.library === icon.library && t.name === icon.name; }); if (!exists) { ov.iconTags.push({ type: 'icon', library: icon.library, name: icon.name, svg: '' }); } }); } break; } } } function handleDeepScanComplete(scanId, ip) { delete activeDeepScans[ip]; renderDiscoveryResults(); } var DOCKER_TRIGGER_PORTS = [2375, 2376, 9443, 5001]; function buildDeepScanCell(ip) { var active = activeDeepScans[ip]; if (active) { return '
' + '
' + '
' + '
' + '' + (active.percent || 0) + '%' + '' + '
'; } return ''; } var discoveryRanges = []; function getCurrentCIDR() { var sel = document.getElementById('verse-disc-preset'); if (!sel) return ''; if (sel.value === 'custom') { var custom = document.getElementById('verse-disc-custom-cidr'); return custom ? custom.value.trim() : ''; } return sel.value || ''; } function getDiscoveryCIDRs() { if (discoveryRanges.length > 0) return discoveryRanges.slice(); var current = getCurrentCIDR(); return current ? [current] : []; } function renderRangePills() { var container = document.getElementById('verse-disc-ranges'); if (!container) return; container.innerHTML = ''; discoveryRanges.forEach(function(cidr, idx) { var pill = document.createElement('span'); pill.style.cssText = 'display:inline-flex;align-items:center;gap:4px;padding:4px 10px;background:var(--accent);color:var(--bg);border-radius:16px;font-size:12px;font-family:monospace'; pill.textContent = cidr; var x = document.createElement('button'); x.style.cssText = 'background:none;border:none;color:var(--bg);font-size:14px;cursor:pointer;padding:0 2px;line-height:1'; x.textContent = '\u2715'; x.addEventListener('click', function() { discoveryRanges.splice(idx, 1); renderRangePills(); }); pill.appendChild(x); container.appendChild(pill); }); } function updateRackDropdowns() { var nd = getGlobal('NODE_DATA') || {}; var canvasRacks = []; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].isRack) { canvasRacks.push({ value: 'canvas:' + nid, label: (nd[nid].name || nid) + ' (on canvas)', capacity: parseInt(nd[nid].rackCapacity) || 42 }); } }); var newRacks = []; discoveryResults.forEach(function(host) { var ov = discoveryOverrides[host.ip] || {}; if (ov.typeToggle === 'rack') { var rackName = ov.name || host.hostname || host.ip; var cap = parseInt(ov.rackCapacity) || 42; newRacks.push({ value: 'new:' + host.ip, label: rackName + ' (new)', capacity: cap, ip: host.ip }); } }); document.querySelectorAll('.disc-rack-cell').forEach(function(cell) { var ip = cell.getAttribute('data-ip'); var ov = discoveryOverrides[ip] || {}; var isRack = ov.typeToggle === 'rack'; if (isRack) { cell.innerHTML = ''; return; } var savedRef = ov.assignedRackRef || ''; var savedUnit = ov.rackUnit || ''; var savedUHeight = ov.uHeight || '1'; var opts = ''; canvasRacks.forEach(function(r) { opts += ''; }); newRacks.forEach(function(r) { if (r.ip === ip) return; opts += ''; }); var html = ''; if (savedRef) { var capacity = 42; canvasRacks.forEach(function(r) { if (r.value === savedRef) capacity = r.capacity; }); newRacks.forEach(function(r) { if (r.value === savedRef) capacity = r.capacity; }); var unitOpts = ''; for (var u = 1; u <= capacity; u++) { unitOpts += ''; } var uhOpts = ''; for (var h = 1; h <= 4; h++) { uhOpts += ''; } html += '
' + '' + '' + '
'; } cell.innerHTML = html; }); document.querySelectorAll('.disc-rack-select').forEach(function(sel) { sel.addEventListener('change', function() { var ip = sel.getAttribute('data-ip'); if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; if (sel.value) { discoveryOverrides[ip].assignedRackRef = sel.value; } else { delete discoveryOverrides[ip].assignedRackRef; delete discoveryOverrides[ip].rackUnit; } updateRackDropdowns(); }); }); document.querySelectorAll('.disc-rack-unit').forEach(function(sel) { sel.addEventListener('change', function() { var ip = sel.getAttribute('data-ip'); if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; discoveryOverrides[ip].rackUnit = sel.value; }); }); document.querySelectorAll('.disc-rack-uheight').forEach(function(sel) { sel.addEventListener('change', function() { var ip = sel.getAttribute('data-ip'); if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; discoveryOverrides[ip].uHeight = sel.value; }); }); } function renderDiscoveryResults() { var tbody = document.getElementById('verse-discovery-tbody'); if (!tbody) return; var count = document.getElementById('verse-discovery-count'); if (count) count.textContent = discoveryResults.length + ' hosts found'; var searchEl = document.getElementById('verse-disc-table-search'); var savedSearch = searchEl ? searchEl.value : ''; tbody.innerHTML = ''; var nd = getGlobal('NODE_DATA') || {}; var canvasIPs = {}; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].ip) canvasIPs[nd[nid].ip] = nid; }); discoveryResults.forEach(function(host) { var nodeId = canvasIPs[host.ip]; if (!nodeId) return; var node = nd[nodeId]; if (!node) return; if (!discoveryOverrides[host.ip]) discoveryOverrides[host.ip] = {}; var ov = discoveryOverrides[host.ip]; if (ov.name === undefined && node.name) { ov.name = node.name; } if (ov.layer === undefined && node.layer) { ov.layer = node.layer; } if (ov.assignedRackRef === undefined && node.assignedRack && nd[node.assignedRack]) { ov.assignedRackRef = 'canvas:' + node.assignedRack; if (ov.rackUnit === undefined) ov.rackUnit = node.rackUnit || ''; if (ov.uHeight === undefined) ov.uHeight = node.uHeight || '1'; } if (ov.typeToggle === undefined && node.isRack) { ov.typeToggle = 'rack'; } ov._seeded = true; }); discoveryResults.forEach(function(host) { if (!host.icon || host.icon.name === 'linux' || host.icon.name === 'terminal') return; if (!discoveryOverrides[host.ip]) discoveryOverrides[host.ip] = {}; var ov = discoveryOverrides[host.ip]; if (ov.iconData === undefined) { ov.iconData = { library: host.icon.library, name: host.icon.name }; if (!ov._seeded) ov._seeded = true; } }); discoveryResults.forEach(function(host) { if (!host.services) return; if (!discoveryOverrides[host.ip]) discoveryOverrides[host.ip] = {}; var ov = discoveryOverrides[host.ip]; if (ov._tagsSeeded) return; var svcNames = Object.values(host.services).filter(function(s) { return s && s.indexOf('Port ') !== 0; }); if (svcNames.length > 0) { var existing = ov.tags ? ov.tags.split(',').map(function(t) { return t.trim(); }).filter(function(t) { return t; }) : []; svcNames.forEach(function(s) { if (existing.indexOf(s) === -1) existing.push(s); }); ov.tags = existing.join(', '); ov._tagsSeeded = true; if (!ov._seeded) ov._seeded = true; } }); discoveryResults.forEach(function(host) { if (!host.serviceIcons || host.serviceIcons.length === 0) return; if (!discoveryOverrides[host.ip]) discoveryOverrides[host.ip] = {}; var ov = discoveryOverrides[host.ip]; if (ov._iconTagsSeeded) return; if (!ov.iconTags) ov.iconTags = []; host.serviceIcons.forEach(function(icon) { if (ov.iconData && ov.iconData.library === icon.library && ov.iconData.name === icon.name) return; var exists = ov.iconTags.some(function(t) { return t.library === icon.library && t.name === icon.name; }); if (!exists) { ov.iconTags.push({ type: 'icon', library: icon.library, name: icon.name, svg: '' }); } }); ov._iconTagsSeeded = true; if (!ov._seeded) ov._seeded = true; }); var editBtn = document.getElementById('verse-disc-edit-btn'); if (editBtn) editBtn.style.display = discoveryResults.length > 0 ? 'inline' : 'none'; var sortedResults = discoveryResults.slice().sort(function(a, b) { var aOnCanvas = canvasIPs[a.ip] ? 1 : 0; var bOnCanvas = canvasIPs[b.ip] ? 1 : 0; return aOnCanvas - bOnCanvas; }); sortedResults.forEach(function(host) { var idx = discoveryResults.indexOf(host); var svcValues = Object.values(host.services || {}); var serviceTags = svcValues.map(function(s) { var isGeneric = s.indexOf('Port ') === 0; var bg = isGeneric ? 'var(--panel)' : 'var(--panel-alt)'; var border = isGeneric ? 'var(--edge-main)' : 'var(--accent)'; var color = isGeneric ? 'var(--text-soft)' : 'var(--accent)'; return '' + escapeHtml(s) + ''; }).join(''); if (host.dockerContainers && host.dockerContainers.length > 0) { host.dockerContainers.forEach(function(c) { var name = c.name || ''; if (!name) return; serviceTags += '' + escapeHtml(name) + ''; }); } var hostname = host.hostname || ''; var nameDetails = []; if (host.dnsName) nameDetails.push('DNS: ' + host.dnsName); if (host.netbiosName) nameDetails.push('NetBIOS: ' + host.netbiosName); if (host.mdnsName) nameDetails.push('mDNS: ' + host.mdnsName); if (host.httpServer) nameDetails.push('HTTP: ' + host.httpServer); if (host.snmpName) nameDetails.push('SNMP: ' + host.snmpName); if (host.snmpDescr) nameDetails.push('Descr: ' + host.snmpDescr); var detailTitle = nameDetails.length > 0 ? nameDetails.join('\n') : ''; var onCanvas = canvasIPs[host.ip]; var hasOverride = discoveryOverrides[host.ip]; var ov = hasOverride || {}; var displayName = ov.name || hostname; var userEdited = hasOverride && !ov._seeded; var overrideIndicator = userEdited ? ' ' : ''; var canvasBadge = onCanvas ? '
on canvas' : ''; var isRackOverride = ov.typeToggle === 'rack'; var isNodeOverride = !ov.typeToggle || ov.typeToggle === 'node'; var nodeActive = isNodeOverride ? 'active' : ''; var rackActive = isRackOverride ? 'active' : ''; var nodeBg = isNodeOverride ? 'var(--accent)' : 'var(--panel)'; var nodeColor = isNodeOverride ? 'var(--bg)' : 'var(--text-soft)'; var rackBg = isRackOverride ? 'var(--accent)' : 'var(--panel)'; var rackColor = isRackOverride ? 'var(--bg)' : 'var(--text-soft)'; var hasDocker = host.ports && DOCKER_TRIGGER_PORTS.some(function(p) { return host.ports.indexOf(p) !== -1; }); var deepScanHtml = hasDocker ? ' ' + buildDeepScanCell(host.ip) : ''; var tr = document.createElement('tr'); tr.style.borderBottom = '1px solid var(--edge-main)'; if (onCanvas) tr.style.opacity = '0.5'; tr.setAttribute('data-ip', host.ip); tr.innerHTML = '' + '' + escapeHtml(host.ip) + canvasBadge + '' + '' + escapeHtml(displayName) + overrideIndicator + ' ' + deepScanHtml + '' + '
' + serviceTags + '
' + '' + '' + '
' + '' + '' + '
' + '' + '' + '' + '' + ''; tbody.appendChild(tr); }); updateRackDropdowns(); document.querySelectorAll('.disc-icon-cell').forEach(function(el) { var ip = el.getAttribute('data-icon-ip'); var ov = discoveryOverrides[ip] || {}; if (ov.iconData && ov.iconData.name) { if (ov.iconData.svg) { el.innerHTML = ov.iconData.svg; var svgEl = el.querySelector('svg'); if (svgEl) { svgEl.style.width = '20px'; svgEl.style.height = '20px'; } } else { fetchDiscoveryIcon(ov.iconData.library, ov.iconData.name, el); } } }); document.querySelectorAll('.disc-layer-select').forEach(function(sel) { sel.addEventListener('change', function() { var ip = sel.getAttribute('data-ip'); if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; discoveryOverrides[ip].layer = sel.value; }); }); document.querySelectorAll('.verse-type-toggle').forEach(function(toggle) { toggle.addEventListener('click', function(e) { var btn = e.target.closest('.verse-type-btn'); if (!btn) return; var ip = toggle.getAttribute('data-ip'); toggle.querySelectorAll('.verse-type-btn').forEach(function(b) { if (b === btn) { b.classList.add('active'); b.style.background = 'var(--accent)'; b.style.color = 'var(--bg)'; } else { b.classList.remove('active'); b.style.background = 'var(--panel)'; b.style.color = 'var(--text-soft)'; } }); if (ip) { if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; var prevType = discoveryOverrides[ip].typeToggle || 'node'; discoveryOverrides[ip].typeToggle = btn.dataset.type; if (btn.dataset.type === 'rack') { delete discoveryOverrides[ip].assignedRackRef; delete discoveryOverrides[ip].rackUnit; } if (prevType === 'rack' && btn.dataset.type === 'node') { Object.keys(discoveryOverrides).forEach(function(otherIp) { if (discoveryOverrides[otherIp].assignedRackRef === 'new:' + ip) { delete discoveryOverrides[otherIp].assignedRackRef; delete discoveryOverrides[otherIp].rackUnit; } }); } updateRackDropdowns(); } }); }); document.querySelectorAll('.disc-row-edit-btn').forEach(function(btn) { btn.addEventListener('click', function(e) { e.stopPropagation(); var ip = btn.getAttribute('data-ip'); var editModalEl = document.getElementById('verse-disc-edit-modal'); if (editModalEl && _renderEditModal) { _renderEditModal(ip); editModalEl.classList.add('active'); } }); }); document.querySelectorAll('.deepscan-start-btn').forEach(function(btn) { btn.addEventListener('click', function(e) { e.stopPropagation(); var ip = btn.getAttribute('data-ip'); var host = null; for (var i = 0; i < discoveryResults.length; i++) { if (discoveryResults[i].ip === ip) { host = discoveryResults[i]; break; } } if (!host) return; btn.disabled = true; btn.textContent = 'Starting...'; fetch('/api/discover/deepscan', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ roomId: ROOM_ID, ip: ip, existingPorts: host.ports || [] }) }).then(function(resp) { refreshCsrf(); return resp.json().then(function(result) { if (!resp.ok) { btn.textContent = 'Deep Scan'; btn.disabled = false; return; } activeDeepScans[ip] = { scanId: result.scanId, percent: 0 }; renderDiscoveryResults(); }); }).catch(function() { btn.textContent = 'Deep Scan'; btn.disabled = false; }); }); }); document.querySelectorAll('.deepscan-cancel-btn').forEach(function(btn) { btn.addEventListener('click', function(e) { e.stopPropagation(); var ip = btn.getAttribute('data-ip'); var active = activeDeepScans[ip]; if (!active) return; fetch('/api/discover/deepscan/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ scanId: active.scanId }) }).then(function() { refreshCsrf(); }).catch(function() { refreshCsrf(); }); delete activeDeepScans[ip]; renderDiscoveryResults(); }); }); var tableSearch = document.getElementById('verse-disc-table-search'); if (tableSearch) { var filterRows = function() { var q = tableSearch.value.toLowerCase().trim(); var rows = document.querySelectorAll('#verse-discovery-tbody tr'); rows.forEach(function(row) { var ip = (row.getAttribute('data-ip') || '').toLowerCase(); var text = row.textContent.toLowerCase(); row.style.display = (!q || ip.indexOf(q) !== -1 || text.indexOf(q) !== -1) ? '' : 'none'; }); }; tableSearch.addEventListener('input', filterRows); if (savedSearch) { tableSearch.value = savedSearch; filterRows(); } } } function escapeHtml(str) { if (!str) return ''; return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function injectDiscoveryUI() { if (!_rc.discoveryAllowed) return; var waitForPing = setInterval(function() { var autoPingSection = document.getElementById('auto-ping-settings'); var checkAllBtn = document.getElementById('check-all-ping-btn'); var target = autoPingSection || checkAllBtn; if (!target) return; clearInterval(waitForPing); var btn = document.createElement('button'); btn.id = 'verse-discover-btn'; btn.style.cssText = 'display:block;width:100%;padding:10px;margin-top:12px;background:var(--accent);color:var(--bg);border:none;border-radius:6px;cursor:pointer;font-size:14px;font-weight:600'; btn.textContent = 'Discover Network Hosts'; btn.addEventListener('click', function() { var modal = document.getElementById('verse-discovery-modal'); if (modal) modal.classList.add('active'); var portRef = document.getElementById('verse-disc-port-ref-body'); if (portRef && !portRef.dataset.loaded) { fetch('/api/discover/ports').then(function(r) { return r.json(); }).then(function(data) { if (!data.ports) return; portRef.dataset.loaded = '1'; var summary = portRef.parentElement.querySelector('summary'); if (summary) summary.textContent = 'Default Scan Ports (' + data.ports.length + ')'; var html = '
'; data.ports.forEach(function(p) { var iconHtml = p.icon ? '' : ''; html += '' + iconHtml + '' + p.port + ' ' + escapeHtml(p.service) + ''; }); html += '
'; portRef.innerHTML = html; portRef.querySelectorAll('.disc-port-ref-icon').forEach(function(el) { fetchDiscoveryIcon('selfhst', el.dataset.iconName, el, 14); }); }).catch(function() {}); } }); var details = target.closest('details') || target.parentNode; details.parentNode.insertBefore(btn, details.nextSibling); }, 200); var modal = document.createElement('div'); modal.id = 'verse-discovery-modal'; modal.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.7);z-index:10000001;justify-content:center;align-items:center'; modal.innerHTML = '
' + '
' + '

Network Discovery

' + '' + '
' + '
' + '
' + '' + '
' + '' + '' + '
' + '
' + '' + '
' + '
' + '
ICMP
' + '
TCP Ports
' + '
DNS
' + '
NetBIOS
' + '
mDNS
' + '
SNMP
' + '
' + '
' + '
' + '' + '' + '
' + '' + '
' + '
' + 'Default Scan Ports (loading...)' + '
' + '
' + '
' + '
' + '' + '' + '
' + '
' + '
' + 'Ready' + '' + '
' + '
' + '
' + '
' + '
' + '' + '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
IPHostname ServicesIconTypeRackLayer
' + '
' + '
' + '
' + '' + '
' + '
'; document.body.appendChild(modal); var editModal = document.createElement('div'); editModal.id = 'verse-disc-edit-modal'; editModal.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.75);z-index:10000002;justify-content:center;align-items:center'; editModal.innerHTML = '
' + '
' + '

Edit Host Details

' + '' + '' + '
' + '
' + '
' + '' + '
' + '
'; document.body.appendChild(editModal); _renderEditModal = renderEditModal; function buildShapeOptions(category, selectedShape) { var shapes = DISC_SHAPES[category] || DISC_SHAPES.basic; return shapes.map(function(s) { return ''; }).join(''); } function buildCategoryOptions(selected) { var cats = Object.keys(DISC_SHAPES); return cats.map(function(c) { return ''; }).join(''); } function renderIconTagBadges(container, ip) { container.innerHTML = ''; var tags = (discoveryOverrides[ip] && discoveryOverrides[ip].iconTags) || []; tags.forEach(function(tag, ti) { var badge = document.createElement('span'); badge.style.cssText = 'display:inline-flex;align-items:center;gap:4px;padding:2px 8px;background:var(--panel);border:1px solid var(--edge-main);border-radius:12px;font-size:11px;color:var(--text-main)'; var svgSpan = ''; if (tag.svg) svgSpan = '' + tag.svg + ''; badge.innerHTML = svgSpan + '' + escapeHtml(tag.name) + ''; var removeBtn = document.createElement('button'); removeBtn.style.cssText = 'background:none;border:none;color:var(--danger);cursor:pointer;font-size:12px;padding:0 2px;line-height:1'; removeBtn.textContent = '\u2715'; removeBtn.addEventListener('click', function() { if (discoveryOverrides[ip] && discoveryOverrides[ip].iconTags) { discoveryOverrides[ip].iconTags.splice(ti, 1); renderIconTagBadges(container, ip); } }); badge.appendChild(removeBtn); container.appendChild(badge); }); } function renderEditModal(scrollToIp) { var body = document.getElementById('verse-disc-edit-body'); if (!body) return; body.innerHTML = ''; var searchInput = document.getElementById('verse-disc-edit-search'); if (searchInput) searchInput.value = ''; var nd = getGlobal('NODE_DATA') || {}; var canvasIPs = {}; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].ip) canvasIPs[nd[nid].ip] = true; }); var hasCards = false; discoveryResults.forEach(function(host, idx) { if (!host) return; hasCards = true; var ov = discoveryOverrides[host.ip] || {}; var displayName = ov.name || host.hostname || host.ip; var ipVal = ov.ip || host.ip; var tagsVal = ov.tags || ''; var cat = ov.category || 'network'; var shp = ov.shape || 'circle'; var pingEnabled = ov.pingEnabled !== undefined ? ov.pingEnabled : true; var probeType = ov.probeType || 'auto'; var tcpPorts = ov.tcpPorts || (host.ports && host.ports.length > 0 ? host.ports.join(', ') : '22, 80, 443'); var pingTimeout = ov.pingTimeout || 3000; var rackCap = ov.rackCapacity || '42'; var iconPreview = ''; if (ov.iconData && ov.iconData.svg) { iconPreview = '' + ov.iconData.svg + '' + '' + escapeHtml(ov.iconData.library + '/' + ov.iconData.name) + ''; } else if (ov.iconData && ov.iconData.name) { iconPreview = '' + '' + escapeHtml(ov.iconData.library + '/' + ov.iconData.name) + ''; } var toggle = document.querySelector('.verse-type-toggle[data-ip="' + host.ip + '"]'); var activeBtn = toggle ? toggle.querySelector('.verse-type-btn.active') : null; var isRack = (ov.typeToggle === 'rack') || (activeBtn && activeBtn.dataset.type === 'rack'); var rackDisplay = isRack ? 'flex' : 'none'; var tcpDisplay = (probeType === 'tcp' || probeType === 'multi') ? 'block' : 'none'; var onCanvas = canvasIPs[host.ip]; var canvasTag = onCanvas ? ' on canvas' : ''; var card = document.createElement('div'); card.style.cssText = 'margin-bottom:16px;padding:14px;border:1px solid var(--edge-main);border-radius:8px;background:var(--panel-alt);transition:border-color 0.3s' + (onCanvas ? ';opacity:0.6' : ''); card.setAttribute('data-edit-ip', host.ip); card.innerHTML = '
' + escapeHtml(host.ip) + canvasTag + '
' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '
' + '
' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + (ov.iconData && ov.iconData.svg ? '' + ov.iconData.svg + '' : getShapePreviewSVG(shp || 'circle')) + '
' + '
' + '
' + '' + '' + iconPreview + '' + '
' + '
' + '' + '' + '
' + '
' + '
' + 'Probe Enabled' + '' + '
' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '
' + '' + '' + '
' + '
' + '
' + '
Appearance
' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '
' + '
' + '' + '' + '' + (ov.nodeSize || 50) + '' + '
' + '
' + '
' + '
' + '
Connections
' + '
' + '' + '' + '' + '' + '
' + '
' + '
' + '
' + '' + '' + '
' + '
'; body.appendChild(card); var iconTagsList = card.querySelector('.disc-edit-icon-tags-list'); if (iconTagsList) renderIconTagBadges(iconTagsList, host.ip); }); if (!hasCards) { body.innerHTML = '
No editable hosts selected. Select hosts in the discovery table first, or all selected hosts are already on canvas.
'; } body.querySelectorAll('.disc-edit-category').forEach(function(sel) { sel.addEventListener('change', function() { var card = sel.closest('[data-edit-ip]'); var ip = card.getAttribute('data-edit-ip'); var shapeSel = card.querySelector('.disc-edit-shape'); shapeSel.innerHTML = buildShapeOptions(sel.value, ''); var preview = card.querySelector('.disc-edit-shape-preview'); if (preview) preview.innerHTML = getShapePreviewSVG(shapeSel.value); if (discoveryOverrides[ip]) delete discoveryOverrides[ip].iconData; var iconPreviewEl = card.querySelector('.disc-edit-icon-preview'); if (iconPreviewEl) iconPreviewEl.innerHTML = ''; saveCardOverride(card, ip); }); }); body.querySelectorAll('.disc-edit-shape').forEach(function(sel) { sel.addEventListener('change', function() { var card = sel.closest('[data-edit-ip]'); var ip = card.getAttribute('data-edit-ip'); var preview = card.querySelector('.disc-edit-shape-preview'); if (preview) preview.innerHTML = getShapePreviewSVG(sel.value); if (discoveryOverrides[ip]) delete discoveryOverrides[ip].iconData; var iconPreviewEl = card.querySelector('.disc-edit-icon-preview'); if (iconPreviewEl) iconPreviewEl.innerHTML = ''; saveCardOverride(card, ip); }); }); body.querySelectorAll('.disc-edit-probe-type').forEach(function(sel) { sel.addEventListener('change', function() { var card = sel.closest('[data-edit-ip]'); var tcpRow = card.querySelector('.disc-edit-tcp-row'); if (tcpRow) tcpRow.style.display = (sel.value === 'tcp' || sel.value === 'multi') ? 'block' : 'none'; var ip = card.getAttribute('data-edit-ip'); saveCardOverride(card, ip); }); }); body.querySelectorAll('.disc-edit-icon-btn').forEach(function(btn) { btn.addEventListener('click', function() { var card = btn.closest('[data-edit-ip]'); var ip = card.getAttribute('data-edit-ip'); if (typeof window.openIconPicker === 'function') { window.openIconPicker(function(iconData) { if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; discoveryOverrides[ip].iconData = iconData; var preview = card.querySelector('.disc-edit-icon-preview'); if (preview && iconData && iconData.name) { if (iconData.svg) { preview.innerHTML = '' + iconData.svg + '' + '' + escapeHtml(iconData.library + '/' + iconData.name) + ''; } else { var fetchSpan = document.createElement('span'); fetchSpan.style.cssText = 'width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center'; preview.innerHTML = ''; preview.appendChild(fetchSpan); fetchDiscoveryIcon(iconData.library, iconData.name, fetchSpan, 24); var label = document.createElement('span'); label.style.cssText = 'font-size:11px;color:var(--accent)'; label.textContent = iconData.library + '/' + iconData.name; preview.appendChild(label); } } var shapePreview = card.querySelector('.disc-edit-shape-preview'); if (shapePreview && iconData && iconData.name) { if (iconData.svg) { shapePreview.innerHTML = '' + iconData.svg + ''; } else { fetchDiscoveryIcon(iconData.library, iconData.name, shapePreview, 36); } } }); } }); }); body.querySelectorAll('.disc-edit-icon-tag-btn').forEach(function(btn) { btn.addEventListener('click', function() { var card = btn.closest('[data-edit-ip]'); var ip = card.getAttribute('data-edit-ip'); if (typeof window.openIconPicker === 'function') { window.openIconPicker(function(iconData) { if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; if (!discoveryOverrides[ip].iconTags) discoveryOverrides[ip].iconTags = []; discoveryOverrides[ip].iconTags.push({ type: 'icon', library: iconData.library, name: iconData.name, svg: iconData.svg || '' }); var list = card.querySelector('.disc-edit-icon-tags-list'); if (list) renderIconTagBadges(list, ip); }); } }); }); body.querySelectorAll('.disc-edit-shape-preview[data-fetch-name]').forEach(function(el) { fetchDiscoveryIcon(el.getAttribute('data-fetch-lib'), el.getAttribute('data-fetch-name'), el, 36); }); body.querySelectorAll('.disc-edit-icon-fetch').forEach(function(el) { fetchDiscoveryIcon(el.getAttribute('data-lib'), el.getAttribute('data-name'), el, 24); }); body.querySelectorAll('.disc-edit-connect-to').forEach(function(sel) { var card = sel.closest('[data-edit-ip]'); var cardIp = card.getAttribute('data-edit-ip'); discoveryResults.forEach(function(h) { if (!h || h.ip === cardIp) return; var hov = discoveryOverrides[h.ip] || {}; var opt = document.createElement('option'); opt.value = h.ip; opt.textContent = (hov.name || h.hostname || h.ip) + ' (' + h.ip + ')'; sel.appendChild(opt); }); var nd = getGlobal('NODE_DATA') || {}; Object.entries(nd).forEach(function(entry) { var opt = document.createElement('option'); opt.value = 'canvas:' + entry[0]; opt.textContent = entry[1].name + ' (canvas)'; sel.appendChild(opt); }); }); body.querySelectorAll('.disc-edit-size').forEach(function(slider) { slider.addEventListener('input', function() { var card = slider.closest('[data-edit-ip]'); var valEl = card.querySelector('.disc-edit-size-value'); if (valEl) valEl.textContent = slider.value; var ip = card.getAttribute('data-edit-ip'); saveCardOverride(card, ip); }); }); body.querySelectorAll('.disc-edit-add-conn-btn').forEach(function(btn) { btn.addEventListener('click', function() { var card = btn.closest('[data-edit-ip]'); var ip = card.getAttribute('data-edit-ip'); var targetSel = card.querySelector('.disc-edit-connect-to'); var fromPort = card.querySelector('.disc-edit-from-port'); var toPort = card.querySelector('.disc-edit-to-port'); if (!targetSel.value) return; if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; if (!discoveryOverrides[ip].connections) discoveryOverrides[ip].connections = []; discoveryOverrides[ip].connections.push({ target: targetSel.value, fromPort: fromPort.value.trim(), toPort: toPort.value.trim() }); fromPort.value = ''; toPort.value = ''; targetSel.value = ''; renderConnList(card, ip); }); }); function renderConnList(card, ip) { var list = card.querySelector('.disc-edit-conn-list'); if (!list) return; list.innerHTML = ''; var conns = (discoveryOverrides[ip] && discoveryOverrides[ip].connections) || []; conns.forEach(function(conn, ci) { var targetLabel = conn.target; if (conn.target.indexOf('canvas:') === 0) { var nid = conn.target.replace('canvas:', ''); var nd = getGlobal('NODE_DATA') || {}; if (nd[nid]) targetLabel = nd[nid].name + ' (canvas)'; } else { var hov = discoveryOverrides[conn.target] || {}; var hst = discoveryResults.find(function(h) { return h && h.ip === conn.target; }); targetLabel = (hov.name || (hst && hst.hostname) || conn.target) + ' (' + conn.target + ')'; } var row = document.createElement('div'); row.style.cssText = 'display:flex;align-items:center;gap:6px;padding:4px 8px;background:var(--panel);border:1px solid var(--edge-main);border-radius:4px;font-size:11px;color:var(--text-main)'; row.innerHTML = '' + escapeHtml(ip) + (conn.fromPort ? ':' + escapeHtml(conn.fromPort) : '') + ' \u2192 ' + escapeHtml(targetLabel) + (conn.toPort ? ':' + escapeHtml(conn.toPort) : '') + ''; var removeBtn = document.createElement('button'); removeBtn.style.cssText = 'background:none;border:none;color:var(--danger);cursor:pointer;font-size:12px;padding:0 4px'; removeBtn.textContent = '\u2715'; removeBtn.addEventListener('click', function() { discoveryOverrides[ip].connections.splice(ci, 1); renderConnList(card, ip); }); row.appendChild(removeBtn); list.appendChild(row); }); } body.querySelectorAll('[data-edit-ip]').forEach(function(card) { var ip = card.getAttribute('data-edit-ip'); renderConnList(card, ip); }); body.querySelectorAll('input, select, textarea').forEach(function(el) { el.addEventListener('change', function() { var card = el.closest('[data-edit-ip]'); if (!card) return; var ip = card.getAttribute('data-edit-ip'); saveCardOverride(card, ip); }); }); if (scrollToIp) { var target = body.querySelector('[data-edit-ip="' + scrollToIp + '"]'); if (target) { setTimeout(function() { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); target.style.borderColor = 'var(--accent)'; setTimeout(function() { target.style.borderColor = ''; }, 2000); }, 100); } } } function saveCardOverride(card, ip) { if (!discoveryOverrides[ip]) discoveryOverrides[ip] = {}; var ov = discoveryOverrides[ip]; var nameEl = card.querySelector('.disc-edit-name'); var ipEl = card.querySelector('.disc-edit-ip'); var tagsEl = card.querySelector('.disc-edit-tags'); var catEl = card.querySelector('.disc-edit-category'); var shapeEl = card.querySelector('.disc-edit-shape'); var rackCapEl = card.querySelector('.disc-edit-rack-cap'); var pingEnabledEl = card.querySelector('.disc-edit-ping-enabled'); var probeTypeEl = card.querySelector('.disc-edit-probe-type'); var tcpPortsEl = card.querySelector('.disc-edit-tcp-ports'); var pingTimeoutEl = card.querySelector('.disc-edit-ping-timeout'); var fillColorEl = card.querySelector('.disc-edit-fill-color'); var borderColorEl = card.querySelector('.disc-edit-border-color'); var sizeEl = card.querySelector('.disc-edit-size'); var notesEl = card.querySelector('.disc-edit-notes'); delete ov._seeded; if (nameEl) ov.name = nameEl.value; if (ipEl) ov.ip = ipEl.value; if (tagsEl) ov.tags = tagsEl.value; if (catEl) ov.category = catEl.value; if (shapeEl) ov.shape = shapeEl.value; if (rackCapEl) ov.rackCapacity = rackCapEl.value; if (pingEnabledEl) ov.pingEnabled = pingEnabledEl.checked; if (probeTypeEl) ov.probeType = probeTypeEl.value; if (tcpPortsEl) ov.tcpPorts = tcpPortsEl.value; if (pingTimeoutEl) ov.pingTimeout = parseInt(pingTimeoutEl.value, 10) || 3000; if (fillColorEl) ov.fillColor = fillColorEl.value; if (borderColorEl) ov.borderColor = borderColorEl.value; if (sizeEl) ov.nodeSize = parseInt(sizeEl.value, 10); if (notesEl) ov.notes = notesEl.value; } modal.addEventListener('click', function(e) { if (e.target === modal) modal.classList.remove('active'); }); document.getElementById('verse-discovery-close').addEventListener('click', function() { modal.classList.remove('active'); }); editModal.addEventListener('click', function(e) { if (e.target === editModal) { editModal.classList.remove('active'); renderDiscoveryResults(); } }); document.getElementById('verse-disc-edit-close').addEventListener('click', function() { editModal.classList.remove('active'); renderDiscoveryResults(); }); document.getElementById('verse-disc-edit-done').addEventListener('click', function() { editModal.classList.remove('active'); renderDiscoveryResults(); }); document.getElementById('verse-disc-edit-btn').addEventListener('click', function() { renderEditModal(); editModal.classList.add('active'); }); document.getElementById('verse-disc-edit-search').addEventListener('input', function() { var q = this.value.toLowerCase().trim(); var body = document.getElementById('verse-disc-edit-body'); if (!body) return; var cards = body.querySelectorAll('[data-edit-ip]'); var visibleCount = 0; var lastVisible = null; cards.forEach(function(card) { var ip = card.getAttribute('data-edit-ip').toLowerCase(); var nameInput = card.querySelector('.disc-edit-name'); var name = nameInput ? nameInput.value.toLowerCase() : ''; if (!q || ip.indexOf(q) !== -1 || name.indexOf(q) !== -1) { card.style.display = ''; visibleCount++; lastVisible = card; } else { card.style.display = 'none'; } }); if (visibleCount === 1 && lastVisible) { lastVisible.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); document.getElementById('verse-disc-preset').addEventListener('change', function() { document.getElementById('verse-disc-custom-row').style.display = this.value === 'custom' ? 'block' : 'none'; }); document.getElementById('verse-disc-snmp').addEventListener('change', function() { document.getElementById('verse-disc-snmp-row').style.display = this.checked ? 'block' : 'none'; }); document.getElementById('verse-disc-add-range').addEventListener('click', function() { var cidr = getCurrentCIDR(); if (cidr && discoveryRanges.indexOf(cidr) === -1) { discoveryRanges.push(cidr); renderRangePills(); } }); document.getElementById('verse-discovery-select-all').addEventListener('change', function(e) { var checks = document.querySelectorAll('.verse-discovery-check'); checks.forEach(function(cb) { cb.checked = e.target.checked; }); }); document.getElementById('verse-discovery-start').addEventListener('click', async function() { var cidrs = discoveryRanges.length > 0 ? discoveryRanges.slice() : getDiscoveryCIDRs(); if (cidrs.length === 0) return; if (discoveryTaskId) { try { await fetch('/api/discover/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ taskId: discoveryTaskId }) }); refreshCsrf(); } catch(e) {} discoveryTaskId = null; } discoveryResults = []; discoveryScanning = true; renderDiscoveryResults(); updateDiscoveryProgress(0, 0, 0); var btn = document.getElementById('verse-discovery-start'); var cancelBtn = document.getElementById('verse-discovery-cancel'); btn.textContent = 'Scanning...'; btn.disabled = true; cancelBtn.style.display = 'inline-block'; var ports = parsePorts(document.getElementById('verse-disc-ports').value); try { var resp = await fetch('/api/discover', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ cidrs: cidrs, roomId: ROOM_ID, options: { icmp: document.getElementById('verse-disc-icmp').checked, tcp: document.getElementById('verse-disc-tcp').checked, dns: document.getElementById('verse-disc-dns').checked, netbios: document.getElementById('verse-disc-netbios').checked, mdns: document.getElementById('verse-disc-mdns').checked, snmp: document.getElementById('verse-disc-snmp').checked, snmpCommunity: document.getElementById('verse-disc-snmp-community').value || 'public', ports: ports } }) }); refreshCsrf(); var result = await resp.json(); if (!resp.ok) { btn.textContent = 'Start Scan'; btn.disabled = false; cancelBtn.style.display = 'none'; discoveryScanning = false; var progressText = document.getElementById('verse-discovery-progress-text'); if (progressText) progressText.textContent = 'Error: ' + (result.error || 'Scan failed'); return; } discoveryTaskId = result.taskId; } catch(e) { btn.textContent = 'Start Scan'; btn.disabled = false; cancelBtn.style.display = 'none'; discoveryScanning = false; } }); document.getElementById('verse-discovery-cancel').addEventListener('click', async function() { if (!discoveryTaskId) return; try { await fetch('/api/discover/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.CSRF_TOKEN }, body: JSON.stringify({ taskId: discoveryTaskId }) }); refreshCsrf(); } catch(e) {} finalizeDiscovery(discoveryResults.length); }); document.getElementById('verse-discovery-add').addEventListener('click', function() { var checks = document.querySelectorAll('.verse-discovery-check:checked'); if (checks.length === 0) return; var nd = getGlobal('NODE_DATA'); var positions = getGlobal('savedPositions'); var sizes = getGlobal('savedSizes'); var styles = getGlobal('savedStyles'); var pushUndo = window.__collabGetVar('pushUndo'); if (pushUndo) pushUndo('add discovered nodes'); var existingIPs = {}; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].ip) existingIPs[nd[nid].ip] = true; }); var cols = Math.ceil(Math.sqrt(checks.length)); var spacing = 120; var cs = getGlobal('canvasState') || { panX: 0, panY: 0, zoom: 1 }; var startX = (-cs.panX / cs.zoom) + 200; var startY = (-cs.panY / cs.zoom) + 200; var added = 0; var entries = []; checks.forEach(function(cb) { var idx = parseInt(cb.dataset.idx, 10); var host = discoveryResults[idx]; if (!host || existingIPs[host.ip]) return; var ov = discoveryOverrides[host.ip] || {}; var toggle = document.querySelector('.verse-type-toggle[data-idx="' + idx + '"]'); var activeBtn = toggle ? toggle.querySelector('.verse-type-btn.active') : null; var isRack = (ov.typeToggle === 'rack') || (activeBtn && activeBtn.dataset.type === 'rack'); entries.push({ host: host, ov: ov, isRack: isRack, idx: idx }); }); entries.sort(function(a, b) { return (b.isRack ? 1 : 0) - (a.isRack ? 1 : 0); }); var newRackIpToNodeId = {}; entries.forEach(function(entry) { var host = entry.host; var ov = entry.ov; var isRack = entry.isRack; var nodeName = ov.name || host.hostname || host.ip; var nodeIp = ov.ip || host.ip; var nodeShape = ov.shape || (isRack ? 'server' : 'circle'); var nodeTags = []; if (ov.tags) { nodeTags = ov.tags.split(',').map(function(t) { return t.trim(); }).filter(function(t) { return t; }); } if (ov.iconTags && ov.iconTags.length > 0) { ov.iconTags.forEach(function(it) { nodeTags.push({ type: 'icon', library: it.library, name: it.name }); }); } var pingEnabled = ov.pingEnabled !== undefined ? ov.pingEnabled : true; var pingTimeout = ov.pingTimeout || 3000; var probeType = ov.probeType || 'auto'; var tcpPortsStr = ov.tcpPorts || (host.ports && host.ports.length > 0 ? host.ports.join(', ') : ''); var tcpPortsList = tcpPortsStr ? tcpPortsStr.split(',').map(function(s) { return parseInt(s.trim(), 10); }).filter(function(p) { return p >= 1 && p <= 65535; }) : []; var probeTypes; if (probeType === 'icmp') { probeTypes = [{ type: 'icmp' }]; } else if (probeType === 'tcp') { probeTypes = [{ type: 'icmp' }]; tcpPortsList.forEach(function(p) { probeTypes.push({ type: 'tcp', port: p }); }); } else if (probeType === 'http') { probeTypes = [{ type: 'http' }]; } else if (probeType === 'multi') { probeTypes = [{ type: 'icmp' }, { type: 'http' }]; tcpPortsList.forEach(function(p) { probeTypes.push({ type: 'tcp', port: p }); }); probeTypes.push({ type: 'dns' }); } else { probeTypes = [{ type: 'icmp' }, { type: 'http' }]; } var nodeId = generateUUID(); var col = added % cols; var row = Math.floor(added / cols); var resolvedRack = ''; var resolvedUnit = ''; var resolvedUHeight = '1'; if (!isRack && ov.assignedRackRef) { var parts = ov.assignedRackRef.split(':'); var refType = parts[0]; var refId = parts.slice(1).join(':'); if (refType === 'canvas' && nd[refId]) { resolvedRack = refId; } else if (refType === 'new' && newRackIpToNodeId[refId]) { resolvedRack = newRackIpToNodeId[refId]; } if (resolvedRack) { resolvedUnit = ov.rackUnit || ''; resolvedUHeight = ov.uHeight || '1'; } } var nodeNotes = []; if (ov.notes && ov.notes.trim()) nodeNotes.push(ov.notes.trim()); nd[nodeId] = { shape: nodeShape, name: nodeName, ip: nodeIp, role: isRack ? 'Rack' : '', tags: nodeTags, notes: nodeNotes, mac: '', rackUnit: resolvedUnit, uHeight: resolvedUHeight, layer: ov.layer || 'layer1', assignedRack: resolvedRack, hostedOn: '', locked: false, groupId: null, ping: { enabled: pingEnabled, protocol: 'http', customUrl: '', timeout: pingTimeout, status: 'unknown', lastCheck: null, probeTypes: probeTypes, detectedServices: host.services || {}, dnsHostname: host.dnsName || '', netbiosName: host.netbiosName || '', mdnsName: host.mdnsName || '', httpServer: host.httpServer || '', snmpName: host.snmpName || '' } }; if (isRack) { nd[nodeId].isRack = true; nd[nodeId].rackCapacity = ov.rackCapacity || '42'; newRackIpToNodeId[host.ip] = nodeId; } positions[nodeId] = { x: startX + col * spacing, y: startY + row * spacing }; sizes[nodeId] = ov.nodeSize || 50; if (!styles[nodeId]) styles[nodeId] = {}; if (!styles[nodeId]['all']) styles[nodeId]['all'] = {}; if (ov.iconData && ov.iconData.name) { styles[nodeId]['all'].icon = { library: ov.iconData.library, name: ov.iconData.name }; } if (ov.fillColor && ov.fillColor !== '#1e293b') { styles[nodeId]['all'].circleColor = ov.fillColor; } if (ov.borderColor && ov.borderColor !== '#475569') { styles[nodeId]['all'].circleBorder = ov.borderColor; } added++; existingIPs[host.ip] = true; }); var edgeData = getGlobal('EDGE_DATA'); var ipToNodeId = {}; Object.keys(nd).forEach(function(nid) { if (nd[nid] && nd[nid].ip) ipToNodeId[nd[nid].ip] = nid; }); entries.forEach(function(entry) { var host = entry.host; var ov = entry.ov; if (!ov.connections || ov.connections.length === 0) return; var fromNodeId = ipToNodeId[host.ip]; if (!fromNodeId) return; ov.connections.forEach(function(conn) { var toNodeId; if (conn.target.indexOf('canvas:') === 0) { toNodeId = conn.target.replace('canvas:', ''); } else { toNodeId = ipToNodeId[conn.target]; } if (!toNodeId || !nd[toNodeId]) return; edgeData.list.push({ id: fromNodeId + '-' + toNodeId + '-' + Date.now() + '-' + Math.random().toString(36).substr(2, 4), from: fromNodeId, to: toNodeId, width: 4, color: '#475569', direction: 'none', routing: 'orthogonal', type: 'main', notes: [], fromPort: conn.fromPort || '', toPort: conn.toPort || '', lineStyle: 'solid', waypoints: [] }); }); }); entries.forEach(function(entry) { delete discoveryOverrides[entry.host.ip]; }); setGlobal('NODE_DATA', nd); setGlobal('savedPositions', positions); setGlobal('savedSizes', sizes); setGlobal('savedStyles', styles); setGlobal('EDGE_DATA', edgeData); var forge = window.__collabGetVar('forgeTheTopology'); if (forge) forge(); renderDiscoveryResults(); sendFullState(); }); var style = document.createElement('style'); style.textContent = '#verse-discovery-modal{display:none}#verse-discovery-modal.active{display:flex}#verse-disc-edit-modal{display:none}#verse-disc-edit-modal.active{display:flex}'; document.head.appendChild(style); } function startCollab() { setupAuditLogInjection(); injectCollabBar(); hookSaveFunction(); overridePingFunctions(); injectProbeUI(); injectDiscoveryUI(); connect(); startStatePolling(); setTimeout(trackSelection, 1000); trackCursor(); } init(); })(); ================================================ FILE: theonefile_verse/public/index.html ================================================ TheOneFile_Verse

TheOneFile_Verse

It turns out there CAN be more than one.

================================================ FILE: theonefile_verse/public/landing.js ================================================ (function() { 'use strict'; function withLoading(fn) { return async function() { var btn = this instanceof HTMLElement ? this : null; if (btn) btn.disabled = true; try { await fn.call(this); } finally { if (btn) btn.disabled = false; } }; } function showToast(message, type) { var stack = document.getElementById('toast-stack'); if (!stack) { stack = document.createElement('div'); stack.id = 'toast-stack'; stack.className = 'toast-stack'; document.body.appendChild(stack); } var toast = document.createElement('div'); toast.className = 'toast-item' + (type ? ' ' + type : ''); toast.textContent = message; stack.appendChild(toast); setTimeout(function() { toast.remove(); if (stack.children.length === 0) stack.remove(); }, 4000); } function h(tag, props) { var node = document.createElement(tag); if (props) { for (var key in props) { if (!props.hasOwnProperty(key)) continue; if (key === 'className') node.className = props[key]; else if (key === 'style') node.setAttribute('style', props[key]); else if (key === 'textContent') node.textContent = props[key]; else if (key.slice(0, 5) === 'data-') node.setAttribute(key, props[key]); else if (key === 'checked') { if (props[key]) node.checked = true; } else node[key] = props[key]; } } for (var i = 2; i < arguments.length; i++) _append(node, arguments[i]); return node; } function _append(parent, child) { if (child == null || child === false) return; if (typeof child === 'string' || typeof child === 'number') { parent.appendChild(document.createTextNode(String(child))); } else if (Array.isArray(child)) { for (var j = 0; j < child.length; j++) _append(parent, child[j]); } else { parent.appendChild(child); } } function clearNode(el) { while (el.firstChild) el.removeChild(el.firstChild); } function setContent(container, children) { clearNode(container); var frag = document.createDocumentFragment(); _append(frag, children); container.appendChild(frag); } var forcedTheme = null; function getTheme() { if (forcedTheme && forcedTheme !== 'user') return forcedTheme; return localStorage.getItem('theme') || 'dark'; } function setTheme(theme) { if (!forcedTheme || forcedTheme === 'user') { localStorage.setItem('theme', theme); } document.documentElement.setAttribute('data-theme', theme); document.getElementById('theme-icon').textContent = theme === 'dark' ? '\u2600' : '\u263E'; } function toggleTheme() { if (forcedTheme && forcedTheme !== 'user') return; setTheme(getTheme() === 'dark' ? 'light' : 'dark'); } function updateThemeToggleVisibility() { var btn = document.querySelector('.theme-toggle'); if (forcedTheme && forcedTheme !== 'user') { btn.style.display = 'none'; } else { btn.style.display = 'block'; } } setTheme(getTheme()); fetch('/api/theme').then(function(r) { return r.json(); }).then(function(data) { if (data.forcedTheme && data.forcedTheme !== 'user') { forcedTheme = data.forcedTheme; setTheme(forcedTheme); } updateThemeToggleVisibility(); if (data.showAdminLink !== false) { var footer = document.getElementById('admin-footer'); if (footer) footer.style.display = ''; } if (data.adminPath) { var link = document.getElementById('admin-link'); if (link) link.href = '/' + data.adminPath; } }).catch(function() { updateThemeToggleVisibility(); }); var selectedFile = null; var selectedFileContent = null; function generateUUID() { if (crypto.randomUUID) return crypto.randomUUID(); return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); } function getOrCreateUserId(roomId) { var key = 'collab-user-' + roomId; var id = localStorage.getItem(key); if (!id) { id = generateUUID(); localStorage.setItem(key, id); } return id; } function openModal(type) { document.getElementById(type + '-modal').classList.add('active'); } function closeModal(type) { var modal = document.getElementById(type + '-modal'); modal.classList.remove('active'); modal.querySelectorAll('input:not([type="checkbox"]):not([type="file"]):not([type="hidden"])').forEach(function(el) { el.value = ''; }); modal.querySelectorAll('select').forEach(function(el) { var sel = el.querySelector('[selected]'); el.selectedIndex = sel ? sel.index : 0; }); modal.querySelectorAll('.error-text').forEach(function(el) { el.textContent = ''; el.classList.remove('active'); }); if (type === '2fa') { pending2FAToken = null; } } function clearAllAuthForms() { ['login-email', 'login-password', 'register-name', 'register-email', 'register-password', 'forgot-email', 'magic-email', '2fa-code', 'settings-new-email', 'settings-email-password' ].forEach(function(id) { var el = document.getElementById(id); if (el) el.value = ''; }); ['login-error', 'register-error', 'forgot-error', 'forgot-success', 'magic-error', 'magic-success', '2fa-error', 'email-change-error', 'email-change-success' ].forEach(function(id) { var el = document.getElementById(id); if (el) { el.textContent = ''; el.classList.remove('active'); } }); pending2FAToken = null; } function showError(type, msg) { var el = document.getElementById(type + '-error'); el.textContent = msg; el.classList.add('active'); el.setAttribute('role', 'alert'); } var fileDrop = document.getElementById('create-file-drop'); var fileInput = document.getElementById('create-file-input'); fileDrop.addEventListener('click', function() { fileInput.click(); }); fileDrop.addEventListener('dragover', function(e) { e.preventDefault(); }); fileDrop.addEventListener('drop', function(e) { e.preventDefault(); handleFile(e.dataTransfer.files[0]); }); fileInput.addEventListener('change', function(e) { handleFile(e.target.files[0]); }); var MAX_FILE_SIZE_MB = 10; var MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024; async function handleFile(file) { if (!file) return; if (file.size > MAX_FILE_SIZE_BYTES) { showError('create', 'File too large. Maximum size is ' + MAX_FILE_SIZE_MB + 'MB'); return; } var ext = file.name.split('.').pop().toLowerCase(); if (['html', 'json', 'csv', 'md', 'markdown', 'txt'].indexOf(ext) === -1) { showError('create', 'Invalid file type'); return; } selectedFile = file; selectedFileContent = await file.text(); document.getElementById('create-file-drop').style.display = 'none'; document.getElementById('create-file-selected').classList.add('active'); document.getElementById('create-file-name').textContent = file.name + ' (' + (file.size / 1024).toFixed(1) + 'KB)'; } function clearFile() { selectedFile = null; selectedFileContent = null; document.getElementById('create-file-drop').style.display = 'block'; document.getElementById('create-file-selected').classList.remove('active'); fileInput.value = ''; } function parseTopologyFile(content, filename) { var ext = filename.split('.').pop().toLowerCase(); if (ext === 'json') { try { return JSON.parse(content); } catch(e) { return null; } } if (ext === 'html') { var match = content.match(/]*id="topology-state"[^>]*>([\s\S]*?)<\/script>/i); if (match) { try { return JSON.parse(match[1]); } catch(e) {} } return null; } if (ext === 'csv') { var m = content.match(/#THEONEFILE_CONFIG:(.+)/); if (m) { try { return JSON.parse(m[1]); } catch(e) {} } return null; } if (['md', 'markdown', 'txt'].indexOf(ext) !== -1) { var m2 = content.match(//); if (m2) { try { return JSON.parse(m2[1].trim()); } catch(e) {} } return null; } return null; } async function createRoom() { var password = document.getElementById('create-password').value; var destructVal = document.getElementById('create-destruct').value; var allowGuestsCheckbox = document.getElementById('create-allow-guests'); var allowGuests = allowGuestsCheckbox ? allowGuestsCheckbox.checked : true; var destructMode = 'time', destructMs = parseInt(destructVal); if (destructVal === 'empty') { destructMode = 'empty'; destructMs = 0; } else if (destructVal === 'never') { destructMode = 'never'; destructMs = 0; } var topology = null; if (selectedFileContent) topology = parseTopologyFile(selectedFileContent, selectedFile.name); var tempId = generateUUID(); var creatorId = getOrCreateUserId(tempId); try { var res = await fetch('/api/room', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrfToken }, body: JSON.stringify({ password: password || null, destructMode: destructMode, destructValue: destructMs, topology: topology, creatorId: creatorId, allowGuests: allowGuests }) }); var data = await res.json(); if (data.error) { showError('create', data.error); return; } localStorage.setItem('collab-user-' + data.id, creatorId); window.location.href = data.url; } catch(e) { showError('create', 'Failed to create room'); } } var joinInput = document.getElementById('join-room-id'); var checking = false; var joinDebounceTimer = null; joinInput.addEventListener('input', function() { var id = joinInput.value.trim(); if (id.indexOf('/s/') !== -1) { id = id.split('/s/')[1].split('?')[0]; joinInput.value = id; } if (id.length < 36) return; if (joinDebounceTimer) clearTimeout(joinDebounceTimer); joinDebounceTimer = setTimeout(async function() { if (checking) return; checking = true; try { var res = await fetch('/api/room/' + id + '/exists'); var data = await res.json(); document.getElementById('join-password-group').style.display = data.hasPassword ? 'block' : 'none'; if (!data.exists) showError('join', 'Room not found'); else document.getElementById('join-error').classList.remove('active'); } catch(e) {} checking = false; }, 300); }); async function joinRoom() { var id = document.getElementById('join-room-id').value.trim(); if (id.indexOf('/s/') !== -1) id = id.split('/s/')[1].split('?')[0]; var password = document.getElementById('join-password').value; if (!id) { showError('join', 'Enter a room ID'); return; } try { var existsRes = await fetch('/api/room/' + id + '/exists'); var exists = await existsRes.json(); if (!exists.exists) { showError('join', 'Room not found'); return; } if (exists.hasPassword) { var verifyRes = await fetch('/api/room/' + id + '/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ password: password }) }); if (!(await verifyRes.json()).valid) { showError('join', 'Invalid password'); return; } } window.location.href = '/s/' + id; } catch(e) { showError('join', 'Failed to join room'); } } document.querySelectorAll('.modal-overlay').forEach(function(el) { el.addEventListener('click', function(e) { if (e.target === el) { var type = el.id.replace('-modal', ''); closeModal(type); } }); }); document.addEventListener('keydown', function(e) { if (e.key === 'Escape') document.querySelectorAll('.modal-overlay.active').forEach(function(m) { var type = m.id.replace('-modal', ''); closeModal(type); }); }); var currentUser = null; var authSettings = null; var oidcProviders = []; var csrfToken = ''; var pending2FAToken = null; fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { csrfToken = d.token; }).catch(function() {}); async function loadAuthState() { try { var settingsRes = await fetch('/api/auth/settings', { credentials: 'include' }); var settingsData = await settingsRes.json(); authSettings = settingsData.settings; oidcProviders = settingsData.providers || []; var userRes = await fetch('/api/auth/me', { credentials: 'include' }); var userData = await userRes.json(); currentUser = userData.user; updateAuthUI(); } catch(e) { console.error('Failed to load auth state:', e); } } function updateAuthUI() { var userMenu = document.getElementById('user-menu'); var authButtonsEl = document.getElementById('auth-buttons'); var guestToggle = document.getElementById('guest-toggle-container'); if (currentUser) { userMenu.style.display = 'flex'; authButtonsEl.style.display = 'none'; document.getElementById('user-avatar').textContent = (currentUser.displayName || currentUser.email || 'U')[0].toUpperCase(); document.getElementById('user-name').textContent = currentUser.displayName || (currentUser.email ? currentUser.email.split('@')[0] : 'User'); } else if (authSettings) { userMenu.style.display = 'none'; var hasOidc = oidcProviders && oidcProviders.length > 0; var registrationOpen = authSettings.authMode === 'open' || authSettings.authMode === 'registration'; if (registrationOpen || hasOidc) { authButtonsEl.style.display = 'flex'; } } if (authSettings && authSettings.allowRoomCreatorGuestSetting) { if (currentUser || authSettings.allowGuestRoomCreation) { guestToggle.style.display = 'flex'; } else { guestToggle.style.display = 'none'; } } else { guestToggle.style.display = 'none'; } renderOidcProviders('login-oidc-providers', 'login'); renderOidcProviders('register-oidc-providers', 'register'); } function renderOidcProviders(containerId, mode) { var container = document.getElementById(containerId); var divider = document.getElementById(mode + '-divider'); clearNode(container); if (oidcProviders.length === 0) { container.style.display = 'none'; divider.style.display = 'none'; return; } container.style.display = 'flex'; divider.style.display = 'flex'; oidcProviders.forEach(function(provider) { var btn = document.createElement('button'); btn.className = 'oidc-btn'; var safeUrl = provider.iconUrl && /^https?:\/\//i.test(provider.iconUrl) ? provider.iconUrl : null; var safeName = document.createElement('span'); safeName.textContent = 'Continue with ' + (provider.name || 'SSO'); if (safeUrl) { var img = document.createElement('img'); img.src = safeUrl; img.alt = provider.name || 'SSO'; btn.appendChild(img); } btn.appendChild(safeName); btn.addEventListener('click', function() { startOidcLogin(provider.id); }); container.appendChild(btn); }); } async function startOidcLogin(providerId) { try { var res = await fetch('/api/auth/oidc/' + providerId); var data = await res.json(); if (data.url) { window.location.href = data.url; } else { showError('login', data.error || 'Failed to start SSO'); } } catch(e) { showError('login', 'Failed to start SSO'); } } async function loginWithPassword() { var email = document.getElementById('login-email').value.trim(); var password = document.getElementById('login-password').value; if (!email || !password) { showError('login', 'Please enter email and password'); return; } try { var res = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email, password: password, csrfToken: csrfToken }) }); var data = await res.json(); if (data.requires2FA) { pending2FAToken = data.pendingToken; closeModal('login'); openModal('2fa'); setTimeout(function() { document.getElementById('2fa-code').focus(); }, 100); return; } if (res.ok && data.success) { window.location.reload(); } else { showError('login', data.error || 'Login failed'); fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { csrfToken = d.token; }).catch(function() {}); } } catch(e) { showError('login', 'Connection error'); } } async function verify2FA() { var code = document.getElementById('2fa-code').value.trim(); if (!code) { showError('2fa', 'Please enter your code'); return; } try { var res = await fetch('/api/auth/2fa/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ pendingToken: pending2FAToken, code: code }) }); var data = await res.json(); if (res.ok && data.success) { window.location.reload(); } else { showError('2fa', data.error || 'Invalid code'); } } catch(e) { showError('2fa', 'Connection error'); } } async function openSettingsModal() { openModal('settings'); await load2FAStatus(); } async function load2FAStatus() { var container = document.getElementById('2fa-status'); try { var res = await fetch('/api/auth/me', { credentials: 'include' }); var data = await res.json(); if (!data.user) return; currentUser = data.user; if (data.user.totpEnabled) { setContent(container, [ h('p', {style: 'color:#22c55e;font-size:14px;margin-bottom:12px'}, '\u2713 2FA is enabled'), h('div', {className: 'form-group'}, h('label', null, 'Password to Disable'), h('input', {type: 'password', id: '2fa-disable-password', placeholder: 'Enter password'})), h('div', {className: 'error-text', id: '2fa-setup-error'}), h('button', {className: 'btn btn-secondary', 'data-action': 'disable2FA', style: 'margin-top:8px'}, 'Disable 2FA') ]); } else { setContent(container, [ h('p', {style: 'color:var(--text-soft);font-size:14px;margin-bottom:12px'}, '2FA is not enabled'), h('div', {className: 'error-text', id: '2fa-setup-error'}), h('button', {className: 'btn btn-secondary', 'data-action': 'setup2FA', style: 'margin-top:8px'}, 'Enable 2FA') ]); } } catch(e) {} } async function setup2FA() { var errEl = document.getElementById('2fa-setup-error'); if (errEl) errEl.textContent = ''; try { var res = await fetch('/api/auth/2fa/setup', { method: 'POST', credentials: 'include', headers: { 'x-csrf-token': csrfToken } }); var data = await res.json(); if (data.error) { if (errEl) errEl.textContent = data.error; return; } var container = document.getElementById('2fa-status'); setContent(container, [ h('p', {style: 'font-size:14px;color:var(--text-soft);margin-bottom:12px'}, 'Scan this QR code with your authenticator app, then enter the code below.'), h('div', {style: 'text-align:center;margin-bottom:16px'}, h('div', {id: '2fa-qr', style: 'display:inline-block;background:white;padding:16px;border-radius:8px'})), h('p', {style: 'font-size:12px;color:var(--text-soft);margin-bottom:16px;word-break:break-all;text-align:center'}, 'Manual entry: ', data.secret), h('div', {className: 'form-group'}, h('label', null, 'Verification Code'), h('input', {type: 'text', id: '2fa-setup-code', placeholder: '000000', maxLength: '6', inputMode: 'numeric', style: 'text-align:center;font-size:20px;letter-spacing:6px'})), h('div', {className: 'error-text', id: '2fa-setup-error'}), h('button', {className: 'btn btn-primary', 'data-action': 'verify2FASetup', style: 'margin-top:8px'}, 'Verify & Enable') ]); var renderSetupQR = function() { try { var el = document.getElementById('2fa-qr'); var qr = qrcode(0, 'M'); qr.addData(data.otpauthUrl); qr.make(); var svg = qr.createSvgTag({ cellSize: 4, margin: 4 }); var parsed = new DOMParser().parseFromString(svg, 'image/svg+xml'); el.appendChild(document.importNode(parsed.documentElement, true)); } catch(e) {} }; if (typeof qrcode !== 'undefined') { renderSetupQR(); } else { var s = document.createElement('script'); s.src = '/qrcode.min.js'; s.onload = renderSetupQR; document.head.appendChild(s); } } catch(e) { if (errEl) errEl.textContent = 'Connection error'; } } async function verify2FASetup() { var code = document.getElementById('2fa-setup-code').value.trim(); var errEl = document.getElementById('2fa-setup-error'); if (!code || code.length !== 6) { if (errEl) errEl.textContent = 'Enter the 6 digit code'; return; } try { var res = await fetch('/api/auth/2fa/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrfToken }, credentials: 'include', body: JSON.stringify({ code: code }) }); var data = await res.json(); if (data.backupCodes) { var container = document.getElementById('2fa-status'); var codeElements = []; data.backupCodes.forEach(function(code, i) { if (i > 0) codeElements.push(h('br', null)); codeElements.push(code); }); setContent(container, [ h('p', {style: 'color:#22c55e;font-size:14px;margin-bottom:12px'}, '\u2713 2FA has been enabled!'), h('p', {style: 'font-size:14px;color:var(--text-soft);margin-bottom:12px'}, 'Save these backup codes in a safe place. Each can only be used once.'), h('div', {style: 'background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:16px;font-family:monospace;font-size:14px;line-height:2'}, codeElements), h('button', {className: 'btn btn-secondary', 'data-action': 'load2FAStatus', style: 'margin-top:16px'}, 'Done') ]); } else { if (errEl) errEl.textContent = data.error || 'Verification failed'; } } catch(e) { if (errEl) errEl.textContent = 'Connection error'; } } async function disable2FA() { var password = document.getElementById('2fa-disable-password').value; var errEl = document.getElementById('2fa-setup-error'); if (!password) { if (errEl) errEl.textContent = 'Password required'; return; } try { var res = await fetch('/api/auth/2fa/disable', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrfToken }, credentials: 'include', body: JSON.stringify({ password: password }) }); var data = await res.json(); if (res.ok && data.success) { await load2FAStatus(); } else { if (errEl) errEl.textContent = data.error || 'Failed to disable 2FA'; } } catch(e) { if (errEl) errEl.textContent = 'Connection error'; } } async function requestEmailChange() { var newEmail = document.getElementById('settings-new-email').value.trim(); var password = document.getElementById('settings-email-password').value; var errEl = document.getElementById('email-change-error'); var successEl = document.getElementById('email-change-success'); errEl.textContent = ''; successEl.textContent = ''; if (!newEmail || !password) { errEl.textContent = 'Email and password required'; return; } try { var res = await fetch('/api/auth/email-change', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrfToken }, credentials: 'include', body: JSON.stringify({ newEmail: newEmail, password: password }) }); var data = await res.json(); if (res.ok && data.success) { successEl.textContent = 'Verification email sent to ' + newEmail; document.getElementById('settings-new-email').value = ''; document.getElementById('settings-email-password').value = ''; } else { errEl.textContent = data.error || 'Failed to request email change'; } } catch(e) { errEl.textContent = 'Connection error'; } } async function registerUser() { var displayName = document.getElementById('register-name').value.trim(); var email = document.getElementById('register-email').value.trim(); var password = document.getElementById('register-password').value; if (!email || !password) { showError('register', 'Please enter email and password'); return; } if (password.length < 8) { showError('register', 'Password must be at least 8 characters'); return; } if (!/[a-zA-Z]/.test(password)) { showError('register', 'Password must contain at least one letter'); return; } if (!/[0-9!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]/.test(password)) { showError('register', 'Password must contain a number or special character'); return; } try { var res = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email, password: password, displayName: displayName, csrfToken: csrfToken }) }); var data = await res.json(); if (data.success) { if (data.requiresVerification) { closeModal('register'); showToast('Please check your email to verify your account.', 'success'); } else { window.location.reload(); } } else { showError('register', data.error || 'Registration failed'); fetch('/api/auth/csrf').then(function(r) { return r.json(); }).then(function(d) { csrfToken = d.token; }).catch(function() {}); } } catch(e) { showError('register', 'Connection error'); } } async function requestPasswordReset() { var email = document.getElementById('forgot-email').value.trim(); if (!email) { showError('forgot', 'Please enter your email'); return; } try { var res = await fetch('/api/auth/forgot-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email }) }); var data = await res.json(); document.getElementById('forgot-error').classList.remove('active'); var success = document.getElementById('forgot-success'); success.textContent = 'If an account exists, we\'ve sent a reset link.'; success.classList.add('active'); } catch(e) { showError('forgot', 'Connection error'); } } async function requestMagicLink() { var email = document.getElementById('magic-email').value.trim(); if (!email) { showError('magic', 'Please enter your email'); return; } try { var res = await fetch('/api/auth/magic-link', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ email: email }) }); var data = await res.json(); document.getElementById('magic-error').classList.remove('active'); var success = document.getElementById('magic-success'); success.textContent = 'If an account exists, we\'ve sent a magic link.'; success.classList.add('active'); } catch(e) { showError('magic', 'Connection error'); } } async function logout() { try { await fetch('/api/logout', { method: 'POST', credentials: 'include' }); } catch(e) {} localStorage.removeItem('collab_token'); localStorage.removeItem('user_token'); currentUser = null; clearAllAuthForms(); document.querySelectorAll('.modal-overlay.active').forEach(function(m) { m.classList.remove('active'); }); window.location.reload(); } var urlParams = new URLSearchParams(window.location.search); if (urlParams.get('auth_error')) { showToast('Authentication error: ' + urlParams.get('auth_error'), 'error'); history.replaceState({}, '', '/'); } if (urlParams.get('verified') === 'true') { showToast('Email verified! You can now sign in.', 'success'); history.replaceState({}, '', '/'); } if (urlParams.get('welcome') === 'true') { showToast('Welcome! Your account has been created.', 'success'); history.replaceState({}, '', '/'); } if (urlParams.get('error')) { var errorMessages = { 'invalid_room': 'That room link is invalid.', 'room_not_found': 'That room no longer exists.', 'room_unavailable': 'Room is temporarily unavailable.', 'not_found': 'Page not found.' }; showToast(errorMessages[urlParams.get('error')] || 'Something went wrong.', 'error'); history.replaceState({}, '', '/'); } loadAuthState(); document.querySelector('.theme-toggle').addEventListener('click', toggleTheme); document.querySelector('[data-action="openSettings"]').addEventListener('click', openSettingsModal); document.querySelector('[data-action="logout"]').addEventListener('click', logout); document.querySelector('[data-action="openLogin"]').addEventListener('click', function() { openModal('login'); }); document.querySelector('[data-action="openRegister"]').addEventListener('click', function() { openModal('register'); }); document.querySelector('[data-action="openCreate"]').addEventListener('click', function() { openModal('create'); }); document.querySelector('[data-action="openJoin"]').addEventListener('click', function() { openModal('join'); }); document.querySelectorAll('[data-close-modal]').forEach(function(btn) { btn.addEventListener('click', function() { closeModal(btn.dataset.closeModal); }); }); document.querySelector('[data-action="createRoom"]').addEventListener('click', withLoading(createRoom)); document.querySelector('[data-action="joinRoom"]').addEventListener('click', withLoading(joinRoom)); document.querySelector('[data-action="loginWithPassword"]').addEventListener('click', withLoading(loginWithPassword)); document.querySelector('[data-action="registerUser"]').addEventListener('click', withLoading(registerUser)); document.querySelector('[data-action="requestPasswordReset"]').addEventListener('click', withLoading(requestPasswordReset)); document.querySelector('[data-action="requestMagicLink"]').addEventListener('click', withLoading(requestMagicLink)); document.querySelector('[data-action="verify2FA"]').addEventListener('click', withLoading(verify2FA)); document.querySelector('[data-action="requestEmailChange"]').addEventListener('click', withLoading(requestEmailChange)); document.querySelector('[data-action="clearFile"]').addEventListener('click', clearFile); document.querySelector('[data-action="openForgot"]').addEventListener('click', function(e) { e.preventDefault(); openModal('forgot'); closeModal('login'); }); document.querySelector('[data-action="openMagic"]').addEventListener('click', function(e) { e.preventDefault(); openModal('magic'); closeModal('login'); }); document.getElementById('2fa-status').addEventListener('click', async function(e) { var target = e.target.closest('[data-action]'); if (!target) return; target.disabled = true; try { var action = target.dataset.action; if (action === 'disable2FA') await disable2FA(); else if (action === 'setup2FA') await setup2FA(); else if (action === 'verify2FASetup') await verify2FASetup(); else if (action === 'load2FAStatus') await load2FAStatus(); } finally { target.disabled = false; } }); })(); ================================================ FILE: theonefile_verse/public/theonefile.html ================================================ The One File: The Networkening

Select Icon

The One File: The Networkening

🔒
?
100%
================================================ FILE: theonefile_verse/redis.conf ================================================ maxmemory 200mb maxmemory-policy volatile-lru appendonly yes ================================================ FILE: theonefile_verse/src/auth.ts ================================================ import * as db from "./database"; import * as oidc from "./oidc"; import * as mailer from "./mailer"; import { createHmac, randomBytes } from "crypto"; export async function hashPassword(password: string): Promise { return await Bun.password.hash(password, { algorithm: "argon2id", memoryCost: 65536, timeCost: 2 }); } export async function verifyPassword(password: string, hash: string): Promise { if (hash.startsWith('$argon2')) { return await Bun.password.verify(password, hash); } const encoder = new TextEncoder(); const data = encoder.encode(password + "theonefile-collab-salt-v1"); const legacyHash = await crypto.subtle.digest("SHA-256", data); const computed = Buffer.from(Buffer.from(legacyHash).toString("hex")); const stored = Buffer.from(hash); if (computed.length !== stored.length) return false; return crypto.timingSafeEqual(computed, stored); } export function isLegacyHash(hash: string): boolean { return !hash.startsWith('$argon2'); } export async function upgradePasswordHash(userId: string, password: string): Promise { const user = db.getUserById(userId); if (!user) return; const newHash = await hashPassword(password); user.passwordHash = newHash; user.updatedAt = new Date().toISOString(); db.updateUser(user); console.log(`[Auth] Upgraded password hash for user ${userId} from legacy SHA-256 to Argon2id`); } export function validatePassword(password: string): { valid: boolean; error?: string } { if (password.length < 8) { return { valid: false, error: "Password must be at least 8 characters" }; } if (password.length > 128) { return { valid: false, error: "Password must be less than 128 characters" }; } if (!/[0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password)) { return { valid: false, error: "Password must contain at least one number or special character" }; } if (!/[a-zA-Z]/.test(password)) { return { valid: false, error: "Password must contain at least one letter" }; } return { valid: true }; } export function validateEmail(email: string): { valid: boolean; error?: string } { if (!email || email.length > 254) { return { valid: false, error: "Invalid email address" }; } const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; if (!emailRegex.test(email)) { return { valid: false, error: "Invalid email format" }; } return { valid: true }; } function normalizeEmail(email: string): string { return email.toLowerCase().trim(); } export async function registerUser( email: string, password: string, displayName?: string, baseUrl?: string ): Promise<{ success: boolean; userId?: string; error?: string; requiresVerification?: boolean }> { const normalizedEmail = normalizeEmail(email); const emailValidation = validateEmail(normalizedEmail); if (!emailValidation.valid) { return { success: false, error: emailValidation.error }; } const passwordValidation = validatePassword(password); if (!passwordValidation.valid) { return { success: false, error: passwordValidation.error }; } const existing = db.getUserByEmail(normalizedEmail); if (existing) { return { success: false, error: "Registration failed. Please try again or use a different email." }; } const authSettings = oidc.getAuthSettings(); if (authSettings.authMode === 'closed') { return { success: false, error: "Registration is closed" }; } if (authSettings.authMode === 'invite_only') { return { success: false, error: "Registration requires an invitation" }; } if (authSettings.authMode === 'oidc_only') { return { success: false, error: "Please use SSO to register" }; } const userId = crypto.randomUUID(); const now = new Date().toISOString(); const passwordHash = await hashPassword(password); const user: db.User = { id: userId, email: normalizedEmail, emailVerified: !authSettings.requireEmailVerification, displayName: displayName || normalizedEmail.split('@')[0], avatarUrl: null, passwordHash, role: 'user', createdAt: now, updatedAt: now, lastLogin: now, isActive: true, failedLoginAttempts: 0, lockedUntil: null, totpSecret: null, totpEnabled: false, totpBackupCodes: null, pendingEmail: null, pendingEmailToken: null }; const { wasFirst: isFirstUser } = db.createUserAtomic(user); db.logAuthEvent('register', user.id, null, { role: user.role, isFirstUser }); if (!isFirstUser && authSettings.requireEmailVerification && baseUrl) { const token = await createVerificationToken(userId); const verifyUrl = `${baseUrl}/auth/verify?token=${token}`; await mailer.sendVerificationEmail(normalizedEmail, user.displayName || 'User', verifyUrl); return { success: true, userId, requiresVerification: true }; } return { success: true, userId }; } const MAX_FAILED_ATTEMPTS = 5; const LOCKOUT_DURATION_MINUTES = 15; export async function loginWithPassword( email: string, password: string, ipAddress: string, userAgent: string ): Promise<{ success: boolean; userId?: string; sessionToken?: string; error?: string; requires2FA?: boolean; pendingToken?: string }> { const normalizedEmail = normalizeEmail(email); const user = db.getUserByEmail(normalizedEmail); if (!user) { return { success: false, error: "Invalid email or password" }; } if (!user.isActive) { return { success: false, error: "Invalid email or password" }; } if (user.lockedUntil) { const lockExpiry = new Date(user.lockedUntil); if (lockExpiry > new Date()) { const remainingMinutes = Math.ceil((lockExpiry.getTime() - Date.now()) / 60000); return { success: false, error: `Account is temporarily locked. Try again in ${remainingMinutes} minute${remainingMinutes !== 1 ? 's' : ''}.` }; } db.resetFailedLogin(user.id); } if (!user.passwordHash) { return { success: false, error: "Please use SSO to login" }; } const valid = await verifyPassword(password, user.passwordHash); if (!valid) { db.incrementFailedLogin(user.id); const updatedUser = db.getUserById(user.id); if (updatedUser && updatedUser.failedLoginAttempts >= MAX_FAILED_ATTEMPTS) { const lockUntil = new Date(Date.now() + LOCKOUT_DURATION_MINUTES * 60 * 1000); db.lockUserAccount(user.id, lockUntil); db.logAuthEvent('account_locked', user.id, ipAddress, { reason: 'too_many_failed_attempts' }); return { success: false, error: `Too many failed attempts. Account locked for ${LOCKOUT_DURATION_MINUTES} minutes.` }; } db.logAuthEvent('login_failed', user.id, ipAddress, { reason: 'invalid_password', attempts: updatedUser?.failedLoginAttempts }); const attemptsRemaining = MAX_FAILED_ATTEMPTS - (updatedUser?.failedLoginAttempts || 0); if (attemptsRemaining <= 2 && attemptsRemaining > 0) { return { success: false, error: `Invalid email or password. ${attemptsRemaining} attempt${attemptsRemaining !== 1 ? 's' : ''} remaining.` }; } return { success: false, error: "Invalid email or password" }; } db.resetFailedLogin(user.id); if (isLegacyHash(user.passwordHash)) { await upgradePasswordHash(user.id, password); } const authSettings = oidc.getAuthSettings(); if (authSettings.requireEmailVerification && !user.emailVerified) { return { success: false, error: "Please verify your email first" }; } if (user.totpEnabled) { const pendingToken = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(pendingToken); db.deleteUserTokensByType(user.id, 'totp_pending'); db.createUserToken({ id: crypto.randomUUID(), userId: user.id, type: 'totp_pending', tokenHash, expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(), usedAt: null, createdAt: new Date().toISOString() }); return { success: false, requires2FA: true, pendingToken, error: undefined }; } user.lastLogin = new Date().toISOString(); user.updatedAt = new Date().toISOString(); user.failedLoginAttempts = 0; user.lockedUntil = null; db.updateUser(user); const sessionToken = await createSessionToken(user.id, ipAddress, userAgent); db.logAuthEvent('login_success', user.id, ipAddress, { method: 'password' }); return { success: true, userId: user.id, sessionToken }; } const MAX_SESSIONS_PER_USER = 10; async function createSessionToken( userId: string, ipAddress: string, userAgent: string ): Promise { const token = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(token); const now = new Date(); const expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); const existing = db.getSessionsByUserId(userId); if (existing.length >= MAX_SESSIONS_PER_USER) { const oldest = existing.slice(MAX_SESSIONS_PER_USER - 1); for (const s of oldest) db.deleteSession(s.id); } db.createUserSession({ id: crypto.randomUUID(), userId, tokenHash, ipAddress, userAgent: userAgent?.substring(0, 500) || null, expiresAt: expiresAt.toISOString(), createdAt: now.toISOString() }); return token; } export async function rotateSessionToken( oldToken: string, ipAddress: string, userAgent: string ): Promise<{ success: boolean; newToken?: string; error?: string }> { const tokenHash = await oidc.hashToken(oldToken); const session = db.getUserSessionByTokenHash(tokenHash); if (!session) { return { success: false, error: "Invalid session" }; } if (new Date(session.expiresAt) < new Date()) { db.deleteUserSession(session.id); return { success: false, error: "Session expired" }; } db.deleteUserSession(session.id); const newToken = await createSessionToken(session.userId, ipAddress, userAgent); return { success: true, newToken }; } async function createVerificationToken(userId: string): Promise { db.deleteUserTokensByType(userId, 'email_verify'); const token = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(token); const now = new Date(); const expiresAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); db.createUserToken({ id: crypto.randomUUID(), userId, type: 'email_verify', tokenHash, expiresAt: expiresAt.toISOString(), usedAt: null, createdAt: now.toISOString() }); return token; } export async function verifyEmail(token: string): Promise<{ success: boolean; error?: string }> { const tokenHash = await oidc.hashToken(token); const userToken = db.getUserTokenByHash(tokenHash); if (!userToken) { return { success: false, error: "Invalid or expired token" }; } if (userToken.type !== 'email_verify') { return { success: false, error: "Invalid token type" }; } if (userToken.usedAt) { return { success: false, error: "Token already used" }; } if (new Date(userToken.expiresAt) < new Date()) { return { success: false, error: "Token expired" }; } const user = db.getUserById(userToken.userId); if (!user) { return { success: false, error: "User not found" }; } user.emailVerified = true; user.updatedAt = new Date().toISOString(); db.updateUser(user); db.markUserTokenUsed(userToken.id); return { success: true }; } const MIN_REQUEST_TIME_MS = 200; async function normalizeResponseTime(startTime: number): Promise { const elapsed = Date.now() - startTime; if (elapsed < MIN_REQUEST_TIME_MS) { await new Promise(r => setTimeout(r, MIN_REQUEST_TIME_MS - elapsed)); } } export async function requestPasswordReset( email: string, baseUrl: string ): Promise<{ success: boolean; error?: string }> { const startTime = Date.now(); const user = db.getUserByEmail(email); if (!user || !user.isActive) { await normalizeResponseTime(startTime); return { success: true }; } db.deleteUserTokensByType(user.id, 'password_reset'); const token = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(token); const now = new Date(); const expiresAt = new Date(now.getTime() + 60 * 60 * 1000); db.createUserToken({ id: crypto.randomUUID(), userId: user.id, type: 'password_reset', tokenHash, expiresAt: expiresAt.toISOString(), usedAt: null, createdAt: now.toISOString() }); const resetUrl = `${baseUrl}/auth/reset-password?token=${token}`; await mailer.sendPasswordResetEmail(user.email!, user.displayName || 'User', resetUrl); await normalizeResponseTime(startTime); return { success: true }; } export async function resetPassword( token: string, newPassword: string ): Promise<{ success: boolean; error?: string }> { const passwordValidation = validatePassword(newPassword); if (!passwordValidation.valid) { return { success: false, error: passwordValidation.error }; } const tokenHash = await oidc.hashToken(token); const userToken = db.getUserTokenByHash(tokenHash); if (!userToken) { return { success: false, error: "Invalid or expired token" }; } if (userToken.type !== 'password_reset') { return { success: false, error: "Invalid token type" }; } if (userToken.usedAt) { return { success: false, error: "Token already used" }; } if (new Date(userToken.expiresAt) < new Date()) { return { success: false, error: "Token expired" }; } const user = db.getUserById(userToken.userId); if (!user) { return { success: false, error: "User not found" }; } user.passwordHash = await hashPassword(newPassword); user.updatedAt = new Date().toISOString(); db.updateUser(user); db.markUserTokenUsed(userToken.id); db.deleteAllUserSessions(user.id); return { success: true }; } export async function requestMagicLink( email: string, baseUrl: string ): Promise<{ success: boolean; error?: string }> { const startTime = Date.now(); const authSettings = oidc.getAuthSettings(); if (!authSettings.allowMagicLinkLogin) { return { success: false, error: "Magic link login is disabled" }; } const user = db.getUserByEmail(email); if (!user || !user.isActive) { await normalizeResponseTime(startTime); return { success: true }; } db.deleteUserTokensByType(user.id, 'magic_link'); const token = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(token); const now = new Date(); const expiresAt = new Date(now.getTime() + 15 * 60 * 1000); db.createUserToken({ id: crypto.randomUUID(), userId: user.id, type: 'magic_link', tokenHash, expiresAt: expiresAt.toISOString(), usedAt: null, createdAt: now.toISOString() }); const loginUrl = `${baseUrl}/auth/magic-link?token=${token}`; await mailer.sendMagicLinkEmail(user.email!, user.displayName || 'User', loginUrl); await normalizeResponseTime(startTime); return { success: true }; } export async function loginWithMagicLink( token: string, ipAddress: string, userAgent: string ): Promise<{ success: boolean; userId?: string; sessionToken?: string; error?: string }> { const tokenHash = await oidc.hashToken(token); const userToken = db.getUserTokenByHash(tokenHash); if (!userToken) { return { success: false, error: "Invalid or expired link" }; } if (userToken.type !== 'magic_link') { return { success: false, error: "Invalid link type" }; } if (userToken.usedAt) { return { success: false, error: "Link already used" }; } if (new Date(userToken.expiresAt) < new Date()) { return { success: false, error: "Link expired" }; } const user = db.getUserById(userToken.userId); if (!user || !user.isActive) { return { success: false, error: "User not found" }; } db.markUserTokenUsed(userToken.id); user.lastLogin = new Date().toISOString(); user.updatedAt = new Date().toISOString(); user.emailVerified = true; db.updateUser(user); const sessionToken = await createSessionToken(user.id, ipAddress, userAgent); return { success: true, userId: user.id, sessionToken }; } export async function logout(token: string): Promise { const tokenHash = await oidc.hashToken(token); db.deleteSessionByTokenHash(tokenHash); } export function logoutAll(userId: string): number { return db.deleteAllUserSessions(userId); } export async function changePassword( userId: string, currentPassword: string, newPassword: string, currentSessionToken?: string ): Promise<{ success: boolean; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (!user.passwordHash) { return { success: false, error: "Account uses SSO only" }; } const valid = await verifyPassword(currentPassword, user.passwordHash); if (!valid) { return { success: false, error: "Current password is incorrect" }; } const passwordValidation = validatePassword(newPassword); if (!passwordValidation.valid) { return { success: false, error: passwordValidation.error }; } user.passwordHash = await hashPassword(newPassword); user.updatedAt = new Date().toISOString(); db.updateUser(user); db.deleteAllUserSessions(userId); return { success: true }; } export function updateProfile( userId: string, updates: { displayName?: string; avatarUrl?: string } ): { success: boolean; error?: string } { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (updates.displayName !== undefined) { if (typeof updates.displayName !== 'string') return { success: false, error: "Invalid display name" }; user.displayName = updates.displayName.substring(0, 100); } if (updates.avatarUrl !== undefined) { if (typeof updates.avatarUrl !== 'string') return { success: false, error: "Invalid avatar URL" }; user.avatarUrl = updates.avatarUrl.substring(0, 500); } user.updatedAt = new Date().toISOString(); db.updateUser(user); return { success: true }; } export function deleteAccount(userId: string): { success: boolean; error?: string } { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (user.role === 'admin') { const adminCount = db.countUsersByRole('admin'); if (adminCount <= 1) { return { success: false, error: "Cannot delete the last admin" }; } } db.deleteUser(userId); return { success: true }; } export interface ParsedSession extends db.UserSession { browser: string; os: string; device: string; location: string; } function parseUserAgent(ua: string | null): { browser: string; os: string; device: string } { if (!ua) return { browser: 'Unknown', os: 'Unknown', device: 'Unknown' }; let browser = 'Unknown'; let os = 'Unknown'; let device = 'Desktop'; if (ua.includes('Mobile') || ua.includes('Android')) device = 'Mobile'; else if (ua.includes('Tablet') || ua.includes('iPad')) device = 'Tablet'; if (ua.includes('Firefox/')) browser = 'Firefox'; else if (ua.includes('Edg/')) browser = 'Edge'; else if (ua.includes('Chrome/')) browser = 'Chrome'; else if (ua.includes('Safari/') && !ua.includes('Chrome')) browser = 'Safari'; else if (ua.includes('Opera') || ua.includes('OPR/')) browser = 'Opera'; if (ua.includes('Windows')) os = 'Windows'; else if (ua.includes('Mac OS X') || ua.includes('macOS')) os = 'macOS'; else if (ua.includes('Linux') && !ua.includes('Android')) os = 'Linux'; else if (ua.includes('Android')) os = 'Android'; else if (ua.includes('iOS') || ua.includes('iPhone') || ua.includes('iPad')) os = 'iOS'; return { browser, os, device }; } function formatIPLocation(ip: string | null): string { if (!ip || ip === 'unknown') return 'Unknown location'; if (ip.startsWith('127.') || ip === '::1') return 'Localhost'; if (ip.startsWith('192.168.') || ip.startsWith('10.') || ip.startsWith('172.')) return 'Local network'; return ip; } export function getUserSessions(userId: string): ParsedSession[] { const sessions = db.getSessionsByUserId(userId); return sessions.map(session => { const parsed = parseUserAgent(session.userAgent); return { ...session, browser: parsed.browser, os: parsed.os, device: parsed.device, location: formatIPLocation(session.ipAddress) }; }); } export function getUserOidcLinks(userId: string): db.UserOidcLink[] { return db.getOidcLinksByUser(userId); } export function unlinkOidcProvider(userId: string, linkId: string): { success: boolean; error?: string } { const links = db.getOidcLinksByUser(userId); const link = links.find(l => l.id === linkId); if (!link) { return { success: false, error: "Link not found" }; } const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (!user.passwordHash && links.length <= 1) { return { success: false, error: "Cannot unlink last login method" }; } db.deleteOidcLink(linkId); return { success: true }; } export async function adminCreateUser( email: string, password: string | null, displayName: string | null, role: 'admin' | 'user' ): Promise<{ success: boolean; userId?: string; error?: string }> { const emailValidation = validateEmail(email); if (!emailValidation.valid) { return { success: false, error: emailValidation.error }; } if (password) { const passwordValidation = validatePassword(password); if (!passwordValidation.valid) { return { success: false, error: passwordValidation.error }; } } const existing = db.getUserByEmail(email); if (existing) { return { success: false, error: "Registration failed. Please try again or use a different email." }; } const userId = crypto.randomUUID(); const now = new Date().toISOString(); const sanitizedDisplayName = displayName ? displayName.substring(0, 100) : email.split('@')[0]; const user: db.User = { id: userId, email, emailVerified: true, displayName: sanitizedDisplayName, avatarUrl: null, passwordHash: password ? await hashPassword(password) : null, role, createdAt: now, updatedAt: now, lastLogin: null, isActive: true, failedLoginAttempts: 0, lockedUntil: null, totpSecret: null, totpEnabled: false, totpBackupCodes: null, pendingEmail: null, pendingEmailToken: null }; db.createUser(user); return { success: true, userId }; } export function adminUpdateUser( userId: string, updates: { displayName?: string; role?: 'admin' | 'user'; isActive?: boolean; emailVerified?: boolean; } ): { success: boolean; error?: string } { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (updates.role === 'user' && user.role === 'admin') { const adminCount = db.countUsersByRole('admin'); if (adminCount <= 1) { return { success: false, error: "Cannot demote the last admin" }; } } if (updates.isActive === false && user.role === 'admin') { const adminCount = db.countUsersByRole('admin'); if (adminCount <= 1) { return { success: false, error: "Cannot disable the last admin" }; } } if (updates.displayName !== undefined) user.displayName = updates.displayName.substring(0, 100); if (updates.role !== undefined) user.role = updates.role; if (updates.isActive !== undefined) user.isActive = updates.isActive; if (updates.emailVerified !== undefined) user.emailVerified = updates.emailVerified; user.updatedAt = new Date().toISOString(); db.updateUser(user); return { success: true }; } export async function adminResetPassword( userId: string, newPassword: string ): Promise<{ success: boolean; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } const passwordValidation = validatePassword(newPassword); if (!passwordValidation.valid) { return { success: false, error: passwordValidation.error }; } user.passwordHash = await hashPassword(newPassword); user.updatedAt = new Date().toISOString(); db.updateUser(user); db.deleteAllUserSessions(userId); return { success: true }; } export function adminDeleteUser(userId: string): { success: boolean; error?: string } { return deleteAccount(userId); } export function cleanupExpiredTokens(): { sessions: number; tokens: number } { return { sessions: db.cleanupExpiredSessions(), tokens: db.cleanupExpiredUserTokens() }; } function base32Encode(buffer: Uint8Array): string { const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; let result = ''; let bits = 0; let value = 0; for (const byte of buffer) { value = (value << 8) | byte; bits += 8; while (bits >= 5) { result += alphabet[(value >>> (bits - 5)) & 31]; bits -= 5; } } if (bits > 0) { result += alphabet[(value << (5 - bits)) & 31]; } return result; } function base32Decode(encoded: string): Uint8Array { const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; const cleanInput = encoded.toUpperCase().replace(/=+$/, ''); const result: number[] = []; let bits = 0; let value = 0; for (const char of cleanInput) { const index = alphabet.indexOf(char); if (index === -1) continue; value = (value << 5) | index; bits += 5; if (bits >= 8) { result.push((value >>> (bits - 8)) & 0xff); bits -= 8; } } return new Uint8Array(result); } function generateTOTPCode(secret: Uint8Array, counter: number): string { const buffer = Buffer.alloc(8); buffer.writeUInt32BE(0, 0); buffer.writeUInt32BE(counter, 4); const hmac = createHmac('sha1', Buffer.from(secret)); hmac.update(buffer); const hash = hmac.digest(); const offset = hash[hash.length - 1] & 0x0f; const code = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff); return (code % Math.pow(10, 6)).toString().padStart(6, '0'); } export function verifyTOTPCode(secret: string, code: string): boolean { const secretBytes = base32Decode(secret); const timeStep = Math.floor(Date.now() / 1000 / 30); for (let i = -1; i <= 1; i++) { if (generateTOTPCode(secretBytes, timeStep + i) === code) { return true; } } return false; } export async function setupTOTP(userId: string): Promise<{ success: boolean; secret?: string; otpauthUrl?: string; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (user.totpEnabled) { return { success: false, error: "2FA is already enabled" }; } const secretBytes = randomBytes(20); const base32secret = base32Encode(new Uint8Array(secretBytes)); const encryptedSecret = await oidc.encryptSecret(base32secret); user.totpSecret = encryptedSecret; user.updatedAt = new Date().toISOString(); db.updateUser(user); const otpauthUrl = `otpauth://totp/TheOneFileVerse:${user.email}?secret=${base32secret}&issuer=TheOneFileVerse&algorithm=SHA1&digits=6&period=30`; db.logAuthEvent('totp_setup_started', userId, null, {}); return { success: true, secret: base32secret, otpauthUrl }; } export async function verifyAndEnableTOTP(userId: string, code: string): Promise<{ success: boolean; backupCodes?: string[]; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (user.totpEnabled) { return { success: false, error: "2FA is already enabled" }; } if (!user.totpSecret) { return { success: false, error: "2FA setup not started" }; } const decryptedSecret = await oidc.decryptSecret(user.totpSecret); if (!verifyTOTPCode(decryptedSecret, code)) { return { success: false, error: "Invalid verification code" }; } const backupCodes: string[] = []; for (let i = 0; i < 10; i++) { backupCodes.push(randomBytes(8).toString('hex')); } const encryptedBackupCodes = await oidc.encryptSecret(JSON.stringify(backupCodes)); user.totpEnabled = true; user.totpBackupCodes = encryptedBackupCodes; user.updatedAt = new Date().toISOString(); db.updateUser(user); db.logAuthEvent('totp_enabled', userId, null, {}); return { success: true, backupCodes }; } export async function disableTOTP(userId: string, password: string): Promise<{ success: boolean; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } if (!user.totpEnabled) { return { success: false, error: "2FA is not enabled" }; } if (!user.passwordHash) { return { success: false, error: "Account uses SSO only" }; } const valid = await verifyPassword(password, user.passwordHash); if (!valid) { return { success: false, error: "Invalid password" }; } user.totpSecret = null; user.totpEnabled = false; user.totpBackupCodes = null; user.updatedAt = new Date().toISOString(); db.updateUser(user); db.logAuthEvent('totp_disabled', userId, null, {}); return { success: true }; } export async function verifyBackupCode(userId: string, code: string): Promise { const user = db.getUserById(userId); if (!user || !user.totpBackupCodes) { return false; } let backupCodes: string[]; try { const decrypted = await oidc.decryptSecret(user.totpBackupCodes); backupCodes = JSON.parse(decrypted); } catch { return false; } const normalizedCode = code.toLowerCase().trim(); const index = backupCodes.findIndex(c => c.toLowerCase() === normalizedCode); if (index === -1) { return false; } backupCodes.splice(index, 1); user.totpBackupCodes = await oidc.encryptSecret(JSON.stringify(backupCodes)); user.updatedAt = new Date().toISOString(); db.updateUser(user); db.logAuthEvent('backup_code_used', userId, null, { remainingCodes: backupCodes.length }); return true; } export async function loginWith2FA( pendingToken: string, totpCode: string, ipAddress: string, userAgent: string ): Promise<{ success: boolean; userId?: string; sessionToken?: string; error?: string }> { const tokenHash = await oidc.hashToken(pendingToken); const userToken = db.getUserTokenByHash(tokenHash); if (!userToken) { return { success: false, error: "Invalid or expired 2FA session" }; } if (userToken.type !== 'totp_pending') { return { success: false, error: "Invalid token type" }; } if (userToken.usedAt) { return { success: false, error: "Token already used" }; } if (new Date(userToken.expiresAt) < new Date()) { db.deleteUserToken(userToken.id); return { success: false, error: "2FA session expired" }; } if (userToken.failedAttempts >= 3) { db.deleteUserToken(userToken.id); return { success: false, error: "Too many failed attempts. Please log in again." }; } const user = db.getUserById(userToken.userId); if (!user || !user.isActive) { return { success: false, error: "User not found" }; } if (!user.totpSecret) { return { success: false, error: "2FA is not configured" }; } const decryptedSecret = await oidc.decryptSecret(user.totpSecret); let codeValid = verifyTOTPCode(decryptedSecret, totpCode); if (!codeValid) { codeValid = await verifyBackupCode(user.id, totpCode); } if (!codeValid) { const attempts = db.incrementTokenFailedAttempts(userToken.id); db.logAuthEvent('login_failed', user.id, ipAddress, { reason: 'invalid_2fa_code', attempts }); if (attempts >= 3) { db.deleteUserToken(userToken.id); return { success: false, error: "Too many failed attempts. Please log in again." }; } return { success: false, error: "Invalid 2FA code" }; } db.markUserTokenUsed(userToken.id); user.lastLogin = new Date().toISOString(); user.updatedAt = new Date().toISOString(); user.failedLoginAttempts = 0; user.lockedUntil = null; db.updateUser(user); const sessionToken = await createSessionToken(user.id, ipAddress, userAgent); db.logAuthEvent('login_success', user.id, ipAddress, { method: 'password_2fa' }); return { success: true, userId: user.id, sessionToken }; } export async function requestEmailChange( userId: string, newEmail: string, password: string, baseUrl: string ): Promise<{ success: boolean; error?: string }> { const user = db.getUserById(userId); if (!user) { return { success: false, error: "User not found" }; } const emailValidation = validateEmail(newEmail); if (!emailValidation.valid) { return { success: false, error: emailValidation.error }; } if (!user.passwordHash) { return { success: false, error: "Account uses SSO only" }; } const valid = await verifyPassword(password, user.passwordHash); if (!valid) { return { success: false, error: "Invalid password" }; } const normalizedNewEmail = newEmail.toLowerCase().trim(); const existing = db.getUserByEmail(normalizedNewEmail); if (existing) { return { success: false, error: "Email is already in use" }; } const token = oidc.generateSecureToken(32); const tokenHash = await oidc.hashToken(token); db.deleteUserTokensByType(user.id, 'email_change'); db.createUserToken({ id: crypto.randomUUID(), userId: user.id, type: 'email_change', tokenHash, expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), usedAt: null, createdAt: new Date().toISOString() }); user.pendingEmail = normalizedNewEmail; user.pendingEmailToken = tokenHash; user.updatedAt = new Date().toISOString(); db.updateUser(user); const verifyUrl = `${baseUrl}/auth/verify-email-change?token=${token}`; await mailer.sendVerificationEmail(normalizedNewEmail, user.displayName || 'User', verifyUrl); db.logAuthEvent('email_change_requested', userId, null, { newEmail: normalizedNewEmail }); return { success: true }; } export async function confirmEmailChange(token: string): Promise<{ success: boolean; error?: string }> { const tokenHash = await oidc.hashToken(token); const userToken = db.getUserTokenByHash(tokenHash); if (!userToken) { return { success: false, error: "Invalid or expired token" }; } if (userToken.type !== 'email_change') { return { success: false, error: "Invalid token type" }; } if (userToken.usedAt) { return { success: false, error: "Token already used" }; } if (new Date(userToken.expiresAt) < new Date()) { return { success: false, error: "Token expired" }; } const user = db.getUserById(userToken.userId); if (!user) { return { success: false, error: "User not found" }; } if (!user.pendingEmail) { return { success: false, error: "No email change pending" }; } const existing = db.getUserByEmail(user.pendingEmail); if (existing) { return { success: false, error: "Email is already in use" }; } const oldEmail = user.email; user.email = user.pendingEmail; user.pendingEmail = null; user.pendingEmailToken = null; user.updatedAt = new Date().toISOString(); db.updateUser(user); db.markUserTokenUsed(userToken.id); db.logAuthEvent('email_changed', user.id, null, { oldEmail, newEmail: user.email }); return { success: true }; } setInterval(() => { cleanupExpiredTokens(); }, 60 * 60 * 1000); ================================================ FILE: theonefile_verse/src/config.ts ================================================ import { readFileSync, existsSync } from "fs"; import { join } from "path"; import * as db from "./database"; import * as auth from "./auth"; import pkg from "../package.json"; export const APP_VERSION = pkg.version || "unknown"; export const PORT = parseInt(process.env.PORT || "10101"); export const DATA_DIR = process.env.DATA_DIR || "./data"; export const ROOMS_DIR = join(DATA_DIR, "rooms"); export const ADMIN_CONFIG_PATH = join(DATA_DIR, "admin.json"); export const SETTINGS_PATH = join(DATA_DIR, "settings.json"); export const ENV_UPDATE_INTERVAL = parseInt(process.env.UPDATE_INTERVAL || "0"); export const ENV_SKIP_UPDATE = process.env.SKIP_UPDATE === "true"; export const ENV_ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || ""; export const ENV_TRUSTED_PROXY_COUNT = process.env.TRUSTED_PROXY_COUNT ? parseInt(process.env.TRUSTED_PROXY_COUNT) : null; export const ENV_TRUSTED_PROXIES = process.env.TRUSTED_PROXIES ? process.env.TRUSTED_PROXIES.split(",").map(s => s.trim()).filter(Boolean) : null; export const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; export function isValidUUID(id: string): boolean { return UUID_REGEX.test(id); } export interface AdminConfig { passwordHash: string; createdAt: string; } export interface InstanceSettings { instancePasswordEnabled: boolean; instancePasswordHash: string | null; updateIntervalHours: number; skipUpdates: boolean; allowPublicRoomCreation: boolean; maxRoomsPerInstance: number; defaultDestructMode: "time" | "empty" | "never"; defaultDestructHours: number; forcedTheme: "user" | "dark" | "light"; rateLimitEnabled: boolean; rateLimitWindow: number; rateLimitMaxAttempts: number; chatEnabled: boolean; cursorSharingEnabled: boolean; nameChangeEnabled: boolean; webhookUrl: string | null; webhookEnabled: boolean; backupEnabled: boolean; backupIntervalHours: number; backupRetentionCount: number; adminPath: string; showAdminLink: boolean; trustedProxyCount: number; trustedProxies: string[]; defaultRoomTheme: string; forceWelcomeModal: boolean; probeEnabled: boolean; discoveryEnabled: boolean; discoveryAdminOnly: boolean; discoveryAllowPublicRanges: boolean; discoveryMaxPrefix: number; } export const defaultSettings: InstanceSettings = { instancePasswordEnabled: false, instancePasswordHash: null, updateIntervalHours: 0, skipUpdates: false, allowPublicRoomCreation: true, maxRoomsPerInstance: 0, defaultDestructMode: "time", defaultDestructHours: 24, forcedTheme: "user", rateLimitEnabled: true, rateLimitWindow: 60, rateLimitMaxAttempts: 10, chatEnabled: true, cursorSharingEnabled: true, nameChangeEnabled: true, webhookUrl: null, webhookEnabled: false, backupEnabled: false, backupIntervalHours: 24, backupRetentionCount: 7, adminPath: "admin", showAdminLink: true, trustedProxyCount: 1, trustedProxies: [], defaultRoomTheme: "", forceWelcomeModal: false, probeEnabled: true, discoveryEnabled: true, discoveryAdminOnly: true, discoveryAllowPublicRanges: false, discoveryMaxPrefix: 20 }; export function loadSettings(): InstanceSettings { const allSettings = db.getAllSettings(); if (Object.keys(allSettings).length === 0) { if (existsSync(SETTINGS_PATH)) { try { const saved = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8")); return { ...defaultSettings, ...saved }; } catch (e: any) { console.error("[Settings]", e.message); return { ...defaultSettings }; } } return { ...defaultSettings }; } const result = { ...defaultSettings }; for (const [key, value] of Object.entries(allSettings)) { try { (result as any)[key] = JSON.parse(value); } catch { (result as any)[key] = value; } } return result; } export function saveSettings(settings: InstanceSettings): void { for (const [key, value] of Object.entries(settings)) { db.setSetting(key, JSON.stringify(value)); } } let instanceSettings = loadSettings(); if (ENV_SKIP_UPDATE) instanceSettings.skipUpdates = true; if (ENV_UPDATE_INTERVAL > 0) instanceSettings.updateIntervalHours = ENV_UPDATE_INTERVAL; if (ENV_TRUSTED_PROXY_COUNT !== null) instanceSettings.trustedProxyCount = ENV_TRUSTED_PROXY_COUNT; if (ENV_TRUSTED_PROXIES !== null) instanceSettings.trustedProxies = ENV_TRUSTED_PROXIES; export function getSettings(): InstanceSettings { return instanceSettings; } export function updateSettings(s: InstanceSettings): void { instanceSettings = s; } export function reloadSettings(): void { instanceSettings = loadSettings(); } export function loadAdminConfig(): AdminConfig | null { const hash = db.getSetting("admin_password_hash"); const createdAt = db.getSetting("admin_created_at"); if (!hash) { if (existsSync(ADMIN_CONFIG_PATH)) { try { return JSON.parse(readFileSync(ADMIN_CONFIG_PATH, "utf-8")); } catch (e: any) { console.error("[Config]", e.message); return null; } } return null; } return { passwordHash: hash, createdAt: createdAt || new Date().toISOString() }; } export function saveAdminConfig(config: AdminConfig): void { db.setSetting("admin_password_hash", config.passwordHash); db.setSetting("admin_created_at", config.createdAt); } export function isAdminConfigured(): boolean { return !!ENV_ADMIN_PASSWORD || hasAdminUser() || getOldAdminPasswordHash() !== null; } export function needsAdminMigration(): boolean { return !hasAdminUser() && getOldAdminPasswordHash() !== null; } export function hasAdminUser(): boolean { return db.countUsersByRole('admin') > 0; } export function getOldAdminPasswordHash(): string | null { return db.getSetting('admin_password_hash'); } export async function verifyAdminPassword(password: string): Promise { if (ENV_ADMIN_PASSWORD) { const maxLen = Math.max(password.length, ENV_ADMIN_PASSWORD.length) + 4; const padded = Buffer.alloc(maxLen, 0); const expected = Buffer.alloc(maxLen, 0); const lenBuf1 = Buffer.alloc(4); const lenBuf2 = Buffer.alloc(4); lenBuf1.writeUInt32BE(password.length); lenBuf2.writeUInt32BE(ENV_ADMIN_PASSWORD.length); Buffer.from(password).copy(padded); lenBuf1.copy(padded, maxLen - 4); Buffer.from(ENV_ADMIN_PASSWORD).copy(expected); lenBuf2.copy(expected, maxLen - 4); return crypto.timingSafeEqual(padded, expected); } const config = loadAdminConfig(); if (!config) return false; return await auth.verifyPassword(password, config.passwordHash); } export async function verifyInstancePassword(password: string): Promise { if (!instanceSettings.instancePasswordEnabled || !instanceSettings.instancePasswordHash) return true; return await auth.verifyPassword(password, instanceSettings.instancePasswordHash); } export function isInstanceLocked(): boolean { return instanceSettings.instancePasswordEnabled && !!instanceSettings.instancePasswordHash; } export function getAdminPath(): string { const path = instanceSettings.adminPath || "admin"; const sanitized = path.replace(/[^a-zA-Z0-9_-]/g, ''); return sanitized || "admin"; } export function isCustomAdminPath(path: string): boolean { const adminPath = getAdminPath(); return path === `/${adminPath}` || path.startsWith(`/${adminPath}/`); } export function validateAdminPath(newPath: string): { valid: boolean; error?: string } { if (!newPath || newPath.length < 2) { return { valid: false, error: "Admin path must be at least 2 characters" }; } if (newPath.length > 50) { return { valid: false, error: "Admin path must be less than 50 characters" }; } if (!/^[a-zA-Z0-9_-]+$/.test(newPath)) { return { valid: false, error: "Admin path can only contain letters, numbers, hyphens, and underscores" }; } const reserved = ["api", "s", "ws", "auth", "public", "static", "assets"]; if (reserved.includes(newPath.toLowerCase())) { return { valid: false, error: "This path is reserved" }; } return { valid: true }; } export function isAdminRoute(path: string): boolean { return path === "/" || path === "/index.html" || path.startsWith("/s/") || path.startsWith("/ws/") || path.startsWith("/api/room"); } export function getExternalOrigin(req: Request): string { const fwdProto = req.headers.get("x-forwarded-proto"); const fwdHost = req.headers.get("x-forwarded-host"); if (fwdProto && fwdHost) { return `${fwdProto.split(",")[0].trim()}://${fwdHost.split(",")[0].trim()}`; } return new URL(req.url).origin; } ================================================ FILE: theonefile_verse/src/database.ts ================================================ import { Database } from "bun:sqlite"; import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync } from "fs"; import { join } from "path"; function sanitizeSearchQuery(query: string): string | null { if (query.length > 100) return null; return query.replace(/[%_\\]/g, '\\$&'); } const DATA_DIR = process.env.DATA_DIR || "./data"; const DB_PATH = join(DATA_DIR, "theonefile.db"); const ROOMS_DIR = join(DATA_DIR, "rooms"); const ADMIN_CONFIG_PATH = join(DATA_DIR, "admin.json"); const SETTINGS_PATH = join(DATA_DIR, "settings.json"); if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true }); const db = new Database(DB_PATH); db.exec("PRAGMA journal_mode = WAL"); db.exec("PRAGMA foreign_keys = ON"); function migrateAddColumn(table: string, column: string, definition: string) { try { const cols = db.prepare(`PRAGMA table_info(${table})`).all() as any[]; if (!cols.some((c: any) => c.name === column)) { db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`); } } catch (e: any) { console.error(`Migration error (${table}.${column}):`, e.message); } } db.exec(` CREATE TABLE IF NOT EXISTS rooms ( id TEXT PRIMARY KEY, created TEXT NOT NULL, last_activity TEXT NOT NULL, creator_id TEXT NOT NULL, password_hash TEXT, destruct_mode TEXT NOT NULL DEFAULT 'time', destruct_value INTEGER NOT NULL DEFAULT 86400000, topology TEXT, owner_user_id TEXT, allow_guests INTEGER NOT NULL DEFAULT 1 ) `); migrateAddColumn("rooms", "owner_user_id", "TEXT"); migrateAddColumn("rooms", "allow_guests", "INTEGER NOT NULL DEFAULT 1"); db.exec(` CREATE TABLE IF NOT EXISTS admin_settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL ) `); db.exec(` CREATE TABLE IF NOT EXISTS audit_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, action TEXT NOT NULL, actor TEXT, actor_ip TEXT, target_type TEXT, target_id TEXT, details TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_audit_logs_timestamp ON audit_logs(timestamp) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs(action) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_audit_logs_target ON audit_logs(target_type, target_id) `); db.exec(` CREATE TABLE IF NOT EXISTS activity_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, room_id TEXT NOT NULL, user_id TEXT, user_name TEXT, event_type TEXT NOT NULL, details TEXT, ip_address TEXT ) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_activity_logs_room ON activity_logs(room_id) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_activity_logs_timestamp ON activity_logs(timestamp) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_activity_logs_room_timestamp ON activity_logs(room_id, timestamp DESC) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_rooms_last_activity ON rooms(last_activity) `); db.exec(` CREATE INDEX IF NOT EXISTS idx_rooms_creator ON rooms(creator_id) `); db.exec(` CREATE TABLE IF NOT EXISTS api_keys ( id TEXT PRIMARY KEY, name TEXT NOT NULL, key_hash TEXT NOT NULL, permissions TEXT NOT NULL, created_at TEXT NOT NULL, last_used TEXT, expires_at TEXT, active INTEGER NOT NULL DEFAULT 1 ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash)`); db.exec(` CREATE TABLE IF NOT EXISTS backups ( id TEXT PRIMARY KEY, filename TEXT NOT NULL, created_at TEXT NOT NULL, size_bytes INTEGER NOT NULL, room_count INTEGER NOT NULL, auto_generated INTEGER NOT NULL DEFAULT 0 ) `); db.exec(` CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, email TEXT UNIQUE, email_verified INTEGER NOT NULL DEFAULT 0, display_name TEXT, avatar_url TEXT, password_hash TEXT, role TEXT NOT NULL DEFAULT 'user', created_at TEXT NOT NULL, updated_at TEXT NOT NULL, last_login TEXT, is_active INTEGER NOT NULL DEFAULT 1, failed_login_attempts INTEGER NOT NULL DEFAULT 0, locked_until TEXT ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_users_role ON users(role)`); migrateAddColumn("users", "failed_login_attempts", "INTEGER NOT NULL DEFAULT 0"); migrateAddColumn("users", "locked_until", "TEXT"); migrateAddColumn("users", "totp_secret", "TEXT"); migrateAddColumn("users", "totp_enabled", "INTEGER NOT NULL DEFAULT 0"); migrateAddColumn("users", "totp_backup_codes", "TEXT"); migrateAddColumn("users", "pending_email", "TEXT"); migrateAddColumn("users", "pending_email_token", "TEXT"); db.exec(` CREATE TABLE IF NOT EXISTS user_oidc_links ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, provider TEXT NOT NULL, provider_user_id TEXT NOT NULL, provider_email TEXT, access_token_encrypted TEXT, refresh_token_encrypted TEXT, token_expires_at TEXT, created_at TEXT NOT NULL, UNIQUE(provider, provider_user_id) ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_oidc_links_user ON user_oidc_links(user_id)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_oidc_links_provider ON user_oidc_links(provider, provider_user_id)`); db.exec(` CREATE TABLE IF NOT EXISTS user_sessions ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash TEXT UNIQUE NOT NULL, ip_address TEXT, user_agent TEXT, expires_at TEXT NOT NULL, created_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_user ON user_sessions(user_id)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_token ON user_sessions(token_hash)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_expires ON user_sessions(expires_at)`); db.exec(` CREATE TABLE IF NOT EXISTS user_tokens ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, type TEXT NOT NULL, token_hash TEXT UNIQUE NOT NULL, expires_at TEXT NOT NULL, used_at TEXT, created_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_user_tokens_hash ON user_tokens(token_hash)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_user_tokens_user ON user_tokens(user_id)`); migrateAddColumn("user_tokens", "failed_attempts", "INTEGER NOT NULL DEFAULT 0"); db.exec(` CREATE TABLE IF NOT EXISTS smtp_configs ( id TEXT PRIMARY KEY, name TEXT NOT NULL, provider_type TEXT NOT NULL, host TEXT, port INTEGER, secure_mode TEXT NOT NULL DEFAULT 'tls', username TEXT, password_encrypted TEXT, api_key_encrypted TEXT, from_email TEXT NOT NULL, from_name TEXT, is_default INTEGER NOT NULL DEFAULT 0, is_active INTEGER NOT NULL DEFAULT 1, allow_insecure_tls INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) `); migrateAddColumn("smtp_configs", "allow_insecure_tls", "INTEGER NOT NULL DEFAULT 0"); db.exec(` CREATE TABLE IF NOT EXISTS oidc_providers ( id TEXT PRIMARY KEY, name TEXT NOT NULL, provider_type TEXT NOT NULL, client_id TEXT NOT NULL, client_secret_encrypted TEXT NOT NULL, issuer_url TEXT, authorization_url TEXT, token_url TEXT, userinfo_url TEXT, jwks_uri TEXT, scopes TEXT NOT NULL DEFAULT 'openid email profile', is_active INTEGER NOT NULL DEFAULT 1, display_order INTEGER NOT NULL DEFAULT 0, icon_url TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) `); db.exec(` CREATE TABLE IF NOT EXISTS user_preferences ( user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, theme TEXT DEFAULT 'system', email_notifications INTEGER NOT NULL DEFAULT 1, default_room_settings TEXT ) `); db.exec(` CREATE TABLE IF NOT EXISTS email_templates ( id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE, subject TEXT NOT NULL, body_html TEXT NOT NULL, body_text TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL ) `); db.exec(` CREATE TABLE IF NOT EXISTS email_logs ( id TEXT PRIMARY KEY, to_email TEXT NOT NULL, template_name TEXT, subject TEXT NOT NULL, status TEXT NOT NULL, error_message TEXT, smtp_config_id TEXT, sent_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_email_logs_date ON email_logs(sent_at)`); db.exec(`CREATE INDEX IF NOT EXISTS idx_email_logs_status ON email_logs(status)`); db.exec(` CREATE TABLE IF NOT EXISTS oidc_states ( state TEXT PRIMARY KEY, provider_id TEXT NOT NULL, code_verifier TEXT NOT NULL, nonce TEXT NOT NULL, redirect_uri TEXT NOT NULL, link_user_id TEXT, post_login_redirect TEXT, created_at TEXT NOT NULL, expires_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_oidc_states_expires ON oidc_states(expires_at)`); migrateAddColumn("oidc_states", "post_login_redirect", "TEXT"); db.exec(` CREATE TABLE IF NOT EXISTS csrf_tokens ( token TEXT PRIMARY KEY, used INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL, expires_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_csrf_tokens_expires ON csrf_tokens(expires_at)`); db.exec(` CREATE TABLE IF NOT EXISTS email_rate_limits ( id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT NOT NULL, action TEXT NOT NULL, created_at TEXT NOT NULL ) `); db.exec(`CREATE INDEX IF NOT EXISTS idx_email_rate_limits_lookup ON email_rate_limits(email, action, created_at)`); export interface OidcState { state: string; providerId: string; codeVerifier: string; nonce: string; redirectUri: string; linkUserId: string | null; postLoginRedirect: string | null; createdAt: string; expiresAt: string; } export interface CsrfToken { token: string; used: boolean; createdAt: string; expiresAt: string; } export interface Room { id: string; created: string; lastActivity: string; creatorId: string; passwordHash: string | null; destruct: { mode: "time" | "empty" | "never"; value: number }; topology: any; ownerUserId: string | null; allowGuests: boolean; } export interface AuditLog { id?: number; timestamp: string; action: string; actor?: string; actorIp?: string; targetType?: string; targetId?: string; details?: any; } export interface ActivityLog { id?: number; timestamp: string; roomId: string; userId?: string; userName?: string; eventType: string; details?: any; ipAddress?: string; } export interface ApiKey { id: string; name: string; keyHash: string; permissions: string[]; createdAt: string; lastUsed?: string; expiresAt?: string; active: boolean; } export interface Backup { id: string; filename: string; createdAt: string; sizeBytes: number; roomCount: number; autoGenerated: boolean; } export interface User { id: string; email: string | null; emailVerified: boolean; displayName: string | null; avatarUrl: string | null; passwordHash: string | null; role: 'admin' | 'user' | 'guest'; createdAt: string; updatedAt: string; lastLogin: string | null; isActive: boolean; failedLoginAttempts: number; lockedUntil: string | null; totpSecret: string | null; totpEnabled: boolean; totpBackupCodes: string | null; pendingEmail: string | null; pendingEmailToken: string | null; } export interface UserOidcLink { id: string; userId: string; provider: string; providerUserId: string; providerEmail: string | null; accessTokenEncrypted: string | null; refreshTokenEncrypted: string | null; tokenExpiresAt: string | null; createdAt: string; } export interface UserSession { id: string; userId: string; tokenHash: string; ipAddress: string | null; userAgent: string | null; expiresAt: string; createdAt: string; } export interface UserToken { id: string; userId: string; type: 'email_verify' | 'password_reset' | 'magic_link' | 'totp_pending' | 'email_change'; tokenHash: string; expiresAt: string; usedAt: string | null; createdAt: string; failedAttempts: number; } export interface SmtpConfig { id: string; name: string; providerType: string; host: string | null; port: number | null; secureMode: 'none' | 'tls' | 'starttls'; username: string | null; passwordEncrypted: string | null; apiKeyEncrypted: string | null; fromEmail: string; fromName: string | null; isDefault: boolean; isActive: boolean; allowInsecureTls: boolean; createdAt: string; updatedAt: string; } export interface OidcProvider { id: string; name: string; providerType: string; clientId: string; clientSecretEncrypted: string; issuerUrl: string | null; authorizationUrl: string | null; tokenUrl: string | null; userinfoUrl: string | null; jwksUri: string | null; scopes: string; isActive: boolean; displayOrder: number; iconUrl: string | null; createdAt: string; updatedAt: string; } export interface UserPreferences { userId: string; theme: string; emailNotifications: boolean; defaultRoomSettings: any; } export interface EmailTemplate { id: string; name: string; subject: string; bodyHtml: string; bodyText: string; createdAt: string; updatedAt: string; } export interface EmailLog { id: string; toEmail: string; templateName: string | null; subject: string; status: 'sent' | 'failed' | 'pending'; errorMessage: string | null; smtpConfigId: string | null; sentAt: string; } const stmtInsertRoom = db.prepare(` INSERT INTO rooms (id, created, last_activity, creator_id, password_hash, destruct_mode, destruct_value, topology, owner_user_id, allow_guests) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtUpdateRoom = db.prepare(` UPDATE rooms SET last_activity = ?, topology = ? WHERE id = ? `); const stmtUpdateRoomSettings = db.prepare(` UPDATE rooms SET allow_guests = ?, owner_user_id = ? WHERE id = ? `); const stmtGetRoom = db.prepare(` SELECT * FROM rooms WHERE id = ? `); const stmtDeleteRoom = db.prepare(` DELETE FROM rooms WHERE id = ? `); const stmtListRooms = db.prepare(` SELECT * FROM rooms ORDER BY created DESC `); const stmtListRoomsPaginated = db.prepare(` SELECT * FROM rooms ORDER BY created DESC LIMIT ? OFFSET ? `); const stmtSearchRooms = db.prepare(` SELECT * FROM rooms WHERE id LIKE ? ESCAPE '\\' OR creator_id LIKE ? ESCAPE '\\' ORDER BY created DESC LIMIT ? OFFSET ? `); const stmtCountRooms = db.prepare(` SELECT COUNT(*) as count FROM rooms `); const stmtGetSetting = db.prepare(` SELECT value FROM admin_settings WHERE key = ? `); const stmtSetSetting = db.prepare(` INSERT OR REPLACE INTO admin_settings (key, value) VALUES (?, ?) `); const stmtDeleteSetting = db.prepare(` DELETE FROM admin_settings WHERE key = ? `); const stmtGetAllSettings = db.prepare(` SELECT key, value FROM admin_settings `); const stmtInsertAuditLog = db.prepare(` INSERT INTO audit_logs (timestamp, action, actor, actor_ip, target_type, target_id, details) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetAuditLogs = db.prepare(` SELECT * FROM audit_logs ORDER BY timestamp DESC LIMIT ? OFFSET ? `); const stmtSearchAuditLogs = db.prepare(` SELECT * FROM audit_logs WHERE action LIKE ? ESCAPE '\\' OR actor LIKE ? ESCAPE '\\' OR target_id LIKE ? ESCAPE '\\' ORDER BY timestamp DESC LIMIT ? OFFSET ? `); const stmtInsertActivityLog = db.prepare(` INSERT INTO activity_logs (timestamp, room_id, user_id, user_name, event_type, details, ip_address) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetActivityLogs = db.prepare(` SELECT * FROM activity_logs WHERE room_id = ? ORDER BY timestamp DESC LIMIT ? OFFSET ? `); const stmtGetAllActivityLogs = db.prepare(` SELECT * FROM activity_logs ORDER BY timestamp DESC LIMIT ? OFFSET ? `); const stmtInsertApiKey = db.prepare(` INSERT INTO api_keys (id, name, key_hash, permissions, created_at, expires_at, active) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetApiKey = db.prepare(` SELECT * FROM api_keys WHERE id = ? AND active = 1 `); const stmtGetApiKeyByHash = db.prepare(` SELECT * FROM api_keys WHERE key_hash = ? AND active = 1 `); const stmtUpdateApiKeyLastUsed = db.prepare(` UPDATE api_keys SET last_used = ? WHERE id = ? `); const stmtListApiKeys = db.prepare(` SELECT id, name, permissions, created_at, last_used, expires_at, active FROM api_keys ORDER BY created_at DESC `); const stmtDeactivateApiKey = db.prepare(` UPDATE api_keys SET active = 0 WHERE id = ? `); const stmtInsertBackup = db.prepare(` INSERT INTO backups (id, filename, created_at, size_bytes, room_count, auto_generated) VALUES (?, ?, ?, ?, ?, ?) `); const stmtListBackups = db.prepare(` SELECT * FROM backups ORDER BY created_at DESC `); const stmtDeleteBackup = db.prepare(` DELETE FROM backups WHERE id = ? `); const stmtGetOldAutoBackups = db.prepare(` SELECT * FROM backups WHERE auto_generated = 1 ORDER BY created_at DESC LIMIT -1 OFFSET ? `); function rowToRoom(row: any): Room | null { if (!row) return null; return { id: row.id, created: row.created, lastActivity: row.last_activity, creatorId: row.creator_id, passwordHash: row.password_hash, destruct: { mode: row.destruct_mode, value: row.destruct_value }, topology: row.topology ? JSON.parse(row.topology) : null, ownerUserId: row.owner_user_id || null, allowGuests: row.allow_guests !== 0 }; } export function createRoom(room: Room): void { stmtInsertRoom.run( room.id, room.created, room.lastActivity, room.creatorId, room.passwordHash, room.destruct.mode, room.destruct.value, room.topology ? JSON.stringify(room.topology) : null, room.ownerUserId || null, room.allowGuests ? 1 : 0 ); } export function getRoom(id: string): Room | null { return rowToRoom(stmtGetRoom.get(id)); } export function updateRoom(id: string, lastActivity: string, topology: any): void { stmtUpdateRoom.run(lastActivity, topology ? JSON.stringify(topology) : null, id); } export function updateRoomSettings(id: string, allowGuests: boolean, ownerUserId: string | null): void { stmtUpdateRoomSettings.run(allowGuests ? 1 : 0, ownerUserId, id); } export function deleteRoom(id: string): boolean { const result = stmtDeleteRoom.run(id); return result.changes > 0; } export function listRooms(limit?: number, offset?: number): Room[] { if (limit !== undefined) { return (stmtListRoomsPaginated.all(limit, offset || 0) as any[]).map(rowToRoom).filter(r => r !== null) as Room[]; } return (stmtListRooms.all() as any[]).map(rowToRoom).filter(r => r !== null) as Room[]; } export function searchRooms(query: string, limit: number = 50, offset: number = 0): Room[] { const sanitized = sanitizeSearchQuery(query); if (!sanitized) return []; const searchPattern = `%${sanitized}%`; return (stmtSearchRooms.all(searchPattern, searchPattern, limit, offset) as any[]) .map(rowToRoom) .filter(r => r !== null) as Room[]; } export function countRooms(): number { const result = stmtCountRooms.get() as { count: number }; return result.count; } export function getSetting(key: string): string | null { const row = stmtGetSetting.get(key) as { value: string } | undefined; return row?.value ?? null; } export function setSetting(key: string, value: string): void { stmtSetSetting.run(key, value); } export function deleteSetting(key: string): void { stmtDeleteSetting.run(key); } export function getAllSettings(): Record { const rows = stmtGetAllSettings.all() as { key: string; value: string }[]; const result: Record = {}; for (const row of rows) { result[row.key] = row.value; } return result; } export function addAuditLog(log: AuditLog): void { stmtInsertAuditLog.run( log.timestamp, log.action, log.actor || null, log.actorIp || null, log.targetType || null, log.targetId || null, log.details ? JSON.stringify(log.details) : null ); } export function getAuditLogs(limit: number = 100, offset: number = 0): AuditLog[] { return (stmtGetAuditLogs.all(limit, offset) as any[]).map(row => ({ id: row.id, timestamp: row.timestamp, action: row.action, actor: row.actor, actorIp: row.actor_ip, targetType: row.target_type, targetId: row.target_id, details: row.details ? JSON.parse(row.details) : null })); } export function searchAuditLogs(query: string, limit: number = 100, offset: number = 0): AuditLog[] { const sanitized = sanitizeSearchQuery(query); if (!sanitized) return []; const searchPattern = `%${sanitized}%`; return (stmtSearchAuditLogs.all(searchPattern, searchPattern, searchPattern, limit, offset) as any[]).map(row => ({ id: row.id, timestamp: row.timestamp, action: row.action, actor: row.actor, actorIp: row.actor_ip, targetType: row.target_type, targetId: row.target_id, details: row.details ? JSON.parse(row.details) : null })); } export function addActivityLog(log: ActivityLog): void { stmtInsertActivityLog.run( log.timestamp, log.roomId, log.userId || null, log.userName || null, log.eventType, log.details ? JSON.stringify(log.details) : null, log.ipAddress || null ); } export function getActivityLogs(roomId: string, limit: number = 100, offset: number = 0): ActivityLog[] { return (stmtGetActivityLogs.all(roomId, limit, offset) as any[]).map(row => ({ id: row.id, timestamp: row.timestamp, roomId: row.room_id, userId: row.user_id, userName: row.user_name, eventType: row.event_type, details: row.details ? JSON.parse(row.details) : null, ipAddress: row.ip_address })); } export function getAllActivityLogs(limit: number = 100, offset: number = 0): ActivityLog[] { return (stmtGetAllActivityLogs.all(limit, offset) as any[]).map(row => ({ id: row.id, timestamp: row.timestamp, roomId: row.room_id, userId: row.user_id, userName: row.user_name, eventType: row.event_type, details: row.details ? JSON.parse(row.details) : null, ipAddress: row.ip_address })); } export function createApiKey(apiKey: ApiKey): void { stmtInsertApiKey.run( apiKey.id, apiKey.name, apiKey.keyHash, JSON.stringify(apiKey.permissions), apiKey.createdAt, apiKey.expiresAt || null, apiKey.active ? 1 : 0 ); } export function getApiKeyById(id: string): ApiKey | null { const row = stmtGetApiKey.get(id) as any; if (!row) return null; return { id: row.id, name: row.name, keyHash: row.key_hash, permissions: (() => { try { return row.permissions ? JSON.parse(row.permissions) : []; } catch { return []; } })(), createdAt: row.created_at, lastUsed: row.last_used, expiresAt: row.expires_at, active: row.active === 1 }; } export function getApiKeyByHash(hash: string): ApiKey | null { const row = stmtGetApiKeyByHash.get(hash) as any; if (!row) return null; return { id: row.id, name: row.name, keyHash: row.key_hash, permissions: (() => { try { return row.permissions ? JSON.parse(row.permissions) : []; } catch { return []; } })(), createdAt: row.created_at, lastUsed: row.last_used, expiresAt: row.expires_at, active: row.active === 1 }; } export function updateApiKeyLastUsed(id: string): void { stmtUpdateApiKeyLastUsed.run(new Date().toISOString(), id); } export function listApiKeys(): Omit[] { return (stmtListApiKeys.all() as any[]).map(row => ({ id: row.id, name: row.name, permissions: (() => { try { return row.permissions ? JSON.parse(row.permissions) : []; } catch { return []; } })(), createdAt: row.created_at, lastUsed: row.last_used, expiresAt: row.expires_at, active: row.active === 1 })); } export function deactivateApiKey(id: string): boolean { const result = stmtDeactivateApiKey.run(id); return result.changes > 0; } export function createBackupRecord(backup: Backup): void { stmtInsertBackup.run( backup.id, backup.filename, backup.createdAt, backup.sizeBytes, backup.roomCount, backup.autoGenerated ? 1 : 0 ); } export function listBackups(): Backup[] { return (stmtListBackups.all() as any[]).map(row => ({ id: row.id, filename: row.filename, createdAt: row.created_at, sizeBytes: row.size_bytes, roomCount: row.room_count, autoGenerated: row.auto_generated === 1 })); } export function deleteBackupRecord(id: string): boolean { const result = stmtDeleteBackup.run(id); return result.changes > 0; } export function getOldAutoBackups(keepCount: number): Backup[] { return (stmtGetOldAutoBackups.all(keepCount) as any[]).map(row => ({ id: row.id, filename: row.filename, createdAt: row.created_at, sizeBytes: row.size_bytes, roomCount: row.room_count, autoGenerated: row.auto_generated === 1 })); } export function migrateFromFlatFiles(): { rooms: number; settings: boolean; admin: boolean } { let roomsMigrated = 0; let settingsMigrated = false; let adminMigrated = false; if (existsSync(ROOMS_DIR)) { const files = readdirSync(ROOMS_DIR).filter(f => f.endsWith(".json")); for (const file of files) { try { const roomPath = join(ROOMS_DIR, file); const roomData = JSON.parse(readFileSync(roomPath, "utf-8")); const existing = getRoom(roomData.id); if (!existing) { createRoom({ id: roomData.id, created: roomData.created, lastActivity: roomData.lastActivity, creatorId: roomData.creatorId, passwordHash: roomData.passwordHash, destruct: roomData.destruct, topology: roomData.topology }); roomsMigrated++; } unlinkSync(roomPath); } catch (e) { console.error(`Failed to migrate room ${file}:`, e); } } } if (existsSync(SETTINGS_PATH)) { try { const settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8")); for (const [key, value] of Object.entries(settings)) { setSetting(key, JSON.stringify(value)); } unlinkSync(SETTINGS_PATH); settingsMigrated = true; } catch (e) { console.error("Failed to migrate settings:", e); } } if (existsSync(ADMIN_CONFIG_PATH)) { try { const adminConfig = JSON.parse(readFileSync(ADMIN_CONFIG_PATH, "utf-8")); setSetting("admin_password_hash", adminConfig.passwordHash); setSetting("admin_created_at", adminConfig.createdAt); unlinkSync(ADMIN_CONFIG_PATH); adminMigrated = true; } catch (e) { console.error("Failed to migrate admin config:", e); } } return { rooms: roomsMigrated, settings: settingsMigrated, admin: adminMigrated }; } export function getDatabase(): Database { return db; } export function closeDatabase(): void { db.close(); } export function healthCheck(): boolean { try { db.prepare("SELECT 1").get(); return true; } catch { return false; } } export function logAuthEvent( action: string, userId: string | null, ipAddress: string | null, details?: Record ): void { addAuditLog({ timestamp: new Date().toISOString(), action: `auth:${action}`, actor: userId, actorIp: ipAddress, targetType: 'user', targetId: userId, details: details }); } const stmtInsertUser = db.prepare(` INSERT INTO users (id, email, email_verified, display_name, avatar_url, password_hash, role, created_at, updated_at, last_login, is_active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtGetUserById = db.prepare(`SELECT * FROM users WHERE id = ?`); const stmtGetUserByEmail = db.prepare(`SELECT * FROM users WHERE email = ? COLLATE NOCASE`); const stmtUpdateUser = db.prepare(` UPDATE users SET email = ?, email_verified = ?, display_name = ?, avatar_url = ?, password_hash = ?, role = ?, updated_at = ?, last_login = ?, is_active = ?, failed_login_attempts = ?, locked_until = ?, totp_secret = ?, totp_enabled = ?, totp_backup_codes = ?, pending_email = ?, pending_email_token = ? WHERE id = ? `); const stmtIncrementFailedLogin = db.prepare(`UPDATE users SET failed_login_attempts = failed_login_attempts + 1, updated_at = ? WHERE id = ?`); const stmtResetFailedLogin = db.prepare(`UPDATE users SET failed_login_attempts = 0, locked_until = NULL, updated_at = ? WHERE id = ?`); const stmtLockUser = db.prepare(`UPDATE users SET locked_until = ?, updated_at = ? WHERE id = ?`); const stmtDeleteUser = db.prepare(`DELETE FROM users WHERE id = ?`); const stmtListUsers = db.prepare(`SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?`); const stmtListUsersByRole = db.prepare(`SELECT * FROM users WHERE role = ? ORDER BY created_at DESC`); const stmtSearchUsers = db.prepare(`SELECT * FROM users WHERE email LIKE ? ESCAPE '\\' OR display_name LIKE ? ESCAPE '\\' ORDER BY created_at DESC LIMIT ? OFFSET ?`); const stmtCountUsers = db.prepare(`SELECT COUNT(*) as count FROM users`); const stmtCountUsersByRole = db.prepare(`SELECT COUNT(*) as count FROM users WHERE role = ?`); function rowToUser(row: any): User | null { if (!row) return null; return { id: row.id, email: row.email, emailVerified: row.email_verified === 1, displayName: row.display_name, avatarUrl: row.avatar_url, passwordHash: row.password_hash, role: row.role, createdAt: row.created_at, updatedAt: row.updated_at, lastLogin: row.last_login, isActive: row.is_active === 1, failedLoginAttempts: row.failed_login_attempts || 0, lockedUntil: row.locked_until, totpSecret: row.totp_secret || null, totpEnabled: row.totp_enabled === 1, totpBackupCodes: row.totp_backup_codes || null, pendingEmail: row.pending_email || null, pendingEmailToken: row.pending_email_token || null }; } export function createUser(user: User): void { stmtInsertUser.run( user.id, user.email, user.emailVerified ? 1 : 0, user.displayName, user.avatarUrl, user.passwordHash, user.role, user.createdAt, user.updatedAt, user.lastLogin, user.isActive ? 1 : 0 ); } export function createUserAtomic(user: User): { created: boolean; wasFirst: boolean } { db.run('BEGIN IMMEDIATE'); try { const count = countUsers(); const wasFirst = count === 0; if (wasFirst) { user.role = 'admin'; user.emailVerified = true; } createUser(user); db.run('COMMIT'); return { created: true, wasFirst }; } catch (e) { db.run('ROLLBACK'); throw e; } } export function getUserById(id: string): User | null { return rowToUser(stmtGetUserById.get(id)); } export function getUserByEmail(email: string): User | null { return rowToUser(stmtGetUserByEmail.get(email)); } export function updateUser(user: User): void { stmtUpdateUser.run( user.email, user.emailVerified ? 1 : 0, user.displayName, user.avatarUrl, user.passwordHash, user.role, user.updatedAt, user.lastLogin, user.isActive ? 1 : 0, user.failedLoginAttempts, user.lockedUntil, user.totpSecret, user.totpEnabled ? 1 : 0, user.totpBackupCodes, user.pendingEmail, user.pendingEmailToken, user.id ); } export function incrementFailedLogin(userId: string): void { stmtIncrementFailedLogin.run(new Date().toISOString(), userId); } export function resetFailedLogin(userId: string): void { stmtResetFailedLogin.run(new Date().toISOString(), userId); } export function lockUserAccount(userId: string, until: Date): void { stmtLockUser.run(until.toISOString(), new Date().toISOString(), userId); } export function deleteUser(id: string): boolean { return stmtDeleteUser.run(id).changes > 0; } export function listUsers(limit: number = 100, offset: number = 0): User[] { return (stmtListUsers.all(limit, offset) as any[]).map(rowToUser).filter(u => u !== null) as User[]; } export function searchUsers(query: string, limit: number = 100, offset: number = 0): User[] { const sanitized = sanitizeSearchQuery(query); if (!sanitized) return []; const pattern = `%${sanitized}%`; return (stmtSearchUsers.all(pattern, pattern, limit, offset) as any[]).map(rowToUser).filter(u => u !== null) as User[]; } export function countUsers(): number { return (stmtCountUsers.get() as { count: number }).count; } export function countUsersByRole(role: string): number { return (stmtCountUsersByRole.get(role) as { count: number }).count; } export function listUsersByRole(role: string): User[] { return (stmtListUsersByRole.all(role) as any[]).map(rowToUser).filter(u => u !== null) as User[]; } const stmtVerifyAdminEmails = db.prepare(`UPDATE users SET email_verified = 1, updated_at = ? WHERE role = 'admin' AND email_verified = 0`); export function verifyAllAdminEmails(): number { return stmtVerifyAdminEmails.run(new Date().toISOString()).changes; } const stmtInsertSession = db.prepare(` INSERT INTO user_sessions (id, user_id, token_hash, ip_address, user_agent, expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetSessionByToken = db.prepare(`SELECT * FROM user_sessions WHERE token_hash = ?`); const stmtGetSessionsByUser = db.prepare(`SELECT * FROM user_sessions WHERE user_id = ? ORDER BY created_at DESC`); const stmtDeleteSession = db.prepare(`DELETE FROM user_sessions WHERE id = ?`); const stmtDeleteSessionByToken = db.prepare(`DELETE FROM user_sessions WHERE token_hash = ?`); const stmtDeleteSessionsByUser = db.prepare(`DELETE FROM user_sessions WHERE user_id = ?`); const stmtDeleteExpiredSessions = db.prepare(`DELETE FROM user_sessions WHERE expires_at < ?`); function rowToSession(row: any): UserSession | null { if (!row) return null; return { id: row.id, userId: row.user_id, tokenHash: row.token_hash, ipAddress: row.ip_address, userAgent: row.user_agent, expiresAt: row.expires_at, createdAt: row.created_at }; } export function createUserSession(session: UserSession): void { stmtInsertSession.run(session.id, session.userId, session.tokenHash, session.ipAddress, session.userAgent, session.expiresAt, session.createdAt); } export function getSessionByTokenHash(tokenHash: string): UserSession | null { return rowToSession(stmtGetSessionByToken.get(tokenHash)); } export function getSessionsByUserId(userId: string): UserSession[] { return (stmtGetSessionsByUser.all(userId) as any[]).map(rowToSession).filter(s => s !== null) as UserSession[]; } export function deleteSession(id: string): boolean { return stmtDeleteSession.run(id).changes > 0; } export function deleteSessionByTokenHash(tokenHash: string): boolean { return stmtDeleteSessionByToken.run(tokenHash).changes > 0; } export function deleteAllUserSessions(userId: string): number { return stmtDeleteSessionsByUser.run(userId).changes; } export function cleanupExpiredSessions(): number { return stmtDeleteExpiredSessions.run(new Date().toISOString()).changes; } export const getUserSessionByTokenHash = getSessionByTokenHash; export const deleteUserSession = deleteSession; const stmtInsertUserToken = db.prepare(` INSERT INTO user_tokens (id, user_id, type, token_hash, expires_at, used_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetUserTokenByHash = db.prepare(`SELECT * FROM user_tokens WHERE token_hash = ?`); const stmtMarkUserTokenUsed = db.prepare(`UPDATE user_tokens SET used_at = ? WHERE id = ?`); const stmtDeleteUserToken = db.prepare(`DELETE FROM user_tokens WHERE id = ?`); const stmtDeleteExpiredUserTokens = db.prepare(`DELETE FROM user_tokens WHERE expires_at < ?`); const stmtDeleteUserTokensByUser = db.prepare(`DELETE FROM user_tokens WHERE user_id = ? AND type = ?`); const stmtIncrementTokenFailedAttempts = db.prepare(`UPDATE user_tokens SET failed_attempts = failed_attempts + 1 WHERE id = ?`); const stmtGetTokenFailedAttempts = db.prepare(`SELECT failed_attempts FROM user_tokens WHERE id = ?`); function rowToUserToken(row: any): UserToken | null { if (!row) return null; return { id: row.id, userId: row.user_id, type: row.type, tokenHash: row.token_hash, expiresAt: row.expires_at, usedAt: row.used_at, createdAt: row.created_at, failedAttempts: row.failed_attempts || 0 }; } export function createUserToken(token: UserToken): void { stmtInsertUserToken.run(token.id, token.userId, token.type, token.tokenHash, token.expiresAt, token.usedAt, token.createdAt); } export function getUserTokenByHash(tokenHash: string): UserToken | null { return rowToUserToken(stmtGetUserTokenByHash.get(tokenHash)); } export function markUserTokenUsed(id: string): void { stmtMarkUserTokenUsed.run(new Date().toISOString(), id); } export function incrementTokenFailedAttempts(id: string): number { stmtIncrementTokenFailedAttempts.run(id); const row = stmtGetTokenFailedAttempts.get(id) as any; return row ? row.failed_attempts : 0; } export function deleteUserToken(id: string): boolean { return stmtDeleteUserToken.run(id).changes > 0; } export function deleteUserTokensByType(userId: string, type: string): number { return stmtDeleteUserTokensByUser.run(userId, type).changes; } export function cleanupExpiredUserTokens(): number { return stmtDeleteExpiredUserTokens.run(new Date().toISOString()).changes; } const stmtInsertOidcLink = db.prepare(` INSERT INTO user_oidc_links (id, user_id, provider, provider_user_id, provider_email, access_token_encrypted, refresh_token_encrypted, token_expires_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtGetOidcLinkById = db.prepare(`SELECT * FROM user_oidc_links WHERE id = ?`); const stmtGetOidcLinkByProvider = db.prepare(`SELECT * FROM user_oidc_links WHERE provider = ? AND provider_user_id = ?`); const stmtGetOidcLinksByUser = db.prepare(`SELECT * FROM user_oidc_links WHERE user_id = ?`); const stmtDeleteOidcLink = db.prepare(`DELETE FROM user_oidc_links WHERE id = ?`); const stmtUpdateOidcLinkTokens = db.prepare(`UPDATE user_oidc_links SET access_token_encrypted = ?, refresh_token_encrypted = ?, token_expires_at = ? WHERE id = ?`); function rowToOidcLink(row: any): UserOidcLink | null { if (!row) return null; return { id: row.id, userId: row.user_id, provider: row.provider, providerUserId: row.provider_user_id, providerEmail: row.provider_email, accessTokenEncrypted: row.access_token_encrypted, refreshTokenEncrypted: row.refresh_token_encrypted, tokenExpiresAt: row.token_expires_at, createdAt: row.created_at }; } export function createOidcLink(link: UserOidcLink): void { stmtInsertOidcLink.run(link.id, link.userId, link.provider, link.providerUserId, link.providerEmail, link.accessTokenEncrypted, link.refreshTokenEncrypted, link.tokenExpiresAt, link.createdAt); } export function getOidcLinkById(id: string): UserOidcLink | null { return rowToOidcLink(stmtGetOidcLinkById.get(id)); } export function getOidcLinkByProvider(provider: string, providerUserId: string): UserOidcLink | null { return rowToOidcLink(stmtGetOidcLinkByProvider.get(provider, providerUserId)); } export function getOidcLinksByUser(userId: string): UserOidcLink[] { return (stmtGetOidcLinksByUser.all(userId) as any[]).map(rowToOidcLink).filter(l => l !== null) as UserOidcLink[]; } export function deleteOidcLink(id: string): boolean { return stmtDeleteOidcLink.run(id).changes > 0; } export function updateOidcLinkTokens(id: string, accessToken: string | null, refreshToken: string | null, expiresAt: string | null): void { stmtUpdateOidcLinkTokens.run(accessToken, refreshToken, expiresAt, id); } const stmtInsertOidcProvider = db.prepare(` INSERT INTO oidc_providers (id, name, provider_type, client_id, client_secret_encrypted, issuer_url, authorization_url, token_url, userinfo_url, jwks_uri, scopes, is_active, display_order, icon_url, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtGetOidcProvider = db.prepare(`SELECT * FROM oidc_providers WHERE id = ?`); const stmtGetOidcProviderByName = db.prepare(`SELECT * FROM oidc_providers WHERE name = ?`); const stmtListOidcProviders = db.prepare(`SELECT * FROM oidc_providers ORDER BY display_order ASC, name ASC`); const stmtListActiveOidcProviders = db.prepare(`SELECT * FROM oidc_providers WHERE is_active = 1 ORDER BY display_order ASC, name ASC`); const stmtUpdateOidcProvider = db.prepare(` UPDATE oidc_providers SET name = ?, provider_type = ?, client_id = ?, client_secret_encrypted = ?, issuer_url = ?, authorization_url = ?, token_url = ?, userinfo_url = ?, jwks_uri = ?, scopes = ?, is_active = ?, display_order = ?, icon_url = ?, updated_at = ? WHERE id = ? `); const stmtDeleteOidcProvider = db.prepare(`DELETE FROM oidc_providers WHERE id = ?`); function rowToOidcProvider(row: any): OidcProvider | null { if (!row) return null; return { id: row.id, name: row.name, providerType: row.provider_type, clientId: row.client_id, clientSecretEncrypted: row.client_secret_encrypted, issuerUrl: row.issuer_url, authorizationUrl: row.authorization_url, tokenUrl: row.token_url, userinfoUrl: row.userinfo_url, jwksUri: row.jwks_uri, scopes: row.scopes, isActive: row.is_active === 1, displayOrder: row.display_order, iconUrl: row.icon_url, createdAt: row.created_at, updatedAt: row.updated_at }; } export function createOidcProvider(provider: OidcProvider): void { stmtInsertOidcProvider.run( provider.id, provider.name, provider.providerType, provider.clientId, provider.clientSecretEncrypted, provider.issuerUrl, provider.authorizationUrl, provider.tokenUrl, provider.userinfoUrl, provider.jwksUri, provider.scopes, provider.isActive ? 1 : 0, provider.displayOrder, provider.iconUrl, provider.createdAt, provider.updatedAt ); } export function getOidcProvider(id: string): OidcProvider | null { return rowToOidcProvider(stmtGetOidcProvider.get(id)); } export function getOidcProviderByName(name: string): OidcProvider | null { return rowToOidcProvider(stmtGetOidcProviderByName.get(name)); } export function listOidcProviders(): OidcProvider[] { return (stmtListOidcProviders.all() as any[]).map(rowToOidcProvider).filter(p => p !== null) as OidcProvider[]; } export function listActiveOidcProviders(): OidcProvider[] { return (stmtListActiveOidcProviders.all() as any[]).map(rowToOidcProvider).filter(p => p !== null) as OidcProvider[]; } export function updateOidcProvider(provider: OidcProvider): void { stmtUpdateOidcProvider.run( provider.name, provider.providerType, provider.clientId, provider.clientSecretEncrypted, provider.issuerUrl, provider.authorizationUrl, provider.tokenUrl, provider.userinfoUrl, provider.jwksUri, provider.scopes, provider.isActive ? 1 : 0, provider.displayOrder, provider.iconUrl, provider.updatedAt, provider.id ); } export function deleteOidcProvider(id: string): boolean { return stmtDeleteOidcProvider.run(id).changes > 0; } const stmtInsertSmtpConfig = db.prepare(` INSERT INTO smtp_configs (id, name, provider_type, host, port, secure_mode, username, password_encrypted, api_key_encrypted, from_email, from_name, is_default, is_active, allow_insecure_tls, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtGetSmtpConfig = db.prepare(`SELECT * FROM smtp_configs WHERE id = ?`); const stmtGetDefaultSmtpConfig = db.prepare(`SELECT * FROM smtp_configs WHERE is_default = 1 AND is_active = 1 LIMIT 1`); const stmtListSmtpConfigs = db.prepare(`SELECT * FROM smtp_configs ORDER BY is_default DESC, name ASC`); const stmtUpdateSmtpConfig = db.prepare(` UPDATE smtp_configs SET name = ?, provider_type = ?, host = ?, port = ?, secure_mode = ?, username = ?, password_encrypted = ?, api_key_encrypted = ?, from_email = ?, from_name = ?, is_default = ?, is_active = ?, allow_insecure_tls = ?, updated_at = ? WHERE id = ? `); const stmtDeleteSmtpConfig = db.prepare(`DELETE FROM smtp_configs WHERE id = ?`); const stmtClearDefaultSmtp = db.prepare(`UPDATE smtp_configs SET is_default = 0`); function rowToSmtpConfig(row: any): SmtpConfig | null { if (!row) return null; return { id: row.id, name: row.name, providerType: row.provider_type, host: row.host, port: row.port, secureMode: row.secure_mode, username: row.username, passwordEncrypted: row.password_encrypted, apiKeyEncrypted: row.api_key_encrypted, fromEmail: row.from_email, fromName: row.from_name, isDefault: row.is_default === 1, isActive: row.is_active === 1, allowInsecureTls: row.allow_insecure_tls === 1, createdAt: row.created_at, updatedAt: row.updated_at }; } export function createSmtpConfig(config: SmtpConfig): void { if (config.isDefault) stmtClearDefaultSmtp.run(); stmtInsertSmtpConfig.run( config.id, config.name, config.providerType, config.host, config.port, config.secureMode, config.username, config.passwordEncrypted, config.apiKeyEncrypted, config.fromEmail, config.fromName, config.isDefault ? 1 : 0, config.isActive ? 1 : 0, config.allowInsecureTls ? 1 : 0, config.createdAt, config.updatedAt ); } export function getSmtpConfig(id: string): SmtpConfig | null { return rowToSmtpConfig(stmtGetSmtpConfig.get(id)); } export function getDefaultSmtpConfig(): SmtpConfig | null { return rowToSmtpConfig(stmtGetDefaultSmtpConfig.get()); } export function listSmtpConfigs(): SmtpConfig[] { return (stmtListSmtpConfigs.all() as any[]).map(rowToSmtpConfig).filter(c => c !== null) as SmtpConfig[]; } export function updateSmtpConfig(config: SmtpConfig): void { if (config.isDefault) stmtClearDefaultSmtp.run(); stmtUpdateSmtpConfig.run( config.name, config.providerType, config.host, config.port, config.secureMode, config.username, config.passwordEncrypted, config.apiKeyEncrypted, config.fromEmail, config.fromName, config.isDefault ? 1 : 0, config.isActive ? 1 : 0, config.allowInsecureTls ? 1 : 0, config.updatedAt, config.id ); } export function deleteSmtpConfig(id: string): boolean { return stmtDeleteSmtpConfig.run(id).changes > 0; } const stmtInsertEmailTemplate = db.prepare(` INSERT INTO email_templates (id, name, subject, body_html, body_text, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?) `); const stmtGetEmailTemplate = db.prepare(`SELECT * FROM email_templates WHERE id = ?`); const stmtGetEmailTemplateByName = db.prepare(`SELECT * FROM email_templates WHERE name = ?`); const stmtListEmailTemplates = db.prepare(`SELECT * FROM email_templates ORDER BY name ASC`); const stmtUpdateEmailTemplate = db.prepare(`UPDATE email_templates SET name = ?, subject = ?, body_html = ?, body_text = ?, updated_at = ? WHERE id = ?`); const stmtDeleteEmailTemplate = db.prepare(`DELETE FROM email_templates WHERE id = ?`); function rowToEmailTemplate(row: any): EmailTemplate | null { if (!row) return null; return { id: row.id, name: row.name, subject: row.subject, bodyHtml: row.body_html, bodyText: row.body_text, createdAt: row.created_at, updatedAt: row.updated_at }; } export function createEmailTemplate(template: EmailTemplate): void { stmtInsertEmailTemplate.run(template.id, template.name, template.subject, template.bodyHtml, template.bodyText, template.createdAt, template.updatedAt); } export function getEmailTemplate(id: string): EmailTemplate | null { return rowToEmailTemplate(stmtGetEmailTemplate.get(id)); } export function getEmailTemplateByName(name: string): EmailTemplate | null { return rowToEmailTemplate(stmtGetEmailTemplateByName.get(name)); } export function listEmailTemplates(): EmailTemplate[] { return (stmtListEmailTemplates.all() as any[]).map(rowToEmailTemplate).filter(t => t !== null) as EmailTemplate[]; } export function updateEmailTemplate(template: EmailTemplate): void { stmtUpdateEmailTemplate.run(template.name, template.subject, template.bodyHtml, template.bodyText, template.updatedAt, template.id); } export function deleteEmailTemplate(id: string): boolean { return stmtDeleteEmailTemplate.run(id).changes > 0; } const stmtInsertEmailLog = db.prepare(` INSERT INTO email_logs (id, to_email, template_name, subject, status, error_message, smtp_config_id, sent_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); const stmtListEmailLogs = db.prepare(`SELECT * FROM email_logs ORDER BY sent_at DESC LIMIT ? OFFSET ?`); const stmtCountEmailLogs = db.prepare(`SELECT COUNT(*) as count FROM email_logs`); const stmtCountEmailLogsByStatus = db.prepare(`SELECT COUNT(*) as count FROM email_logs WHERE status = ?`); function rowToEmailLog(row: any): EmailLog | null { if (!row) return null; return { id: row.id, toEmail: row.to_email, templateName: row.template_name, subject: row.subject, status: row.status, errorMessage: row.error_message, smtpConfigId: row.smtp_config_id, sentAt: row.sent_at }; } export function createEmailLog(log: EmailLog): void { stmtInsertEmailLog.run(log.id, log.toEmail, log.templateName, log.subject, log.status, log.errorMessage, log.smtpConfigId, log.sentAt); } export function listEmailLogs(limit: number = 100, offset: number = 0): EmailLog[] { return (stmtListEmailLogs.all(limit, offset) as any[]).map(rowToEmailLog).filter(l => l !== null) as EmailLog[]; } export function countEmailLogs(): number { return (stmtCountEmailLogs.get() as { count: number }).count; } export function countEmailLogsByStatus(status: string): number { return (stmtCountEmailLogsByStatus.get(status) as { count: number }).count; } export function clearEmailLogs(): number { return db.exec(`DELETE FROM email_logs`).changes; } export function clearAuditLogs(): number { return db.exec(`DELETE FROM audit_logs`).changes; } export function clearActivityLogs(): number { return db.exec(`DELETE FROM activity_logs`).changes; } const stmtUpsertUserPreferences = db.prepare(` INSERT INTO user_preferences (user_id, theme, email_notifications, default_room_settings) VALUES (?, ?, ?, ?) ON CONFLICT(user_id) DO UPDATE SET theme = excluded.theme, email_notifications = excluded.email_notifications, default_room_settings = excluded.default_room_settings `); const stmtGetUserPreferences = db.prepare(`SELECT * FROM user_preferences WHERE user_id = ?`); function rowToUserPreferences(row: any): UserPreferences | null { if (!row) return null; return { userId: row.user_id, theme: row.theme, emailNotifications: row.email_notifications === 1, defaultRoomSettings: row.default_room_settings ? JSON.parse(row.default_room_settings) : null }; } export function saveUserPreferences(prefs: UserPreferences): void { stmtUpsertUserPreferences.run(prefs.userId, prefs.theme, prefs.emailNotifications ? 1 : 0, prefs.defaultRoomSettings ? JSON.stringify(prefs.defaultRoomSettings) : null); } export function getUserPreferences(userId: string): UserPreferences | null { return rowToUserPreferences(stmtGetUserPreferences.get(userId)); } export function initializeDefaultEmailTemplates(): void { const now = new Date().toISOString(); const defaults = [ { id: 'emailVerify', name: 'Email Verification', subject: 'Verify your email | TheOneFile_Verse', bodyHtml: `

Verify Your Email

Hello {{displayName}},

Please click the button below to verify your email address:

Verify Email

Or copy and paste this link: {{verifyUrl}}

This link expires in 24 hours.

If you didn't create an account, you can ignore this email.

`, bodyText: `Verify Your Email\n\nHello {{displayName}},\n\nPlease visit this link to verify your email:\n{{verifyUrl}}\n\nThis link expires in 24 hours.\n\nIf you didn't create an account, you can ignore this email.` }, { id: 'passwordReset', name: 'Password Reset', subject: 'Reset your password | TheOneFile_Verse', bodyHtml: `

Reset Your Password

Hello {{displayName}},

We received a request to reset your password. Click the button below to create a new password:

Reset Password

Or copy and paste this link: {{resetUrl}}

This link expires in 1 hour.

If you didn't request a password reset, you can ignore this email.

`, bodyText: `Reset Your Password\n\nHello {{displayName}},\n\nWe received a request to reset your password.\n\nVisit this link to create a new password:\n{{resetUrl}}\n\nThis link expires in 1 hour.\n\nIf you didn't request a password reset, you can ignore this email.` }, { id: 'magicLink', name: 'Magic Link', subject: 'Your login link | TheOneFile_Verse', bodyHtml: `

Your Login Link

Hello {{displayName}},

Click the button below to sign in to TheOneFile_Verse:

Sign In

Or copy and paste this link: {{loginUrl}}

This link expires in 15 minutes and can only be used once.

`, bodyText: `Your Login Link\n\nHello {{displayName}},\n\nVisit this link to sign in:\n{{loginUrl}}\n\nThis link expires in 15 minutes and can only be used once.` }, { id: 'roomInvite', name: 'Room Invitation', subject: 'You\'ve been invited to collaborate | TheOneFile_Verse', bodyHtml: `

You're Invited!

Hello,

{{inviterName}} has invited you to collaborate on a room in TheOneFile_Verse.

Join Room

Or copy and paste this link: {{roomUrl}}

`, bodyText: `You're Invited!\n\nHello,\n\n{{inviterName}} has invited you to collaborate on a room in TheOneFile_Verse.\n\nJoin here: {{roomUrl}}` } ]; const legacyNames = ['email_verification', 'password_reset', 'magic_link', 'room_invitation']; for (const legacyName of legacyNames) { const legacy = getEmailTemplateByName(legacyName); if (legacy) { deleteEmailTemplate(legacy.id); } } for (const template of defaults) { const existing = getEmailTemplateByName(template.name); if (!existing) { createEmailTemplate({ ...template, createdAt: now, updatedAt: now }); } } } const stmtInsertOidcState = db.prepare(` INSERT INTO oidc_states (state, provider_id, code_verifier, nonce, redirect_uri, link_user_id, post_login_redirect, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) `); const stmtGetOidcState = db.prepare(`SELECT * FROM oidc_states WHERE state = ?`); const stmtDeleteOidcState = db.prepare(`DELETE FROM oidc_states WHERE state = ?`); const stmtDeleteExpiredOidcStates = db.prepare(`DELETE FROM oidc_states WHERE expires_at < ?`); const stmtCountOidcStates = db.prepare(`SELECT COUNT(*) as count FROM oidc_states`); const stmtDeleteOldestOidcStates = db.prepare(`DELETE FROM oidc_states WHERE state IN (SELECT state FROM oidc_states ORDER BY created_at ASC LIMIT ?)`); function rowToOidcState(row: any): OidcState | null { if (!row) return null; return { state: row.state, providerId: row.provider_id, codeVerifier: row.code_verifier, nonce: row.nonce, redirectUri: row.redirect_uri, linkUserId: row.link_user_id, postLoginRedirect: row.post_login_redirect || null, createdAt: row.created_at, expiresAt: row.expires_at }; } export function createOidcState(oidcState: OidcState): void { stmtInsertOidcState.run( oidcState.state, oidcState.providerId, oidcState.codeVerifier, oidcState.nonce, oidcState.redirectUri, oidcState.linkUserId, oidcState.postLoginRedirect, oidcState.createdAt, oidcState.expiresAt ); } export function getOidcState(state: string): OidcState | null { return rowToOidcState(stmtGetOidcState.get(state)); } export function deleteOidcState(state: string): boolean { return stmtDeleteOidcState.run(state).changes > 0; } export function cleanupExpiredOidcStates(): number { return stmtDeleteExpiredOidcStates.run(new Date().toISOString()).changes; } export function countOidcStates(): number { return (stmtCountOidcStates.get() as { count: number }).count; } export function deleteOldestOidcStates(count: number): number { return stmtDeleteOldestOidcStates.run(count).changes; } const stmtInsertCsrfToken = db.prepare(` INSERT INTO csrf_tokens (token, used, created_at, expires_at) VALUES (?, ?, ?, ?) `); const stmtGetCsrfToken = db.prepare(`SELECT * FROM csrf_tokens WHERE token = ?`); const stmtMarkCsrfTokenUsed = db.prepare(`UPDATE csrf_tokens SET used = 1 WHERE token = ?`); const stmtDeleteCsrfToken = db.prepare(`DELETE FROM csrf_tokens WHERE token = ?`); const stmtDeleteExpiredCsrfTokens = db.prepare(`DELETE FROM csrf_tokens WHERE expires_at < ?`); const stmtCountCsrfTokens = db.prepare(`SELECT COUNT(*) as count FROM csrf_tokens`); const stmtDeleteOldestCsrfTokens = db.prepare(`DELETE FROM csrf_tokens WHERE token IN (SELECT token FROM csrf_tokens ORDER BY created_at ASC LIMIT ?)`); function rowToCsrfToken(row: any): CsrfToken | null { if (!row) return null; return { token: row.token, used: row.used === 1, createdAt: row.created_at, expiresAt: row.expires_at }; } export function createCsrfToken(csrfToken: CsrfToken): void { stmtInsertCsrfToken.run( csrfToken.token, csrfToken.used ? 1 : 0, csrfToken.createdAt, csrfToken.expiresAt ); } export function getCsrfToken(token: string): CsrfToken | null { return rowToCsrfToken(stmtGetCsrfToken.get(token)); } export function markCsrfTokenUsed(token: string): boolean { return stmtMarkCsrfTokenUsed.run(token).changes > 0; } export function deleteCsrfToken(token: string): boolean { return stmtDeleteCsrfToken.run(token).changes > 0; } export function cleanupExpiredCsrfTokens(): number { return stmtDeleteExpiredCsrfTokens.run(new Date().toISOString()).changes; } export function countCsrfTokens(): number { return (stmtCountCsrfTokens.get() as { count: number }).count; } export function deleteOldestCsrfTokens(count: number): number { return stmtDeleteOldestCsrfTokens.run(count).changes; } const stmtInsertEmailRateLimit = db.prepare(`INSERT INTO email_rate_limits (email, action, created_at) VALUES (?, ?, ?)`); const stmtCountEmailRateLimits = db.prepare(`SELECT COUNT(*) as count FROM email_rate_limits WHERE email = ? AND action = ? AND created_at > ?`); const stmtCleanupEmailRateLimits = db.prepare(`DELETE FROM email_rate_limits WHERE created_at < ?`); export function recordEmailRateLimit(email: string, action: string): void { stmtInsertEmailRateLimit.run(email.toLowerCase().trim(), action, new Date().toISOString()); } export function countEmailRateLimitAttempts(email: string, action: string, windowSeconds: number): number { const cutoff = new Date(Date.now() - windowSeconds * 1000).toISOString(); return (stmtCountEmailRateLimits.get(email.toLowerCase().trim(), action, cutoff) as { count: number }).count; } export function cleanupEmailRateLimits(maxAgeSeconds: number = 3600): number { const cutoff = new Date(Date.now() - maxAgeSeconds * 1000).toISOString(); return stmtCleanupEmailRateLimits.run(cutoff).changes; } ================================================ FILE: theonefile_verse/src/index.ts ================================================ import * as db from "./database"; import * as redis from "./redis"; import * as oidc from "./oidc"; import { APP_VERSION, PORT, ENV_ADMIN_PASSWORD, getSettings, isAdminConfigured, isInstanceLocked, isValidUUID } from "./config"; import { securityHeaders, getClientIP, getTokenFromRequest, relativeRedirect } from "./security"; import { startTokenCleanupIntervals, validateInstanceToken } from "./tokens"; import { startRateLimitCleanupIntervals, checkWsConnectionLimit } from "./rate-limit"; import { loadRoom, restartBackupTimer, clearBackupTimer, clearUpdateTimer, deleteRoomData, scheduleDestruction, initializeTheOneFile } from "./rooms"; import { websocketHandlers, type WsData } from "./websocket"; const CONFIGURED_ORIGINS = process.env.CORS_ORIGIN?.split(",").map(o => o.trim()).filter(Boolean) || null; import * as setupRoutes from "./routes/setup"; import * as adminAuthRoutes from "./routes/admin-auth"; import * as adminRoomsRoutes from "./routes/admin-rooms"; import * as userAuthRoutes from "./routes/user-auth"; import * as adminUsersRoutes from "./routes/admin-users"; import * as adminAuthSettingsRoutes from "./routes/admin-auth-settings"; import * as instanceAccessRoutes from "./routes/instance-access"; import * as adminSettingsRoutes from "./routes/admin-settings"; import * as adminLogsRoutes from "./routes/admin-logs"; import * as adminBackupsRoutes from "./routes/admin-backups"; import * as adminApikeysRoutes from "./routes/admin-apikeys"; import * as roomRoutes from "./routes/room"; import * as networkRoutes from "./routes/network-routes"; import * as publicRoutes from "./routes/public"; async function handleRequest(req: Request, server: any): Promise { const url = new URL(req.url); const path = url.pathname; if (req.method === 'POST' || req.method === 'PUT') { if (path !== '/api/admin/upload-html') { const cl = parseInt(req.headers.get('content-length') || '0'); if (cl > 5 * 1024 * 1024) { return new Response('Payload too large', { status: 413 }); } } } if (path.match(/^\/ws\/[\w-]+$/)) { const clientIp = getClientIP(req); if (!checkWsConnectionLimit(clientIp)) { return new Response("Too many WebSocket connections", { status: 429 }); } const roomId = path.split("/")[2]; if (!isValidUUID(roomId)) { return new Response("Invalid room ID", { status: 400 }); } const room = loadRoom(roomId); if (!room) return new Response("Room not found", { status: 404 }); if (ENV_ADMIN_PASSWORD || isInstanceLocked()) { const token = getTokenFromRequest(req); if (!token || !validateInstanceToken(token)) return new Response("Unauthorized", { status: 401 }); } const authSettings = oidc.getAuthSettings(); const requireWsToken = authSettings.productionMode || process.env.REQUIRE_WS_TOKEN === 'true'; const upgraded = server.upgrade(req, { data: { roomId, authenticated: !requireWsToken } }); if (upgraded) return undefined; return new Response("WebSocket upgrade failed", { status: 400 }); } const requestOrigin = req.headers.get("origin") || new URL(req.url).origin; let allowedOrigin: string; if (CONFIGURED_ORIGINS && CONFIGURED_ORIGINS.length > 0) { allowedOrigin = CONFIGURED_ORIGINS.includes(requestOrigin) ? requestOrigin : CONFIGURED_ORIGINS[0]; } else { allowedOrigin = new URL(req.url).origin; } const corsHeaders = { "Access-Control-Allow-Origin": allowedOrigin, "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization, x-csrf-token", "Access-Control-Allow-Credentials": "true", ...securityHeaders }; if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders }); let response: Response | null; response = await setupRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminAuthRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminRoomsRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await userAuthRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminUsersRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminAuthSettingsRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await instanceAccessRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminSettingsRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminLogsRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminBackupsRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await adminApikeysRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await roomRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await networkRoutes.handle(req, path, url, corsHeaders); if (response) return response; response = await publicRoutes.handle(req, path, url, corsHeaders); if (response) return response; return relativeRedirect("/?error=not_found"); } const server = Bun.serve({ port: PORT, async fetch(req, server) { const start = performance.now(); const response = await handleRequest(req, server); if (response) { const path = new URL(req.url).pathname; if (path !== '/api/health' && !path.startsWith('/ws/')) { console.log(`[HTTP] ${req.method} ${path} ${response.status} ${(performance.now() - start).toFixed(1)}ms`); } } return response; }, websocket: { perMessageDeflate: true, maxPayloadLength: 5 * 1024 * 1024, ...websocketHandlers } }); const migrationResult = db.migrateFromFlatFiles(); if (migrationResult.rooms > 0 || migrationResult.settings || migrationResult.admin) { console.log(`[Migration] Migrated: ${migrationResult.rooms} rooms, settings: ${migrationResult.settings}, admin: ${migrationResult.admin}`); } redis.connectRedis().then(connected => { if (connected) console.log("[Redis] Connected successfully"); else console.log("[Redis] Not available, using in-memory fallback"); }); restartBackupTimer(); db.initializeDefaultEmailTemplates(); db.verifyAllAdminEmails(); await initializeTheOneFile(); startTokenCleanupIntervals(); startRateLimitCleanupIntervals(); const settings = getSettings(); console.log(`TheOneFile Verse v${APP_VERSION} | http://localhost:${PORT}`); if (ENV_ADMIN_PASSWORD) console.log(`Instance password lock: ENV`); else if (isInstanceLocked()) console.log(`Instance password lock: Settings`); if (settings.skipUpdates) console.log(`Auto updates: Disabled`); else if (settings.updateIntervalHours > 0) console.log(`Auto updates: Every ${settings.updateIntervalHours}h`); if (settings.backupEnabled) console.log(`Auto backups: Every ${settings.backupIntervalHours}h, keep ${settings.backupRetentionCount}`); console.log(`Admin: ${isAdminConfigured() ? 'Configured' : 'Not set up'} | Rooms: ${db.countRooms()}`); const allRooms = db.listRooms(); for (const room of allRooms) { if (room.destruct.mode === "time") { const elapsed = Date.now() - new Date(room.lastActivity).getTime(); const remaining = room.destruct.value - elapsed; if (remaining <= 0) deleteRoomData(room.id); else scheduleDestruction(room.id, remaining); } } function shutdown() { console.log("[Shutdown] Shutting down..."); server.stop(); clearUpdateTimer(); clearBackupTimer(); redis.disconnectRedis(); db.closeDatabase(); process.exit(0); } process.on("SIGTERM", shutdown); process.on("SIGINT", shutdown); process.on("uncaughtException", (err) => { console.error("[Fatal]", err); shutdown(); }); process.on("unhandledRejection", (err) => { console.error("[UnhandledRejection]", err); }); ================================================ FILE: theonefile_verse/src/mailer.ts ================================================ import * as db from "./database"; import { decryptSecret } from "./oidc"; import { connect as tlsConnect, TLSSocket } from "tls"; import { Socket } from "net"; function escapeHtml(str: string): string { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } interface EmailMessage { to: string; subject: string; html: string; text: string; } interface SendResult { success: boolean; messageId?: string; error?: string; } interface SmtpResponse { code: number; message: string; lines: string[]; } export async function sendEmail(message: EmailMessage): Promise { const config = db.getDefaultSmtpConfig(); if (!config) { return { success: false, error: "No SMTP configuration found" }; } return sendEmailWithConfig(message, config); } export async function sendEmailWithConfig( message: EmailMessage, config: db.SmtpConfig ): Promise { const logId = crypto.randomUUID(); if (config.allowInsecureTls) { console.warn(`[Mailer] WARNING: Insecure TLS is enabled for SMTP config "${config.name}". This disables certificate verification and is NOT recommended for production use.`); } try { let password: string | null = null; if (config.passwordEncrypted) { try { password = await decryptSecret(config.passwordEncrypted); } catch (e) { console.error("[Mailer] Failed to decrypt password"); return logAndReturn(logId, message, config, false, "Failed to decrypt SMTP password"); } } const result = await sendViaSMTP(message, config, password); return logAndReturn(logId, message, config, result.success, result.error); } catch (e: any) { console.error("[Mailer] Send error:", e); return logAndReturn(logId, message, config, false, e.message || "Unknown error"); } } function logAndReturn( id: string, message: EmailMessage, config: db.SmtpConfig, success: boolean, error?: string ): SendResult { db.createEmailLog({ id, toEmail: message.to, templateName: null, subject: message.subject, status: success ? 'sent' : 'failed', errorMessage: error || null, smtpConfigId: config.id, sentAt: new Date().toISOString() }); return { success, messageId: success ? id : undefined, error }; } class SmtpClient { private socket: any = null; private buffer = ""; private responsePromise: { resolve: (r: SmtpResponse) => void; reject: (e: Error) => void } | null = null; private isSecure = false; private config: db.SmtpConfig; private debug = true; constructor(config: db.SmtpConfig) { this.config = config; } private log(...args: any[]) { if (this.debug) console.log("[SMTP]", ...args); } async connect(): Promise { const { host, port, secureMode } = this.config; if (!host || !port) { throw new Error("SMTP host and port are required"); } this.log(`Connecting to ${host}:${port} (${secureMode})`); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error("Connection timeout")); }, 30000); if (secureMode === 'tls') { const tlsSocket = tlsConnect({ host: host, port: port, rejectUnauthorized: !this.config.allowInsecureTls, servername: host }); tlsSocket.once('secureConnect', () => { clearTimeout(timeout); this.isSecure = true; this.socket = { write: (data: string) => tlsSocket.write(data), end: () => tlsSocket.end(), rawSocket: tlsSocket }; tlsSocket.on('data', (data) => this.handleData(data)); tlsSocket.on('error', (err) => this.handleError(err)); tlsSocket.on('close', () => this.handleClose()); this.readResponse().then(greeting => { if (greeting.code !== 220) { reject(new Error(`Server greeting failed: ${greeting.message}`)); } else { this.log("Connected (TLS), greeting:", greeting.code); resolve(); } }).catch(reject); }); tlsSocket.once('error', (err) => { clearTimeout(timeout); reject(err); }); } else { const netSocket = new Socket(); netSocket.connect(port, host, () => { clearTimeout(timeout); this.socket = { write: (data: string) => netSocket.write(data), end: () => netSocket.end(), rawSocket: netSocket }; netSocket.on('data', (data) => this.handleData(data)); netSocket.on('error', (err) => this.handleError(err)); netSocket.on('close', () => this.handleClose()); this.readResponse().then(greeting => { if (greeting.code !== 220) { reject(new Error(`Server greeting failed: ${greeting.message}`)); } else { this.log("Connected, greeting:", greeting.code); resolve(); } }).catch(reject); }); netSocket.once('error', (err) => { clearTimeout(timeout); reject(err); }); } }); } private handleData(data: Buffer) { this.buffer += data.toString(); this.processBuffer(); } private handleError(error: Error) { this.log("Socket error:", error.message); if (this.responsePromise) { this.responsePromise.reject(error); this.responsePromise = null; } } private handleClose() { this.log("Socket closed"); if (this.responsePromise) { this.responsePromise.reject(new Error("Connection closed unexpectedly")); this.responsePromise = null; } } private processBuffer() { const lines = this.buffer.split('\r\n'); for (let i = 0; i < lines.length - 1; i++) { const line = lines[i]; if (line.length < 3) continue; const code = parseInt(line.substring(0, 3), 10); const isContinuation = line.charAt(3) === '-'; if (!isContinuation && this.responsePromise) { const allLines = lines.slice(0, i + 1); this.buffer = lines.slice(i + 1).join('\r\n'); this.responsePromise.resolve({ code, message: line.substring(4), lines: allLines }); this.responsePromise = null; return; } } } private readResponse(): Promise { return new Promise((resolve, reject) => { const timeout = setTimeout(() => { this.responsePromise = null; reject(new Error("Response timeout")); }, 30000); this.responsePromise = { resolve: (r) => { clearTimeout(timeout); resolve(r); }, reject: (e) => { clearTimeout(timeout); reject(e); } }; this.processBuffer(); }); } private async command(cmd: string, expectedCodes: number[] = [250]): Promise { this.log(">>>", cmd.startsWith("AUTH") || cmd.includes("@") ? cmd.split(" ")[0] + " ***" : cmd); this.socket.write(cmd + "\r\n"); const response = await this.readResponse(); this.log("<<<", response.code, response.message); if (!expectedCodes.includes(response.code)) { throw new Error(`SMTP error ${response.code}: ${response.message}`); } return response; } async ehlo(): Promise { const response = await this.command(`EHLO ${this.config.host}`, [250]); return response.lines; } async startTls(): Promise { if (this.isSecure) return []; await this.command("STARTTLS", [220]); this.log("Upgrading to TLS..."); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { reject(new Error("TLS upgrade timeout")); }, 15000); try { const rawSocket = this.socket.rawSocket as Socket; if (!rawSocket) { clearTimeout(timeout); reject(new Error("Cannot upgrade to TLS: no raw socket available")); return; } rawSocket.removeAllListeners('data'); rawSocket.removeAllListeners('error'); rawSocket.removeAllListeners('close'); const tlsSocket = tlsConnect({ socket: rawSocket, host: this.config.host!, rejectUnauthorized: !this.config.allowInsecureTls, servername: this.config.host! }); tlsSocket.once('secureConnect', () => { clearTimeout(timeout); this.log("TLS handshake successful"); this.isSecure = true; this.buffer = ""; this.socket = { write: (data: string) => tlsSocket.write(data), end: () => tlsSocket.end(), rawSocket: tlsSocket }; tlsSocket.on('data', (data) => this.handleData(data)); tlsSocket.on('error', (err) => this.handleError(err)); tlsSocket.on('close', () => this.handleClose()); this.ehlo().then(caps => resolve(caps)).catch(reject); }); tlsSocket.once('error', (err) => { clearTimeout(timeout); reject(err); }); } catch (e: any) { clearTimeout(timeout); reject(e); } }); } async authenticate(username: string, password: string, capabilities: string[]): Promise { const supportsLogin = capabilities.some(l => l.toUpperCase().includes('AUTH') && l.toUpperCase().includes('LOGIN')); const supportsPlain = capabilities.some(l => l.toUpperCase().includes('AUTH') && l.toUpperCase().includes('PLAIN')); if (supportsLogin) { await this.command("AUTH LOGIN", [334]); await this.command(Buffer.from(username).toString('base64'), [334]); await this.command(Buffer.from(password).toString('base64'), [235]); } else if (supportsPlain) { const credentials = Buffer.from(`\0${username}\0${password}`).toString('base64'); await this.command(`AUTH PLAIN ${credentials}`, [235]); } else { throw new Error("Server does not support LOGIN or PLAIN authentication"); } this.log("Authenticated successfully"); } async mailFrom(email: string): Promise { await this.command(`MAIL FROM:<${email}>`, [250]); } async rcptTo(email: string): Promise { await this.command(`RCPT TO:<${email}>`, [250, 251]); } async data(content: string): Promise { await this.command("DATA", [354]); const escapedContent = content.replace(/^\./gm, '..'); const finalContent = escapedContent.endsWith('\r\n') ? escapedContent : escapedContent + '\r\n'; this.socket.write(finalContent + ".\r\n"); const response = await this.readResponse(); if (response.code !== 250) { throw new Error(`DATA failed: ${response.code} ${response.message}`); } this.log("Message accepted"); } async quit(): Promise { try { await this.command("QUIT", [221]); } catch {} this.close(); } close() { if (this.socket) { try { this.socket.end(); } catch {} this.socket = null; } } } async function sendViaSMTP( message: EmailMessage, config: db.SmtpConfig, password: string | null ): Promise { if (!config.host || !config.port) { return { success: false, error: "SMTP host and port are required" }; } const client = new SmtpClient(config); try { console.log(`[Mailer] Connecting to ${config.host}:${config.port} (${config.secureMode})`); await client.connect(); console.log("[Mailer] Connected successfully"); let capabilities = await client.ehlo(); console.log("[Mailer] EHLO capabilities:", capabilities.join(", ")); if (config.secureMode === 'starttls') { const supportsTls = capabilities.some(line => line.toUpperCase().includes('STARTTLS') ); if (supportsTls) { console.log("[Mailer] Starting TLS upgrade..."); const newCaps = await client.startTls(); if (newCaps.length > 0) { capabilities = newCaps; console.log("[Mailer] Post-TLS capabilities:", capabilities.join(", ")); } } else { client.close(); throw new Error("STARTTLS required but server does not support it. Refusing to send credentials over plaintext."); } } if (config.username && password) { console.log("[Mailer] Authenticating as:", config.username); await client.authenticate(config.username, password, capabilities); console.log("[Mailer] Authentication successful"); } console.log("[Mailer] Sending MAIL FROM:", config.fromEmail); await client.mailFrom(config.fromEmail); console.log("[Mailer] Sending RCPT TO:", message.to); await client.rcptTo(message.to); console.log("[Mailer] Sending message data..."); const messageContent = buildMessage(message, config); await client.data(messageContent); console.log("[Mailer] Message sent, closing connection"); await client.quit(); return { success: true }; } catch (e: any) { client.close(); console.error("[Mailer] SMTP error:", e.message); console.error("[Mailer] Stack:", e.stack); return { success: false, error: e.message }; } } function stripCRLF(str: string): string { return str.replace(/[\r\n]/g, ''); } function buildMessage(message: EmailMessage, config: db.SmtpConfig): string { const boundary = `----=_Part_${Date.now()}_${crypto.randomUUID().replace(/-/g, '')}`; const messageId = `<${crypto.randomUUID()}@${config.host}>`; const date = new Date().toUTCString(); const safeName = config.fromName ? stripCRLF(config.fromName) : ''; const safeFromEmail = stripCRLF(config.fromEmail); const fromHeader = safeName ? `"${safeName.replace(/"/g, '\\"')}" <${safeFromEmail}>` : safeFromEmail; const subjectEncoded = encodeSubject(stripCRLF(message.subject)); const headers = [ `Message-ID: ${messageId}`, `Date: ${date}`, `From: ${fromHeader}`, `To: ${stripCRLF(message.to)}`, `Subject: ${subjectEncoded}`, `MIME-Version: 1.0`, `Content-Type: multipart/alternative; boundary="${boundary}"`, `X-Mailer: TheOneFile_Verse`, `` ]; const textPart = [ `--${boundary}`, `Content-Type: text/plain; charset="utf-8"`, `Content-Transfer-Encoding: quoted-printable`, ``, encodeQuotedPrintable(message.text), `` ]; const htmlPart = [ `--${boundary}`, `Content-Type: text/html; charset="utf-8"`, `Content-Transfer-Encoding: quoted-printable`, ``, encodeQuotedPrintable(message.html), `` ]; const ending = [`--${boundary}--`, ``]; return [...headers, ...textPart, ...htmlPart, ...ending].join('\r\n'); } function encodeSubject(subject: string): string { if (/^[\x20-\x7E]*$/.test(subject)) { return subject; } const encoded = Buffer.from(subject, 'utf-8').toString('base64'); return `=?UTF-8?B?${encoded}?=`; } function encodeQuotedPrintable(text: string): string { const lines: string[] = []; let currentLine = ""; for (let i = 0; i < text.length; i++) { const char = text[i]; const code = char.charCodeAt(0); let encoded: string; if (char === '\r' && text[i + 1] === '\n') { if (currentLine) { lines.push(currentLine); currentLine = ""; } lines.push(""); i++; continue; } else if (char === '\n') { if (currentLine) { lines.push(currentLine); currentLine = ""; } lines.push(""); continue; } else if (code >= 33 && code <= 126 && char !== '=') { encoded = char; } else if (char === ' ' || char === '\t') { encoded = char; } else { const bytes = Buffer.from(char, 'utf-8'); encoded = Array.from(bytes) .map(b => '=' + b.toString(16).toUpperCase().padStart(2, '0')) .join(''); } if (currentLine.length + encoded.length > 73) { lines.push(currentLine + "="); currentLine = encoded; } else { currentLine += encoded; } } if (currentLine) { lines.push(currentLine); } return lines.join('\r\n'); } export async function sendTemplatedEmail( to: string, templateName: string, variables: Record ): Promise { const template = db.getEmailTemplateByName(templateName); if (!template) { return { success: false, error: `Template '${templateName}' not found` }; } let subject = template.subject; let html = template.bodyHtml; let text = template.bodyText; for (const [key, value] of Object.entries(variables)) { const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'g'); const escapedValueForHtml = escapeHtml(value); const safeValue = value.replace(/[\r\n]/g, ''); subject = subject.replace(pattern, safeValue); html = html.replace(pattern, escapedValueForHtml); text = text.replace(pattern, value); } return sendEmail({ to, subject, html, text }); } export async function sendVerificationEmail( to: string, displayName: string, verifyUrl: string ): Promise { return sendTemplatedEmail(to, 'Email Verification', { displayName, verifyUrl }); } export async function sendPasswordResetEmail( to: string, displayName: string, resetUrl: string ): Promise { return sendTemplatedEmail(to, 'Password Reset', { displayName, resetUrl }); } export async function sendMagicLinkEmail( to: string, displayName: string, loginUrl: string ): Promise { return sendTemplatedEmail(to, 'Magic Link', { displayName, loginUrl }); } export async function sendRoomInvitationEmail( to: string, inviterName: string, roomUrl: string ): Promise { return sendTemplatedEmail(to, 'Room Invitation', { inviterName, roomUrl }); } export async function testSmtpConfig(config: db.SmtpConfig): Promise { return sendEmailWithConfig({ to: config.fromEmail, subject: 'TheOneFile_Verse - SMTP Test', html: '

SMTP Test Successful

Your SMTP configuration is working correctly.

', text: 'SMTP Test Successful\n\nYour SMTP configuration is working correctly.' }, config); } export function getEmailStats(): { total: number; sent: number; failed: number; } { return { total: db.countEmailLogs(), sent: db.countEmailLogsByStatus('sent'), failed: db.countEmailLogsByStatus('failed') }; } ================================================ FILE: theonefile_verse/src/network.ts ================================================ const IPV4_RE = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/; const HOSTNAME_RE = /^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/; const CIDR_RE = /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})$/; export interface ProbeConfig { type: "icmp" | "tcp" | "http" | "dns"; port?: number; path?: string; url?: string; } export interface ProbeResult { type: string; port?: number; status: "online" | "offline" | "error"; responseTime: number | null; detail?: string; } export interface BatchTarget { nodeId: string; target: string; probes: ProbeConfig[]; timeout: number; } export interface BatchResult { status: "online" | "offline" | "unknown"; rtt: number | null; results: ProbeResult[]; } export interface DiscoveryOptions { icmp: boolean; tcp: boolean; dns: boolean; netbios: boolean; mdns: boolean; snmp: boolean; snmpCommunity: string; ports: number[]; } export interface DiscoveredHost { ip: string; hostname: string; ports: number[]; services: Record; icon: { library: string; name: string }; serviceIcons: { library: string; name: string }[]; dnsName: string; netbiosName: string; mdnsName: string; httpServer: string; snmpName: string; snmpDescr: string; } interface DiscoveryHandle { taskId: string; cancelled: boolean; cancel: () => void; } const activeDiscoveries = new Map(); const PORT_SERVICE_MAP: Record = { 21: "FTP", 22: "SSH", 23: "Telnet", 25: "SMTP", 53: "DNS", 80: "HTTP", 110: "POP3", 111: "RPC", 135: "MSRPC", 139: "NetBIOS", 143: "IMAP", 161: "SNMP", 443: "HTTPS", 445: "SMB", 465: "SMTPS", 514: "Syslog", 515: "LPD", 587: "Submission", 631: "IPP", 993: "IMAPS", 995: "POP3S", 1194: "OpenVPN", 1433: "MSSQL", 1521: "Oracle", 1880: "Node RED", 1883: "MQTT", 2283: "Immich", 2342: "PhotoPrism", 2368: "Ghost", 2375: "Docker API", 2376: "Docker TLS", 3000: "Grafana", 3001: "Uptime Kuma", 3100: "Loki", 3306: "MySQL", 3389: "RDP", 3456: "Vikunja", 3579: "Ombi", 4533: "Navidrome", 4646: "Nomad", 4822: "Guacamole", 5001: "Dockge", 5055: "Overseerr", 5060: "SIP", 5380: "Technitium", 5432: "PostgreSQL", 5601: "Kibana", 5672: "AMQP", 5678: "n8n", 5900: "VNC", 6052: "ESPHome", 6379: "Redis", 6767: "Bazarr", 6789: "NZBGet", 7575: "Homarr", 7878: "Radarr", 8000: "Paperless ngx", 8006: "Proxmox VE", 8007: "Proxmox BS", 8065: "Mattermost", 8080: "HTTP Alt", 8083: "Calibre Web", 8086: "InfluxDB", 8096: "Jellyfin", 8112: "Deluge", 8123: "Home Assistant", 8181: "Tautulli", 8200: "Vault", 8384: "Syncthing", 8443: "HTTPS Alt", 8500: "Consul", 8686: "Lidarr", 8787: "Readarr", 8883: "MQTTS", 8920: "Emby", 8971: "Frigate", 8989: "Sonarr", 9001: "MinIO", 9090: "Prometheus", 9091: "Authelia", 9100: "JetDirect", 9117: "Jackett", 9200: "Elasticsearch", 9443: "Portainer", 9696: "Prowlarr", 10000: "Webmin", 11434: "Ollama", 13378: "Audiobookshelf", 19999: "Netdata", 25600: "Komga", 27017: "MongoDB", 32400: "Plex", 51820: "WireGuard", 61208: "Glances", }; const DEFAULT_SCAN_PORTS = [22, 23, 25, 53, 80, 110, 135, 139, 143, 161, 443, 445, 515, 587, 631, 993, 1433, 1880, 2283, 2342, 2375, 2376, 3000, 3001, 3100, 3306, 3389, 4646, 4822, 5001, 5055, 5380, 5432, 5601, 5678, 5900, 6379, 6767, 7575, 7878, 8000, 8006, 8007, 8065, 8080, 8083, 8086, 8096, 8112, 8123, 8181, 8200, 8384, 8443, 8500, 8686, 8787, 8920, 8971, 8989, 9001, 9090, 9091, 9100, 9117, 9443, 9696, 10000, 11434, 13378, 19999, 25600, 27017, 32400, 61208]; interface ServiceIconEntry { ports: number[]; library: string; name: string; } const SERVICE_ICON_MAP: ServiceIconEntry[] = [ { ports: [8006, 8007], library: "selfhst", name: "proxmox" }, { ports: [32400], library: "selfhst", name: "plex" }, { ports: [8096], library: "selfhst", name: "jellyfin" }, { ports: [8920], library: "selfhst", name: "emby" }, { ports: [8989], library: "selfhst", name: "sonarr" }, { ports: [7878], library: "selfhst", name: "radarr" }, { ports: [8686], library: "selfhst", name: "lidarr" }, { ports: [8787], library: "selfhst", name: "readarr" }, { ports: [9696], library: "selfhst", name: "prowlarr" }, { ports: [6767], library: "selfhst", name: "bazarr" }, { ports: [5055], library: "selfhst", name: "overseerr" }, { ports: [8181], library: "selfhst", name: "tautulli" }, { ports: [3579], library: "selfhst", name: "ombi" }, { ports: [4533], library: "selfhst", name: "navidrome" }, { ports: [13378], library: "selfhst", name: "audiobookshelf" }, { ports: [25600], library: "selfhst", name: "komga" }, { ports: [9117], library: "selfhst", name: "jackett" }, { ports: [8083], library: "selfhst", name: "calibre-web" }, { ports: [8971], library: "selfhst", name: "frigate" }, { ports: [8123], library: "selfhst", name: "home-assistant" }, { ports: [1880], library: "selfhst", name: "node-red" }, { ports: [6052], library: "selfhst", name: "esphome" }, { ports: [5678], library: "selfhst", name: "n8n" }, { ports: [3001], library: "selfhst", name: "uptime-kuma" }, { ports: [19999], library: "selfhst", name: "netdata" }, { ports: [3000], library: "selfhst", name: "grafana" }, { ports: [9090], library: "selfhst", name: "prometheus" }, { ports: [5601], library: "selfhst", name: "kibana" }, { ports: [3100], library: "selfhst", name: "loki" }, { ports: [61208], library: "selfhst", name: "glances" }, { ports: [2283], library: "selfhst", name: "immich" }, { ports: [2342], library: "selfhst", name: "photoprism" }, { ports: [9443], library: "selfhst", name: "portainer" }, { ports: [5001], library: "selfhst", name: "dockge" }, { ports: [2375, 2376], library: "selfhst", name: "docker" }, { ports: [9091], library: "selfhst", name: "authelia" }, { ports: [8384], library: "selfhst", name: "syncthing" }, { ports: [5380], library: "selfhst", name: "technitium-dns" }, { ports: [8000], library: "selfhst", name: "paperless-ngx" }, { ports: [8112], library: "selfhst", name: "deluge" }, { ports: [6789], library: "selfhst", name: "nzbget" }, { ports: [7575], library: "selfhst", name: "homarr" }, { ports: [8065], library: "selfhst", name: "mattermost" }, { ports: [8086], library: "selfhst", name: "influxdb" }, { ports: [2368], library: "selfhst", name: "ghost" }, { ports: [3456], library: "selfhst", name: "vikunja" }, { ports: [11434], library: "selfhst", name: "ollama" }, { ports: [4822], library: "selfhst", name: "guacamole" }, { ports: [8500], library: "selfhst", name: "hashicorp-consul" }, { ports: [8200], library: "selfhst", name: "hashicorp-vault" }, { ports: [4646], library: "selfhst", name: "hashicorp-nomad" }, { ports: [9001], library: "selfhst", name: "minio" }, { ports: [1194], library: "selfhst", name: "openvpn" }, { ports: [51820], library: "selfhst", name: "wireguard" }, { ports: [10000], library: "selfhst", name: "webmin" }, { ports: [3306], library: "selfhst", name: "mysql" }, { ports: [5432], library: "selfhst", name: "postgresql" }, { ports: [6379], library: "selfhst", name: "redis" }, { ports: [27017], library: "selfhst", name: "mongodb" }, { ports: [9200], library: "selfhst", name: "elasticsearch" }, { ports: [1883, 8883], library: "selfhst", name: "mosquitto" }, { ports: [5060], library: "selfhst", name: "asterisk" }, { ports: [5672], library: "selfhst", name: "rabbitmq" }, { ports: [9100, 515, 631], library: "selfhst", name: "cups" }, { ports: [25, 465, 587], library: "selfhst", name: "mailcow" }, { ports: [179], library: "selfhst", name: "openwrt" }, { ports: [3389], library: "selfhst", name: "windows" }, { ports: [5900], library: "selfhst", name: "vnc" }, { ports: [22], library: "selfhst", name: "terminal" }, ]; const DEFAULT_ICON = { library: "selfhst", name: "linux" }; export function validateIPv4(ip: string): boolean { const match = IPV4_RE.exec(ip); if (!match) return false; for (let i = 1; i <= 4; i++) { const octet = parseInt(match[i], 10); if (octet < 0 || octet > 255) return false; } return true; } export function validateHostname(host: string): boolean { if (!host || host.length > 253) return false; return HOSTNAME_RE.test(host); } export function validateTarget(target: string): boolean { return validateIPv4(target) || validateHostname(target); } export function isRFC1918(ip: string): boolean { const match = IPV4_RE.exec(ip); if (!match) return false; const a = parseInt(match[1], 10); const b = parseInt(match[2], 10); if (a === 10) return true; if (a === 172 && b >= 16 && b <= 31) return true; if (a === 192 && b === 168) return true; if (a === 127) return true; if (a === 169 && b === 254) return true; return false; } export function validatePort(port: number): boolean { return Number.isInteger(port) && port >= 1 && port <= 65535; } function ipToInt(ip: string): number { const parts = ip.split(".").map(Number); return ((parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) >>> 0; } function intToIp(n: number): string { return [(n >>> 24) & 255, (n >>> 16) & 255, (n >>> 8) & 255, n & 255].join("."); } export function validateCIDR(cidr: string, allowPublic: boolean, maxPrefix: number): { valid: boolean; error?: string; firstIP?: string; lastIP?: string; count?: number } { const match = CIDR_RE.exec(cidr); if (!match) return { valid: false, error: "Invalid CIDR format" }; const ip = match[1]; const prefix = parseInt(match[2], 10); if (!validateIPv4(ip)) return { valid: false, error: "Invalid IP address" }; if (prefix < 0 || prefix > 32) return { valid: false, error: "Prefix must be 0-32" }; if (prefix < maxPrefix) return { valid: false, error: `Prefix must be /${maxPrefix} or larger (smaller range)` }; if (!allowPublic && !isRFC1918(ip)) { return { valid: false, error: "Only private (RFC1918) ranges allowed" }; } const ipInt = ipToInt(ip); const mask = prefix === 0 ? 0 : (~0 << (32 - prefix)) >>> 0; const network = (ipInt & mask) >>> 0; const broadcast = (network | ~mask) >>> 0; const count = broadcast - network + 1; return { valid: true, firstIP: intToIp(network), lastIP: intToIp(broadcast), count, }; } async function probeICMP(target: string, timeoutMs: number): Promise { const timeoutSec = Math.max(1, Math.ceil(timeoutMs / 1000)); const start = performance.now(); try { const proc = Bun.spawn(["ping", "-c", "1", "-W", String(timeoutSec), target], { stdout: "pipe", stderr: "ignore", }); const exitCode = await proc.exited; const elapsed = Math.round(performance.now() - start); if (exitCode === 0) { const output = await new Response(proc.stdout).text(); const rttMatch = /time[=<](\d+\.?\d*)\s*ms/i.exec(output); const rtt = rttMatch ? Math.round(parseFloat(rttMatch[1])) : elapsed; return { type: "icmp", status: "online", responseTime: rtt }; } return { type: "icmp", status: "offline", responseTime: null }; } catch { return { type: "icmp", status: "error", responseTime: null, detail: "ping failed" }; } } async function probeTCP(target: string, port: number, timeoutMs: number): Promise { const start = performance.now(); try { const socket = await Promise.race([ Bun.connect({ hostname: target, port, socket: { data() {}, open(socket) { socket.end(); }, error() {}, close() {}, }, }), new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); const elapsed = Math.round(performance.now() - start); const service = PORT_SERVICE_MAP[port] || ""; return { type: "tcp", port, status: "online", responseTime: elapsed, detail: service || undefined }; } catch { return { type: "tcp", port, status: "offline", responseTime: null }; } } async function probeHTTP(target: string, config: ProbeConfig, timeoutMs: number): Promise { const url = config.url || `http://${target}${config.path || "/"}`; const start = performance.now(); try { const resp = await fetch(url, { method: "HEAD", signal: AbortSignal.timeout(timeoutMs), redirect: "manual", }); const elapsed = Math.round(performance.now() - start); return { type: "http", status: resp.status < 500 ? "online" : "error", responseTime: elapsed, detail: `${resp.status} ${resp.statusText}`, }; } catch { return { type: "http", status: "offline", responseTime: null }; } } async function probeDNS(target: string, timeoutMs: number): Promise { const start = performance.now(); try { if (validateIPv4(target)) { const proc = Bun.spawn(["nslookup", target], { stdout: "pipe", stderr: "ignore", }); const raceResult = await Promise.race([ proc.exited, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); const elapsed = Math.round(performance.now() - start); const output = await new Response(proc.stdout).text(); const nameMatch = /name\s*=\s*(\S+)/i.exec(output); const hostname = nameMatch ? nameMatch[1].replace(/\.$/, "") : ""; return { type: "dns", status: raceResult === 0 ? "online" : "offline", responseTime: elapsed, detail: hostname || undefined }; } else { const results = await Bun.dns.resolve(target); const elapsed = Math.round(performance.now() - start); const ip = results.length > 0 ? (results[0] as any).address || String(results[0]) : ""; return { type: "dns", status: "online", responseTime: elapsed, detail: ip || undefined }; } } catch { return { type: "dns", status: "offline", responseTime: null }; } } export async function probeTarget(target: string, probes: ProbeConfig[], timeout: number): Promise<{ status: "online" | "offline" | "unknown"; rtt: number | null; results: ProbeResult[] }> { const cappedTimeout = Math.min(timeout, 10000); const results: ProbeResult[] = []; for (const probe of probes) { let result: ProbeResult; switch (probe.type) { case "icmp": result = await probeICMP(target, cappedTimeout); break; case "tcp": if (!probe.port || !validatePort(probe.port)) continue; result = await probeTCP(target, probe.port, cappedTimeout); break; case "http": result = await probeHTTP(target, probe, cappedTimeout); break; case "dns": result = await probeDNS(target, cappedTimeout); break; default: continue; } results.push(result); } const onlineResults = results.filter((r) => r.status === "online"); let status: "online" | "offline" | "unknown" = "unknown"; if (results.length === 0) status = "unknown"; else if (onlineResults.length > 0) status = "online"; else status = "offline"; const rtts = onlineResults.map((r) => r.responseTime).filter((t): t is number => t !== null); const rtt = rtts.length > 0 ? Math.min(...rtts) : null; return { status, rtt, results }; } export async function probeBatch(targets: BatchTarget[]): Promise> { const results: Record = {}; const batchSize = 10; for (let i = 0; i < targets.length; i += batchSize) { const batch = targets.slice(i, i + batchSize); const promises = batch.map(async (t) => { const result = await probeTarget(t.target, t.probes, t.timeout); results[t.nodeId] = result; }); await Promise.all(promises); } return results; } export function getServiceIcon(ports: number[]): { library: string; name: string } { for (const entry of SERVICE_ICON_MAP) { for (const port of ports) { if (entry.ports.includes(port)) return { library: entry.library, name: entry.name }; } } return { ...DEFAULT_ICON }; } const GENERIC_ICON_NAMES = new Set(["terminal", "windows", "vnc", "cups", "mailcow", "openwrt"]); export function getServiceIcons(ports: number[]): { library: string; name: string }[] { const icons: { library: string; name: string }[] = []; const seen = new Set(); for (const entry of SERVICE_ICON_MAP) { if (GENERIC_ICON_NAMES.has(entry.name)) continue; for (const port of ports) { if (entry.ports.includes(port)) { const key = entry.library + "/" + entry.name; if (!seen.has(key)) { seen.add(key); icons.push({ library: entry.library, name: entry.name }); } break; } } } return icons; } export function getDefaultPortList(): { port: number; service: string; icon: string | null }[] { return DEFAULT_SCAN_PORTS.map(port => { const service = PORT_SERVICE_MAP[port] || `Port ${port}`; let icon: string | null = null; for (const entry of SERVICE_ICON_MAP) { if (entry.ports.includes(port)) { icon = entry.name; break; } } return { port, service, icon }; }); } function getServicesForPorts(ports: number[]): Record { const services: Record = {}; for (const port of ports) { if (PORT_SERVICE_MAP[port]) services[port] = PORT_SERVICE_MAP[port]; else services[port] = `Port ${port}`; } return services; } async function reverseDNS(ip: string, timeoutMs: number): Promise { try { const proc = Bun.spawn(["nslookup", ip], { stdout: "pipe", stderr: "ignore" }); const raceResult = await Promise.race([ proc.exited, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); if (raceResult !== 0) return ""; const output = await new Response(proc.stdout).text(); const nameMatch = /name\s*=\s*(\S+)/i.exec(output); return nameMatch ? nameMatch[1].replace(/\.$/, "") : ""; } catch { return ""; } } async function resolveNetBIOS(ip: string, timeoutMs: number): Promise { try { const proc = Bun.spawn(["nmblookup", "-A", ip], { stdout: "pipe", stderr: "ignore" }); const raceResult = await Promise.race([ proc.exited, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); if (raceResult !== 0) { const output = await new Response(proc.stdout).text(); const nameMatch = /(\S+)\s+<00>\s+-\s+/i.exec(output); if (nameMatch) return nameMatch[1]; } const output = await new Response(proc.stdout).text(); const nameMatch = /(\S+)\s+<00>\s+-\s+/i.exec(output); return nameMatch ? nameMatch[1] : ""; } catch { return ""; } } async function resolveMDNS(ip: string, timeoutMs: number): Promise { try { const proc = Bun.spawn(["avahi-resolve", "-a", ip], { stdout: "pipe", stderr: "ignore" }); const raceResult = await Promise.race([ proc.exited, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); if (raceResult !== 0) return ""; const output = await new Response(proc.stdout).text(); const parts = output.trim().split(/\s+/); return parts.length >= 2 ? parts[1] : ""; } catch { return ""; } } async function resolveHTTPServer(ip: string, timeoutMs: number): Promise { try { const resp = await fetch(`http://${ip}/`, { method: "HEAD", signal: AbortSignal.timeout(timeoutMs), redirect: "manual", }); const server = resp.headers.get("server") || ""; if (server) return server; const xPowered = resp.headers.get("x-powered-by") || ""; return xPowered; } catch { return ""; } } interface DNSFingerprint { serviceName: string; icon?: { library: string; name: string }; extraServices?: Record; } async function fingerprintDNS(ip: string, openPorts: number[], timeoutMs: number): Promise { if (openPorts.includes(5380)) { return { serviceName: "Technitium DNS", icon: { library: "selfhst", name: "technitium-dns" } }; } const adguardPorts = [80, 3000, 443].filter(p => openPorts.includes(p)); for (const port of adguardPorts) { try { const protocol = port === 443 ? "https" : "http"; const portSuffix = (port === 80 || port === 443) ? "" : `:${port}`; const resp = await fetch(`${protocol}://${ip}${portSuffix}/control/status`, { signal: AbortSignal.timeout(timeoutMs), redirect: "manual", }); if (resp.status === 401 || resp.status === 403 || resp.ok) { const isAdGuard = resp.status === 401 || resp.status === 403; if (!isAdGuard && resp.ok) { const text = await resp.text(); if (!text.includes("running") && !text.includes("version")) continue; } const extra: Record = {}; if (port !== 80 && port !== 443) extra[port] = "AdGuard Home"; return { serviceName: "AdGuard Home", icon: { library: "selfhst", name: "adguard-home" }, extraServices: Object.keys(extra).length > 0 ? extra : undefined, }; } } catch {} } const piholePorts = [80, 443].filter(p => openPorts.includes(p)); for (const port of piholePorts) { const protocol = port === 443 ? "https" : "http"; try { const resp = await fetch(`${protocol}://${ip}/admin/api.php`, { signal: AbortSignal.timeout(timeoutMs), redirect: "manual", }); if (resp.ok || resp.status === 401 || resp.status === 403) { return { serviceName: "Pi-hole", icon: { library: "selfhst", name: "pihole" } }; } } catch {} try { const resp = await fetch(`${protocol}://${ip}/api/`, { signal: AbortSignal.timeout(timeoutMs), redirect: "manual", }); if (resp.ok || resp.status === 401 || resp.status === 403) { return { serviceName: "Pi-hole", icon: { library: "selfhst", name: "pihole" } }; } } catch {} } return { serviceName: "DNS" }; } async function resolveSNMP(ip: string, community: string, timeoutMs: number): Promise<{ sysName: string; sysDescr: string }> { const timeoutSec = Math.max(1, Math.ceil(timeoutMs / 1000)); try { const proc = Bun.spawn( ["snmpget", "-v2c", "-c", community, "-t", String(timeoutSec), "-r", "0", ip, "1.3.6.1.2.1.1.5.0", "1.3.6.1.2.1.1.1.0"], { stdout: "pipe", stderr: "ignore" }, ); const raceResult = await Promise.race([ proc.exited, new Promise((_, reject) => setTimeout(() => reject(new Error("timeout")), timeoutMs)), ]); if (raceResult !== 0) return { sysName: "", sysDescr: "" }; const output = await new Response(proc.stdout).text(); const lines = output.split("\n"); let sysName = ""; let sysDescr = ""; for (const line of lines) { const valMatch = /STRING:\s*"?([^"]*)"?/i.exec(line); if (!valMatch) continue; if (line.includes("1.3.6.1.2.1.1.5.0")) sysName = valMatch[1].trim(); else if (line.includes("1.3.6.1.2.1.1.1.0")) sysDescr = valMatch[1].trim(); } return { sysName, sysDescr }; } catch { return { sysName: "", sysDescr: "" }; } } function bestHostname(host: DiscoveredHost): string { return host.netbiosName || host.mdnsName || host.dnsName || host.ip; } function cidrToIPs(cidr: string): string[] { const validation = validateCIDR(cidr, true, 20); if (!validation.valid || !validation.firstIP || !validation.count) return []; const firstInt = ipToInt(validation.firstIP); const ips: string[] = []; for (let i = 0; i < validation.count; i++) { const ip = intToIp(firstInt + i); if (!ip.endsWith(".0") && !ip.endsWith(".255")) { ips.push(ip); } } return ips; } export async function startDiscovery( taskId: string, roomId: string, cidrs: string[], options: DiscoveryOptions, onProgress: (percent: number, scanned: number, total: number, rangeIndex: number, totalRanges: number) => void, onFound: (host: DiscoveredHost) => void, onComplete: (totalFound: number) => void, ): Promise { const allIPs: { ip: string; rangeIndex: number }[] = []; for (let r = 0; r < cidrs.length; r++) { const ips = cidrToIPs(cidrs[r]); for (const ip of ips) { allIPs.push({ ip, rangeIndex: r }); } } if (allIPs.length === 0) throw new Error("No valid IPs in ranges"); const handle: DiscoveryHandle = { taskId, cancelled: false, cancel() { this.cancelled = true; }, }; activeDiscoveries.set(taskId, handle); const userPorts = options.ports && options.ports.length > 0 ? options.ports.filter(validatePort) : []; const scanPorts = [...new Set([...DEFAULT_SCAN_PORTS, ...userPorts])].sort((a, b) => a - b); const totalRanges = cidrs.length; (async () => { let scanned = 0; let found = 0; const total = allIPs.length; const pingBatchSize = 50; try { for (let i = 0; i < allIPs.length; i += pingBatchSize) { if (handle.cancelled) break; const batch = allIPs.slice(i, i + pingBatchSize); const pingResults = await Promise.all( batch.map(async (entry) => { if (handle.cancelled) return null; const result = await probeICMP(entry.ip, 1500); return result.status === "online" ? entry : null; }), ); const aliveEntries = pingResults.filter((e): e is { ip: string; rangeIndex: number } => e !== null); for (const entry of aliveEntries) { if (handle.cancelled) break; const host: DiscoveredHost = { ip: entry.ip, hostname: "", ports: [], services: {}, icon: { ...DEFAULT_ICON }, serviceIcons: [], dnsName: "", netbiosName: "", mdnsName: "", httpServer: "", snmpName: "", snmpDescr: "", }; if (options.tcp) { const portBatchSize = 10; for (let p = 0; p < scanPorts.length; p += portBatchSize) { if (handle.cancelled) break; const portBatch = scanPorts.slice(p, p + portBatchSize); const portResults = await Promise.all( portBatch.map(async (port) => { const result = await probeTCP(entry.ip, port, 1500); return result.status === "online" ? port : null; }), ); const openPorts = portResults.filter((p): p is number => p !== null); host.ports.push(...openPorts); } host.services = getServicesForPorts(host.ports); if (host.ports.includes(53)) { const dnsResult = await fingerprintDNS(entry.ip, host.ports, 2000); host.services[53] = dnsResult.serviceName; if (dnsResult.icon) host.icon = dnsResult.icon; if (dnsResult.extraServices) { for (const [portStr, svcName] of Object.entries(dnsResult.extraServices)) { host.services[parseInt(portStr, 10)] = svcName; } } if (!dnsResult.icon) host.icon = getServiceIcon(host.ports); } else { host.icon = getServiceIcon(host.ports); } host.serviceIcons = getServiceIcons(host.ports); } const namePromises: Promise[] = []; if (options.dns) { namePromises.push(reverseDNS(entry.ip, 2000).then((name) => { host.dnsName = name; })); } if (options.netbios) { namePromises.push(resolveNetBIOS(entry.ip, 2000).then((name) => { host.netbiosName = name; })); } if (options.mdns) { namePromises.push(resolveMDNS(entry.ip, 2000).then((name) => { host.mdnsName = name; })); } if (host.ports.includes(80) || host.ports.includes(443) || host.ports.includes(8080)) { namePromises.push(resolveHTTPServer(entry.ip, 2000).then((server) => { host.httpServer = server; })); } if (options.snmp && options.snmpCommunity && (host.ports.includes(161) || !options.tcp)) { namePromises.push( resolveSNMP(entry.ip, options.snmpCommunity, 3000).then((result) => { host.snmpName = result.sysName; host.snmpDescr = result.sysDescr; }), ); } await Promise.all(namePromises); host.hostname = bestHostname(host); found++; onFound(host); } scanned += batch.length; const percent = Math.round((scanned / total) * 100); const currentRange = batch.length > 0 ? batch[batch.length - 1].rangeIndex : 0; onProgress(percent, scanned, total, currentRange, totalRanges); } onComplete(found); } finally { activeDiscoveries.delete(taskId); } })(); return handle; } export function cancelDiscovery(taskId: string): boolean { const handle = activeDiscoveries.get(taskId); if (!handle) return false; handle.cancel(); activeDiscoveries.delete(taskId); return true; } export function hasActiveDiscovery(roomId: string): boolean { for (const [, handle] of activeDiscoveries) { if (!handle.cancelled) return true; } return false; } export function hasActiveDiscoveryForRoom(roomId: string, taskPrefix: string): boolean { for (const [taskId, handle] of activeDiscoveries) { if (taskId.startsWith(taskPrefix) && !handle.cancelled) return true; } return false; } export function validateProbeConfig(probes: unknown): probes is ProbeConfig[] { if (!Array.isArray(probes)) return false; if (probes.length === 0 || probes.length > 20) return false; const validTypes = ["icmp", "tcp", "http", "dns"]; for (const probe of probes) { if (!probe || typeof probe !== "object") return false; if (!validTypes.includes(probe.type)) return false; if (probe.type === "tcp" && (!probe.port || !validatePort(probe.port))) return false; } return true; } export const DOCKER_TRIGGER_PORTS = [2375, 2376, 9443, 5001]; const DOCKER_DEEP_SCAN_PORTS: number[] = []; for (let p = 1000; p <= 10000; p++) DOCKER_DEEP_SCAN_PORTS.push(p); for (let p = 30000; p <= 33000; p++) DOCKER_DEEP_SCAN_PORTS.push(p); export interface DockerContainer { name: string; image: string; ports: { hostPort: number; containerPort: number; protocol: string }[]; state: string; } interface DeepScanHandle { scanId: string; ip: string; cancelled: boolean; cancel: () => void; } const activeDeepScans = new Map(); async function queryDockerAPI(ip: string, timeoutMs: number): Promise { for (const port of [2375, 2376]) { try { const protocol = port === 2376 ? "https" : "http"; const resp = await fetch(`${protocol}://${ip}:${port}/containers/json?all=false`, { signal: AbortSignal.timeout(timeoutMs), }); if (!resp.ok) continue; const containers = await resp.json(); if (!Array.isArray(containers)) continue; return containers.map((c: any) => ({ name: Array.isArray(c.Names) && c.Names.length > 0 ? c.Names[0].replace(/^\//, "") : "unknown", image: c.Image || "", ports: Array.isArray(c.Ports) ? c.Ports.filter((p: any) => p.PublicPort) .map((p: any) => ({ hostPort: p.PublicPort, containerPort: p.PrivatePort || p.PublicPort, protocol: p.Type || "tcp", })) : [], state: c.State || "", })); } catch { continue; } } return null; } export async function startDeepScan( scanId: string, ip: string, existingPorts: number[], onProgress: (percent: number, scanned: number, total: number) => void, onUpdate: (newPorts: number[], newServices: Record, containers: DockerContainer[] | null) => void, onComplete: () => void, ): Promise { const handle: DeepScanHandle = { scanId, ip, cancelled: false, cancel() { this.cancelled = true; }, }; activeDeepScans.set(scanId, handle); (async () => { try { const hasDockerAPI = existingPorts.includes(2375) || existingPorts.includes(2376); let containers: DockerContainer[] | null = null; const discoveredPorts: number[] = []; const discoveredServices: Record = {}; if (hasDockerAPI) { containers = await queryDockerAPI(ip, 5000); if (containers) { for (const container of containers) { for (const pm of container.ports) { if (!existingPorts.includes(pm.hostPort) && !discoveredPorts.includes(pm.hostPort)) { discoveredPorts.push(pm.hostPort); } const imageName = container.image.split(":")[0].split("/").pop() || container.image; discoveredServices[pm.hostPort] = `${imageName} (${container.name})`; } } onProgress(100, 1, 1); onUpdate(discoveredPorts, discoveredServices, containers); onComplete(); return; } } const existingSet = new Set(existingPorts); const portsToScan = DOCKER_DEEP_SCAN_PORTS.filter(p => !existingSet.has(p)); const total = portsToScan.length; let scanned = 0; const deepBatchSize = 20; for (let i = 0; i < portsToScan.length; i += deepBatchSize) { if (handle.cancelled) break; const batch = portsToScan.slice(i, i + deepBatchSize); const results = await Promise.allSettled( batch.map(async (port) => { const result = await probeTCP(ip, port, 1500); return result.status === "online" ? port : null; }), ); for (const r of results) { if (r.status === "fulfilled" && r.value !== null) { const port = r.value; if (!discoveredPorts.includes(port)) { discoveredPorts.push(port); discoveredServices[port] = PORT_SERVICE_MAP[port] || `Port ${port}`; } } } scanned += batch.length; const percent = Math.round((scanned / total) * 100); onProgress(percent, scanned, total); } onUpdate(discoveredPorts, discoveredServices, null); onComplete(); } finally { activeDeepScans.delete(scanId); } })(); return handle; } export function cancelDeepScan(scanId: string): boolean { const handle = activeDeepScans.get(scanId); if (!handle) return false; handle.cancel(); activeDeepScans.delete(scanId); return true; } export function hasActiveDeepScan(ip: string): boolean { for (const [, handle] of activeDeepScans) { if (handle.ip === ip && !handle.cancelled) return true; } return false; } ================================================ FILE: theonefile_verse/src/oidc.ts ================================================ import * as db from "./database"; const DEBUG_OIDC = process.env.DEBUG_OIDC === 'true'; if (DEBUG_OIDC) { const authSettings = db.getSetting('authSettings'); const isProduction = authSettings ? JSON.parse(authSettings).productionMode : false; if (isProduction) { console.warn('[Security] WARNING: DEBUG_OIDC is enabled in production mode!'); console.warn('[Security] This may expose sensitive information in logs. Disable DEBUG_OIDC for production.'); } } function logOidcError(message: string, ...args: any[]): void { if (DEBUG_OIDC) { console.error('[OIDC]', message, ...args); } else { console.error('[OIDC]', message); } } function logOidcDebug(message: string, ...args: any[]): void { if (DEBUG_OIDC) { console.log('[OIDC]', message, ...args); } } const MAX_OIDC_STATES = 10000; const OIDC_STATE_TTL_MS = 10 * 60 * 1000; const ID_TOKEN_CLOCK_SKEW_MS = parseInt(process.env.OIDC_CLOCK_SKEW_SECONDS || '120') * 1000; const CSRF_TOKEN_TTL_MS = 60 * 60 * 1000; const MAX_CSRF_TOKENS = 10000; function cleanupOldestOidcStates(): void { db.cleanupExpiredOidcStates(); const count = db.countOidcStates(); if (count <= MAX_OIDC_STATES) return; db.deleteOldestOidcStates(count - MAX_OIDC_STATES + 100); } setInterval(() => { db.cleanupExpiredOidcStates(); db.cleanupExpiredCsrfTokens(); }, 60 * 1000); function generateRandomString(length: number): string { const array = new Uint8Array(length); crypto.getRandomValues(array); return base64UrlEncode(array); } function generateCodeVerifier(): string { const array = new Uint8Array(32); crypto.getRandomValues(array); return base64UrlEncode(array); } async function generateCodeChallenge(verifier: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(verifier); const hash = await crypto.subtle.digest('SHA-256', data); return base64UrlEncode(new Uint8Array(hash)); } function base64UrlEncode(buffer: Uint8Array): string { let str = ''; for (const byte of buffer) { str += String.fromCharCode(byte); } return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } const ENCRYPTION_KEY_LENGTH = 32; const PBKDF2_ITERATIONS = 600000; const PBKDF2_SALT_LENGTH = 16; let encryptionKey: CryptoKey | null = null; async function deriveKeyFromSecret(secret: string, salt: Uint8Array): Promise { const encoder = new TextEncoder(); const keyMaterial = await crypto.subtle.importKey( 'raw', encoder.encode(secret), 'PBKDF2', false, ['deriveBits', 'deriveKey'] ); return await crypto.subtle.deriveKey( { name: 'PBKDF2', salt: salt, iterations: PBKDF2_ITERATIONS, hash: 'SHA-256' }, keyMaterial, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt'] ); } async function getEncryptionKeyMaterial(): Promise { const envKey = process.env.ENCRYPTION_KEY; if (envKey) { if (envKey.length < 32 || !/^[0-9a-fA-F]+$/.test(envKey)) { console.error('[FATAL] ENCRYPTION_KEY must be a hex string of at least 32 characters.'); console.error('[FATAL] Generate one with: openssl rand -hex 32'); process.exit(1); } const encoder = new TextEncoder(); const hash = await crypto.subtle.digest('SHA-256', encoder.encode(envKey)); return new Uint8Array(hash); } const authSettings = db.getSetting('authSettings'); const isProduction = authSettings ? JSON.parse(authSettings).productionMode : false; if (isProduction) { console.error('='.repeat(70)); console.error('[FATAL] ENCRYPTION_KEY environment variable is required in production mode.'); console.error('[FATAL] Set ENCRYPTION_KEY in your environment before starting the server.'); console.error('[FATAL] Generate one with: openssl rand -hex 32'); console.error('='.repeat(70)); process.exit(1); } let keyHex = db.getSetting('encryption_key'); if (!keyHex) { const keyBytes = new Uint8Array(ENCRYPTION_KEY_LENGTH); crypto.getRandomValues(keyBytes); keyHex = Array.from(keyBytes, b => b.toString(16).padStart(2, '0')).join(''); db.setSetting('encryption_key', keyHex); console.warn('='.repeat(70)); console.warn('[SECURITY WARNING] ENCRYPTION_KEY environment variable not set.'); console.warn('[SECURITY WARNING] A random key has been generated and stored in the database.'); console.warn('[SECURITY WARNING] This is acceptable for development but NOT for production.'); console.warn('[SECURITY WARNING] Enable productionMode and set ENCRYPTION_KEY for production.'); console.warn('='.repeat(70)); } return new Uint8Array(keyHex.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16))); } async function getEncryptionKey(salt: Uint8Array): Promise { const keyMaterial = await getEncryptionKeyMaterial(); const importedKey = await crypto.subtle.importKey( 'raw', keyMaterial, 'PBKDF2', false, ['deriveBits', 'deriveKey'] ); return await crypto.subtle.deriveKey( { name: 'PBKDF2', salt: salt, iterations: PBKDF2_ITERATIONS, hash: 'SHA-256' }, importedKey, { name: 'AES-GCM', length: 256 }, false, ['encrypt', 'decrypt'] ); } export async function encryptSecret(plaintext: string): Promise { const salt = crypto.getRandomValues(new Uint8Array(PBKDF2_SALT_LENGTH)); const key = await getEncryptionKey(salt); const iv = crypto.getRandomValues(new Uint8Array(12)); const encoder = new TextEncoder(); const encrypted = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, key, encoder.encode(plaintext) ); const combined = new Uint8Array(salt.length + iv.length + encrypted.byteLength); combined.set(salt); combined.set(iv, salt.length); combined.set(new Uint8Array(encrypted), salt.length + iv.length); return base64UrlEncode(combined); } export async function decryptSecret(ciphertext: string): Promise { const combined = Uint8Array.from(atob(ciphertext.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); const isNewFormat = combined.length >= 44; if (isNewFormat) { const salt = combined.slice(0, PBKDF2_SALT_LENGTH); const iv = combined.slice(PBKDF2_SALT_LENGTH, PBKDF2_SALT_LENGTH + 12); const encrypted = combined.slice(PBKDF2_SALT_LENGTH + 12); const key = await getEncryptionKey(salt); const decrypted = await crypto.subtle.decrypt( { name: 'AES-GCM', iv }, key, encrypted ); return new TextDecoder().decode(decrypted); } else { const legacySalt = new TextEncoder().encode('theonefile-verse-encryption-v1'); const key = await getEncryptionKey(legacySalt); const iv = combined.slice(0, 12); const encrypted = combined.slice(12); const decrypted = await crypto.subtle.decrypt( { name: 'AES-GCM', iv }, key, encrypted ); return new TextDecoder().decode(decrypted); } } interface OidcDiscovery { issuer: string; authorization_endpoint: string; token_endpoint: string; userinfo_endpoint: string; jwks_uri: string; scopes_supported?: string[]; revocation_endpoint?: string; } async function discoverOidcEndpoints(issuerUrl: string): Promise { try { const wellKnownUrl = issuerUrl.replace(/\/$/, '') + '/.well-known/openid-configuration'; const res = await fetch(wellKnownUrl); if (!res.ok) return null; const disc = await res.json(); if (!disc.authorization_endpoint || !disc.token_endpoint) return null; const normExpected = issuerUrl.replace(/\/$/, ''); const normActual = (disc.issuer || '').replace(/\/$/, ''); if (normActual && normActual !== normExpected) { logOidcError('Discovery issuer mismatch', { expected: normExpected, got: normActual }); return null; } return disc; } catch { return null; } } export interface OidcAuthUrl { url: string; state: string; } export interface OidcUserInfo { sub: string; email?: string; email_verified?: boolean; name?: string; preferred_username?: string; picture?: string; } export interface OidcTokenResponse { access_token: string; token_type: string; expires_in?: number; refresh_token?: string; id_token?: string; } export async function generateAuthorizationUrl( providerId: string, baseUrl: string, linkUserId?: string, postLoginRedirect?: string ): Promise { const provider = db.getOidcProvider(providerId); if (!provider || !provider.isActive) return null; const codeVerifier = generateCodeVerifier(); const codeChallenge = await generateCodeChallenge(codeVerifier); const state = generateRandomString(32); const nonce = generateRandomString(32); const redirectUri = `${baseUrl}/auth/callback/${providerId}`; cleanupOldestOidcStates(); const now = new Date(); const expiresAt = new Date(now.getTime() + OIDC_STATE_TTL_MS); db.createOidcState({ state, providerId, codeVerifier, nonce, redirectUri, linkUserId: linkUserId || null, postLoginRedirect: postLoginRedirect || null, createdAt: now.toISOString(), expiresAt: expiresAt.toISOString() }); let authUrl = provider.authorizationUrl; if (provider.issuerUrl && !authUrl) { const discovery = await discoverOidcEndpoints(provider.issuerUrl); if (discovery) { authUrl = discovery.authorization_endpoint; } } if (!authUrl) return null; let scopes = provider.scopes || 'openid email profile'; if (!scopes.split(' ').includes('openid')) scopes = 'openid ' + scopes; const params = new URLSearchParams({ response_type: 'code', client_id: provider.clientId, redirect_uri: redirectUri, scope: scopes, state, nonce, code_challenge: codeChallenge, code_challenge_method: 'S256' }); return { url: `${authUrl}?${params.toString()}`, state }; } export async function exchangeCodeForTokens( providerId: string, code: string, state: string ): Promise<{ tokens: OidcTokenResponse; userInfo: OidcUserInfo; linkUserId?: string; postLoginRedirect?: string } | null> { const storedState = db.getOidcState(state); if (!storedState || storedState.providerId !== providerId) { return null; } if (new Date(storedState.expiresAt) < new Date()) { db.deleteOidcState(state); return null; } db.deleteOidcState(state); const provider = db.getOidcProvider(providerId); if (!provider) return null; let tokenUrl = provider.tokenUrl; let userinfoUrl = provider.userinfoUrl; let jwksUri = provider.jwksUri; if (provider.issuerUrl && (!tokenUrl || !userinfoUrl || !jwksUri)) { const discovery = await discoverOidcEndpoints(provider.issuerUrl); if (discovery) { tokenUrl = tokenUrl || discovery.token_endpoint; userinfoUrl = userinfoUrl || discovery.userinfo_endpoint; jwksUri = jwksUri || discovery.jwks_uri; } } if (!tokenUrl) return null; let clientSecret: string; try { clientSecret = await decryptSecret(provider.clientSecretEncrypted); } catch { return null; } const tokenParams = new URLSearchParams({ grant_type: 'authorization_code', client_id: provider.clientId, client_secret: clientSecret, code, redirect_uri: storedState.redirectUri, code_verifier: storedState.codeVerifier }); const storedNonce = storedState.nonce; const storedLinkUserId = storedState.linkUserId; const storedPostLoginRedirect = storedState.postLoginRedirect; try { const tokenRes = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: tokenParams.toString() }); if (!tokenRes.ok) { const errText = await tokenRes.text(); logOidcError('Token exchange failed', errText.substring(0, 200).replace(/access_token[^&]*/gi, 'access_token=[REDACTED]').replace(/refresh_token[^&]*/gi, 'refresh_token=[REDACTED]')); return null; } const tokens: OidcTokenResponse = await tokenRes.json(); if (tokens.token_type && tokens.token_type.toLowerCase() !== 'bearer') { logOidcError('Unsupported token type', tokens.token_type); return null; } let userInfo: OidcUserInfo | null = null; if (tokens.id_token) { userInfo = await parseIdToken( tokens.id_token, storedNonce, jwksUri, provider.issuerUrl, provider.clientId ); } if (!userInfo && userinfoUrl) { const userInfoRes = await fetch(userinfoUrl, { headers: { 'Authorization': `Bearer ${tokens.access_token}` } }); if (userInfoRes.ok) { userInfo = await userInfoRes.json(); } } if (!userInfo || !userInfo.sub) { logOidcError('Could not get user info'); return null; } return { tokens, userInfo, linkUserId: storedLinkUserId || undefined, postLoginRedirect: storedPostLoginRedirect || undefined }; } catch (e) { logOidcError('Token exchange error', e); return null; } } const MAX_JWKS_CACHE_ENTRIES = 100; const jwksCache = new Map(); function cleanupJwksCache(): void { if (jwksCache.size <= MAX_JWKS_CACHE_ENTRIES) return; const entries = Array.from(jwksCache.entries()) .sort((a, b) => a[1].fetchedAt - b[1].fetchedAt); const toRemove = entries.slice(0, jwksCache.size - MAX_JWKS_CACHE_ENTRIES + 10); for (const [key] of toRemove) { jwksCache.delete(key); } } async function sleep(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } async function fetchJwks(jwksUri: string): Promise { const cached = jwksCache.get(jwksUri); if (cached && Date.now() - cached.fetchedAt < 60 * 60 * 1000) { return cached.keys; } const maxRetries = 3; const baseDelayMs = 100; for (let attempt = 0; attempt < maxRetries; attempt++) { try { const res = await fetch(jwksUri); if (!res.ok) { if (attempt < maxRetries - 1) { const jitter = new Uint32Array(1); crypto.getRandomValues(jitter); const delay = baseDelayMs * Math.pow(2, attempt) + (jitter[0] % 100); await sleep(delay); continue; } return []; } const data = await res.json(); const keys = data.keys || []; cleanupJwksCache(); jwksCache.set(jwksUri, { keys, fetchedAt: Date.now() }); return keys; } catch { if (attempt < maxRetries - 1) { const jitter = new Uint32Array(1); crypto.getRandomValues(jitter); const delay = baseDelayMs * Math.pow(2, attempt) + (jitter[0] % 100); await sleep(delay); continue; } return []; } } return []; } function getHashAlgorithm(alg: string): string { if (alg.endsWith('384')) return 'SHA-384'; if (alg.endsWith('512')) return 'SHA-512'; return 'SHA-256'; } async function importJwkForVerify(jwk: JsonWebKey, headerAlg?: string): Promise { try { const alg = jwk.alg || headerAlg; if (!alg) return null; let algorithm: RsaHashedImportParams | EcKeyImportParams; if (alg.startsWith('RS')) { algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: { name: getHashAlgorithm(alg) } }; } else if (alg.startsWith('ES')) { algorithm = { name: 'ECDSA', namedCurve: jwk.crv || 'P-256' }; } else { return null; } return await crypto.subtle.importKey('jwk', jwk, algorithm, false, ['verify']); } catch { return null; } } async function verifyJwtSignature(token: string, jwks: JsonWebKey[]): Promise { const parts = token.split('.'); if (parts.length !== 3) return false; try { const header = JSON.parse(atob(parts[0].replace(/-/g, '+').replace(/_/g, '/'))); const signature = Uint8Array.from(atob(parts[2].replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0)); const signedData = new TextEncoder().encode(parts[0] + '.' + parts[1]); const matchingKeys = header.kid ? jwks.filter(k => k.kid === header.kid) : jwks; for (const jwk of matchingKeys) { const key = await importJwkForVerify(jwk, header.alg); if (!key) continue; const alg = jwk.alg || header.alg; if (!alg) continue; let verifyAlg: AlgorithmIdentifier | RsaPssParams | EcdsaParams; if (alg.startsWith('RS')) { verifyAlg = { name: 'RSASSA-PKCS1-v1_5' }; } else if (alg.startsWith('ES')) { verifyAlg = { name: 'ECDSA', hash: { name: getHashAlgorithm(alg) } }; } else { continue; } const valid = await crypto.subtle.verify(verifyAlg, key, signature, signedData); if (valid) return true; } return false; } catch (e) { logOidcError('JWT signature verification error', e); return false; } } async function parseIdToken( idToken: string, expectedNonce: string, jwksUri?: string | null, expectedIssuer?: string | null, expectedAudience?: string | null ): Promise { try { const parts = idToken.split('.'); if (parts.length !== 3) return null; if (jwksUri) { const jwks = await fetchJwks(jwksUri); if (jwks.length === 0) { logOidcError('Failed to fetch JWKS for signature verification'); return null; } const signatureValid = await verifyJwtSignature(idToken, jwks); if (!signatureValid) { logOidcError('ID token signature verification failed'); return null; } } const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'))); if (expectedIssuer) { const normalizedExpected = expectedIssuer.replace(/\/$/, ''); const normalizedActual = (payload.iss || '').replace(/\/$/, ''); if (normalizedActual !== normalizedExpected) { logOidcError('Issuer mismatch', { expected: normalizedExpected, got: normalizedActual }); return null; } } if (expectedAudience) { const aud = payload.aud; const audArray = Array.isArray(aud) ? aud : [aud]; if (!audArray.includes(expectedAudience)) { logOidcError('Audience mismatch', { expected: expectedAudience, got: aud }); return null; } if (audArray.length > 1 && payload.azp !== expectedAudience) { logOidcError('Authorized party (azp) mismatch for multi-audience token'); return null; } } if (typeof payload.nonce !== 'string' || typeof expectedNonce !== 'string' || payload.nonce.length !== expectedNonce.length || !crypto.timingSafeEqual(Buffer.from(payload.nonce), Buffer.from(expectedNonce))) { logOidcError('Nonce mismatch'); return null; } if (payload.exp && payload.exp * 1000 < Date.now() - ID_TOKEN_CLOCK_SKEW_MS) { logOidcError('ID token expired'); return null; } if (payload.nbf && payload.nbf * 1000 > Date.now() + ID_TOKEN_CLOCK_SKEW_MS) { logOidcError('ID token not yet valid (nbf)'); return null; } if (payload.iat && payload.iat * 1000 < Date.now() - getIdTokenMaxAgeMs()) { logOidcError('ID token too old'); return null; } if (payload.iat && payload.iat * 1000 > Date.now() + ID_TOKEN_CLOCK_SKEW_MS) { logOidcError('ID token issued in the future'); return null; } if (!payload.sub) { logOidcError('ID token missing required sub claim'); return null; } return { sub: payload.sub, email: payload.email, email_verified: payload.email_verified, name: payload.name || payload.preferred_username, preferred_username: payload.preferred_username, picture: payload.picture }; } catch { return null; } } export async function processOidcCallback( providerId: string, code: string, state: string, ipAddress: string, userAgent: string, currentUserToken?: string | null ): Promise<{ success: boolean; userId?: string; sessionToken?: string; error?: string; isNewUser?: boolean; isLinked?: boolean; message?: string; postLoginRedirect?: string; }> { const result = await exchangeCodeForTokens(providerId, code, state); if (!result) { return { success: false, error: 'Failed to exchange code for tokens' }; } const { tokens, userInfo, linkUserId, postLoginRedirect } = result; const provider = db.getOidcProvider(providerId); if (!provider) { return { success: false, error: 'Provider not found' }; } const existingLink = db.getOidcLinkByProvider(provider.name, userInfo.sub); if (existingLink) { const encryptedAccess = tokens.access_token ? await encryptSecret(tokens.access_token) : null; const encryptedRefresh = tokens.refresh_token ? await encryptSecret(tokens.refresh_token) : null; const expiresAt = tokens.expires_in ? new Date(Date.now() + tokens.expires_in * 1000).toISOString() : null; db.updateOidcLinkTokens(existingLink.id, encryptedAccess, encryptedRefresh, expiresAt); const user = db.getUserById(existingLink.userId); if (user) { user.lastLogin = new Date().toISOString(); user.updatedAt = new Date().toISOString(); db.updateUser(user); } const sessionToken = await createUserSessionToken(existingLink.userId, ipAddress, userAgent); db.logAuthEvent('oidc_login', existingLink.userId, ipAddress, { provider: provider.name, providerUserId: userInfo.sub }); return { success: true, userId: existingLink.userId, sessionToken, isNewUser: false, postLoginRedirect }; } if (linkUserId) { if (currentUserToken) { const currentUser = await validateUserSessionToken(currentUserToken); if (!currentUser || currentUser.id !== linkUserId) { return { success: false, error: 'Session expired or invalid for account linking' }; } } else { return { success: false, error: 'Authentication required for account linking' }; } const user = db.getUserById(linkUserId); if (!user) { return { success: false, error: 'User not found for linking' }; } const encryptedAccess = tokens.access_token ? await encryptSecret(tokens.access_token) : null; const encryptedRefresh = tokens.refresh_token ? await encryptSecret(tokens.refresh_token) : null; const expiresAt = tokens.expires_in ? new Date(Date.now() + tokens.expires_in * 1000).toISOString() : null; db.createOidcLink({ id: crypto.randomUUID(), userId: linkUserId, provider: provider.name, providerUserId: userInfo.sub, providerEmail: userInfo.email || null, accessTokenEncrypted: encryptedAccess, refreshTokenEncrypted: encryptedRefresh, tokenExpiresAt: expiresAt, createdAt: new Date().toISOString() }); db.logAuthEvent('oidc_link', linkUserId, ipAddress, { provider: provider.name, providerUserId: userInfo.sub }); return { success: true, userId: linkUserId, isNewUser: false, isLinked: true, message: `Successfully linked ${provider.name} account`, postLoginRedirect }; } const authSettings = getAuthSettings(); let existingUser: db.User | null = null; if (authSettings.oidcEmailMatching && userInfo.email && userInfo.email_verified) { const candidate = db.getUserByEmail(userInfo.email.toLowerCase().trim()); if (candidate && candidate.emailVerified) existingUser = candidate; } if (existingUser) { const encryptedAccess = tokens.access_token ? await encryptSecret(tokens.access_token) : null; const encryptedRefresh = tokens.refresh_token ? await encryptSecret(tokens.refresh_token) : null; const expiresAt = tokens.expires_in ? new Date(Date.now() + tokens.expires_in * 1000).toISOString() : null; db.createOidcLink({ id: crypto.randomUUID(), userId: existingUser.id, provider: provider.name, providerUserId: userInfo.sub, providerEmail: userInfo.email || null, accessTokenEncrypted: encryptedAccess, refreshTokenEncrypted: encryptedRefresh, tokenExpiresAt: expiresAt, createdAt: new Date().toISOString() }); existingUser.lastLogin = new Date().toISOString(); existingUser.updatedAt = new Date().toISOString(); db.updateUser(existingUser); const sessionToken = await createUserSessionToken(existingUser.id, ipAddress, userAgent); db.logAuthEvent('oidc_login_email_match', existingUser.id, ipAddress, { provider: provider.name, providerUserId: userInfo.sub, matchedEmail: userInfo.email }); return { success: true, userId: existingUser.id, sessionToken, isNewUser: false, postLoginRedirect }; } if (authSettings.authMode === 'closed') { return { success: false, error: 'Registration is currently closed', postLoginRedirect }; } if (authSettings.authMode === 'invite_only') { return { success: false, error: 'Registration requires an invitation', postLoginRedirect }; } const userId = crypto.randomUUID(); const now = new Date().toISOString(); const newUser: db.User = { id: userId, email: userInfo.email || null, emailVerified: userInfo.email_verified || false, displayName: userInfo.name || userInfo.preferred_username || null, avatarUrl: userInfo.picture || null, passwordHash: null, role: 'user', createdAt: now, updatedAt: now, lastLogin: now, isActive: true, failedLoginAttempts: 0, lockedUntil: null, totpSecret: null, totpEnabled: false, totpBackupCodes: null, pendingEmail: null, pendingEmailToken: null }; const { wasFirst } = db.createUserAtomic(newUser); if (wasFirst) { newUser.role = 'admin'; newUser.emailVerified = true; db.updateUser(newUser); } const encryptedAccess = tokens.access_token ? await encryptSecret(tokens.access_token) : null; const encryptedRefresh = tokens.refresh_token ? await encryptSecret(tokens.refresh_token) : null; const expiresAt = tokens.expires_in ? new Date(Date.now() + tokens.expires_in * 1000).toISOString() : null; db.createOidcLink({ id: crypto.randomUUID(), userId, provider: provider.name, providerUserId: userInfo.sub, providerEmail: userInfo.email || null, accessTokenEncrypted: encryptedAccess, refreshTokenEncrypted: encryptedRefresh, tokenExpiresAt: expiresAt, createdAt: now }); const sessionToken = await createUserSessionToken(userId, ipAddress, userAgent); db.logAuthEvent('oidc_register', userId, ipAddress, { provider: provider.name, providerUserId: userInfo.sub, role: newUser.role, isFirstUser: wasFirst }); return { success: true, userId, sessionToken, isNewUser: true, postLoginRedirect }; } const MAX_SESSIONS_PER_USER = 10; async function createUserSessionToken( userId: string, ipAddress: string, userAgent: string ): Promise { const token = generateSecureToken(32); const tokenHash = await hashToken(token); const now = new Date(); const expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); const existing = db.getSessionsByUserId(userId); if (existing.length >= MAX_SESSIONS_PER_USER) { const oldest = existing.slice(MAX_SESSIONS_PER_USER - 1); for (const s of oldest) db.deleteSession(s.id); } db.createUserSession({ id: crypto.randomUUID(), userId, tokenHash, ipAddress, userAgent: userAgent?.substring(0, 500) || null, expiresAt: expiresAt.toISOString(), createdAt: now.toISOString() }); return token; } export async function hashToken(token: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(token); const hash = await crypto.subtle.digest('SHA-256', data); return Array.from(new Uint8Array(hash), b => b.toString(16).padStart(2, '0')).join(''); } export function generateSecureToken(bytes: number = 32): string { const array = new Uint8Array(bytes); crypto.getRandomValues(array); return Array.from(array, b => b.toString(16).padStart(2, '0')).join(''); } export async function validateUserSessionToken( token: string, currentIP?: string, currentUserAgent?: string ): Promise { const tokenHash = await hashToken(token); const session = db.getSessionByTokenHash(tokenHash); if (!session) return null; if (new Date(session.expiresAt) < new Date()) { db.deleteSession(session.id); return null; } const user = db.getUserById(session.userId); if (!user || !user.isActive) return null; if (currentIP && session.ipAddress && session.ipAddress !== currentIP) { db.logAuthEvent('session_ip_change', session.userId, currentIP, { originalIP: session.ipAddress, newIP: currentIP, sessionId: session.id }); } return user; } export async function refreshOidcTokens(linkId: string): Promise<{ success: boolean; accessToken?: string; error?: string; }> { const link = db.getOidcLinkById(linkId); if (!link || !link.refreshTokenEncrypted) { return { success: false, error: 'No refresh token available' }; } const provider = db.getOidcProviderByName(link.provider); if (!provider) { return { success: false, error: 'Provider not found' }; } let tokenUrl = provider.tokenUrl; if (!tokenUrl && provider.issuerUrl) { const discovery = await discoverOidcEndpoints(provider.issuerUrl); if (discovery) { tokenUrl = discovery.token_endpoint; } } if (!tokenUrl) { return { success: false, error: 'No token endpoint configured for provider' }; } let refreshToken: string; try { refreshToken = await decryptSecret(link.refreshTokenEncrypted); } catch { return { success: false, error: 'Failed to decrypt refresh token' }; } let clientSecret: string | null = null; if (provider.clientSecretEncrypted) { try { clientSecret = await decryptSecret(provider.clientSecretEncrypted); } catch { return { success: false, error: 'Failed to decrypt client secret' }; } } try { const params = new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, client_id: provider.clientId }); if (clientSecret) { params.set('client_secret', clientSecret); } const tokenRes = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString() }); if (!tokenRes.ok) { const errText = await tokenRes.text(); logOidcError('Token refresh failed', errText.substring(0, 200).replace(/access_token[^&]*/gi, 'access_token=[REDACTED]').replace(/refresh_token[^&]*/gi, 'refresh_token=[REDACTED]')); return { success: false, error: 'Token refresh failed' }; } const tokens = await tokenRes.json(); const encryptedAccess = tokens.access_token ? await encryptSecret(tokens.access_token) : null; const encryptedRefresh = tokens.refresh_token ? await encryptSecret(tokens.refresh_token) : link.refreshTokenEncrypted; const expiresAt = tokens.expires_in ? new Date(Date.now() + tokens.expires_in * 1000).toISOString() : null; db.updateOidcLinkTokens(link.id, encryptedAccess, encryptedRefresh, expiresAt); return { success: true, accessToken: tokens.access_token }; } catch (e: any) { logOidcError('Token refresh error', e); return { success: false, error: 'Token refresh error' }; } } export async function revokeUserOidcTokens(userId: string): Promise { const links = db.getOidcLinksByUser(userId); for (const link of links) { try { const provider = db.getOidcProviderByName(link.provider); if (!provider) continue; let revocationUrl: string | undefined; if (provider.issuerUrl) { const discovery = await discoverOidcEndpoints(provider.issuerUrl); revocationUrl = discovery?.revocation_endpoint ?? undefined; } if (!revocationUrl) continue; let clientSecret: string | null = null; if (provider.clientSecretEncrypted) { try { clientSecret = await decryptSecret(provider.clientSecretEncrypted); } catch { continue; } } const tokensToRevoke: { token: string; hint: string }[] = []; if (link.accessTokenEncrypted) { try { const accessToken = await decryptSecret(link.accessTokenEncrypted); tokensToRevoke.push({ token: accessToken, hint: 'access_token' }); } catch {} } if (link.refreshTokenEncrypted) { try { const refreshToken = await decryptSecret(link.refreshTokenEncrypted); tokensToRevoke.push({ token: refreshToken, hint: 'refresh_token' }); } catch {} } for (const { token, hint } of tokensToRevoke) { try { const params = new URLSearchParams({ token, token_type_hint: hint, client_id: provider.clientId }); if (clientSecret) params.set('client_secret', clientSecret); await fetch(revocationUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params.toString() }); } catch (e: any) { logOidcError(`Token revocation failed for provider ${link.provider}`, e); } } db.updateOidcLinkTokens(link.id, null, null, null); } catch (e: any) { logOidcError(`Failed to revoke tokens for OIDC link ${link.id}`, e); } } } export interface AuthSettings { authMode: 'open' | 'registration' | 'oidc_only' | 'invite_only' | 'closed'; allowGuestRoomCreation: boolean; allowGuestRoomJoin: boolean; allowRoomCreatorGuestSetting: boolean; oidcEmailMatching: boolean; requireEmailVerification: boolean; allowMagicLinkLogin: boolean; shareButtonEnabled: boolean; productionMode: boolean; idTokenMaxAgeHours: number; emailRateLimitWindowSeconds: number; emailRateLimitMaxAttempts: number; } export function getAuthSettings(): AuthSettings { const defaults: AuthSettings = { authMode: 'open', allowGuestRoomCreation: true, allowGuestRoomJoin: true, allowRoomCreatorGuestSetting: true, oidcEmailMatching: false, requireEmailVerification: false, allowMagicLinkLogin: true, shareButtonEnabled: true, productionMode: false, idTokenMaxAgeHours: 0.167, emailRateLimitWindowSeconds: 300, emailRateLimitMaxAttempts: 3 }; try { const stored = db.getSetting('authSettings'); if (stored) { return { ...defaults, ...JSON.parse(stored) }; } } catch (e: any) { console.error('[OIDC] Failed to parse auth settings:', e.message); } return defaults; } export function saveAuthSettings(settings: Partial): void { const current = getAuthSettings(); const merged = { ...current, ...settings }; db.setSetting('authSettings', JSON.stringify(merged)); } function getIdTokenMaxAgeMs(): number { const settings = getAuthSettings(); return settings.idTokenMaxAgeHours * 60 * 60 * 1000; } function sanitizeIconUrl(url: string | null): string | null { if (!url) return null; try { const parsed = new URL(url); if (parsed.protocol === 'https:' || parsed.protocol === 'http:') return url; return null; } catch { return null; } } export function getActiveProviders(): { id: string; name: string; iconUrl: string | null }[] { return db.listActiveOidcProviders().map(p => ({ id: p.id, name: p.name, iconUrl: sanitizeIconUrl(p.iconUrl) })); } export function getSessionCookie(name: string, value: string, maxAge: number = 2592000): string { const settings = getAuthSettings(); if (settings.productionMode) { return `__Host-${name}=${value}; Path=/; HttpOnly; SameSite=Strict; Secure; Partitioned; Max-Age=${maxAge}`; } return `${name}=${value}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${maxAge}`; } export function getClearCookie(name: string): string { const settings = getAuthSettings(); if (settings.productionMode) { return `__Host-${name}=; Path=/; HttpOnly; SameSite=Strict; Secure; Partitioned; Max-Age=0`; } return `${name}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`; } export function getSessionCookieName(baseName: string): string { const settings = getAuthSettings(); return settings.productionMode ? `__Host-${baseName}` : baseName; } function cleanupOldestCsrfTokens(): void { const count = db.countCsrfTokens(); if (count <= MAX_CSRF_TOKENS) return; db.deleteOldestCsrfTokens(count - MAX_CSRF_TOKENS + 100); } export function generateCsrfToken(): string { cleanupOldestCsrfTokens(); const token = generateSecureToken(32); const now = new Date(); const expiresAt = new Date(now.getTime() + CSRF_TOKEN_TTL_MS); db.createCsrfToken({ token, used: false, createdAt: now.toISOString(), expiresAt: expiresAt.toISOString() }); return token; } export function validateCsrfToken(token: string): boolean { if (!token) return false; const data = db.getCsrfToken(token); if (!data) return false; if (new Date(data.expiresAt) < new Date()) { db.deleteCsrfToken(token); return false; } if (data.used) { db.deleteCsrfToken(token); return false; } db.markCsrfTokenUsed(token); return true; } export function getCsrfCookie(token: string): string { const settings = getAuthSettings(); const secure = settings.productionMode ? '; Secure' : ''; return `csrf_token=${token}; Path=/; HttpOnly; SameSite=Strict${secure}; Max-Age=3600`; } export function validateRedirectUrl(redirectUrl: string | null, baseUrl: string): string { if (!redirectUrl) { return '/'; } const sanitized = redirectUrl.trim().toLowerCase(); const dangerousSchemes = ['javascript:', 'data:', 'vbscript:', 'file:', 'blob:']; for (const scheme of dangerousSchemes) { if (sanitized.startsWith(scheme)) { return '/'; } } const original = redirectUrl.trim(); if (original.startsWith('/') && !original.startsWith('//')) { if (original.includes('..') || original.includes('\\')) { return '/'; } return original; } try { const redirectOrigin = new URL(original).origin; const baseOrigin = new URL(baseUrl).origin; if (redirectOrigin === baseOrigin) { const url = new URL(original); return url.pathname + url.search + url.hash; } } catch { } return '/'; } ================================================ FILE: theonefile_verse/src/rate-limit.ts ================================================ import * as redis from "./redis"; import * as db from "./database"; import * as oidc from "./oidc"; import { type InstanceSettings } from "./config"; interface RateLimitEntry { count: number; resetAt: number; } const MAX_RATE_LIMIT_ENTRIES = 10000; const rateLimitStore = new Map(); interface WsTokenBucket { tokens: number; lastRefill: number; } const WS_RATE_LIMITS = { state: { bucketSize: 10, refillRate: 2 }, chat: { bucketSize: 5, refillRate: 1 }, cursor: { bucketSize: 30, refillRate: 15 }, typing: { bucketSize: 5, refillRate: 1 }, presence: { bucketSize: 20, refillRate: 5 }, default: { bucketSize: 20, refillRate: 5 } }; const MAX_WS_RATE_LIMIT_BUCKETS = 50000; const wsRateLimitBuckets = new Map(); export function checkWsRateLimit(connectionId: string, messageType: string): boolean { const limits = WS_RATE_LIMITS[messageType as keyof typeof WS_RATE_LIMITS] || WS_RATE_LIMITS.default; const key = `${connectionId}:${messageType}`; const now = Date.now(); let bucket = wsRateLimitBuckets.get(key); if (!bucket) { bucket = { tokens: limits.bucketSize, lastRefill: now }; wsRateLimitBuckets.set(key, bucket); } const elapsed = (now - bucket.lastRefill) / 1000; bucket.tokens = Math.min(limits.bucketSize, bucket.tokens + elapsed * limits.refillRate); bucket.lastRefill = now; if (bucket.tokens >= 1) { bucket.tokens -= 1; return true; } return false; } export async function checkRateLimit(ip: string, endpoint: string, settings: InstanceSettings, maxOverride?: number, windowOverride?: number): Promise { if (!settings.rateLimitEnabled) return true; const key = `${ip}:${endpoint}`; const maxAttempts = maxOverride ?? settings.rateLimitMaxAttempts; const windowSeconds = windowOverride ?? settings.rateLimitWindow; if (redis.isRedisConnected()) { return await redis.checkRateLimitRedis(key, maxAttempts, windowSeconds); } if (rateLimitStore.size > MAX_RATE_LIMIT_ENTRIES) { const now = Date.now(); for (const [k, v] of rateLimitStore.entries()) { if (now > v.resetAt) rateLimitStore.delete(k); } if (rateLimitStore.size > MAX_RATE_LIMIT_ENTRIES) { const entries = [...rateLimitStore.entries()].sort((a, b) => a[1].resetAt - b[1].resetAt); const toRemove = entries.length - Math.floor(MAX_RATE_LIMIT_ENTRIES * 0.75); for (let i = 0; i < toRemove; i++) rateLimitStore.delete(entries[i][0]); } } const now = Date.now(); const entry = rateLimitStore.get(key); const window = windowSeconds * 1000; if (!entry || now > entry.resetAt) { rateLimitStore.set(key, { count: 1, resetAt: now + window }); return true; } if (entry.count >= maxAttempts) { return false; } entry.count++; return true; } export async function checkEmailRateLimit(email: string, action: string, settings: InstanceSettings): Promise { if (!settings.rateLimitEnabled) return true; const authSettings = oidc.getAuthSettings(); const windowSeconds = authSettings.emailRateLimitWindowSeconds; const maxAttempts = authSettings.emailRateLimitMaxAttempts; const normalizedEmail = email.toLowerCase().trim(); if (redis.isRedisConnected()) { const key = `email:${normalizedEmail}:${action}`; return await redis.checkRateLimitRedis(key, maxAttempts, windowSeconds); } const currentCount = db.countEmailRateLimitAttempts(normalizedEmail, action, windowSeconds); if (currentCount >= maxAttempts) { return false; } db.recordEmailRateLimit(normalizedEmail, action); return true; } const wsConnectionCounts = new Map(); const MAX_WS_CONNECTIONS_PER_IP = 50; const WS_CONNECTION_WINDOW = 3600 * 1000; export function checkWsConnectionLimit(clientIp: string): boolean { const now = Date.now(); const wsEntry = wsConnectionCounts.get(clientIp); if (wsEntry && now < wsEntry.resetAt && wsEntry.count >= MAX_WS_CONNECTIONS_PER_IP) { return false; } if (!wsEntry || now > wsEntry.resetAt) { wsConnectionCounts.set(clientIp, { count: 1, resetAt: now + WS_CONNECTION_WINDOW }); } else { wsEntry.count++; } return true; } export function startRateLimitCleanupIntervals(): void { setInterval(() => { const now = Date.now(); const staleThreshold = 60 * 1000; for (const [key, bucket] of wsRateLimitBuckets.entries()) { if (now - bucket.lastRefill > staleThreshold) { wsRateLimitBuckets.delete(key); } } if (wsRateLimitBuckets.size > MAX_WS_RATE_LIMIT_BUCKETS) { const entries = [...wsRateLimitBuckets.entries()].sort((a, b) => a[1].lastRefill - b[1].lastRefill); const toRemove = entries.length - Math.floor(MAX_WS_RATE_LIMIT_BUCKETS * 0.75); for (let i = 0; i < toRemove; i++) wsRateLimitBuckets.delete(entries[i][0]); } }, 30 * 1000); setInterval(() => { const now = Date.now(); for (const [key, entry] of rateLimitStore.entries()) { if (now > entry.resetAt) { rateLimitStore.delete(key); } } db.cleanupEmailRateLimits(3600); }, 60 * 1000); setInterval(() => { const now = Date.now(); for (const [ip, entry] of wsConnectionCounts.entries()) { if (now > entry.resetAt) wsConnectionCounts.delete(ip); } }, 5 * 60 * 1000); } ================================================ FILE: theonefile_verse/src/redis.ts ================================================ import { createClient, RedisClientType } from "redis"; const REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379"; let client: RedisClientType | null = null; let subscriber: RedisClientType | null = null; let isConnected = false; const messageHandlers = new Map void>>(); export async function connectRedis(): Promise { try { client = createClient({ url: REDIS_URL }); subscriber = client.duplicate(); client.on("error", (err) => { console.error("[Redis] Client error:", err.message); isConnected = false; }); subscriber.on("error", (err) => { console.error("[Redis] Subscriber error:", err.message); }); await client.connect(); await subscriber.connect(); isConnected = true; console.log("[Redis] Connected to", REDIS_URL); subscriber.on("message", (channel, message) => { const handlers = messageHandlers.get(channel); if (handlers) { handlers.forEach((handler) => handler(message, channel)); } }); return true; } catch (err: any) { console.error("[Redis] Connection failed:", err.message); isConnected = false; return false; } } export function isRedisConnected(): boolean { return isConnected && client !== null; } const RATE_LIMIT_LUA = ` local c = redis.call('INCR', KEYS[1]) if c == 1 then redis.call('EXPIRE', KEYS[1], ARGV[1]) end return c `; export async function checkRateLimitRedis( key: string, maxAttempts: number, windowSeconds: number ): Promise { if (!client || !isConnected) return false; try { const redisKey = `ratelimit:${key}`; const current = await client.eval(RATE_LIMIT_LUA, { keys: [redisKey], arguments: [String(windowSeconds)] }) as number; return current <= maxAttempts; } catch (err: any) { console.error("[Redis] Rate limit check failed, denying request (fail-closed):", err.message); return false; } } export async function setSessionToken( token: string, data: { type: string; createdAt: number } | Record, ttlSeconds: number = 604800 ): Promise { if (!client || !isConnected) return false; try { await client.setEx(`session:${token}`, ttlSeconds, JSON.stringify(data)); return true; } catch (err: any) { console.error("[Redis] Set session token failed:", err.message); return false; } } export async function getSessionToken(token: string): Promise<{ type: string; createdAt: number } | null> { if (!client || !isConnected) return null; try { const data = await client.get(`session:${token}`); return data ? JSON.parse(data) : null; } catch (err: any) { console.error("[Redis] Get session token failed:", err.message); return null; } } export async function deleteSessionToken(token: string): Promise { if (!client || !isConnected) return false; try { await client.del(`session:${token}`); return true; } catch (err: any) { console.error("[Redis] Delete session token failed:", err.message); return false; } } export async function setUserPresence( roomId: string, userId: string, userData: any, ttlSeconds: number = 300 ): Promise { if (!client || !isConnected) return false; try { const userKey = `presence:${roomId}:${userId}`; await client.setEx(userKey, ttlSeconds, JSON.stringify(userData)); return true; } catch (err: any) { console.error("[Redis] Set user presence failed:", err.message); return false; } } export async function getUserPresence(roomId: string, userId: string): Promise { if (!client || !isConnected) return null; try { const data = await client.get(`presence:${roomId}:${userId}`); return data ? JSON.parse(data) : null; } catch (err: any) { console.error("[Redis] Get user presence failed:", err.message); return null; } } export async function getAllUserPresence(roomId: string): Promise> { const result = new Map(); if (!client || !isConnected) return result; try { const pattern = `presence:${roomId}:*`; let cursor = 0; const keys: string[] = []; do { const reply = await client.scan(cursor, { MATCH: pattern, COUNT: 100 }); cursor = reply.cursor; keys.push(...reply.keys); } while (cursor !== 0); if (keys.length === 0) return result; const values = await client.mGet(keys); for (let i = 0; i < keys.length; i++) { const userId = keys[i].split(':').slice(2).join(':'); if (values[i]) { try { result.set(userId, JSON.parse(values[i])); } catch (e: any) { console.error("[Redis] Presence JSON parse failed:", e.message); } } } } catch (err: any) { console.error("[Redis] Get all user presence failed:", err.message); } return result; } export async function removeUserPresence(roomId: string, userId: string): Promise { if (!client || !isConnected) return false; try { await client.del(`presence:${roomId}:${userId}`); return true; } catch (err: any) { console.error("[Redis] Remove user presence failed:", err.message); return false; } } export async function setRoomStateCache(roomId: string, state: any, ttlSeconds: number = 3600): Promise { if (!client || !isConnected) return false; try { await client.setEx(`roomstate:${roomId}`, ttlSeconds, JSON.stringify(state)); return true; } catch (err: any) { console.error("[Redis] Set room state cache failed:", err.message); return false; } } export async function getRoomStateCache(roomId: string): Promise { if (!client || !isConnected) return null; try { const data = await client.get(`roomstate:${roomId}`); return data ? JSON.parse(data) : null; } catch (err: any) { console.error("[Redis] Get room state cache failed:", err.message); return null; } } export async function deleteRoomStateCache(roomId: string): Promise { if (!client || !isConnected) return false; try { await client.del(`roomstate:${roomId}`); return true; } catch (err: any) { console.error("[Redis] Delete room state cache failed:", err.message); return false; } } export async function publishMessage(channel: string, message: string): Promise { if (!client || !isConnected) return false; try { await client.publish(channel, message); return true; } catch (err: any) { console.error("[Redis] Publish message failed:", err.message); return false; } } export async function subscribeToChannel( channel: string, handler: (message: string, channel: string) => void ): Promise { if (!subscriber || !isConnected) return; try { if (!messageHandlers.has(channel)) { messageHandlers.set(channel, new Set()); await subscriber.subscribe(channel, (message, ch) => { const handlers = messageHandlers.get(ch); if (handlers) { handlers.forEach((h) => h(message, ch)); } }); } messageHandlers.get(channel)!.add(handler); } catch (err: any) { console.error("[Redis] Subscribe to channel failed:", err.message); } } export async function unsubscribeFromChannel( channel: string, handler?: (message: string, channel: string) => void ): Promise { if (!subscriber || !isConnected) return; try { if (handler) { const handlers = messageHandlers.get(channel); if (handlers) { handlers.delete(handler); if (handlers.size === 0) { messageHandlers.delete(channel); await subscriber.unsubscribe(channel); } } } else { messageHandlers.delete(channel); await subscriber.unsubscribe(channel); } } catch (err: any) { console.error("[Redis] Unsubscribe from channel failed:", err.message); } } export async function publishToRoom(roomId: string, message: any): Promise { await publishMessage(`room:${roomId}`, JSON.stringify(message)); } export async function subscribeToRoom( roomId: string, handler: (message: any) => void ): Promise<() => Promise> { const wrappedHandler = (msg: string) => { try { handler(JSON.parse(msg)); } catch (err: any) { console.error("[Redis] Room message parse failed:", err.message); } }; await subscribeToChannel(`room:${roomId}`, wrappedHandler); return async () => { await unsubscribeFromChannel(`room:${roomId}`, wrappedHandler); }; } export async function incrementCounter(key: string): Promise { if (!client || !isConnected) return 0; try { return await client.incr(`counter:${key}`); } catch (err: any) { console.error("[Redis] Increment counter failed:", err.message); return 0; } } export async function getCounter(key: string): Promise { if (!client || !isConnected) return 0; try { const value = await client.get(`counter:${key}`); return value ? parseInt(value, 10) : 0; } catch (err: any) { console.error("[Redis] Get counter failed:", err.message); return 0; } } export async function setWithExpiry(key: string, value: string, ttlSeconds: number): Promise { if (!client || !isConnected) return false; try { await client.setEx(key, ttlSeconds, value); return true; } catch (err: any) { console.error("[Redis] Set with expiry failed:", err.message); return false; } } export async function getValue(key: string): Promise { if (!client || !isConnected) return null; try { return await client.get(key); } catch (err: any) { console.error("[Redis] Get value failed:", err.message); return null; } } export async function deleteKey(key: string): Promise { if (!client || !isConnected) return false; try { await client.del(key); return true; } catch (err: any) { console.error("[Redis] Delete key failed:", err.message); return false; } } export async function ping(): Promise { if (!client || !isConnected) return false; try { const result = await client.ping(); return result === "PONG"; } catch { return false; } } export async function disconnectRedis(): Promise { try { if (subscriber) { await subscriber.quit(); subscriber = null; } if (client) { await client.quit(); client = null; } isConnected = false; console.log("[Redis] Disconnected"); } catch (err: any) { console.error("[Redis] Disconnect failed:", err.message); } } export function getRedisClient(): RedisClientType | null { return client; } ================================================ FILE: theonefile_verse/src/rooms.ts ================================================ import { existsSync, mkdirSync } from "fs"; import { unlink } from "fs/promises"; import { join } from "path"; import * as db from "./database"; import * as redis from "./redis"; import * as auth from "./auth"; import { DATA_DIR, ROOMS_DIR, getSettings, updateSettings, isValidUUID, type InstanceSettings } from "./config"; if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true }); if (!existsSync(ROOMS_DIR)) mkdirSync(ROOMS_DIR, { recursive: true }); export interface Room { id: string; created: string; lastActivity: string; creatorId: string; passwordHash: string | null; destruct: { mode: "time" | "empty" | "never"; value: number }; topology: any; ownerUserId: string | null; allowGuests: boolean; } export interface RoomMeta { connectedUsers: number; destructTimer?: Timer; } export const roomMeta: Map = new Map(); export const roomConnections: Map> = new Map(); export const roomUsers: Map> = new Map(); export const roomUsedNames: Map> = new Map(); export const roomChatHistory: Map = new Map(); export async function hashPassword(password: string): Promise { return await auth.hashPassword(password); } export async function verifyPassword(password: string, hash: string): Promise { return await auth.verifyPassword(password, hash); } export function loadRoom(id: string): Room | null { if (!isValidUUID(id)) return null; return db.getRoom(id); } export function saveRoom(room: Room): void { if (!isValidUUID(room.id)) return; const existing = db.getRoom(room.id); if (existing) { db.updateRoom(room.id, room.lastActivity, room.topology); } else { db.createRoom(room); } if (redis.isRedisConnected() && room.topology) { redis.setRoomStateCache(room.id, room.topology, 3600); } } export function deleteRoomData(id: string): boolean { const result = db.deleteRoom(id); if (result) { roomMeta.delete(id); roomUsedNames.delete(id); roomChatHistory.delete(id); if (redis.isRedisConnected()) { redis.deleteRoomStateCache(id); } } return result; } export function scheduleDestruction(roomId: string, delayMs: number): void { const meta = roomMeta.get(roomId) || { connectedUsers: 0 }; if (meta.destructTimer) clearTimeout(meta.destructTimer); meta.destructTimer = setTimeout(() => { const room = loadRoom(roomId); if (room && room.destruct.mode === "time") { console.log(`[Room] ${roomId} self destructed`); deleteRoomData(roomId); } }, delayMs); roomMeta.set(roomId, meta); } export function resetDestructionTimer(roomId: string): void { const room = loadRoom(roomId); if (room && room.destruct.mode === "time") { scheduleDestruction(roomId, room.destruct.value); } } export let theOneFileHtml = ""; const theOneFilePath = join(process.cwd(), "public", "theonefile.html"); export function extractThemePresets(): Array<{key: string, label: string}> { if (!theOneFileHtml) return []; const themes: Array<{key: string, label: string}> = []; const selectMatch = theOneFileHtml.match(/id="welcome-theme-select"[^>]*>([\s\S]*?)<\/select>/); if (selectMatch) { const optionRegex = /]*>([^<]+)<\/option>/g; let m; while ((m = optionRegex.exec(selectMatch[1])) !== null) { if (m[1]) themes.push({ key: m[1], label: m[2] }); } } if (themes.length === 0) { const presetsMatch = theOneFileHtml.match(/THEME_PRESETS\s*=\s*\{([\s\S]*?)\n\};/); if (presetsMatch) { const keyRegex = /^\s+(\w+)\s*:/gm; let km; while ((km = keyRegex.exec(presetsMatch[1])) !== null) { themes.push({ key: km[1], label: km[1] }); } } } return themes; } export const GITHUB_RAW_URL = "https://raw.githubusercontent.com/gelatinescreams/The-One-File/main/theonefile-networkening.html"; export let currentFileVersion = ""; export function getExpectedTheOneFileHash(): string | null { return db.getSetting("theOneFileHash"); } export function setExpectedTheOneFileHash(hash: string): void { db.setSetting("theOneFileHash", hash); } export function extractVersionFromHtml(html: string): string { const match = html.match(/THE_ONE_FILE_VERSION\s*=\s*["']([^"']+)["']/); return match ? match[1].replace(/^["']+|["']+$/g, '') : "unknown"; } export function isNewerVersion(latest: string, current: string): boolean { const parse = (v: string) => v.replace(/^v/i, '').split('.').map(n => parseInt(n) || 0); const l = parse(latest); const c = parse(current); for (let i = 0; i < Math.max(l.length, c.length); i++) { const lv = l[i] || 0; const cv = c[i] || 0; if (lv > cv) return true; if (lv < cv) return false; } return false; } export async function computeSha256Hash(content: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(content); const hashBuffer = await crypto.subtle.digest("SHA-256", data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => b.toString(16).padStart(2, "0")).join(""); } export async function fetchLatestFromGitHub(): Promise { try { console.log("[Update] Fetching from GitHub..."); const res = await fetch(GITHUB_RAW_URL); if (!res.ok) return false; const html = await res.text(); const downloadedHash = await computeSha256Hash(html); const expectedHash = getExpectedTheOneFileHash(); if (expectedHash) { if (downloadedHash !== expectedHash) { console.error(`[Update] INTEGRITY CHECK FAILED!`); console.error(`[Update] Expected: ${expectedHash}`); console.error(`[Update] Got: ${downloadedHash}`); console.error(`[Update] File rejected - possible tampering or update. Admin must update the expected hash.`); return false; } console.log(`[Update] Integrity verified (SHA-256: ${downloadedHash.substring(0, 16)}...)`); } else { console.log(`[Update] No integrity hash set. Current file hash: ${downloadedHash}`); console.log(`[Update] Admin can set this hash in settings to enable integrity checking.`); } const previousVersion = currentFileVersion; await Bun.write(theOneFilePath, html); theOneFileHtml = html; currentFileVersion = extractVersionFromHtml(html); db.setSetting("lastUpdateTimestamp", new Date().toISOString()); db.setSetting("latestFetchedVersion", currentFileVersion); console.log(`[Update] Downloaded v${currentFileVersion} (${(html.length / 1024).toFixed(1)}KB)${previousVersion && previousVersion !== currentFileVersion ? ` from v${previousVersion}` : ''}`); return true; } catch (e: any) { console.error("[Update]", e.message); return false; } } export function setTheOneFileHtml(html: string): void { theOneFileHtml = html; currentFileVersion = extractVersionFromHtml(html); } export function getTheOneFilePath(): string { return theOneFilePath; } let updateTimer: Timer | null = null; export function restartUpdateTimer(): void { const settings = getSettings(); if (updateTimer) clearInterval(updateTimer); updateTimer = null; if (settings.updateIntervalHours > 0 && !settings.skipUpdates) { updateTimer = setInterval(() => { fetchLatestFromGitHub(); }, settings.updateIntervalHours * 60 * 60 * 1000); console.log(`[Update] Auto update every ${settings.updateIntervalHours} hours`); } } export function clearUpdateTimer(): void { if (updateTimer) clearInterval(updateTimer); updateTimer = null; } export async function initializeTheOneFile(): Promise { const settings = getSettings(); if (settings.skipUpdates) { const localFile = Bun.file(theOneFilePath); if (await localFile.exists()) { theOneFileHtml = await localFile.text(); console.log("[Update] Using local file (updates disabled)"); } } else { await fetchLatestFromGitHub(); if (!theOneFileHtml) { const cachedFile = Bun.file(theOneFilePath); if (await cachedFile.exists()) { theOneFileHtml = await cachedFile.text(); console.log("[Update] Using cached file"); } } } if (theOneFileHtml) { currentFileVersion = extractVersionFromHtml(theOneFileHtml); if (currentFileVersion !== "unknown") console.log(`[Update] Current version: v${currentFileVersion}`); } restartUpdateTimer(); } export interface ValidationResult { valid: boolean; error?: string; edition?: string; } export interface TopologyValidationResult { valid: boolean; error?: string; sanitized?: any; } const TOPOLOGY_LIMITS = { maxSizeBytes: 5 * 1024 * 1024, maxDepth: 20, maxArrayLength: 10000, maxObjectKeys: 10000, maxStringLength: 1 * 1024 * 1024 }; function checkJsonDepthAndSize(obj: any, currentDepth: number = 0): { valid: boolean; error?: string } { if (currentDepth > TOPOLOGY_LIMITS.maxDepth) { return { valid: false, error: `Topology exceeds maximum nesting depth of ${TOPOLOGY_LIMITS.maxDepth}` }; } if (obj === null || obj === undefined) { return { valid: true }; } if (typeof obj === 'string') { if (obj.length > TOPOLOGY_LIMITS.maxStringLength) { return { valid: false, error: `String value exceeds maximum length of ${TOPOLOGY_LIMITS.maxStringLength / 1024}KB` }; } return { valid: true }; } if (Array.isArray(obj)) { if (obj.length > TOPOLOGY_LIMITS.maxArrayLength) { return { valid: false, error: `Array exceeds maximum length of ${TOPOLOGY_LIMITS.maxArrayLength}` }; } for (const item of obj) { const result = checkJsonDepthAndSize(item, currentDepth + 1); if (!result.valid) return result; } return { valid: true }; } if (typeof obj === 'object') { const keys = Object.keys(obj); if (keys.length > TOPOLOGY_LIMITS.maxObjectKeys) { return { valid: false, error: `Object exceeds maximum keys of ${TOPOLOGY_LIMITS.maxObjectKeys}` }; } for (const key of keys) { const result = checkJsonDepthAndSize(obj[key], currentDepth + 1); if (!result.valid) return result; } return { valid: true }; } return { valid: true }; } const ALLOWED_TAGS = new Set([ 'a', 'abbr', 'address', 'article', 'aside', 'b', 'bdi', 'bdo', 'blockquote', 'br', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'em', 'figcaption', 'figure', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'i', 'img', 'ins', 'kbd', 'li', 'main', 'mark', 'nav', 'ol', 'p', 'picture', 'pre', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'small', 'source', 'span', 'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'time', 'tr', 'u', 'ul', 'var', 'wbr', 'input', 'label', 'select', 'option', 'textarea', 'button', 'canvas', 'audio', 'video' ]); const ALLOWED_ATTRS = new Set([ 'id', 'class', 'title', 'lang', 'dir', 'role', 'tabindex', 'aria-label', 'aria-hidden', 'aria-expanded', 'aria-controls', 'aria-describedby', 'data-id', 'data-type', 'data-value', 'data-node-id', 'data-edge-id', 'data-tab-id', 'data-tab', 'data-color', 'data-size', 'data-x', 'data-y', 'data-width', 'data-height', 'data-source', 'data-target', 'data-label', 'data-index', 'data-selected', 'data-locked', 'data-visible', 'data-active', 'data-state', 'data-mode', 'data-theme', 'data-collapsed', 'data-position', 'data-group', 'data-parent', 'data-layer', 'data-order', 'data-shape', 'data-font-size', 'data-font-family', 'data-text-align', 'data-stroke', 'data-fill', 'data-opacity', 'data-rotation', 'data-style', 'data-content', 'href', 'src', 'alt', 'width', 'height', 'colspan', 'rowspan', 'target', 'rel', 'type', 'value', 'placeholder', 'name', 'for', 'checked', 'disabled', 'readonly', 'maxlength', 'min', 'max', 'step', 'rows', 'cols', 'wrap', 'autoplay', 'controls', 'loop', 'muted', 'preload', 'poster', 'contenteditable', 'spellcheck', 'draggable', 'hidden', 'open', 'start', 'reversed', 'datetime', 'cite', 'loading', 'decoding', 'crossorigin', 'referrerpolicy', 'sizes', 'srcset', 'media' ]); function isAllowedDataAttr(name: string): boolean { if (!name.startsWith('data-')) return false; return /^data-[a-z][a-z0-9-]*$/.test(name); } function sanitizeUrl(url: string): string { let decoded = url .replace(/&#x([0-9a-f]+);?/gi, (_: string, h: string) => String.fromCharCode(parseInt(h, 16))) .replace(/&#(\d+);?/gi, (_: string, d: string) => String.fromCharCode(parseInt(d, 10))) .replace(/[\t\n\r\x00]/g, ''); const clean = decoded.replace(/\s/g, '').toLowerCase(); if (clean.startsWith('javascript:') || clean.startsWith('vbscript:')) return ''; if (clean.startsWith('data:') && !/^data:image\/(png|jpe?g|gif|webp|bmp|ico)/i.test(clean)) return 'data:blocked'; return url; } export function sanitizeHtmlString(str: string): string { if (typeof str !== 'string') return str; return str.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)\b([^>]*)?\/?>/g, (match, tagName, attrsStr) => { const tag = tagName.toLowerCase(); const isClosing = match.startsWith('`; const selfClosing = match.endsWith('/>') || ['br', 'hr', 'img', 'input', 'col', 'source', 'wbr'].includes(tag); let safeAttrs = ''; if (attrsStr) { const attrRegex = /([a-zA-Z][a-zA-Z0-9-]*)\s*(?:=\s*(?:"([^"]*)"|'([^']*)'|([^\s>"']+)))?/g; let attrMatch; while ((attrMatch = attrRegex.exec(attrsStr)) !== null) { const attrName = attrMatch[1].toLowerCase(); const attrVal = attrMatch[2] ?? attrMatch[3] ?? attrMatch[4] ?? ''; if (/^on/i.test(attrName)) continue; if (attrName === 'style') continue; if (attrName === 'srcdoc') continue; if (attrName === 'formaction') continue; if (!ALLOWED_ATTRS.has(attrName) && !isAllowedDataAttr(attrName)) continue; let safeVal = attrVal; if (attrName === 'href' || attrName === 'src' || attrName === 'action' || attrName === 'poster') { safeVal = sanitizeUrl(attrVal); } if (attrName === 'target') { safeVal = '_blank'; } safeAttrs += ` ${attrName}="${safeVal.replace(/"/g, '"')}"`; if (attrName === 'target') { safeAttrs += ' rel="noopener noreferrer"'; } } } return selfClosing ? `<${tag}${safeAttrs} />` : `<${tag}${safeAttrs}>`; }); } export function sanitizeTopologyStrings(obj: any): any { if (obj === null || obj === undefined) return obj; if (typeof obj === 'string') return sanitizeHtmlString(obj); if (Array.isArray(obj)) return obj.map(sanitizeTopologyStrings); if (typeof obj === 'object') { const result: any = {}; for (const key of Object.keys(obj)) { result[key] = sanitizeTopologyStrings(obj[key]); } return result; } return obj; } export function validateTopology(topology: any): TopologyValidationResult { if (topology === null || topology === undefined) { return { valid: true, sanitized: null }; } let jsonStr: string; try { jsonStr = JSON.stringify(topology); } catch { return { valid: false, error: "Topology is not valid JSON" }; } if (jsonStr.length > TOPOLOGY_LIMITS.maxSizeBytes) { return { valid: false, error: `Topology exceeds maximum size of ${TOPOLOGY_LIMITS.maxSizeBytes / (1024 * 1024)}MB` }; } const depthCheck = checkJsonDepthAndSize(topology); if (!depthCheck.valid) { return { valid: false, error: depthCheck.error }; } if (typeof topology !== 'object' || Array.isArray(topology)) { return { valid: false, error: "Topology must be an object" }; } const typeChecks: Array<{ key: string; expectedType: string; isArray?: boolean }> = [ { key: 'nodeData', expectedType: 'object' }, { key: 'edgeData', expectedType: 'object' }, { key: 'nodePositions', expectedType: 'object' }, { key: 'nodeSizes', expectedType: 'object' }, { key: 'nodeStyles', expectedType: 'object' }, { key: 'rectData', expectedType: 'object' }, { key: 'textData', expectedType: 'object' }, { key: 'imageData', expectedType: 'object' }, { key: 'documentTabs', expectedType: 'object', isArray: true }, { key: 'edgeLegend', expectedType: 'object' }, { key: 'zoneLegend', expectedType: 'object' }, { key: 'currentTabIndex', expectedType: 'number' }, ]; for (const check of typeChecks) { if (topology[check.key] !== undefined && topology[check.key] !== null) { const actualType = typeof topology[check.key]; const isArray = Array.isArray(topology[check.key]); if (check.isArray) { if (!isArray) { return { valid: false, error: `Topology field '${check.key}' must be an array` }; } } else if (check.expectedType === 'object') { if (actualType !== 'object' || isArray) { return { valid: false, error: `Topology field '${check.key}' must be an object` }; } } else if (actualType !== check.expectedType) { return { valid: false, error: `Topology field '${check.key}' must be a ${check.expectedType}` }; } } } return { valid: true, sanitized: sanitizeTopologyStrings(topology) }; } export function validateTheOneFileHtml(html: string): ValidationResult { if (!html || html.length < 1000) { return { valid: false, error: "File too small to be valid" }; } if (!html.trim().startsWith("") && !html.trim().startsWith(" p < 0 || p > 255)) return false; if (parts[0] === 127 || parts[0] === 10 || parts[0] === 0) return false; if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return false; if (parts[0] === 192 && parts[1] === 168) return false; if (parts[0] === 169 && parts[1] === 254) return false; if (parts.every(p => p === 255)) return false; } if (hostname.includes(':')) { if (hostname === '::1' || hostname === '::') return false; if (/^fe80:/i.test(hostname)) return false; if (/^f[cd][0-9a-f]{2}:/i.test(hostname)) return false; if (/^::ffff:/i.test(hostname)) return false; if (/^100::/i.test(hostname)) return false; } return true; } catch { return false; } } export async function sendWebhook(event: string, data: any): Promise { const settings = getSettings(); if (!settings.webhookEnabled || !settings.webhookUrl) return; if (!isValidWebhookUrl(settings.webhookUrl)) { console.error('[Webhook] Blocked request to disallowed URL:', settings.webhookUrl); return; } try { await fetch(settings.webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ event, timestamp: new Date().toISOString(), data }) }); } catch (e: any) { console.error('[Webhook] Failed to send webhook:', e.message); } } const BACKUPS_DIR = join(DATA_DIR, "backups"); if (!existsSync(BACKUPS_DIR)) mkdirSync(BACKUPS_DIR, { recursive: true }); export async function createBackup(autoGenerated: boolean = false): Promise<{ id: string; filename: string; size: number } | null> { try { const settings = getSettings(); const id = crypto.randomUUID(); const timestamp = new Date().toISOString().replace(/[:.]/g, "").slice(0, 15); const filename = `backup_${timestamp}_${id.slice(0, 8)}.json`; const rooms = db.listRooms(); const dbSettings = db.getAllSettings(); const backupData = { version: 1, timestamp: new Date().toISOString(), rooms, settings: dbSettings }; const content = JSON.stringify(backupData, null, 2); await Bun.write(join(BACKUPS_DIR, filename), content); const size = content.length; db.createBackupRecord({ id, filename, createdAt: new Date().toISOString(), sizeBytes: size, roomCount: rooms.length, autoGenerated }); if (autoGenerated && settings.backupRetentionCount > 0) { const oldBackups = db.getOldAutoBackups(settings.backupRetentionCount); for (const backup of oldBackups) { const backupPath = join(BACKUPS_DIR, backup.filename); try { await unlink(backupPath); } catch {} db.deleteBackupRecord(backup.id); } } return { id, filename, size }; } catch (e: any) { console.error("[Backup]", e.message); return null; } } export async function restoreBackup(backupId: string): Promise<{ success: boolean; error?: string; roomsRestored?: number }> { const backups = db.listBackups(); const backup = backups.find(b => b.id === backupId); if (!backup) return { success: false, error: "Backup not found" }; const backupPath = join(BACKUPS_DIR, backup.filename); const backupFile = Bun.file(backupPath); if (!await backupFile.exists()) return { success: false, error: "Backup file missing" }; try { const content = await backupFile.text(); const data = JSON.parse(content); if (!data.rooms || !Array.isArray(data.rooms)) return { success: false, error: "Invalid backup format" }; let roomsRestored = 0; for (const room of data.rooms) { const existing = db.getRoom(room.id); if (!existing) { if (room.topology) room.topology = sanitizeTopologyStrings(room.topology); db.createRoom(room); roomsRestored++; } } return { success: true, roomsRestored }; } catch (e: any) { console.error("[Backup]", e.message); return { success: false, error: "Failed to parse backup" }; } } export function getBackupsDir(): string { return BACKUPS_DIR; } let backupTimer: Timer | null = null; export function restartBackupTimer(): void { const settings = getSettings(); if (backupTimer) clearInterval(backupTimer); backupTimer = null; if (settings.backupEnabled && settings.backupIntervalHours > 0) { backupTimer = setInterval(() => { createBackup(true); }, settings.backupIntervalHours * 60 * 60 * 1000); console.log(`[Backup] Auto backup every ${settings.backupIntervalHours} hours`); } } export function clearBackupTimer(): void { if (backupTimer) clearInterval(backupTimer); backupTimer = null; } ================================================ FILE: theonefile_verse/src/routes/admin-apikeys.ts ================================================ import * as db from "../database"; import { getClientIP, apiError, validateAdminOrApiKey } from "../security"; import { securityHeaders } from "../security"; import { hashApiKey } from "../tokens"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/api-keys" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const keys = db.listApiKeys(); return Response.json({ keys }, { headers: corsHeaders }); } if (path === "/api/admin/api-keys" && req.method === "POST") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.name) return Response.json({ error: "Name required" }, { status: 400, headers: corsHeaders }); const id = crypto.randomUUID(); const rawKey = `tof_${crypto.randomUUID().replace(/-/g, "")}`; const keyHash = await hashApiKey(rawKey); const permissions = body.permissions || ["read"]; const expiresAt = body.expiresInDays ? new Date(Date.now() + body.expiresInDays * 24 * 60 * 60 * 1000).toISOString() : null; db.createApiKey({ id, name: body.name, keyHash, permissions, createdAt: new Date().toISOString(), expiresAt, active: true }); const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "api_key_created", actor, actorIp: getClientIP(req), targetType: "api_key", targetId: id, details: { name: body.name } }); return Response.json({ id, key: rawKey, name: body.name, permissions, expiresAt }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/api-keys\/[\w-]+$/) && req.method === "DELETE") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const keyId = path.split("/")[4]; if (db.deactivateApiKey(keyId)) { const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "api_key_revoked", actor, actorIp: getClientIP(req), targetType: "api_key", targetId: keyId }); return Response.json({ revoked: true }, { headers: corsHeaders }); } return Response.json({ error: "API key not found" }, { status: 404, headers: corsHeaders }); } if (path === "/api/admin/export" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const rooms = db.listRooms(); const settings = db.getAllSettings(); const exportData = { version: 1, exportedAt: new Date().toISOString(), rooms, settings }; const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "data_exported", actor, actorIp: getClientIP(req), details: { roomCount: rooms.length } }); return new Response(JSON.stringify(exportData, null, 2), { headers: { "Content-Type": "application/json", "Content-Disposition": `attachment; filename="theonefile_export_${new Date().toISOString().slice(0, 10)}.json"`, ...securityHeaders } }); } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-auth-settings.ts ================================================ import * as oidc from "../oidc"; import * as db from "../database"; import * as mailer from "../mailer"; import { getClientIP, apiError, validateAdminUser } from "../security"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/auth-settings" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } return Response.json(oidc.getAuthSettings(), { headers: corsHeaders }); } if (path === "/api/admin/auth-settings" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); oidc.saveAuthSettings(body); db.addAuditLog({ timestamp: new Date().toISOString(), action: "auth_settings_changed", actor: adminUser.id, actorIp: getClientIP(req), details: body }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/admin/oidc-providers" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const providers = db.listOidcProviders().map(p => ({ id: p.id, name: p.name, providerType: p.providerType, clientId: p.clientId, issuerUrl: p.issuerUrl, authorizationUrl: p.authorizationUrl, tokenUrl: p.tokenUrl, userinfoUrl: p.userinfoUrl, scopes: p.scopes, isActive: p.isActive, displayOrder: p.displayOrder, iconUrl: p.iconUrl, createdAt: p.createdAt })); return Response.json({ providers }, { headers: corsHeaders }); } if (path === "/api/admin/oidc-providers" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.name || !body.clientId || !body.clientSecret) { return Response.json({ error: "Name, client ID, and client secret are required" }, { status: 400, headers: corsHeaders }); } const encryptedSecret = await oidc.encryptSecret(body.clientSecret); const now = new Date().toISOString(); const provider: db.OidcProvider = { id: crypto.randomUUID(), name: body.name, providerType: body.providerType || 'generic', clientId: body.clientId, clientSecretEncrypted: encryptedSecret, issuerUrl: body.issuerUrl || null, authorizationUrl: body.authorizationUrl || null, tokenUrl: body.tokenUrl || null, userinfoUrl: body.userinfoUrl || null, jwksUri: body.jwksUri || null, scopes: body.scopes || 'openid email profile', isActive: body.isActive !== false, displayOrder: body.displayOrder || 0, iconUrl: body.iconUrl || null, createdAt: now, updatedAt: now }; db.createOidcProvider(provider); db.addAuditLog({ timestamp: now, action: "oidc_provider_created", actor: adminUser.id, actorIp: getClientIP(req), targetType: "oidc_provider", targetId: provider.id, details: { name: provider.name } }); return Response.json({ success: true, id: provider.id }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/oidc-providers\/[\w-]+$/) && req.method === "PUT") { const providerId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const existing = db.getOidcProvider(providerId); if (!existing) { return Response.json({ error: "Provider not found" }, { status: 404, headers: corsHeaders }); } const now = new Date().toISOString(); const updated: db.OidcProvider = { ...existing, name: body.name ?? existing.name, providerType: body.providerType ?? existing.providerType, clientId: body.clientId ?? existing.clientId, clientSecretEncrypted: body.clientSecret ? await oidc.encryptSecret(body.clientSecret) : existing.clientSecretEncrypted, issuerUrl: body.issuerUrl !== undefined ? body.issuerUrl : existing.issuerUrl, authorizationUrl: body.authorizationUrl !== undefined ? body.authorizationUrl : existing.authorizationUrl, tokenUrl: body.tokenUrl !== undefined ? body.tokenUrl : existing.tokenUrl, userinfoUrl: body.userinfoUrl !== undefined ? body.userinfoUrl : existing.userinfoUrl, jwksUri: body.jwksUri !== undefined ? body.jwksUri : existing.jwksUri, scopes: body.scopes ?? existing.scopes, isActive: body.isActive ?? existing.isActive, displayOrder: body.displayOrder ?? existing.displayOrder, iconUrl: body.iconUrl !== undefined ? body.iconUrl : existing.iconUrl, updatedAt: now }; db.updateOidcProvider(updated); db.addAuditLog({ timestamp: now, action: "oidc_provider_updated", actor: adminUser.id, actorIp: getClientIP(req), targetType: "oidc_provider", targetId: providerId }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/oidc-providers\/[\w-]+$/) && req.method === "DELETE") { const providerId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } if (db.deleteOidcProvider(providerId)) { db.addAuditLog({ timestamp: new Date().toISOString(), action: "oidc_provider_deleted", actor: adminUser.id, actorIp: getClientIP(req), targetType: "oidc_provider", targetId: providerId }); return Response.json({ success: true }, { headers: corsHeaders }); } return Response.json({ error: "Provider not found" }, { status: 404, headers: corsHeaders }); } if (path === "/api/admin/smtp-configs" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const configs = db.listSmtpConfigs().map(c => ({ id: c.id, name: c.name, providerType: c.providerType, host: c.host, port: c.port, secureMode: c.secureMode, username: c.username, fromEmail: c.fromEmail, fromName: c.fromName, isDefault: c.isDefault, isActive: c.isActive, createdAt: c.createdAt })); return Response.json({ configs }, { headers: corsHeaders }); } if (path === "/api/admin/smtp-configs" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.name || !body.fromEmail) { return Response.json({ error: "Name and from email are required" }, { status: 400, headers: corsHeaders }); } const encryptedPassword = body.password ? await oidc.encryptSecret(body.password) : null; const now = new Date().toISOString(); const config: db.SmtpConfig = { id: crypto.randomUUID(), name: body.name, providerType: body.providerType || 'smtp', host: body.host || null, port: body.port || null, secureMode: body.secureMode || 'tls', username: body.username || null, passwordEncrypted: encryptedPassword, apiKeyEncrypted: null, fromEmail: body.fromEmail, fromName: body.fromName || null, isDefault: body.isDefault || false, isActive: body.isActive !== false, createdAt: now, updatedAt: now }; db.createSmtpConfig(config); db.addAuditLog({ timestamp: now, action: "smtp_config_created", actor: adminUser.id, actorIp: getClientIP(req), targetType: "smtp_config", targetId: config.id, details: { name: config.name } }); return Response.json({ success: true, id: config.id }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/smtp-configs\/[\w-]+$/) && req.method === "PUT") { const configId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const existing = db.getSmtpConfig(configId); if (!existing) { return Response.json({ error: "Config not found" }, { status: 404, headers: corsHeaders }); } const now = new Date().toISOString(); const updated: db.SmtpConfig = { ...existing, name: body.name ?? existing.name, providerType: body.providerType ?? existing.providerType, host: body.host !== undefined ? body.host : existing.host, port: body.port !== undefined ? body.port : existing.port, secureMode: body.secureMode ?? existing.secureMode, username: body.username !== undefined ? body.username : existing.username, passwordEncrypted: body.password ? await oidc.encryptSecret(body.password) : existing.passwordEncrypted, fromEmail: body.fromEmail ?? existing.fromEmail, fromName: body.fromName !== undefined ? body.fromName : existing.fromName, isDefault: body.isDefault ?? existing.isDefault, isActive: body.isActive ?? existing.isActive, updatedAt: now }; db.updateSmtpConfig(updated); db.addAuditLog({ timestamp: now, action: "smtp_config_updated", actor: adminUser.id, actorIp: getClientIP(req), targetType: "smtp_config", targetId: configId }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/admin/smtp-configs/test" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const now = new Date().toISOString(); let passwordEncrypted: string | null = null; if (body.password) { passwordEncrypted = await oidc.encryptSecret(body.password); } const testConfig: db.SmtpConfig = { id: "test-" + crypto.randomUUID(), name: body.name || "Test", providerType: "smtp", host: body.host, port: body.port || 587, secureMode: body.secureMode || "starttls", username: body.username || null, passwordEncrypted, apiKeyEncrypted: null, fromEmail: body.fromEmail, fromName: body.fromName || null, isDefault: false, isActive: true, createdAt: now, updatedAt: now }; const result = await mailer.testSmtpConfig(testConfig); return Response.json(result, { headers: corsHeaders }); } catch (e: any) { return Response.json({ success: false, error: e.message || "Test failed" }, { headers: corsHeaders }); } } if (path.match(/^\/api\/admin\/smtp-configs\/[\w-]+\/test$/) && req.method === "POST") { const configId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const config = db.getSmtpConfig(configId); if (!config) { return Response.json({ error: "Config not found" }, { status: 404, headers: corsHeaders }); } const result = await mailer.testSmtpConfig(config); return Response.json(result, { headers: corsHeaders }); } if (path.match(/^\/api\/admin\/smtp-configs\/[\w-]+$/) && req.method === "DELETE") { const configId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } if (db.deleteSmtpConfig(configId)) { db.addAuditLog({ timestamp: new Date().toISOString(), action: "smtp_config_deleted", actor: adminUser.id, actorIp: getClientIP(req), targetType: "smtp_config", targetId: configId }); return Response.json({ success: true }, { headers: corsHeaders }); } return Response.json({ error: "Config not found" }, { status: 404, headers: corsHeaders }); } if (path === "/api/admin/email-logs" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const limit = Math.min(parseInt(url.searchParams.get("limit") || "100") || 100, 1000); const offset = parseInt(url.searchParams.get("offset") || "0"); const logs = db.listEmailLogs(limit, offset); const stats = mailer.getEmailStats(); return Response.json({ logs, stats }, { headers: corsHeaders }); } if (path === "/api/admin/email-logs" && req.method === "DELETE") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } db.clearEmailLogs(); db.addAuditLog({ timestamp: new Date().toISOString(), action: "email_logs_cleared", actor: adminUser.email || "admin", actorIp: getClientIP(req) }); return Response.json({ success: true }, { headers: corsHeaders }); } if (path === "/api/admin/email-templates" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } return Response.json({ templates: db.listEmailTemplates() }, { headers: corsHeaders }); } if (path.match(/^\/api\/admin\/email-templates\/[\w-]+$/) && req.method === "PUT") { const templateId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const existing = db.getEmailTemplate(templateId); if (!existing) { return Response.json({ error: "Template not found" }, { status: 404, headers: corsHeaders }); } const updated: db.EmailTemplate = { ...existing, subject: body.subject ?? existing.subject, bodyHtml: body.bodyHtml ?? existing.bodyHtml, bodyText: body.bodyText ?? existing.bodyText, updatedAt: new Date().toISOString() }; db.updateEmailTemplate(updated); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-auth.ts ================================================ import * as auth from "../auth"; import * as oidc from "../oidc"; import * as db from "../database"; import * as redis from "../redis"; import { getSettings, getAdminPath, needsAdminMigration, hasAdminUser, verifyAdminPassword, getExternalOrigin } from "../config"; import { getClientIP, serveHtml, apiError, validateAdminUser, getTokenFromRequest, getUserTokenFromRequest, relativeRedirect } from "../security"; import { checkRateLimit } from "../rate-limit"; import { removeAdminToken, removeInstanceToken } from "../tokens"; import { adminDashboardHtml, adminLoginHtml, migrationPageHtml } from "../templates"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { const adminPath = getAdminPath(); const settings = getSettings(); if (path === `/${adminPath}`) { if (needsAdminMigration()) { const migrationWithPath = migrationPageHtml.replace(/\/admin\b(?!-)/g, `/${adminPath}`); return serveHtml(migrationWithPath, 'admin', req); } if (!hasAdminUser()) { return relativeRedirect("/"); } const adminUser = await validateAdminUser(req); if (!adminUser) { return relativeRedirect(`/${adminPath}/login`); } const dashboardWithPath = adminDashboardHtml .replace('ADMIN_PATH_PLACEHOLDER', adminPath) .replace(/\/admin\b(?!-)/g, `/${adminPath}`); return serveHtml(dashboardWithPath, 'admin', req); } if (path === `/${adminPath}/login`) { if (needsAdminMigration()) { return relativeRedirect(`/${adminPath}`); } if (!hasAdminUser()) { return relativeRedirect("/"); } const loginWithPath = adminLoginHtml.replace('ADMIN_PATH_PLACEHOLDER', adminPath).replace(/\/admin\b(?!-)/g, `/${adminPath}`); return serveHtml(loginWithPath, 'admin', req); } if (path === "/api/admin/login" && req.method === "POST") { if (!hasAdminUser()) { return Response.json({ error: "No admin user configured" }, { status: 400, headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "admin-login", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (!body.email || !body.password) { return Response.json({ error: "Email and password required" }, { status: 400, headers: corsHeaders }); } const result = await auth.loginWithPassword(body.email, body.password, clientIP, req.headers.get("user-agent") || ""); if (result.requires2FA) { const user = db.getUserByEmail(body.email); if (!user || user.role !== 'admin') { return Response.json({ error: "Not authorized as admin" }, { status: 403, headers: corsHeaders }); } return Response.json({ requires2FA: true, pendingToken: result.pendingToken }, { headers: corsHeaders }); } if (!result.success || !result.sessionToken) { return Response.json({ error: result.error || "Invalid credentials" }, { status: 403, headers: corsHeaders }); } const user = db.getUserByEmail(body.email); if (!user || user.role !== 'admin') { return Response.json({ error: "Not authorized as admin" }, { status: 403, headers: corsHeaders }); } return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", result.sessionToken) } }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/admin/migrate" && req.method === "POST") { if (!needsAdminMigration()) { return Response.json({ error: "Migration not needed" }, { status: 400, headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "admin-migrate", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (!body.oldPassword || !body.email) { return Response.json({ error: "Current password and email required" }, { status: 400, headers: corsHeaders }); } if (!(await verifyAdminPassword(body.oldPassword))) { return Response.json({ error: "Invalid current password" }, { status: 403, headers: corsHeaders }); } const emailValidation = auth.validateEmail(body.email); if (!emailValidation.valid) { return Response.json({ error: emailValidation.error }, { status: 400, headers: corsHeaders }); } const newPassword = body.newPassword || body.oldPassword; const passwordValidation = auth.validatePassword(newPassword); if (!passwordValidation.valid) { return Response.json({ error: passwordValidation.error }, { status: 400, headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); const result = await auth.registerUser(body.email, newPassword, body.email.split('@')[0], baseUrl); if (!result.success) { return Response.json({ error: result.error || "Migration failed" }, { status: 400, headers: corsHeaders }); } db.deleteSetting('admin_password_hash'); db.deleteSetting('admin_created_at'); const loginResult = await auth.loginWithPassword(body.email, newPassword, clientIP, req.headers.get("user-agent") || ""); if (!loginResult.success || !loginResult.sessionToken) { return Response.json({ error: "Migration succeeded but login failed" }, { status: 400, headers: corsHeaders }); } return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", loginResult.sessionToken) } }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/logout" && req.method === "POST") { const collabToken = getTokenFromRequest(req); if (collabToken) { await removeAdminToken(collabToken); removeInstanceToken(collabToken); if (redis.isRedisConnected()) await redis.deleteSessionToken(collabToken); } const userToken = getUserTokenFromRequest(req); if (userToken) { const user = await oidc.validateUserSessionToken(userToken); if (user) { oidc.revokeUserOidcTokens(user.id).catch(e => console.error('[OIDC] Token revocation error:', e)); } await auth.logout(userToken); if (redis.isRedisConnected()) await redis.deleteSessionToken(userToken); } const clearCookies = [ oidc.getClearCookie("collab_token"), oidc.getClearCookie("user_token") ].join(", "); return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": clearCookies } }); } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-backups.ts ================================================ import { join } from "path"; import { unlink } from "fs/promises"; import * as db from "../database"; import { getClientIP, validateAdminOrApiKey } from "../security"; import { securityHeaders } from "../security"; import { createBackup, restoreBackup, getBackupsDir } from "../rooms"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/backups" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const backups = db.listBackups(); return Response.json({ backups }, { headers: corsHeaders }); } if (path === "/api/admin/backups" && req.method === "POST") { const { user, apiKey } = await validateAdminOrApiKey(req, "write"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const result = await createBackup(false); if (result) { const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "backup_created", actor, actorIp: getClientIP(req), targetType: "backup", targetId: result.id }); return Response.json({ success: true, backup: result }, { headers: corsHeaders }); } return Response.json({ error: "Failed to create backup" }, { status: 500, headers: corsHeaders }); } if (path.match(/^\/api\/admin\/backups\/[\w-]+\/restore$/) && req.method === "POST") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const backupId = path.split("/")[4]; const result = await restoreBackup(backupId); if (result.success) { const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "backup_restored", actor, actorIp: getClientIP(req), targetType: "backup", targetId: backupId, details: { roomsRestored: result.roomsRestored } }); } return Response.json(result, { headers: corsHeaders }); } if (path.match(/^\/api\/admin\/backups\/[\w-]+\/download$/) && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const backupId = path.split("/")[4]; const backups = db.listBackups(); const backup = backups.find(b => b.id === backupId); if (!backup) return Response.json({ error: "Backup not found" }, { status: 404, headers: corsHeaders }); const BACKUPS_DIR = getBackupsDir(); const backupPath = join(BACKUPS_DIR, backup.filename); const backupFile = Bun.file(backupPath); if (!await backupFile.exists()) return Response.json({ error: "Backup file missing" }, { status: 404, headers: corsHeaders }); return new Response(backupFile, { headers: { "Content-Type": "application/json", "Content-Disposition": `attachment; filename="${backup.filename}"`, ...securityHeaders } }); } if (path.match(/^\/api\/admin\/backups\/[\w-]+$/) && req.method === "DELETE") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const backupId = path.split("/")[4]; const backups = db.listBackups(); const backup = backups.find(b => b.id === backupId); if (!backup) return Response.json({ error: "Backup not found" }, { status: 404, headers: corsHeaders }); const BACKUPS_DIR = getBackupsDir(); const backupPath = join(BACKUPS_DIR, backup.filename); try { await unlink(backupPath); } catch {} db.deleteBackupRecord(backupId); const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "backup_deleted", actor, actorIp: getClientIP(req), targetType: "backup", targetId: backupId }); return Response.json({ deleted: true }, { headers: corsHeaders }); } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-logs.ts ================================================ import * as db from "../database"; import { getClientIP, validateAdminOrApiKey } from "../security"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/audit-logs" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const query = url.searchParams.get("q") || ""; const limit = Math.min(parseInt(url.searchParams.get("limit") || "100") || 100, 1000); const offset = parseInt(url.searchParams.get("offset") || "0"); const logs = query ? db.searchAuditLogs(query, limit, offset) : db.getAuditLogs(limit, offset); return Response.json({ logs }, { headers: corsHeaders }); } if (path === "/api/admin/audit-logs" && req.method === "DELETE") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } db.clearAuditLogs(); return Response.json({ success: true }, { headers: corsHeaders }); } if (path === "/api/admin/activity-logs" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const roomId = url.searchParams.get("room") || ""; const limit = Math.min(parseInt(url.searchParams.get("limit") || "100") || 100, 1000); const offset = parseInt(url.searchParams.get("offset") || "0"); const logs = roomId ? db.getActivityLogs(roomId, limit, offset) : db.getAllActivityLogs(limit, offset); return Response.json({ logs }, { headers: corsHeaders }); } if (path === "/api/admin/activity-logs" && req.method === "DELETE") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const actor = user ? (user.email || "admin") : `apikey:${apiKey!.name}`; db.clearActivityLogs(); db.addAuditLog({ timestamp: new Date().toISOString(), action: "activity_logs_cleared", actor, actorIp: getClientIP(req) }); return Response.json({ success: true }, { headers: corsHeaders }); } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-rooms.ts ================================================ import * as db from "../database"; import { isValidUUID } from "../config"; import { getClientIP, validateAdminOrApiKey } from "../security"; import { roomMeta, deleteRoomData } from "../rooms"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/rooms" && req.method === "GET") { const { user, apiKey } = await validateAdminOrApiKey(req, "read"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const searchQuery = url.searchParams.get("q") || ""; const limit = Math.min(parseInt(url.searchParams.get("limit") || "100") || 100, 1000); const offset = parseInt(url.searchParams.get("offset") || "0"); const dbRooms = searchQuery ? db.searchRooms(searchQuery, limit, offset) : db.listRooms(limit, offset); const rooms = dbRooms.map(room => { const meta = roomMeta.get(room.id); return { id: room.id, created: room.created, lastActivity: room.lastActivity, hasPassword: !!room.passwordHash, destruct: room.destruct, connectedUsers: meta?.connectedUsers || 0 }; }); return Response.json({ rooms, total: db.countRooms() }, { headers: corsHeaders }); } if (path.match(/^\/api\/admin\/rooms\/[\w-]+$/) && req.method === "DELETE") { const { user, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!user && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const id = path.split("/")[4]; if (!isValidUUID(id)) { return Response.json({ error: "Invalid room ID" }, { status: 400, headers: corsHeaders }); } if (deleteRoomData(id)) { const actor = user ? user.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "room_deleted", actor, actorIp: getClientIP(req), targetType: "room", targetId: id }); return Response.json({ deleted: true }, { headers: corsHeaders }); } return Response.json({ error: "Room not found" }, { status: 404, headers: corsHeaders }); } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-settings.ts ================================================ import * as db from "../database"; import { getSettings, updateSettings, saveSettings, validateAdminPath, ENV_ADMIN_PASSWORD, APP_VERSION } from "../config"; import { getClientIP, apiError, validateAdminUser, validateAdminOrApiKey } from "../security"; import { hashPassword, theOneFileHtml, currentFileVersion, extractThemePresets, computeSha256Hash, validateTheOneFileHtml, fetchLatestFromGitHub, getExpectedTheOneFileHash, setExpectedTheOneFileHash, setTheOneFileHtml, getTheOneFilePath, restartUpdateTimer, clearUpdateTimer, isValidWebhookUrl, restartBackupTimer, extractVersionFromHtml, isNewerVersion } from "../rooms"; const GITHUB_RAW_URL = "https://raw.githubusercontent.com/gelatinescreams/The-One-File/main/theonefile-networkening.html"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/settings" && req.method === "GET") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "read"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const settings = getSettings(); const { instancePasswordHash, ...safeSettings } = settings; const fileValidation = validateTheOneFileHtml(theOneFileHtml); const currentFileHash = theOneFileHtml ? await computeSha256Hash(theOneFileHtml) : null; const expectedFileHash = getExpectedTheOneFileHash(); return Response.json({ ...safeSettings, instancePasswordSet: !!instancePasswordHash, envAdminPasswordSet: !!ENV_ADMIN_PASSWORD, currentFileSize: theOneFileHtml.length, currentFileEdition: fileValidation.valid ? fileValidation.edition : "invalid", currentFileHash, expectedFileHash, integrityCheckEnabled: !!expectedFileHash, integrityCheckPassed: expectedFileHash ? currentFileHash === expectedFileHash : null, availableThemes: extractThemePresets(), currentFileVersion: currentFileVersion || "unknown", lastUpdateTimestamp: db.getSetting("lastUpdateTimestamp") || null, latestGitHubVersion: db.getSetting("latestGitHubVersion") || null, lastVersionCheck: db.getSetting("lastVersionCheck") || null }, { headers: corsHeaders }); } if (path === "/api/admin/settings" && req.method === "POST") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (body.instancePassword !== undefined && body.instancePassword !== "" && body.instancePassword.length < 10) { return Response.json({ error: "Password must be at least 10 characters" }, { status: 400, headers: corsHeaders }); } if (body.webhookUrl && !isValidWebhookUrl(body.webhookUrl)) { return Response.json({ error: "Invalid webhook URL: must be http(s) and not point to private/internal addresses" }, { status: 400, headers: corsHeaders }); } if (body.adminPath !== undefined) { const validation = validateAdminPath(body.adminPath); if (!validation.valid) { return Response.json({ error: validation.error }, { status: 400, headers: corsHeaders }); } } if (body.theOneFileHash !== undefined && body.theOneFileHash !== "" && body.theOneFileHash !== null && body.theOneFileHash !== "current") { if (typeof body.theOneFileHash !== "string" || !/^[a-f0-9]{64}$/i.test(body.theOneFileHash)) { return Response.json({ error: "Invalid hash format. Must be 64 hex characters, 'current', or empty to disable." }, { status: 400, headers: corsHeaders }); } } const settings = { ...getSettings() }; if (typeof body.instancePasswordEnabled === "boolean") { settings.instancePasswordEnabled = body.instancePasswordEnabled; } if (body.instancePassword !== undefined) { if (body.instancePassword === "") { settings.instancePasswordHash = null; } else if (body.instancePassword.length >= 10) { settings.instancePasswordHash = await hashPassword(body.instancePassword); } } if (typeof body.updateIntervalHours === "number") { settings.updateIntervalHours = Math.max(0, body.updateIntervalHours); } if (typeof body.skipUpdates === "boolean") { settings.skipUpdates = body.skipUpdates; } if (typeof body.allowPublicRoomCreation === "boolean") { settings.allowPublicRoomCreation = body.allowPublicRoomCreation; } if (typeof body.maxRoomsPerInstance === "number") { settings.maxRoomsPerInstance = Math.max(0, body.maxRoomsPerInstance); } if (body.defaultDestructMode && ["time", "empty", "never"].includes(body.defaultDestructMode)) { settings.defaultDestructMode = body.defaultDestructMode; } if (typeof body.defaultDestructHours === "number") { settings.defaultDestructHours = Math.max(1, body.defaultDestructHours); } if (body.forcedTheme && ["user", "dark", "light"].includes(body.forcedTheme)) { settings.forcedTheme = body.forcedTheme; } if (typeof body.defaultRoomTheme === 'string') { const validKeys = extractThemePresets().map(t => t.key); if (body.defaultRoomTheme === '' || validKeys.includes(body.defaultRoomTheme)) { settings.defaultRoomTheme = body.defaultRoomTheme; } } if (typeof body.rateLimitEnabled === "boolean") { settings.rateLimitEnabled = body.rateLimitEnabled; } if (typeof body.rateLimitWindow === "number") { settings.rateLimitWindow = Math.max(10, Math.min(3600, body.rateLimitWindow)); } if (typeof body.rateLimitMaxAttempts === "number") { settings.rateLimitMaxAttempts = Math.max(1, Math.min(100, body.rateLimitMaxAttempts)); } if (typeof body.chatEnabled === "boolean") { settings.chatEnabled = body.chatEnabled; } if (typeof body.cursorSharingEnabled === "boolean") { settings.cursorSharingEnabled = body.cursorSharingEnabled; } if (typeof body.nameChangeEnabled === "boolean") { settings.nameChangeEnabled = body.nameChangeEnabled; } if (typeof body.probeEnabled === "boolean") { settings.probeEnabled = body.probeEnabled; } if (typeof body.discoveryEnabled === "boolean") { settings.discoveryEnabled = body.discoveryEnabled; } if (typeof body.discoveryAdminOnly === "boolean") { settings.discoveryAdminOnly = body.discoveryAdminOnly; } if (typeof body.discoveryAllowPublicRanges === "boolean") { settings.discoveryAllowPublicRanges = body.discoveryAllowPublicRanges; } if (typeof body.discoveryMaxPrefix === "number") { settings.discoveryMaxPrefix = Math.max(20, Math.min(32, body.discoveryMaxPrefix)); } if (typeof body.webhookEnabled === "boolean") { settings.webhookEnabled = body.webhookEnabled; } if (body.webhookUrl !== undefined) { settings.webhookUrl = body.webhookUrl || null; } if (typeof body.backupEnabled === "boolean") { settings.backupEnabled = body.backupEnabled; } if (typeof body.backupIntervalHours === "number") { settings.backupIntervalHours = Math.max(1, Math.min(168, body.backupIntervalHours)); } if (typeof body.backupRetentionCount === "number") { settings.backupRetentionCount = Math.max(1, Math.min(100, body.backupRetentionCount)); } if (body.adminPath !== undefined) { settings.adminPath = body.adminPath; } if (typeof body.showAdminLink === "boolean") { settings.showAdminLink = body.showAdminLink; } if (typeof body.forceWelcomeModal === "boolean") { settings.forceWelcomeModal = body.forceWelcomeModal; } if (body.theOneFileHash !== undefined) { if (body.theOneFileHash === "" || body.theOneFileHash === null) { db.deleteSetting("theOneFileHash"); console.log("[Security] TheOneFile integrity checking disabled by admin"); } else if (body.theOneFileHash === "current") { if (theOneFileHtml) { const currentHash = await computeSha256Hash(theOneFileHtml); setExpectedTheOneFileHash(currentHash); console.log(`[Security] TheOneFile integrity hash set to current file: ${currentHash.substring(0, 16)}...`); } } else { setExpectedTheOneFileHash(body.theOneFileHash.toLowerCase()); console.log(`[Security] TheOneFile integrity hash set: ${body.theOneFileHash.substring(0, 16)}...`); } } updateSettings(settings); saveSettings(settings); if (typeof body.updateIntervalHours === "number" || typeof body.skipUpdates === "boolean") { restartUpdateTimer(); } if (typeof body.backupEnabled === "boolean" || typeof body.backupIntervalHours === "number") { restartBackupTimer(); } const actor = adminUser ? adminUser.id : `apikey:${apiKey!.name}`; db.addAuditLog({ timestamp: new Date().toISOString(), action: "settings_changed", actor, actorIp: getClientIP(req), details: body }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/admin/update" && req.method === "POST") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const settings = getSettings(); if (settings.skipUpdates) { return Response.json({ error: "Updates disabled" }, { status: 400, headers: corsHeaders }); } const previousVersion = currentFileVersion; const success = await fetchLatestFromGitHub(); return Response.json({ success, size: theOneFileHtml.length, version: currentFileVersion, previousVersion }, { headers: corsHeaders }); } if (path === "/api/admin/version-check" && req.method === "GET") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "read"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const res = await fetch(GITHUB_RAW_URL, { signal: AbortSignal.timeout(15000) }); if (!res.ok) { return Response.json({ error: "GitHub unreachable" }, { status: 502, headers: corsHeaders }); } const html = await res.text(); const latestVersion = extractVersionFromHtml(html); const now = new Date().toISOString(); db.setSetting("latestGitHubVersion", latestVersion); db.setSetting("lastVersionCheck", now); return Response.json({ currentVersion: currentFileVersion || "unknown", latestVersion, updateAvailable: latestVersion !== "unknown" && currentFileVersion !== "unknown" && isNewerVersion(latestVersion, currentFileVersion), lastChecked: now }, { headers: corsHeaders }); } catch (e: any) { return Response.json({ error: e.message || "Version check failed" }, { status: 500, headers: corsHeaders }); } } if (path === "/api/admin/upload-html" && req.method === "POST") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const formData = await req.formData(); const file = formData.get("file") as File | null; if (!file) { return Response.json({ error: "No file provided" }, { status: 400, headers: corsHeaders }); } if (file.size > 50 * 1024 * 1024) { return Response.json({ error: "File too large. Maximum size is 50MB." }, { status: 400, headers: corsHeaders }); } const html = await file.text(); const validationResult = validateTheOneFileHtml(html); if (!validationResult.valid) { return Response.json({ error: validationResult.error }, { status: 400, headers: corsHeaders }); } const theOneFilePath = getTheOneFilePath(); await Bun.write(theOneFilePath, html); setTheOneFileHtml(html); const settings = getSettings(); settings.skipUpdates = true; updateSettings(settings); saveSettings(settings); clearUpdateTimer(); console.log(`[Upload] Admin uploaded local file (${(html.length / 1024).toFixed(1)}KB) - ${validationResult.edition}`); return Response.json({ success: true, size: html.length, edition: validationResult.edition }, { headers: corsHeaders }); } catch (e) { return Response.json({ error: "Failed to process upload" }, { status: 500, headers: corsHeaders }); } } if (path === "/api/admin/source-mode" && req.method === "POST") { const { user: adminUser, apiKey } = await validateAdminOrApiKey(req, "admin"); if (!adminUser && !apiKey) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const settings = getSettings(); if (body.mode === "github") { settings.skipUpdates = false; updateSettings(settings); saveSettings(settings); await fetchLatestFromGitHub(); restartUpdateTimer(); return Response.json({ success: true, mode: "github", size: theOneFileHtml.length }, { headers: corsHeaders }); } else if (body.mode === "local") { settings.skipUpdates = true; updateSettings(settings); saveSettings(settings); clearUpdateTimer(); return Response.json({ success: true, mode: "local" }, { headers: corsHeaders }); } return Response.json({ error: "Invalid mode" }, { status: 400, headers: corsHeaders }); } catch (e: any) { console.error("[API]", e.message); return Response.json({ error: "Invalid request" }, { status: 400, headers: corsHeaders }); } } return null; } ================================================ FILE: theonefile_verse/src/routes/admin-users.ts ================================================ import * as auth from "../auth"; import * as db from "../database"; import { getClientIP, apiError, validateAdminUser } from "../security"; import { getExternalOrigin } from "../config"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (path === "/api/admin/users" && req.method === "GET") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const searchQuery = url.searchParams.get("q") || ""; const limit = Math.min(parseInt(url.searchParams.get("limit") || "100") || 100, 1000); const offset = parseInt(url.searchParams.get("offset") || "0"); const users = searchQuery ? db.searchUsers(searchQuery, limit, offset) : db.listUsers(limit, offset); const safeUsers = users.map(u => { const { passwordHash, totpSecret, totpBackupCodes, pendingEmailToken, ...safe } = u; return safe; }); return Response.json({ users: safeUsers, total: db.countUsers() }, { headers: corsHeaders }); } if (path === "/api/admin/users" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const result = await auth.adminCreateUser(body.email, body.password, body.displayName, body.role || 'user'); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } db.addAuditLog({ timestamp: new Date().toISOString(), action: "user_created", actor: adminUser.id, actorIp: getClientIP(req), targetType: "user", targetId: result.userId }); return Response.json({ success: true, userId: result.userId }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/users\/[\w-]+$/) && req.method === "PUT") { const userId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); const result = auth.adminUpdateUser(userId, body); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } db.addAuditLog({ timestamp: new Date().toISOString(), action: "user_updated", actor: adminUser.id, actorIp: getClientIP(req), targetType: "user", targetId: userId, details: body }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/users\/[\w-]+\/reset-password$/) && req.method === "POST") { const userId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const user = db.getUserById(userId); if (!user) { return Response.json({ error: "User not found" }, { status: 404, headers: corsHeaders }); } if (!user.email) { return Response.json({ error: "User has no email address" }, { status: 400, headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); await auth.requestPasswordReset(user.email, baseUrl); db.addAuditLog({ timestamp: new Date().toISOString(), action: "user_password_reset_sent", actor: adminUser.id, actorIp: getClientIP(req), targetType: "user", targetId: userId }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders, "Failed to send reset email", 500); } } if (path.match(/^\/api\/admin\/users\/[\w-]+\/set-password$/) && req.method === "POST") { const userId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.password || typeof body.password !== 'string') { return Response.json({ error: "Password is required" }, { status: 400, headers: corsHeaders }); } const result = await auth.adminResetPassword(userId, body.password); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } db.addAuditLog({ timestamp: new Date().toISOString(), action: "user_password_set", actor: adminUser.id, actorIp: getClientIP(req), targetType: "user", targetId: userId }); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/admin\/users\/[\w-]+$/) && req.method === "DELETE") { const userId = path.split("/")[4]; const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const result = auth.adminDeleteUser(userId); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } db.addAuditLog({ timestamp: new Date().toISOString(), action: "user_deleted", actor: adminUser.id, actorIp: getClientIP(req), targetType: "user", targetId: userId }); return Response.json({ success: true }, { headers: corsHeaders }); } return null; } ================================================ FILE: theonefile_verse/src/routes/instance-access.ts ================================================ import * as oidc from "../oidc"; import { ENV_ADMIN_PASSWORD, isInstanceLocked, isAdminRoute, getSettings, verifyAdminPassword, verifyInstancePassword } from "../config"; import { getClientIP, apiError, serveHtml, getTokenFromRequest, validateAdminUser } from "../security"; import { checkRateLimit } from "../rate-limit"; import { validateInstanceToken, storeInstanceToken } from "../tokens"; import { instanceLoginPageHtml } from "../templates"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if ((ENV_ADMIN_PASSWORD || isInstanceLocked()) && isAdminRoute(path)) { const token = getTokenFromRequest(req); const adminUser = await validateAdminUser(req); const hasInstanceAccess = (token && validateInstanceToken(token)) || adminUser; if (!hasInstanceAccess) { if (path === "/" || path === "/index.html" || path.startsWith("/s/")) { return serveHtml(instanceLoginPageHtml, 'public', req); } return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } } if (path === "/api/instance-login" && req.method === "POST") { if (!ENV_ADMIN_PASSWORD && !isInstanceLocked()) { return Response.json({ error: "Instance not locked" }, { status: 400, headers: corsHeaders }); } const clientIP = getClientIP(req); const settings = getSettings(); if (!(await checkRateLimit(clientIP, "instance-login", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); let valid = false; if (ENV_ADMIN_PASSWORD) { valid = await verifyAdminPassword(body.password); } else { valid = await verifyInstancePassword(body.password); } if (valid) { const token = crypto.randomUUID(); storeInstanceToken(token); return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("collab_token", token, 604800) } }); } return Response.json({ error: "Invalid password" }, { status: 403, headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } return null; } ================================================ FILE: theonefile_verse/src/routes/network-routes.ts ================================================ import * as network from "../network"; import * as db from "../database"; import { getSettings, isValidUUID } from "../config"; import { getClientIP, apiError, validateRequestCsrf, csrfReject, validateAdminUser } from "../security"; import { checkRateLimit } from "../rate-limit"; import { roomConnections } from "../rooms"; import { fetchLatestFromGitHub, theOneFileHtml } from "../rooms"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { const settings = getSettings(); if (path === "/api/probe" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); if (!settings.probeEnabled) { return Response.json({ error: "Probing is disabled" }, { status: 403, headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "probe", settings, 60))) { return Response.json({ error: "Too many probe requests. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); const target = body.target; const probes = body.probes; const timeout = Math.min(Math.max(parseInt(body.timeout) || 3000, 1000), 10000); if (!target || typeof target !== "string" || !network.validateTarget(target)) { return Response.json({ error: "Invalid target" }, { status: 400, headers: corsHeaders }); } if (!network.validateProbeConfig(probes)) { return Response.json({ error: "Invalid probe configuration" }, { status: 400, headers: corsHeaders }); } const result = await network.probeTarget(target, probes, timeout); return Response.json(result, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/probe/batch" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); if (!settings.probeEnabled) { return Response.json({ error: "Probing is disabled" }, { status: 403, headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "probe-batch", settings, 30))) { return Response.json({ error: "Too many batch probe requests. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (!body.targets || !Array.isArray(body.targets) || body.targets.length === 0 || body.targets.length > 50) { return Response.json({ error: "Invalid targets (1-50 required)" }, { status: 400, headers: corsHeaders }); } const validTargets: network.BatchTarget[] = []; for (const t of body.targets) { if (!t.nodeId || typeof t.nodeId !== "string") continue; if (!t.target || !network.validateTarget(t.target)) continue; if (!network.validateProbeConfig(t.probes)) continue; const timeout = Math.min(Math.max(parseInt(t.timeout) || 3000, 1000), 10000); validTargets.push({ nodeId: t.nodeId, target: t.target, probes: t.probes, timeout }); } if (validTargets.length === 0) { return Response.json({ error: "No valid targets" }, { status: 400, headers: corsHeaders }); } const results = await network.probeBatch(validTargets); return Response.json({ results }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/discover/ports" && req.method === "GET") { return Response.json({ ports: network.getDefaultPortList() }, { headers: corsHeaders }); } if (path === "/api/discover" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); if (!settings.discoveryEnabled) { return Response.json({ error: "Discovery is disabled" }, { status: 403, headers: corsHeaders }); } if (settings.discoveryAdminOnly) { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Discovery requires admin access" }, { status: 401, headers: corsHeaders }); } } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "discover", settings))) { return Response.json({ error: "Too many discovery requests. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); const roomId = body.roomId; if (!roomId || !isValidUUID(roomId)) { return Response.json({ error: "Valid room ID required" }, { status: 400, headers: corsHeaders }); } let cidrs: string[] = []; if (Array.isArray(body.cidrs) && body.cidrs.length > 0) { cidrs = body.cidrs.filter((c: unknown) => typeof c === "string" && c.length > 0); } else if (body.cidr && typeof body.cidr === "string") { cidrs = [body.cidr]; } if (cidrs.length === 0) { return Response.json({ error: "At least one CIDR range required" }, { status: 400, headers: corsHeaders }); } if (cidrs.length > 10) { return Response.json({ error: "Maximum 10 ranges per scan" }, { status: 400, headers: corsHeaders }); } let totalCount = 0; for (const cidr of cidrs) { const validation = network.validateCIDR(cidr, settings.discoveryAllowPublicRanges, settings.discoveryMaxPrefix); if (!validation.valid) { return Response.json({ error: `${cidr}: ${validation.error}` }, { status: 400, headers: corsHeaders }); } totalCount += validation.count || 0; } const taskPrefix = `disc-${roomId}`; if (network.hasActiveDiscoveryForRoom(roomId, taskPrefix)) { return Response.json({ error: "A scan is already running for this room" }, { status: 409, headers: corsHeaders }); } const taskId = `${taskPrefix}-${Date.now()}`; const options: network.DiscoveryOptions = { icmp: body.options?.icmp !== false, tcp: body.options?.tcp !== false, dns: body.options?.dns !== false, netbios: body.options?.netbios !== false, mdns: body.options?.mdns !== false, snmp: body.options?.snmp === true, snmpCommunity: (typeof body.options?.snmpCommunity === "string" && body.options.snmpCommunity.length <= 64) ? body.options.snmpCommunity : "public", ports: Array.isArray(body.options?.ports) ? body.options.ports.filter((p: unknown) => typeof p === "number" && network.validatePort(p)) : [], }; const connections = roomConnections.get(roomId); await network.startDiscovery( taskId, roomId, cidrs, options, (percent, scanned, total, rangeIndex, totalRanges) => { if (connections) { const msg = JSON.stringify({ type: "discovery-progress", taskId, percent, scanned, total, rangeIndex, totalRanges }); for (const ws of connections) ws.send(msg); } }, (host) => { if (connections) { const msg = JSON.stringify({ type: "discovery-found", taskId, host }); for (const ws of connections) ws.send(msg); } }, (totalFound) => { if (connections) { const msg = JSON.stringify({ type: "discovery-complete", taskId, totalFound }); for (const ws of connections) ws.send(msg); } }, ); return Response.json({ taskId, count: totalCount, ranges: cidrs.length }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/discover/cancel" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); try { const body = await req.json(); if (!body.taskId || typeof body.taskId !== "string") { return Response.json({ error: "Task ID required" }, { status: 400, headers: corsHeaders }); } const cancelled = network.cancelDiscovery(body.taskId); return Response.json({ cancelled }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/discover/deepscan" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); if (!settings.discoveryEnabled) { return Response.json({ error: "Discovery is disabled" }, { status: 403, headers: corsHeaders }); } if (settings.discoveryAdminOnly) { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Discovery requires admin access" }, { status: 401, headers: corsHeaders }); } } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "deepscan", settings, 10, 120))) { return Response.json({ error: "Too many deep scan requests. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); const roomId = body.roomId; if (!roomId || !isValidUUID(roomId)) { return Response.json({ error: "Valid room ID required" }, { status: 400, headers: corsHeaders }); } const ip = body.ip; if (!ip || typeof ip !== "string" || !network.validateIPv4(ip)) { return Response.json({ error: "Valid IP address required" }, { status: 400, headers: corsHeaders }); } if (!network.isRFC1918(ip)) { return Response.json({ error: "Only private IP addresses allowed for deep scan" }, { status: 400, headers: corsHeaders }); } if (network.hasActiveDeepScan(ip)) { return Response.json({ error: "A deep scan is already running for this host" }, { status: 409, headers: corsHeaders }); } const existingPorts: number[] = Array.isArray(body.existingPorts) ? body.existingPorts.filter((p: unknown) => typeof p === "number" && network.validatePort(p)) : []; const scanId = `deepscan-${ip}-${Date.now()}`; const connections = roomConnections.get(roomId); await network.startDeepScan( scanId, ip, existingPorts, (percent, scanned, total) => { if (connections) { const msg = JSON.stringify({ type: "deepscan-progress", scanId, ip, percent, scanned, total }); for (const ws of connections) ws.send(msg); } }, (newPorts, newServices, containers) => { if (connections) { const newIcons = network.getServiceIcons(newPorts); const msg = JSON.stringify({ type: "deepscan-update", scanId, ip, newPorts, newServices, containers, newIcons }); for (const ws of connections) ws.send(msg); } }, () => { if (connections) { const msg = JSON.stringify({ type: "deepscan-complete", scanId, ip }); for (const ws of connections) ws.send(msg); } }, ); return Response.json({ scanId, ip }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/discover/deepscan/cancel" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); try { const body = await req.json(); if (!body.scanId || typeof body.scanId !== "string") { return Response.json({ error: "Scan ID required" }, { status: 400, headers: corsHeaders }); } const cancelled = network.cancelDeepScan(body.scanId); return Response.json({ cancelled }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/refresh" && req.method === "POST") { const adminUser = await validateAdminUser(req); if (!adminUser) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } if (settings.skipUpdates) return Response.json({ error: "Updates disabled" }, { status: 400, headers: corsHeaders }); const success = await fetchLatestFromGitHub(); return Response.json({ success, size: theOneFileHtml.length }, { headers: corsHeaders }); } return null; } ================================================ FILE: theonefile_verse/src/routes/public.ts ================================================ import { join } from "path"; import * as oidc from "../oidc"; import * as db from "../database"; import * as redis from "../redis"; import { APP_VERSION, getSettings, isValidUUID, getAdminPath } from "../config"; import { serveHtml, securityHeaders, getUserTokenFromRequest, validateAdminUser, relativeRedirect } from "../security"; import { theOneFileHtml, loadRoom } from "../rooms"; const STATIC_FILES: Record = { "/collab.js": { path: "public/collab.js", type: "application/javascript", cache: "no-cache" }, "/collab-init.js": { path: "public/collab-init.js", type: "application/javascript", cache: "no-cache" }, "/collab-save-hook.js": { path: "public/collab-save-hook.js", type: "application/javascript", cache: "no-cache" }, "/collab.css": { path: "public/collab.css", type: "text/css", cache: "no-cache" }, "/landing.js": { path: "public/landing.js", type: "application/javascript", cache: "public, max-age=3600" }, "/admin-dashboard.js": { path: "public/admin-dashboard.js", type: "application/javascript", cache: "public, max-age=3600" }, "/admin-auth.js": { path: "public/admin-auth.js", type: "application/javascript", cache: "public, max-age=3600" }, "/admin-pages.js": { path: "public/admin-pages.js", type: "application/javascript", cache: "public, max-age=3600" }, "/qrcode.min.js": { path: "public/qrcode.min.js", type: "application/javascript", cache: "public, max-age=86400" } }; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { const settings = getSettings(); if (path === "/api/version" && req.method === "GET") { return Response.json({ version: APP_VERSION }, { headers: corsHeaders }); } if (path === "/api/health" && req.method === "GET") { const uptime = process.uptime(); let dbOk = false; try { dbOk = db.healthCheck(); } catch {} let redisOk = false; try { redisOk = await redis.ping(); } catch {} const status = dbOk ? "ok" : "degraded"; return Response.json({ status, version: APP_VERSION, uptime: Math.floor(uptime), components: { database: dbOk ? "ok" : "error", redis: redisOk ? "ok" : "unavailable" }, rooms: db.countRooms() }, { headers: corsHeaders }); } if (path === "/api/theme" && req.method === "GET") { const authSettings = oidc.getAuthSettings(); return Response.json({ forcedTheme: settings.forcedTheme, chatEnabled: settings.chatEnabled, cursorSharingEnabled: settings.cursorSharingEnabled, nameChangeEnabled: settings.nameChangeEnabled, shareButtonEnabled: authSettings.shareButtonEnabled, showAdminLink: settings.showAdminLink, ...(settings.showAdminLink ? { adminPath: getAdminPath() } : {}) }, { headers: corsHeaders }); } if (path.match(/^\/s\/[\w-]+$/)) { const id = path.split("/")[2]; if (!isValidUUID(id)) { return relativeRedirect("/?error=invalid_room"); } const room = loadRoom(id); if (!room) return relativeRedirect("/?error=room_not_found"); if (!theOneFileHtml) return relativeRedirect("/?error=room_unavailable"); let injectedHtml = theOneFileHtml.replace('', ''); const adminUser = await validateAdminUser(req); const isAdmin = !!adminUser; let isOwner = false; if (room.ownerUserId) { const userToken = getUserTokenFromRequest(req); if (userToken) { const user = await oidc.validateUserSessionToken(userToken); if (user && user.id === room.ownerUserId) isOwner = true; } } const roomCsrfToken = oidc.generateCsrfToken(); const safeRoomConfig = JSON.stringify({ roomId: id, roomHasPassword: !!room.passwordHash && !isAdmin, isAdmin, csrfToken: roomCsrfToken, isCreator: isOwner || isAdmin, defaultRoomTheme: settings.defaultRoomTheme || '', forceWelcomeModal: settings.forceWelcomeModal || false, probeEnabled: settings.probeEnabled, discoveryEnabled: settings.discoveryEnabled, discoveryAllowed: settings.discoveryEnabled && (isAdmin || !settings.discoveryAdminOnly) }); const configBlock = ` `; injectedHtml = injectedHtml.replace(/<\/body>\s*<\/html>\s*$/i, configBlock + "\n"); return serveHtml(injectedHtml, 'room', req); } if (path === "/" || path === "/index.html") { const file = Bun.file(join(process.cwd(), "public", "index.html")); if (await file.exists()) return serveHtml(await file.text(), 'public', req); } const staticEntry = STATIC_FILES[path]; if (staticEntry) { const file = Bun.file(join(process.cwd(), staticEntry.path)); if (await file.exists()) { return new Response(file, { headers: { "Content-Type": staticEntry.type, ...securityHeaders, "Cache-Control": staticEntry.cache } }); } } if (path === "/favicon.ico") { return new Response(null, { status: 204 }); } return null; } ================================================ FILE: theonefile_verse/src/routes/room.ts ================================================ import * as oidc from "../oidc"; import * as db from "../database"; import { getSettings, isValidUUID } from "../config"; import { getClientIP, apiError, validateRequestCsrf, csrfReject, getUserTokenFromRequest, validateAdminUser } from "../security"; import { checkRateLimit } from "../rate-limit"; import { generateWsSessionToken, generateRoomAccessToken, validateRoomAccessToken, WS_TOKEN_EXPIRY } from "../tokens"; import { loadRoom, saveRoom, deleteRoomData, scheduleDestruction, hashPassword, verifyPassword, validateTopology, sendWebhook, type Room } from "../rooms"; const ROOM_ACCESS_COOKIE_REGEX = /(?:^|;\s*)room_access=([^;]+)/; const HOST_ROOM_ACCESS_COOKIE_REGEX = /(?:^|;\s*)__Host-room_access=([^;]+)/; function extractRoomAccessCookie(cookies: string, prodMode: boolean): string { const match = cookies.match(prodMode ? HOST_ROOM_ACCESS_COOKIE_REGEX : ROOM_ACCESS_COOKIE_REGEX); return match ? match[1] : ''; } export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { const settings = getSettings(); if (path === "/api/room" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "room-create", settings))) { return Response.json({ error: "Too many rooms created. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); const creatorId = body.creatorId && isValidUUID(body.creatorId) ? body.creatorId : crypto.randomUUID(); const validDestructModes = ["time", "empty", "never"]; const destructMode = validDestructModes.includes(body.destructMode) ? body.destructMode : "time"; const maxDestructValue = 30 * 24 * 60 * 60 * 1000; const destructValue = typeof body.destructValue === "number" ? Math.min(Math.max(0, body.destructValue), maxDestructValue) : 86400000; if (body.password && body.password.length > 0 && body.password.length < 8) { return Response.json({ error: "Room password must be at least 8 characters" }, { status: 400, headers: corsHeaders }); } const passwordHash = body.password && body.password.length >= 8 ? await hashPassword(body.password) : null; const id = crypto.randomUUID(); const userToken = getUserTokenFromRequest(req); let ownerUserId: string | null = null; if (userToken) { const user = await oidc.validateUserSessionToken(userToken); if (user) ownerUserId = user.id; } const authSettings = oidc.getAuthSettings(); if (!authSettings.allowGuestRoomCreation && !ownerUserId) { return Response.json({ error: "Please sign in to create a room" }, { status: 401, headers: corsHeaders }); } if (settings.maxRoomsPerInstance > 0 && db.countRooms() >= settings.maxRoomsPerInstance) { return Response.json({ error: "Maximum number of rooms reached" }, { status: 403, headers: corsHeaders }); } const allowGuests = body.allowGuests !== false && authSettings.allowGuestRoomJoin; let validatedTopology = null; if (body.topology) { const topologyValidation = validateTopology(body.topology); if (!topologyValidation.valid) { return Response.json({ error: topologyValidation.error || "Invalid topology data" }, { status: 400, headers: corsHeaders }); } validatedTopology = topologyValidation.sanitized; } const room: Room = { id, created: new Date().toISOString(), lastActivity: new Date().toISOString(), creatorId, passwordHash, destruct: { mode: destructMode, value: destructValue }, topology: validatedTopology, ownerUserId, allowGuests }; saveRoom(room); if (room.destruct.mode === "time") scheduleDestruction(id, room.destruct.value); sendWebhook("room_created", { roomId: id, hasPassword: !!room.passwordHash, destructMode, creatorId }); return Response.json({ id, url: `/s/${id}`, hasPassword: !!room.passwordHash, allowGuests: room.allowGuests }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path.match(/^\/api\/room\/[\w-]+\/verify$/) && req.method === "POST") { const id = path.split("/")[3]; if (!isValidUUID(id)) { return Response.json({ error: "Invalid room ID" }, { status: 400, headers: corsHeaders }); } const room = loadRoom(id); if (!room) return Response.json({ error: "Room not found" }, { status: 404, headers: corsHeaders }); if (!room.passwordHash) return Response.json({ valid: true }, { headers: corsHeaders }); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, `room-verify-${id}`, settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); const valid = await verifyPassword(body.password || "", room.passwordHash); if (valid) { const accessToken = generateRoomAccessToken(id); const prodMode = oidc.getAuthSettings().productionMode; const cookieName = prodMode ? '__Host-room_access' : 'room_access'; const cookieFlags = prodMode ? '; HttpOnly; Secure; SameSite=Strict; Path=/; Partitioned' : '; HttpOnly; SameSite=Strict; Path=/'; const responseHeaders = { ...corsHeaders, 'Set-Cookie': `${cookieName}=${accessToken}; Max-Age=86400${cookieFlags}` }; return Response.json({ valid: true }, { headers: responseHeaders }); } return Response.json({ valid: false }, { headers: corsHeaders }); } catch (e: any) { console.error("[API]", e.message); return Response.json({ valid: false }, { headers: corsHeaders }); } } if (path.match(/^\/api\/room\/[\w-]+\/access$/) && req.method === "GET") { const id = path.split("/")[3]; if (!isValidUUID(id)) return Response.json({ authorized: false }, { status: 400, headers: corsHeaders }); const room = loadRoom(id); if (!room) return Response.json({ authorized: false }, { status: 404, headers: corsHeaders }); if (!room.passwordHash) return Response.json({ authorized: true }, { headers: corsHeaders }); const prodMode = oidc.getAuthSettings().productionMode; const cookies = req.headers.get('cookie') || ''; const token = extractRoomAccessCookie(cookies, prodMode); return Response.json({ authorized: validateRoomAccessToken(token, id) }, { headers: corsHeaders }); } if (path.match(/^\/api\/room\/[\w-]+$/) && req.method === "DELETE") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const id = path.split("/")[3]; if (!isValidUUID(id)) { return Response.json({ error: "Invalid room ID" }, { status: 400, headers: corsHeaders }); } const room = loadRoom(id); if (!room) return Response.json({ error: "Room not found" }, { status: 404, headers: corsHeaders }); const userToken = getUserTokenFromRequest(req); if (userToken) { const user = await oidc.validateUserSessionToken(userToken); if (user) { if (user.role === 'admin' || (room.ownerUserId && user.id === room.ownerUserId)) { deleteRoomData(id); db.addAuditLog({ timestamp: new Date().toISOString(), action: "room_deleted", actor: user.id, actorIp: getClientIP(req), targetType: "room", targetId: id }); return Response.json({ deleted: true }, { headers: corsHeaders }); } } } return Response.json({ error: "Only room owner or admin can delete" }, { status: 403, headers: corsHeaders }); } if (path.match(/^\/api\/room\/[\w-]+\/exists$/) && req.method === "GET") { const id = path.split("/")[3]; if (!isValidUUID(id)) { return Response.json({ exists: false }, { headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "room-exists", settings))) { return Response.json({ error: "Too many requests. Try again later." }, { status: 429, headers: corsHeaders }); } const room = loadRoom(id); if (!room) return Response.json({ exists: false }, { headers: corsHeaders }); return Response.json({ exists: true, hasPassword: !!room.passwordHash }, { headers: corsHeaders }); } if (path.match(/^\/api\/room\/[\w-]+\/ws-token$/) && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const id = path.split("/")[3]; if (!isValidUUID(id)) { return Response.json({ error: "Invalid room ID" }, { status: 400, headers: corsHeaders }); } const room = loadRoom(id); if (!room) return Response.json({ error: "Room not found" }, { status: 404, headers: corsHeaders }); if (room.passwordHash) { const prodMode = oidc.getAuthSettings().productionMode; const cookies = req.headers.get('cookie') || ''; const accessToken = extractRoomAccessCookie(cookies, prodMode); if (!validateRoomAccessToken(accessToken, id)) { return Response.json({ error: "Room password required" }, { status: 403, headers: corsHeaders }); } } if (room.allowGuests === false) { const userToken = getUserTokenFromRequest(req); if (!userToken) return Response.json({ error: "Authentication required" }, { status: 401, headers: corsHeaders }); const user = await oidc.validateUserSessionToken(userToken); if (!user) return Response.json({ error: "Authentication required" }, { status: 401, headers: corsHeaders }); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, `ws-token-${id}`, settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); let collabUserId: string; const userToken = getUserTokenFromRequest(req); if (userToken) { const user = await oidc.validateUserSessionToken(userToken); collabUserId = user ? user.id : crypto.randomUUID(); } else { collabUserId = crypto.randomUUID(); } const wsToken = await generateWsSessionToken(id, collabUserId); return Response.json({ wsToken, expiresIn: WS_TOKEN_EXPIRY / 1000, collabUserId }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } return null; } ================================================ FILE: theonefile_verse/src/routes/setup.ts ================================================ import * as auth from "../auth"; import * as oidc from "../oidc"; import * as db from "../database"; import { isAdminConfigured, hasAdminUser, getSettings, getExternalOrigin } from "../config"; import { getClientIP, serveHtml, apiError } from "../security"; import { checkRateLimit } from "../rate-limit"; import { setupPageHtml } from "../templates"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { if (!isAdminConfigured() && (path === "/" || path === "/index.html")) { return serveHtml(setupPageHtml, 'public', req); } if (path === "/api/setup" && req.method === "POST") { if (hasAdminUser()) { return Response.json({ error: "Admin already configured" }, { status: 400, headers: corsHeaders }); } const clientIP = getClientIP(req); const settings = getSettings(); if (!(await checkRateLimit(clientIP, "setup", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (!body.email || !body.email.includes('@')) { return Response.json({ error: "Valid email required" }, { status: 400, headers: corsHeaders }); } if (!body.password || body.password.length < 8) { return Response.json({ error: "Password must be at least 8 characters" }, { status: 400, headers: corsHeaders }); } const emailValidation = auth.validateEmail(body.email); if (!emailValidation.valid) { return Response.json({ error: emailValidation.error }, { status: 400, headers: corsHeaders }); } const passwordValidation = auth.validatePassword(body.password); if (!passwordValidation.valid) { return Response.json({ error: passwordValidation.error }, { status: 400, headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); const result = await auth.registerUser(body.email, body.password, body.email.split('@')[0], baseUrl); if (!result.success) { return Response.json({ error: result.error || "Registration failed" }, { status: 400, headers: corsHeaders }); } const loginResult = await auth.loginWithPassword(body.email, body.password, clientIP, req.headers.get("user-agent") || ""); if (!loginResult.success || !loginResult.sessionToken) { return Response.json({ error: "Account created but login failed" }, { status: 400, headers: corsHeaders }); } return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", loginResult.sessionToken) } }); } catch (e: any) { return apiError(e, corsHeaders); } } return null; } ================================================ FILE: theonefile_verse/src/routes/user-auth.ts ================================================ import * as auth from "../auth"; import * as oidc from "../oidc"; import * as redis from "../redis"; import { getSettings, getExternalOrigin } from "../config"; import { getClientIP, apiError, validateRequestCsrf, csrfReject, getUserTokenFromRequest, serveHtml, relativeRedirect } from "../security"; import { checkRateLimit, checkEmailRateLimit } from "../rate-limit"; import { userLoginHtml, userRegisterHtml, userForgotPasswordHtml, getPasswordResetHtml } from "../templates"; export async function handle(req: Request, path: string, url: URL, corsHeaders: Record): Promise { const settings = getSettings(); if (path === "/api/auth/settings" && req.method === "GET") { const authSettings = oidc.getAuthSettings(); const providers = oidc.getActiveProviders(); return Response.json({ settings: authSettings, providers }, { headers: corsHeaders }); } if (path === "/api/auth/providers" && req.method === "GET") { const providers = oidc.getActiveProviders(); return Response.json(providers, { headers: corsHeaders }); } if (path === "/api/auth/csrf" && req.method === "GET") { const csrfToken = oidc.generateCsrfToken(); return new Response(JSON.stringify({ token: csrfToken }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getCsrfCookie(csrfToken) } }); } if (path === "/api/auth/register" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "register", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (typeof body.email !== "string" || typeof body.password !== "string" || (body.displayName !== undefined && body.displayName !== null && typeof body.displayName !== "string")) { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } const csrfToken = body.csrfToken || req.headers.get("x-csrf-token"); if (!oidc.validateCsrfToken(csrfToken)) { return Response.json({ error: "Invalid security token. Please refresh and try again." }, { status: 403, headers: corsHeaders }); } if (body.email && !(await checkEmailRateLimit(body.email, "register", settings))) { return Response.json({ error: "Too many registration attempts for this email. Try again later." }, { status: 429, headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); const result = await auth.registerUser(body.email, body.password, body.displayName, baseUrl); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } if (result.requiresVerification) { return Response.json({ success: true, requiresVerification: true }, { headers: corsHeaders }); } const loginResult = await auth.loginWithPassword(body.email, body.password, clientIP, req.headers.get("user-agent") || ""); if (loginResult.success) { return new Response(JSON.stringify({ success: true, userId: loginResult.userId }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", loginResult.sessionToken!) } }); } return Response.json({ success: true, userId: result.userId }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/login" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "user-login", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (typeof body.email !== "string" || typeof body.password !== "string") { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } const csrfToken = body.csrfToken || req.headers.get("x-csrf-token"); if (!oidc.validateCsrfToken(csrfToken)) { return Response.json({ error: "Invalid security token. Please refresh and try again." }, { status: 403, headers: corsHeaders }); } const result = await auth.loginWithPassword(body.email, body.password, clientIP, req.headers.get("user-agent") || ""); if (result.requires2FA) { return Response.json({ requires2FA: true, pendingToken: result.pendingToken }, { headers: corsHeaders }); } if (!result.success) { return Response.json({ error: result.error }, { status: 401, headers: corsHeaders }); } return new Response(JSON.stringify({ success: true, userId: result.userId }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", result.sessionToken!) } }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/2fa/login" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "2fa-login", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (!body.pendingToken || !body.code || typeof body.pendingToken !== "string" || typeof body.code !== "string") { return Response.json({ error: "Token and code required" }, { status: 400, headers: corsHeaders }); } const result = await auth.loginWith2FA(body.pendingToken, body.code, clientIP, req.headers.get("user-agent") || ""); if (!result.success) { return Response.json({ error: result.error }, { status: 401, headers: corsHeaders }); } return new Response(JSON.stringify({ success: true, userId: result.userId }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": oidc.getSessionCookie("user_token", result.sessionToken!) } }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/me" && req.method === "GET") { const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ user: null }, { headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ user: null }, { headers: corsHeaders }); } const { passwordHash, totpSecret, totpBackupCodes, pendingEmailToken, ...safeUser } = user; return Response.json({ user: safeUser }, { headers: corsHeaders }); } if (path === "/api/auth/logout" && req.method === "POST") { const token = getUserTokenFromRequest(req); if (token) { const user = await oidc.validateUserSessionToken(token); if (user) { oidc.revokeUserOidcTokens(user.id).catch(e => console.error('[OIDC] Token revocation error:', e)); } await auth.logout(token); if (redis.isRedisConnected()) await redis.deleteSessionToken(token); } const clearCookies = [ oidc.getClearCookie("collab_token"), oidc.getClearCookie("user_token") ].join(", "); return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json", "Set-Cookie": clearCookies } }); } if (path.match(/^\/api\/auth\/oidc\/[\w-]+\/login$/) && req.method === "GET") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "oidc-init", settings))) { return relativeRedirect("/?auth_error=rate_limited"); } const providerId = path.split("/")[4]; const baseUrl = getExternalOrigin(req); const redirectParam = url.searchParams.get("redirect"); const validatedRedirect = oidc.validateRedirectUrl(redirectParam, baseUrl); const result = await oidc.generateAuthorizationUrl(providerId, baseUrl, undefined, validatedRedirect); if (!result) { return relativeRedirect("/?auth_error=provider_unavailable"); } return Response.redirect(result.url, 302); } if (path.match(/^\/api\/auth\/oidc\/[\w-]+$/) && req.method === "GET") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "oidc-init", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const providerId = path.split("/")[4]; const baseUrl = getExternalOrigin(req); let linkUserId: string | undefined = undefined; const linkParam = url.searchParams.get("link"); if (linkParam) { const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Authentication required for account linking" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Authentication required for account linking" }, { status: 401, headers: corsHeaders }); } if (user.id !== linkParam) { return Response.json({ error: "Cannot link to another user's account" }, { status: 403, headers: corsHeaders }); } linkUserId = linkParam; } const result = await oidc.generateAuthorizationUrl(providerId, baseUrl, linkUserId); if (!result) { return Response.json({ error: "Provider not available" }, { status: 400, headers: corsHeaders }); } return Response.json({ url: result.url, state: result.state }, { headers: corsHeaders }); } if (path.match(/^\/auth\/callback\/[\w-]+$/) && req.method === "GET") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "oidc-callback", settings))) { return relativeRedirect("/?auth_error=rate_limited"); } const providerId = path.split("/")[3]; const code = url.searchParams.get("code"); const state = url.searchParams.get("state"); const error = url.searchParams.get("error"); if (error) { return relativeRedirect(`/?auth_error=${encodeURIComponent(error)}`); } if (!code || !state) { return relativeRedirect("/?auth_error=missing_params"); } const currentUserToken = getUserTokenFromRequest(req); const result = await oidc.processOidcCallback(providerId, code, state, clientIP, req.headers.get("user-agent") || "", currentUserToken); if (!result.success) { return relativeRedirect(`/?auth_error=${encodeURIComponent(result.error || "unknown")}`); } let redirectTo = "/"; if (result.isNewUser) { redirectTo = "/?welcome=true"; } else if (result.postLoginRedirect && result.postLoginRedirect !== "/") { redirectTo = result.postLoginRedirect; } return new Response(null, { status: 302, headers: { "Location": redirectTo, "Set-Cookie": oidc.getSessionCookie("user_token", result.sessionToken!), "X-Content-Type-Options": "nosniff", "Cache-Control": "no-store" } }); } if (path === "/auth/login" && req.method === "GET") { return serveHtml(userLoginHtml, 'public', req); } if (path === "/auth/register" && req.method === "GET") { return serveHtml(userRegisterHtml, 'public', req); } if (path === "/auth/forgot-password" && req.method === "GET") { return serveHtml(userForgotPasswordHtml, 'public', req); } if (path === "/auth/verify" && req.method === "GET") { const token = url.searchParams.get("token"); if (!token) { return relativeRedirect("/?verify_error=missing_token"); } const result = await auth.verifyEmail(token); if (!result.success) { return relativeRedirect(`/?verify_error=${encodeURIComponent(result.error || "unknown")}`); } return relativeRedirect("/?verified=true"); } if (path === "/api/auth/forgot-password" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "forgot-password", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (typeof body.email !== "string") { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } if (body.email && !(await checkEmailRateLimit(body.email, "password-reset", settings))) { return Response.json({ success: true }, { headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); await auth.requestPasswordReset(body.email, baseUrl); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/auth/reset-password" && req.method === "GET") { const token = url.searchParams.get("token"); if (!token) { return relativeRedirect("/?reset_error=missing_token"); } return serveHtml(getPasswordResetHtml(token), 'public', req); } if (path === "/api/auth/reset-password" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "reset-password", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (typeof body.token !== "string" || typeof body.password !== "string") { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } const csrfToken = body.csrfToken || req.headers.get("x-csrf-token"); if (!oidc.validateCsrfToken(csrfToken)) { return Response.json({ error: "Invalid security token. Please refresh and try again." }, { status: 403, headers: corsHeaders }); } const result = await auth.resetPassword(body.token, body.password); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/magic-link" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "magic-link", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } try { const body = await req.json(); if (typeof body.email !== "string") { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } if (body.email && !(await checkEmailRateLimit(body.email, "magic-link", settings))) { return Response.json({ success: true }, { headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); await auth.requestMagicLink(body.email, baseUrl); return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/auth/magic-link" && req.method === "GET") { const token = url.searchParams.get("token"); if (!token) { return relativeRedirect("/?magic_error=missing_token"); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "magic-link-verify", settings))) { return relativeRedirect("/?magic_error=rate_limited"); } const result = await auth.loginWithMagicLink(token, clientIP, req.headers.get("user-agent") || ""); if (!result.success) { return relativeRedirect(`/?magic_error=${encodeURIComponent(result.error || "unknown")}`); } return new Response(null, { status: 302, headers: { "Location": "/", "Set-Cookie": oidc.getSessionCookie("user_token", result.sessionToken!), "X-Content-Type-Options": "nosniff", "Cache-Control": "no-store" } }); } if (path === "/api/auth/profile" && req.method === "PUT") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "profile-update", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!validateRequestCsrf(req, body)) return csrfReject(corsHeaders); if (typeof body !== "object" || body === null || Array.isArray(body)) { return Response.json({ error: "Invalid input" }, { status: 400, headers: corsHeaders }); } const result = auth.updateProfile(user.id, body); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/change-password" && req.method === "POST") { const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "change-password", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!validateRequestCsrf(req, body)) return csrfReject(corsHeaders); if (typeof body.currentPassword !== "string" || typeof body.newPassword !== "string") { return Response.json({ error: "Invalid input types" }, { status: 400, headers: corsHeaders }); } const result = await auth.changePassword(user.id, body.currentPassword, body.newPassword); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/sessions" && req.method === "GET") { const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const sessions = auth.getUserSessions(user.id); return Response.json({ sessions }, { headers: corsHeaders }); } if (path === "/api/auth/sessions" && req.method === "DELETE") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const count = auth.logoutAll(user.id); return Response.json({ success: true, loggedOut: count }, { headers: corsHeaders }); } if (path === "/api/auth/oidc-links" && req.method === "GET") { const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const links = auth.getUserOidcLinks(user.id).map(l => ({ id: l.id, provider: l.provider, providerEmail: l.providerEmail, createdAt: l.createdAt })); return Response.json({ links }, { headers: corsHeaders }); } if (path.match(/^\/api\/auth\/oidc-links\/[\w-]+$/) && req.method === "DELETE") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const linkId = path.split("/")[4]; const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const result = auth.unlinkOidcProvider(user.id, linkId); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } if (path === "/api/auth/2fa/setup" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "2fa-setup", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const result = await auth.setupTOTP(user.id); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ secret: result.secret, otpauthUrl: result.otpauthUrl }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/2fa/verify" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "2fa-verify", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.code || typeof body.code !== "string" || body.code.length !== 6) { return Response.json({ error: "Valid 6 digit code required" }, { status: 400, headers: corsHeaders }); } const result = await auth.verifyAndEnableTOTP(user.id, body.code); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true, backupCodes: result.backupCodes }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/2fa/disable" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "2fa-disable", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.password || typeof body.password !== "string") { return Response.json({ error: "Password required" }, { status: 400, headers: corsHeaders }); } const result = await auth.disableTOTP(user.id, body.password); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/api/auth/email-change" && req.method === "POST") { if (!validateRequestCsrf(req)) return csrfReject(corsHeaders); const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "email-change", settings))) { return Response.json({ error: "Too many attempts. Try again later." }, { status: 429, headers: corsHeaders }); } const token = getUserTokenFromRequest(req); if (!token) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } const user = await oidc.validateUserSessionToken(token); if (!user) { return Response.json({ error: "Unauthorized" }, { status: 401, headers: corsHeaders }); } try { const body = await req.json(); if (!body.newEmail || !body.password || typeof body.newEmail !== "string" || typeof body.password !== "string") { return Response.json({ error: "New email and password required" }, { status: 400, headers: corsHeaders }); } const baseUrl = getExternalOrigin(req); const result = await auth.requestEmailChange(user.id, body.newEmail, body.password, baseUrl); if (!result.success) { return Response.json({ error: result.error }, { status: 400, headers: corsHeaders }); } return Response.json({ success: true }, { headers: corsHeaders }); } catch (e: any) { return apiError(e, corsHeaders); } } if (path === "/auth/verify-email-change" && req.method === "GET") { const token = url.searchParams.get("token"); if (!token) { return relativeRedirect("/?email_change_error=missing_token"); } const clientIP = getClientIP(req); if (!(await checkRateLimit(clientIP, "email-change-verify", settings))) { return relativeRedirect("/?email_change_error=rate_limited"); } const result = await auth.confirmEmailChange(token); if (!result.success) { return relativeRedirect(`/?email_change_error=${encodeURIComponent(result.error || "unknown")}`); } return relativeRedirect("/?email_changed=true"); } return null; } ================================================ FILE: theonefile_verse/src/security.ts ================================================ import * as oidc from "./oidc"; import * as db from "./database"; import { getSettings, getExternalOrigin } from "./config"; import { validateApiKey } from "./tokens"; const IPV4_REGEX = /^(\d{1,3}\.){3}\d{1,3}$/; const IPV6_REGEX = /^([\da-fA-F]{0,4}:){2,7}[\da-fA-F]{0,4}$/; export function isValidIP(ip: string): boolean { return IPV4_REGEX.test(ip) || IPV6_REGEX.test(ip) || ip === '::1'; } export function getClientIP(req: Request): string { const xForwardedFor = req.headers.get("x-forwarded-for"); if (xForwardedFor) { const ips = xForwardedFor.split(",").map(ip => ip.trim()).filter(isValidIP); if (ips.length === 0) return "unknown"; const settings = getSettings(); if (settings.trustedProxies.length > 0) { for (let i = ips.length - 1; i >= 0; i--) { if (!settings.trustedProxies.includes(ips[i])) { return ips[i]; } } } if (settings.trustedProxyCount > 0) { const index = Math.max(0, ips.length - settings.trustedProxyCount); return ips[index] || ips[0]; } return ips[0]; } const realIp = req.headers.get("x-real-ip"); if (realIp && isValidIP(realIp.trim())) return realIp.trim(); return "unknown"; } export function getSecurityHeaders(pageType: 'admin' | 'public' | 'room' | 'api' = 'public'): Record { const headers: Record = { "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "strict-origin-when-cross-origin" }; headers["Permissions-Policy"] = "camera=(), microphone=(), geolocation=(), payment=(), usb=()"; headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains; preload"; if (pageType === 'api') { headers["Cache-Control"] = "no-store"; } else if (pageType === 'admin') { headers["Content-Security-Policy"] = `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'`; } else if (pageType === 'room') { headers["Content-Security-Policy"] = `default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' wss: ws: https://cdn.jsdelivr.net https://raw.githubusercontent.com; frame-ancestors 'none'; base-uri 'self'`; } else { headers["Content-Security-Policy"] = `default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' wss: ws:; frame-ancestors 'none'; base-uri 'self'`; } return headers; } export const securityHeaders: Record = { "X-Content-Type-Options": "nosniff", "X-Frame-Options": "DENY", "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "strict-origin-when-cross-origin", "Permissions-Policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=()", "Cache-Control": "no-store" }; export function serveHtml(html: string, pageType: 'admin' | 'public' | 'room' = 'public', req?: Request): Response { const headers: Record = { "Content-Type": "text/html; charset=utf-8", ...getSecurityHeaders(pageType), "Vary": "Accept-Encoding" }; if (req && html.length > 1024 && (req.headers.get('accept-encoding') || '').includes('gzip')) { headers["Content-Encoding"] = "gzip"; return new Response(Bun.gzipSync(Buffer.from(html)), { headers }); } return new Response(html, { headers }); } export function apiError(e: any, corsHeaders: Record, message = "Invalid request", status = 400): Response { console.error("[API]", e.message); return Response.json({ error: message }, { status, headers: corsHeaders }); } export function validateRequestCsrf(req: Request, body?: any): boolean { const headerToken = req.headers.get("x-csrf-token"); const bodyToken = body?.csrfToken; const token = headerToken || bodyToken; if (token && oidc.validateCsrfToken(token)) return true; const origin = req.headers.get("origin"); const externalOrigin = getExternalOrigin(req); if (origin) return origin === externalOrigin; const referer = req.headers.get("referer"); if (referer) { try { return new URL(referer).origin === externalOrigin; } catch { return false; } } return false; } export function csrfReject(corsHeaders: Record): Response { return Response.json({ error: "Invalid security token. Please refresh and try again." }, { status: 403, headers: corsHeaders }); } export function getTokenFromRequest(req: Request): string | null { const cookie = req.headers.get("cookie") || ""; const match = cookie.match(/(?:^|;\s*)collab_token=([^;]+)/); if (match) return match[1]; const auth = req.headers.get("authorization") || ""; if (auth.startsWith("Bearer ")) return auth.slice(7); return null; } export function getUserTokenFromRequest(req: Request): string | null { const cookie = req.headers.get("cookie") || ""; const hostMatch = cookie.match(/__Host-user_token=([^;]+)/); if (hostMatch) return hostMatch[1]; const match = cookie.match(/user_token=([^;]+)/); if (match) return match[1]; const auth = req.headers.get("authorization") || ""; if (auth.startsWith("Bearer ")) return auth.slice(7); return null; } export function relativeRedirect(path: string, status: number = 302): Response { return new Response(null, { status, headers: { Location: path } }); } export async function validateAdminUser(req: Request): Promise { const method = req.method; if (method === "POST" || method === "PUT" || method === "DELETE") { if (!validateRequestCsrf(req)) return null; } const token = getUserTokenFromRequest(req); if (!token) return null; const user = await oidc.validateUserSessionToken(token); if (!user || user.role !== 'admin') return null; return user; } export async function validateAdminOrApiKey( req: Request, requiredPermission: string = "read" ): Promise<{ user: db.User | null; apiKey: db.ApiKey | null }> { const auth = req.headers.get("authorization") || ""; if (auth.startsWith("Bearer tof_")) { const key = auth.slice(7); const apiKey = await validateApiKey(key); if (!apiKey || !apiKey.active) return { user: null, apiKey: null }; if (!apiKey.permissions.includes(requiredPermission) && !apiKey.permissions.includes("admin")) { return { user: null, apiKey: null }; } return { user: null, apiKey }; } const user = await validateAdminUser(req); return { user, apiKey: null }; } ================================================ FILE: theonefile_verse/src/templates.ts ================================================ export const setupPageHtml = ` Setup - The One File Collab

Welcome to The One File Collab

Create your admin account to get started

The first user created becomes the administrator.
`; export const migrationPageHtml = ` Migrate Admin - The One File Collab

Migrate to User Account

Convert your admin password to a user account

Enter your current admin password and a new email to create your admin user account. This is a one time migration.
`; export const loginPageHtml = ` Login - The One File Collab `; export const instanceLoginPageHtml = ` Access - The One File Collab `; export const userLoginHtml = ` Login - The One File Collab `; export const userRegisterHtml = ` Register - The One File Collab `; export const userForgotPasswordHtml = ` Forgot Password - The One File Collab `; export const adminDashboardHtml = ` Admin - The One File Collab

Admin Dashboard

Back to App

All Rooms

0 selected

User Management

Authentication Mode

Default Auth Mode
How users can access the system
Require Email Verification
Users must verify email before accessing
Allow Magic Link Login
Users can login via email link
Match OIDC Emails
Auto link OIDC accounts with matching email. Only enable with trusted providers

Security

Production Mode
Enable HTTPS secure cookies. Required for production
ID Token Max Age (hours)
Maximum age for OIDC ID tokens before they are considered too old
Email Rate Limit Window (seconds)
Time window for email rate limiting
Email Rate Limit Max Attempts
Maximum email requests per address within window

Guest Access

Allow Guest Room Creation
Unregistered users can create rooms
Allow Guest Room Join
Unregistered users can join rooms
Room Creator Guest Setting
Let room creators choose guest access per room
Share Button
Show share button in rooms

OIDC Providers

Configure OpenID Connect providers for SSO

SMTP Configuration

Configure email delivery for verification and notifications

Email Templates

Email Logs

Instance Access

Password Lock
Require password to access the entire instance
Admin Panel Path
Custom URL path for the admin panel (default: admin)
/
Show Admin Link
Show admin panel link in the landing page footer

TheOneFile Source

Source Mode
Choose where to load TheOneFile from
Update Interval
Hours between auto updates (0 = manual only)
Changelog

Appearance

Theme
Force a theme for all users or let them choose

Room Defaults

Default Self Destruct
Default expiration for new rooms
hours
Max Rooms
Maximum rooms allowed (0 = unlimited)
Default Room Theme
Theme preset for new rooms (from loaded file)
Public Room Creation
Allow anyone to create rooms

Rate Limiting

Enable Rate Limiting
Protect against brute force attacks
Limit Settings
Max attempts per time window
attempts per seconds

Collaboration Features

Chat
Enable chat in rooms
Cursor Sharing
Show other users cursors
Name Changes
Allow users to change name after joining
Welcome Modal
Always show welcome setup when joining rooms

Network Probing

Server-Side Probing
Enable real ICMP/TCP/HTTP/DNS probes from server
Network Discovery
Allow subnet scanning to discover hosts
Discovery Admin Only
Restrict network discovery to admin users
Allow Public Ranges
Allow scanning non-private (public) IP ranges
Max Scan Size
Minimum CIDR prefix (larger = smaller range)
/

Webhooks

Enable Webhooks
Send notifications for events
Webhook URL
POST endpoint for notifications

Automatic Backups

Enable Auto Backup
Automatically backup data
Backup Settings
Interval and retention
Every hours, keep backups

Activity Log

Audit Log

Backups

API Keys

`; export const adminLoginHtml = ` Admin Login - The One File Collab `; export function getPasswordResetHtml(token: string): string { const safePageData = JSON.stringify({ token }).replace(/ Reset Password - TheOneFile_Verse

Reset Password

Enter your new password

Password reset successfully! Go to home
`; } ================================================ FILE: theonefile_verse/src/tokens.ts ================================================ import * as redis from "./redis"; import * as oidc from "./oidc"; import * as db from "./database"; interface TokenEntry { token: string; createdAt: number; } const ADMIN_TOKENS = new Map(); const INSTANCE_TOKENS = new Map(); const TOKEN_EXPIRY = 7 * 24 * 60 * 60 * 1000; const ROOM_ACCESS_TOKENS = new Map(); const ROOM_ACCESS_EXPIRY = 24 * 60 * 60 * 1000; interface WsSessionToken { roomId: string; collabUserId: string; createdAt: number; expiresAt: number; } const WS_SESSION_TOKENS = new Map(); export const WS_TOKEN_EXPIRY = 5 * 60 * 1000; export async function generateWsSessionToken(roomId: string, collabUserId: string): Promise { const token = oidc.generateSecureToken(32); const now = Date.now(); const tokenData: WsSessionToken = { roomId, collabUserId, createdAt: now, expiresAt: now + WS_TOKEN_EXPIRY }; if (redis.isRedisConnected()) { await redis.setSessionToken(`ws:${token}`, tokenData, Math.ceil(WS_TOKEN_EXPIRY / 1000)); } else { WS_SESSION_TOKENS.set(token, tokenData); } return token; } export async function validateWsSessionToken(token: string, roomId: string): Promise<{ valid: boolean; collabUserId?: string }> { if (!token) return { valid: false }; let tokenData: WsSessionToken | null = null; if (redis.isRedisConnected()) { tokenData = await redis.getSessionToken(`ws:${token}`) as WsSessionToken | null; if (tokenData) { await redis.deleteSessionToken(`ws:${token}`); } } else { tokenData = WS_SESSION_TOKENS.get(token) || null; if (tokenData) { WS_SESSION_TOKENS.delete(token); } } if (!tokenData) return { valid: false }; if (Date.now() > tokenData.expiresAt) return { valid: false }; if (tokenData.roomId !== roomId) return { valid: false }; return { valid: true, collabUserId: tokenData.collabUserId }; } const MAX_WS_SESSION_TOKENS = 50000; export function generateRoomAccessToken(roomId: string): string { const token = oidc.generateSecureToken(32); ROOM_ACCESS_TOKENS.set(token, { roomId, expiresAt: Date.now() + ROOM_ACCESS_EXPIRY }); if (ROOM_ACCESS_TOKENS.size > 10000) { const now = Date.now(); for (const [k, v] of ROOM_ACCESS_TOKENS) { if (now > v.expiresAt) ROOM_ACCESS_TOKENS.delete(k); } } return token; } export function validateRoomAccessToken(token: string, roomId: string): boolean { const data = ROOM_ACCESS_TOKENS.get(token); if (!data) return false; if (Date.now() > data.expiresAt) { ROOM_ACCESS_TOKENS.delete(token); return false; } return data.roomId === roomId; } export async function generateAdminToken(): Promise { const token = oidc.generateSecureToken(32); const data = { type: "admin", createdAt: Date.now() }; if (redis.isRedisConnected()) { await redis.setSessionToken(token, data, 604800); } else { ADMIN_TOKENS.set(token, { token, createdAt: Date.now() }); } return token; } export async function validateAdminToken(token: string): Promise { if (redis.isRedisConnected()) { const data = await redis.getSessionToken(token); if (!data || data.type !== "admin") return false; if (Date.now() - data.createdAt > TOKEN_EXPIRY) { await redis.deleteSessionToken(token); return false; } return true; } const entry = ADMIN_TOKENS.get(token); if (!entry) return false; if (Date.now() - entry.createdAt > TOKEN_EXPIRY) { ADMIN_TOKENS.delete(token); return false; } return true; } export function generateInstanceToken(): string { const token = oidc.generateSecureToken(32); INSTANCE_TOKENS.set(token, Date.now()); return token; } export function validateInstanceToken(token: string): boolean { const createdAt = INSTANCE_TOKENS.get(token); if (!createdAt) return false; if (Date.now() - createdAt > TOKEN_EXPIRY) { INSTANCE_TOKENS.delete(token); return false; } return true; } export function storeInstanceToken(token: string): void { INSTANCE_TOKENS.set(token, Date.now()); } export function removeInstanceToken(token: string): void { INSTANCE_TOKENS.delete(token); } export async function removeAdminToken(token: string): Promise { ADMIN_TOKENS.delete(token); } export async function hashApiKey(key: string): Promise { const encoder = new TextEncoder(); const data = encoder.encode(key); const hash = await crypto.subtle.digest("SHA-256", data); return Buffer.from(hash).toString("hex"); } export async function validateApiKey(key: string): Promise { const hash = await hashApiKey(key); const apiKey = db.getApiKeyByHash(hash); if (!apiKey) return null; if (apiKey.expiresAt && new Date(apiKey.expiresAt) < new Date()) return null; db.updateApiKeyLastUsed(apiKey.id); return apiKey; } export function startTokenCleanupIntervals(): void { setInterval(() => { const now = Date.now(); for (const [token, data] of WS_SESSION_TOKENS.entries()) { if (now > data.expiresAt) { WS_SESSION_TOKENS.delete(token); } } if (WS_SESSION_TOKENS.size > MAX_WS_SESSION_TOKENS) { const entries = [...WS_SESSION_TOKENS.entries()].sort((a, b) => a[1].createdAt - b[1].createdAt); const toRemove = entries.length - Math.floor(MAX_WS_SESSION_TOKENS * 0.75); for (let i = 0; i < toRemove; i++) WS_SESSION_TOKENS.delete(entries[i][0]); } }, 60 * 1000); setInterval(() => { const now = Date.now(); for (const [token, entry] of ADMIN_TOKENS.entries()) { if (now - entry.createdAt > TOKEN_EXPIRY) { ADMIN_TOKENS.delete(token); } } if (ADMIN_TOKENS.size > 10000) { const sorted = [...ADMIN_TOKENS.entries()].sort((a, b) => a[1].createdAt - b[1].createdAt); for (let i = 0; i < sorted.length - 5000; i++) { ADMIN_TOKENS.delete(sorted[i][0]); } } }, 10 * 60 * 1000); setInterval(() => { const now = Date.now(); for (const [token, createdAt] of INSTANCE_TOKENS.entries()) { if (now - createdAt > TOKEN_EXPIRY) INSTANCE_TOKENS.delete(token); } if (INSTANCE_TOKENS.size > 1000) { const sorted = [...INSTANCE_TOKENS.entries()].sort((a, b) => a[1] - b[1]); for (let i = 0; i < sorted.length - 500; i++) INSTANCE_TOKENS.delete(sorted[i][0]); } }, 10 * 60 * 1000); } export function cleanupExpiredRoomTokens(): void { const now = Date.now(); for (const [k, v] of ROOM_ACCESS_TOKENS) { if (now > v.expiresAt) ROOM_ACCESS_TOKENS.delete(k); } } ================================================ FILE: theonefile_verse/src/websocket.ts ================================================ import * as redis from "./redis"; import * as oidc from "./oidc"; import * as db from "./database"; import * as auth from "./auth"; import { roomConnections, roomUsers, roomMeta, roomUsedNames, roomChatHistory, loadRoom, saveRoom, deleteRoomData, scheduleDestruction, resetDestructionTimer, validateTopology, sanitizeTopologyStrings, type Room, type RoomMeta } from "./rooms"; import { validateWsSessionToken } from "./tokens"; import { checkWsRateLimit } from "./rate-limit"; import { getSettings, isValidUUID } from "./config"; export interface WsData { roomId?: string; connectionId?: string; userId?: string; verifiedUserId?: string; authenticated?: boolean; } export const websocketHandlers = { open(ws: any) { const roomId = (ws.data as WsData)?.roomId; if (!roomId) return; const connectionId = crypto.randomUUID(); (ws.data as WsData).connectionId = connectionId; if (!roomConnections.has(roomId)) roomConnections.set(roomId, new Set()); roomConnections.get(roomId)!.add(ws); if (!roomUsers.has(roomId)) roomUsers.set(roomId, new Map()); ws.subscribe(roomId); const meta = roomMeta.get(roomId) || { connectedUsers: 0 }; meta.connectedUsers++; if (meta.destructTimer) { clearTimeout(meta.destructTimer); meta.destructTimer = undefined; } roomMeta.set(roomId, meta); }, async message(ws: any, message: any) { const roomId = (ws.data as WsData)?.roomId; const connectionId = (ws.data as WsData)?.connectionId; if (!roomId || !connectionId) return; let msg; try { msg = JSON.parse(message.toString()); } catch { return; } if (msg.type === 'auth') { if ((ws.data as WsData).authenticated) { ws.send(JSON.stringify({ type: 'auth-ok' })); return; } const token = msg.token; if (!token || typeof token !== 'string') { ws.send(JSON.stringify({ type: 'auth-error', error: 'Token required' })); ws.close(4001, 'Authentication failed'); return; } const tokenValidation = await validateWsSessionToken(token, roomId); if (!tokenValidation.valid) { ws.send(JSON.stringify({ type: 'auth-error', error: 'Invalid or expired token' })); ws.close(4001, 'Authentication failed'); return; } (ws.data as WsData).authenticated = true; (ws.data as WsData).verifiedUserId = tokenValidation.collabUserId; ws.send(JSON.stringify({ type: 'auth-ok' })); return; } if (!(ws.data as WsData).authenticated) { ws.send(JSON.stringify({ type: 'auth-error', error: 'Authenticate first' })); ws.close(4001, 'Not authenticated'); return; } const validTypes = ['join', 'leave', 'presence', 'state', 'patch', 'chat', 'cursor', 'typing']; if (!msg.type || !validTypes.includes(msg.type)) return; if (!checkWsRateLimit(connectionId, msg.type)) { ws.send(JSON.stringify({ type: 'rate-limited', messageType: msg.type })); return; } const messageStr = message.toString(); const maxSize = msg.type === 'state' ? 5 * 1024 * 1024 : 1024; if (messageStr.length > maxSize) return; if (msg.type === 'chat') { if (!msg.text || typeof msg.text !== 'string') return; if (msg.text.length > 500) msg.text = msg.text.substring(0, 500); msg.text = msg.text.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); if (!roomChatHistory.has(roomId)) roomChatHistory.set(roomId, []); const history = roomChatHistory.get(roomId)!; history.push({ ...msg, timestamp: Date.now() }); if (history.length > 100) history.splice(0, history.length - 100); ws.publish(roomId, JSON.stringify(msg)); resetDestructionTimer(roomId); return; } if (msg.type === 'join' && msg.user) { let userId = msg.user.id; if (!userId || !isValidUUID(userId)) return; const verifiedUserId = (ws.data as WsData)?.verifiedUserId; if (verifiedUserId) { if (userId !== verifiedUserId) { ws.send(JSON.stringify({ type: 'error', error: 'User ID mismatch with session token' })); return; } } let rawName = msg.user.name; if (rawName && typeof rawName === 'string') { rawName = rawName.substring(0, 30).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').trim(); } msg.user = { id: userId, name: rawName || '', color: msg.user.color || '' }; const userName = rawName?.toLowerCase().trim(); const users = roomUsers.get(roomId)!; if (!roomUsedNames.has(roomId)) roomUsedNames.set(roomId, new Map()); const usedNames = roomUsedNames.get(roomId)!; const existingUser = users.get(userId); const isNameChange = existingUser && existingUser.name?.toLowerCase().trim() !== userName; const isNewUser = !existingUser; if (userName && (isNewUser || isNameChange)) { const nameOwner = usedNames.get(userName); if (nameOwner && nameOwner !== userId) { ws.send(JSON.stringify({ type: 'name-rejected', reason: 'Name already taken in this room' })); return; } if (isNameChange && existingUser?.name) { usedNames.delete(existingUser.name.toLowerCase().trim()); } usedNames.set(userName, userId); } (ws.data as WsData).userId = userId; users.delete(userId); users.set(userId, msg.user); const existingUsers = Array.from(users.values()).filter(u => u.id !== userId); if (existingUsers.length > 0) ws.send(JSON.stringify({ type: 'users', users: existingUsers })); if (isNewUser) { const room = loadRoom(roomId); if (room && room.topology) { ws.send(JSON.stringify({ type: 'initial-state', state: sanitizeTopologyStrings(room.topology) })); } else { ws.send(JSON.stringify({ type: 'initial-state', state: null })); } const chatHistory = roomChatHistory.get(roomId); if (chatHistory && chatHistory.length > 0) { ws.send(JSON.stringify({ type: 'chat-history', messages: chatHistory })); } db.addActivityLog({ timestamp: new Date().toISOString(), roomId, userId, userName: rawName, eventType: "join" }); if (redis.isRedisConnected()) { redis.setUserPresence(roomId, userId, msg.user, 300); } } const connections = roomConnections.get(roomId); if (connections) { const joinMsg = JSON.stringify(msg); connections.forEach(client => { if (client !== ws && client.readyState === 1) client.send(joinMsg); }); } } else if (msg.type === 'presence') { const wsUserId = (ws.data as WsData)?.userId; if (!wsUserId) return; msg.userId = wsUserId; const users = roomUsers.get(roomId); if (users) { const user = users.get(wsUserId); if (user) { if (Array.isArray(msg.selectedNodes)) { user.selectedNodes = msg.selectedNodes.filter((id: unknown) => typeof id === 'string' && /^[\w-]+$/.test(id)).slice(0, 50); msg.selectedNodes = user.selectedNodes; } if (typeof msg.editingNode === 'string' && /^[\w-]+$/.test(msg.editingNode)) { user.editingNode = msg.editingNode; } else if (msg.editingNode === null) { user.editingNode = null; } } } ws.publish(roomId, JSON.stringify(msg)); } else if (msg.type === 'state') { if (msg.state) { const topologyValidation = validateTopology(msg.state); if (!topologyValidation.valid) { ws.send(JSON.stringify({ type: 'error', error: topologyValidation.error || 'Invalid state data' })); return; } ws.publish(roomId, JSON.stringify({ type: 'state', state: topologyValidation.sanitized })); const room = loadRoom(roomId); if (room) { room.topology = topologyValidation.sanitized; room.lastActivity = new Date().toISOString(); saveRoom(room); } } else { ws.publish(roomId, message); } } else if (msg.type === 'patch') { if (msg.patch) { msg.patch = sanitizeTopologyStrings(msg.patch); } ws.publish(roomId, JSON.stringify(msg)); } else { const wsUserId = (ws.data as WsData)?.userId; if (wsUserId && msg.userId) msg.userId = wsUserId; ws.publish(roomId, JSON.stringify(msg)); } resetDestructionTimer(roomId); }, close(ws: any) { const roomId = (ws.data as WsData)?.roomId; const userId = (ws.data as WsData)?.userId; if (!roomId) return; const connections = roomConnections.get(roomId); if (connections) { connections.delete(ws); if (connections.size === 0) roomConnections.delete(roomId); } if (userId) { const users = roomUsers.get(roomId); if (users) { const user = users.get(userId); users.delete(userId); if (connections && connections.size > 0) { const leaveMsg = JSON.stringify({ type: 'leave', userId }); connections.forEach(client => { if (client.readyState === 1) client.send(leaveMsg); }); } if (users.size === 0) roomUsers.delete(roomId); db.addActivityLog({ timestamp: new Date().toISOString(), roomId, userId, userName: user?.name, eventType: "leave" }); if (redis.isRedisConnected()) { redis.removeUserPresence(roomId, userId); } } } ws.unsubscribe(roomId); const meta = roomMeta.get(roomId); if (meta) { meta.connectedUsers = Math.max(0, meta.connectedUsers - 1); if (meta.connectedUsers === 0) { const room = loadRoom(roomId); if (room) { if (room.destruct.mode === "empty") { deleteRoomData(roomId); } else if (room.destruct.mode === "time") { scheduleDestruction(roomId, room.destruct.value); } } } } } };