HospitalityNet MSP Platform
Complete technical reference for developers building on, extending, or maintaining the HospitalityNet Managed Service Provider platform. Covers architecture, data model, component system, and deployment.
What is HospitalityNet?
HospitalityNet is a Managed Service Provider (MSP) platform purpose-built for the hospitality industry. It provides hotel groups, resorts, clubs, and convention centres with enterprise-grade WiFi network management, real-time monitoring, guest experience tracking, and support ticketing β all from a single, multi-tenant web dashboard.
System Architecture
HospitalityNet is a 100% client-side static web application with no server-side backend. All data persistence is via the Genspark RESTful Table API.
Request / Response Flow
index.html (Property Portal) or super-admin.html (MSP Dashboard).<script> tags and external JS files (js/app.js, js/data.js, js/sa-data.js, js/super-admin.js) execute on DOMContentLoaded.saRand()) generates 734 deterministic property records for the property list. The NOC/MSP view uses pre-seeded real DB data via the Table API.fetch('tables/{table}'). Responses are consumed directly in the browser. The API is CORS-enabled and project-scoped.Key principle β No Backend: There is no Node.js server, Python backend, or database server to manage. The entire platform runs as static files. The Genspark Table API handles all data persistence. This means zero DevOps, instant deployment, and no server maintenance.
Technology Stack
Intentionally minimal. No build tools, no frameworks, no package.json. Pure vanilla web technologies with selective CDN libraries.
| Layer | Technology | Purpose | Version |
|---|---|---|---|
| Structure | HTML5 | Semantic markup, accessibility, SVG topology canvas | HTML5 |
| Styling | CSS3 / Custom Properties | Light enterprise theme, CSS vars for theming, responsive layouts | CSS3 |
| Logic | Vanilla JavaScript (ES2022) | All interactivity, data rendering, API calls, SVG manipulation | ES2022 |
| Charts | Chart.js | Bandwidth, stream, WAN line charts | 4.x (CDN) |
| Canvas | Canvas API | Score gauge, WiFi floor heatmap | Native |
| Icons | Font Awesome 6 Free | All UI icons, device type icons, status indicators | 6.4.0 (CDN) |
| Fonts | Google Fonts β Inter + JetBrains Mono | UI typography, code blocks | CDN |
| Data | Genspark Table API | RESTful data persistence for all 15 tables | v1 |
| Hosting | Genspark Static Hosting | Automatic git-based deployment | β |
File Structure
A flat, well-organised project with clear separation between entry points, stylesheets, scripts, and assets.
JavaScript Modules
Four JavaScript files handle all platform functionality. Each has a distinct responsibility boundary.
js/data.js β Property Portal Seed Data
Defines all static demo data for the property portal: access points, switches, network events, guest sessions, support tickets, SSID profiles, bandwidth snapshots, and vouchers. Data is structured as JavaScript arrays/objects and imported inline by index.html.
// Key exports from js/data.js const accessPoints = [ /* AP objects */ ]; const switches = [ /* switch objects */ ]; const guestSessions = [ /* session objects */ ]; const tickets = [ /* support ticket objects */ ];
js/sa-data.js β Super Admin Seed Data
Generates 734 property records deterministically via a seeded PRNG function saRand(seed). This ensures the same data is generated on every page load without network calls. Hotel groups, property metadata, health scores, and MSP staff are defined here.
// Seeded PRNG β deterministic random function saRand(seed) { let s = seed % 2147483647; if (s <= 0) s += 2147483646; return () => { s = s * 16807 % 2147483647; return (s - 1) / 2147483646; }; } // Generates 734 unique property records with same values every run const _SA_PROPS = generateProperties(734);
js/app.js β Property Portal Logic
Handles all interactivity for the property portal: tab switching, AP list rendering, guest session table, ticket management, SSID configuration, bandwidth charts, the SVG network topology builder, and the ISP detail panel.
Key Functions
| Function | Description |
|---|---|
renderTopologyDiagram() | Builds the static SVG topology for non-interactive card view |
_topoDrawNode(svg, node, x, y) | Draws individual AP/switch/router nodes on the SVG canvas |
topoClickNode(nodeId) | Shows the slide-in detail panel for a clicked topology node |
topoISPEdit(nodeId) | Renders the ISP detail editing form in the panel |
topoISPSave(nodeId) | Saves ISP detail edits back to node.extra, shows toast |
showToast(msg, type) | Shows a toast notification (success/error/info) |
js/super-admin.js β MSP Dashboard Logic
Powers the entire super-admin dashboard: the SA tab system, property list with 734 entries, ticket management, the Group Dashboard with Chart.js charts, and the interactive network topology builder.
Key Functions
| Function | Description |
|---|---|
saShowTab(tab, btn) | Lazy-renders each SA tab on first click, then shows/hides |
_gdDrawGauge(canvas, score) | Canvas API: draws animated score gauge for group health |
gdRenderHeatmap() | Canvas API: draws WiFi floor heatmap with AP markers |
_gdBuildStreamChart() | Chart.js: multi-line bandwidth stream chart |
_gdBuildWANChart() | Chart.js: WAN utilisation chart |
gdTopoClickNode(nodeId) | Group Dashboard topology node click handler |
CSS Architecture & Theme System
The platform uses a light enterprise theme defined by CSS custom properties. No preprocessors required.
Core Design Tokens (CSS Variables)
/* Defined in css/style.css :root */ :root { /* Brand colours */ --primary: #1a73e8; /* Google Blue β buttons, links, accents */ --primary-dark: #0d5bc7; /* Hover state */ --primary-light: #e8f0fe; /* Backgrounds, badges */ --success: #00c853; /* Online status, positive */ --warning: #f59e0b; /* Warning status, alerts */ --danger: #ef4444; /* Offline, error, critical */ /* Layout */ --bg: #f0f4f8; /* Page background */ --card-bg: #ffffff; /* Card background */ --border: #e5e7eb; /* All borders */ --shadow: 0 2px 10px rgba(0,0,0,0.06); /* Typography */ --text-primary: #1a1f36; /* Headlines, labels */ --text-secondary: #6b7280; /* Body text, subtext */ --text-muted: #9ca3af; /* Placeholder, disabled */ --font-sans: 'Inter', system-ui, sans-serif; --font-mono: 'JetBrains Mono', monospace; }
CSS File Organisation
| File | Scope | Key Blocks |
|---|---|---|
css/style.css |
Property Portal + Global | Reset, layout, header/nav, AP cards, guest table, network topology nodes (.tfd-node), ISP panel, toast, charts |
css/super-admin.css |
Super Admin only | SA sidebar, property list, ticket views, Group Dashboard (.gd-* prefix), topology canvas, badge/status styles |
css/login.css |
Login page only | Login card, animation, gradient background |
Group Dashboard uses scoped CSS: All GD styles use the .gd-root scope class and .gd-* BEM-style naming to prevent collision with the rest of the SA dashboard. KPI cards use per-card CSS custom properties (--gd-kpi-accent, --gd-kpi-bg) for colour variation.
Database Schema
All 15 tables, their field counts, primary key conventions, and foreign key relationships. Data is persisted via the Genspark Table API.
ID conventions: All IDs are prefixed by entity type: prop-, grp-, ap-, sw-, tkt-, msp-, usr-p, vch-, ssid-, bw-, alog-, topo-. Use the prefix to identify entity type without a DB lookup.
Data Flow Diagram
How data moves through the platform from network devices to the management dashboard.
Real-Time Monitoring Flow
tables/bandwidth_snapshots every 5 minSA Tab System
The Super Admin dashboard uses a lazy-rendering tab system. Tabs are only initialised when first clicked, preventing unnecessary API calls and DOM manipulation on page load.
How It Works
// Each tab has an entry in _SA_TABS array const _SA_TABS = [ { id: 'overview', init: initOverview, rendered: false }, { id: 'properties', init: initProperties, rendered: false }, { id: 'group-dash', init: initGroupDash, rendered: false }, // ... ]; // Tab click handler β lazy renders on first call function saShowTab(tabId, btn) { const tab = _SA_TABS.find(t => t.id === tabId); if (!tab.rendered) { tab.init(); // only runs once tab.rendered = true; } // Show this tab's panel, hide all others hideAllTabs(); document.getElementById(`sa-tab-${tabId}`).style.display = 'block'; }
To add a new tab: (1) Add an HTML panel <div id="sa-tab-newtab"></div> in super-admin.html. (2) Add a button to .sa-page-tabs. (3) Add entry to _SA_TABS array in js/super-admin.js. (4) Write the init function. See the Adding a Tab guide.
Network Topology Engine
The interactive network topology is built on SVG with a custom node rendering engine and a slide-in detail panel for each device type.
Node Drawing Architecture
// Node size constants β APs use compact size const AW = 130, AH = 46, AR = 8; // AP width/height/radius const NW = 130, NH = 58, NR = 10; // General node size // TOPO_TYPE_META defines icon, colour, and bg per device type const TOPO_TYPE_META = { isp: { icon: 'π', color: '#1a73e8', bg: '#e8f0fe', label: 'ISP' }, router: { icon: 'π', color: '#0ea5e9', bg: '#e0f2fe', label: 'Router' }, switch: { icon: 'π', color: '#8b5cf6', bg: '#ede9fe', label: 'Switch' }, ap: { icon: 'π‘', color: '#00c853', bg: '#dcfce7', label: 'AP' }, }; // _topoDrawNode renders foreignObject HTML inside SVG function _topoDrawNode(svg, node, x, y) { const fo = createSVGElement('foreignObject'); fo.setAttribute('x', x - NW/2); fo.setAttribute('y', y - NH/2); // AP nodes use inline SVG WiFi-AP icon // Upper-tier nodes use emoji icon in icon box }
ISP Detail Panel β topoClickNode Type Branch
When a node is clicked, topoClickNode(nodeId) checks node.type and renders type-specific HTML. The ISP branch renders 4 sections: Account, Account Manager, Support, and Subnet/IP Details. Edit mode uses topoISPEdit() + topoISPSave().
Roles & Permissions
The platform has two distinct user tiers with 5 role types. Permissions are enforced at the UI layer and should be enforced at the API layer in production.
- View all properties & groups
- Edit any property config
- Manage MSP staff accounts
- View & manage all tickets
- View full audit logs
- Group dashboard & analytics
- View all properties
- Manage & resolve tickets
- Reboot APs remotely
- View bandwidth & telemetry
- Cannot create users
- Cannot delete properties
- Full access to own property
- Create & manage vouchers
- View guest sessions
- Create support tickets
- Cannot access other properties
- Cannot edit network topology
- View own property dashboard
- View guest sessions
- Create support tickets
- Cannot edit SSID config
- Cannot manage users
- Cannot view billing
Audit Trail
Every significant action in the platform must create an audit_logs record. The audit trail is immutable β records are append-only and should never be updated or deleted.
Auditable Action Types
| Action Code | When to Use |
|---|---|
LOGIN / LOGOUT | User authentication events |
CREATE | New record created (property, ticket, voucher, user) |
UPDATE | Record fields modified |
DELETE | Record soft-deleted |
CONFIG_CHANGE | SSID, AP, or switch configuration modified |
AP_REBOOT | Remote AP reboot triggered |
TICKET_CLOSE | Support ticket resolved/closed |
EXPORT | Data export performed |
// Standard audit log entry pattern async function writeAuditLog({ actor, action, resource, changes }) { return fetch('tables/audit_logs', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: `alog-${Date.now()}-${Math.random().toString(36).slice(2,6)}`, actor_id: actor.id, actor_name: actor.name, actor_role: actor.role, property_id: resource.property_id || null, action, resource_type: resource.type, resource_id: resource.id, resource_name: resource.name, changes: JSON.stringify(changes), // {field: [old, new]} ip_address: 'client-side', occurred_at: new Date().toISOString() }) }); }
Adding a New Table
Follow these steps to add a new data entity to the platform with full CRUD support.
TableSchemaUpdate tool with your new table's fields. Always include an id field of type text.// Example: adding an "iptv_channels" table TableSchemaUpdate({ name: 'iptv_channels', fields: [ { name: 'id', type: 'text', description: 'Channel ID' }, { name: 'property_id', type: 'text', description: 'FK β properties.id' }, { name: 'name', type: 'text', description: 'Channel name' }, { name: 'number', type: 'number', description: 'Channel number' }, { name: 'is_active', type: 'bool', description: 'Active flag' } ] })
TableDataAdd to insert representative rows. Use prefixed IDs: iptv-001, iptv-002, etc.js/app.js or js/super-admin.js. Follow the existing pattern.async function loadIPTVChannels(propertyId) { const { data } = await (await fetch( 'tables/iptv_channels?limit=200' )).json(); return data.filter(ch => ch.property_id === propertyId); }
init function. Render results to the DOM.api-docs.html covering GET, POST, PATCH, DELETE for the new table.Adding a New SA Tab
The Super Admin tab system is designed to be extended. Follow these 4 steps.
// Step 1: Add tab button in super-admin.html <button class="sa-tab-btn" onclick="saShowTab('iptv', this)"> <i class="fa-solid fa-tv"></i> IPTV </button> // Step 2: Add tab panel in super-admin.html <div id="sa-tab-iptv" class="sa-tab-panel" style="display:none;"> <!-- Your HTML goes here --> </div> // Step 3: Add to _SA_TABS array in js/super-admin.js { id: 'iptv', init: initIPTVTab, rendered: false } // Step 4: Write the init function async function initIPTVTab() { const panel = document.getElementById('sa-tab-iptv'); const channels = await loadIPTVChannels('prop-001'); panel.innerHTML = channels .map(ch => `<div class="iptv-row">${ch.number} β ${ch.name}</div>`) .join(''); }
Deployment
Because this is a static site, deployment is trivial. No build pipeline, no Docker, no server management.
Database persistence: All data stored in Genspark Tables is tied to your project. If you migrate to a different hosting provider, you will need to export and re-import your table data. The Table API follows standard REST conventions, making migration straightforward.
Local Development Setup
Since there's no build step, local development is instant. You just need a static file server.
# Option 1: Python (usually pre-installed) python3 -m http.server 8080 # Visit: http://localhost:8080/index.html # Option 2: Node.js serve npx serve . # Visit: http://localhost:3000 # Option 3: VS Code Live Server extension # Right-click index.html β "Open with Live Server"
CORS note: The Genspark Table API only works from the hosted platform URL, not from localhost. For local development, use the mock data in js/data.js and js/sa-data.js which require no network calls. The API layer activates automatically when deployed to the Genspark hosted environment.
Testing & Quality Checks
The platform uses Playwright for automated browser-based testing to catch JavaScript errors and rendering issues.
Pre-Deployment Checklist
- Run Playwright on
index.htmlβ zero console errors/warnings - Run Playwright on
super-admin.htmlβ zero console errors/warnings - Run Playwright on
api-docs.htmlβ zero console errors - Test all SA tabs render without errors
- Test Group Dashboard charts render
- Test topology node click panel
- Test ISP edit/save flow
- Verify all Table API calls return 200/201
- Mobile responsiveness check (Chrome DevTools)
- Test search and pagination in property list
Console = zero tolerance: Any JavaScript error or unhandled promise rejection indicates a bug. The platform's quality bar is zero console output on all entry point pages after load and interaction.