265 lines
8.1 KiB
Markdown
265 lines
8.1 KiB
Markdown
# admin.derez.ai — UI Reuse Guide
|
||
|
||
Stripped-down version: **Servers page only**. No Sales, no CRM, no API Keys.
|
||
|
||
---
|
||
|
||
## 1. UI Architecture (Single HTML File)
|
||
|
||
The entire front-end is a **single-page app** in a single `index.html` with:
|
||
|
||
| File | Role |
|
||
|---|---|
|
||
| `index.html` | Full DOM layout: sidebar, sections, modals (login, confirm) |
|
||
| `styles.css` | All styles: layout, sidebar, cards, tables, badges, modal, toast, server dashboard |
|
||
| `app.js` | State, auth, API helpers, routing, all CRUD for each section |
|
||
|
||
The pattern is straightforward — you can keep one file per section or keep it monolithic. The CSS and JS are written in vanilla ES6+ with no build step.
|
||
|
||
---
|
||
|
||
## 2. Login & Session (Cookie-Based)
|
||
|
||
### How it works
|
||
|
||
1. User fills email + password in `#login-modal` (inside `#login-backdrop`).
|
||
2. `doSignIn()` POSTs to the auth endpoint with `{ email, password }`.
|
||
3. The backend returns an object with a `sessionid` field.
|
||
4. The session ID and email are saved in cookies:
|
||
- `al_session` — the session token
|
||
- `al_email` — the signed-in email
|
||
|
||
### On page load
|
||
|
||
```js
|
||
const _boot = getCookie("al_session");
|
||
if (_boot) {
|
||
currentSession = _boot;
|
||
currentEmail = getCookie("al_email") || "";
|
||
showApp(); // hides login modal, shows sidebar
|
||
loadData(); // loads your default section data
|
||
} else {
|
||
showAuth(); // shows login modal
|
||
}
|
||
```
|
||
|
||
### Cookie helpers (already in `app.js`)
|
||
|
||
```js
|
||
setCookie(name, value, days) // SameSite=Strict
|
||
getCookie(name)
|
||
deleteCookie(name)
|
||
```
|
||
|
||
### API fetch wrapper
|
||
|
||
```js
|
||
async function apiFetch(url, options = {})
|
||
```
|
||
|
||
- Automatically attaches `X-Session-Id` header from `currentSession`.
|
||
- On HTTP 401, deletes cookies, clears local state, and reloads the page (back to login).
|
||
|
||
### Sign out
|
||
|
||
```js
|
||
function doSignOut()
|
||
```
|
||
|
||
- Sends a `DELETE` to the auth endpoint with the session ID.
|
||
- Deletes cookies (`al_session`, `al_email`).
|
||
- Clears `localStorage`.
|
||
- Shows the login screen again.
|
||
|
||
### What you need to change for a new project
|
||
|
||
| Constant / Variable | Change to |
|
||
|---|---|
|
||
| `const API_BASE` (L2) | Your backend base URL, e.g. `"https://api.yourproject.com/webhook"` |
|
||
| `ROUTES.auth` (L6) | Your login endpoint path, e.g. `"/auth/login"` |
|
||
| Cookie names `al_session` / `al_email` | Rename to avoid conflicts, e.g. `"myapp_session"` |
|
||
| `apiFetch` 401 handler | Customize or keep (auto-redirects to login) |
|
||
|
||
---
|
||
|
||
## 3. How Sections Work (Routing)
|
||
|
||
### Sidebar navigation
|
||
|
||
Each sidebar item in `index.html`:
|
||
|
||
```html
|
||
<div class="nav-item" data-section="servers"> ... Servers</div>
|
||
```
|
||
|
||
The click handler (L175–239 in `app.js`):
|
||
|
||
1. Reads `el.dataset.section` → e.g. `"servers"`
|
||
2. Toggles `.active` class on the nav item
|
||
3. Toggles `.active` class on `#section-servers`
|
||
4. Sets the page title from a label map
|
||
5. Shows the refresh button
|
||
6. Lazy-loads data if empty
|
||
|
||
### Corresponding section element
|
||
|
||
```html
|
||
<div class="section" id="section-servers"> ... </div>
|
||
```
|
||
|
||
Only one `.section` has `.active` at a time.
|
||
|
||
---
|
||
|
||
## 4. Servers Page (Dashboard)
|
||
|
||
### Data flow
|
||
|
||
```
|
||
serversLoadData()
|
||
├── GET https://n8n.derez.ai/webhook/server ← seat list (fetched directly, no auth)
|
||
│ Returns: [{ server: "hostname-01" }, ...]
|
||
├── For each server:
|
||
│ GET apiUrl(ROUTES.servers) + "?server=<name>" ← full dashboard (authenticated)
|
||
│ Parses item.text (JSON string) or item directly
|
||
│ Stores in serversData[]
|
||
└── serversRenderTabs() + serversRenderDashboard(0)
|
||
```
|
||
|
||
### Dashboard DOM structure
|
||
|
||
```
|
||
.section#section-servers
|
||
├── .card-header
|
||
│ ├── Tab bar: .server-tabs / #server-tabs-strip
|
||
│ └── Buttons (Update All, Harden All — optional)
|
||
└── .card#server-dashboard
|
||
├── Summary card (name, OS, kernel, uptime, status badge)
|
||
├── KPI row (CPU, RAM, Disk, Security Score)
|
||
├── Performance bars (CPU, RAM, Disk usage)
|
||
├── Security checks (SSH, Seccomp, AppArmor, SELinux)
|
||
├── Exposed ports
|
||
├── Action advice (priority items, upgrades)
|
||
└── Details: containers, packages, storage, Podman
|
||
```
|
||
|
||
### Key data shape (`serversData[i]`)
|
||
|
||
```js
|
||
{
|
||
server: {
|
||
name: "hostname-01",
|
||
os: "Ubuntu 22.04",
|
||
kernel: "5.15.0-xxx",
|
||
uptime: "42 days"
|
||
},
|
||
summary: {
|
||
overall_status: "green" | "yellow" | "red"
|
||
},
|
||
performance: {
|
||
cpu_idle_percent: 85.3,
|
||
ram_percent: 62,
|
||
ram_gb: 7.8,
|
||
total_ram_gb: 16
|
||
},
|
||
storage: {
|
||
total_gb: 256,
|
||
used_gb: 120,
|
||
percent: 47
|
||
},
|
||
kpis: {
|
||
kpi_19_security_score: 72
|
||
},
|
||
security: {
|
||
ssh_password_auth: false,
|
||
ssh_root_login: false,
|
||
seccomp_enabled: true,
|
||
apparmor_enabled: true,
|
||
selinux_enabled: false,
|
||
firewall_exposed_services: ["22", "80", "443"]
|
||
},
|
||
action_advice: {
|
||
priority_actions: [],
|
||
upgrade_needed: true,
|
||
ram_upgrade_recommended: false,
|
||
container_cleanup_needed: false
|
||
},
|
||
containers: [ /* … */ ],
|
||
packages: [ /* … */ ],
|
||
podman: { /* … */ },
|
||
seats: { server: "hostname-01", seat: 3 }
|
||
}
|
||
```
|
||
|
||
### What you need to change for the servers page
|
||
|
||
| Item | Change to |
|
||
|---|---|
|
||
| Seat list URL (hardcoded `https://n8n.derez.ai/webhook/server` in `serversLoadData`) | Your server list endpoint |
|
||
| `ROUTES.servers` (L10) | Your server dashboard endpoint path |
|
||
| The `item.text` JSON parsing (L918) | Adjust if your API shape differs |
|
||
| Dashboard widget content (render function L983+) | Keep, expand, or trim as needed |
|
||
|
||
---
|
||
|
||
## 5. What's Stripped: No Sales, No CRM, No Keys
|
||
|
||
The following have been **removed** from this consolidated doc — you should delete them from the HTML/CSS/JS when reusing:
|
||
|
||
### `index.html` — Remove these sidebar nav items
|
||
|
||
- `<div class="nav-item" data-section="keys">` (L84–100)
|
||
- `<div class="nav-item" data-section="crm">` (L112–129)
|
||
- `<div class="nav-item" data-section="sales">` (L130–147)
|
||
|
||
Also remove the corresponding `.section` elements:
|
||
|
||
- `section-keys` (the div near L1060)
|
||
- `section-crm` (the div near L1098)
|
||
- `section-sales` (the div near L1098–1106)
|
||
|
||
### `app.js` — Remove these functions & state
|
||
|
||
- State: `keysData` (L22), `crmRecords` (L23), `crmSortKey` (L24), `crmSortDir` (L25)
|
||
- Labels: `keys`, `sales`, `crm` entries from the label map (L192–194)
|
||
- Lazy-loads: the `if (key === "keys")` and `if (key === "crm")` blocks (L233–237)
|
||
- Functions: `keysLoadRecords`, `keysRender`, `keysDelete` (L1303–1398)
|
||
- Functions: `crmLoadRecords`, `crmRender`, `crmClearFilters`, `crmToggleSort`, `crmUpdateDeleteBtn`, `crmToggleAll`, `crmDeleteContact`, `crmDeleteSelected`, `crmSetStageSelected`, `crmOpenEdit`, `crmCloseEdit`, `crmSaveEdit` (L1401–1823)
|
||
|
||
### `styles.css` — Remove CRM-specific styles
|
||
|
||
- `.crm-filter-input` and related rules (L824–838+)
|
||
- `.crm-search-row th` (L839–842)
|
||
|
||
---
|
||
|
||
## 6. What You Keep (Optional Sections)
|
||
|
||
If you also want **DNS**, **Instances**, or **Backup** in your new project, their patterns are the same:
|
||
|
||
| Section | Endpoint | Functions (in `app.js`) | Section ID |
|
||
|---|---|---|---|
|
||
| **DNS** | `ROUTES.dns` | `dnsLoadRecords`, `dnsRender`, `dnsDeleteRecord`, `dnsAddRecord` | `#section-dns` |
|
||
| **Instances** | `ROUTES.instances` | `instancesLoadRecords`, `instancesRender`, `instancesCopySSH`, `instancesDelete`, `instancesOpenEdit`, `instancesCloseEdit`, `instancesSaveEdit` | `#section-instances` |
|
||
| **Backup** | `ROUTES.backup` | `backupLoadRecords`, `backupRender`, `backupDelete` | `#section-backup` |
|
||
|
||
Each follows the same lazy-load, render, CRUD pattern.
|
||
|
||
---
|
||
|
||
## 7. Quick Start for a New Project
|
||
|
||
1. Copy `index.html`, `styles.css`, `app.js` to your project.
|
||
2. In `app.js`:
|
||
- Change `API_BASE` to your backend URL.
|
||
- Change `ROUTES` entries to match your API paths.
|
||
- Update the cookie names if desired.
|
||
- Remove `keys`, `crm`, `sales` code (see §5).
|
||
3. In `index.html`:
|
||
- Remove keys, CRM, and Sales nav items and section elements.
|
||
- Update the page title in `<head>`.
|
||
- Update the brand text "derez.ai" in the sidebar.
|
||
4. In `styles.css`:
|
||
- Remove CRM-specific CSS.
|
||
5. Update the server seat-list URL in `serversLoadData()` to your own endpoint.
|
||
6. Serve from any static server — no build step required. |