2 Commits

Author SHA1 Message Date
syntaxbullet
9804456257 docs: Remove completed and draft feature tickets from the tickets directory. 2026-01-07 13:49:04 +01:00
syntaxbullet
259b8d6875 feat: replace mock dashboard data with live telemetry 2026-01-07 13:47:02 +01:00
7 changed files with 145 additions and 154 deletions

38
src/lib/logger.test.ts Normal file
View File

@@ -0,0 +1,38 @@
import { describe, it, expect, beforeEach } from "bun:test";
import { logger, getRecentLogs } from "./logger";
describe("Logger Buffer", () => {
// Note: Since the buffer is a module-level variable, it persists across tests.
// In a real scenario we might want a reset function, but for now we'll just check relative additions.
it("should add logs to the buffer", () => {
const initialLength = getRecentLogs().length;
logger.info("Test Info Log");
const newLogs = getRecentLogs();
expect(newLogs.length).toBe(initialLength + 1);
expect(newLogs[0]?.message).toBe("Test Info Log");
expect(newLogs[0]?.type).toBe("info");
});
it("should cap the buffer size at 50", () => {
// Fill the buffer
for (let i = 0; i < 60; i++) {
logger.debug(`Log overflow test ${i}`);
}
const logs = getRecentLogs();
expect(logs.length).toBeLessThanOrEqual(50);
expect(logs[0]?.message).toBe("Log overflow test 59");
});
it("should handle different log levels", () => {
logger.error("Critical Error");
logger.success("Operation Successful");
const logs = getRecentLogs();
expect(logs[0]?.type).toBe("success");
expect(logs[1]?.type).toBe("error");
});
});

View File

@@ -3,12 +3,29 @@ import { WebServer } from "@/web/server";
/**
* Centralized logging utility with consistent formatting
*/
const LOG_BUFFER_SIZE = 50;
const logBuffer: Array<{ time: string; type: string; message: string }> = [];
function addToBuffer(type: string, message: string) {
const time = new Date().toLocaleTimeString();
logBuffer.unshift({ time, type, message });
if (logBuffer.length > LOG_BUFFER_SIZE) {
logBuffer.pop();
}
}
export function getRecentLogs() {
return logBuffer;
}
export const logger = {
/**
* General information message
*/
info: (message: string, ...args: any[]) => {
console.log(` ${message}`, ...args);
addToBuffer("info", message);
try { WebServer.broadcastLog("info", message); } catch { }
},
@@ -17,6 +34,7 @@ export const logger = {
*/
success: (message: string, ...args: any[]) => {
console.log(`${message}`, ...args);
addToBuffer("success", message);
try { WebServer.broadcastLog("success", message); } catch { }
},
@@ -25,6 +43,7 @@ export const logger = {
*/
warn: (message: string, ...args: any[]) => {
console.warn(`⚠️ ${message}`, ...args);
addToBuffer("warning", message);
try { WebServer.broadcastLog("warning", message); } catch { }
},
@@ -33,6 +52,7 @@ export const logger = {
*/
error: (message: string, ...args: any[]) => {
console.error(`${message}`, ...args);
addToBuffer("error", message);
try { WebServer.broadcastLog("error", message); } catch { }
},
@@ -41,6 +61,7 @@ export const logger = {
*/
debug: (message: string, ...args: any[]) => {
console.log(`🔍 ${message}`, ...args);
addToBuffer("debug", message);
try { WebServer.broadcastLog("debug", message); } catch { }
},
};

View File

@@ -1,20 +1,23 @@
import { BaseLayout } from "../views/layout";
import { AuroraClient } from "@/lib/BotClient";
import { getRecentLogs } from "@/lib/logger";
export function dashboardRoute(): Response {
// Gather real data where possible, mock where not
// Gather real data
const guildCount = AuroraClient.guilds.cache.size;
const userCount = AuroraClient.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0); // Approximation
const userCount = AuroraClient.guilds.cache.reduce((acc, guild) => acc + guild.memberCount, 0);
const commandCount = AuroraClient.commands.size;
const ping = AuroraClient.ws.ping;
// In a real app, these would be dynamic charts or lists
const mockedActivity = [
{ time: "10:42:01", type: "info", message: "User 'Syntax' ran /profile" },
{ time: "10:41:55", type: "success", message: "Task 'HourlyCleanup' completed" },
{ time: "10:40:12", type: "warning", message: "API Latency spike detected (150ms)" },
{ time: "10:39:00", type: "info", message: "Bot connected to Gateway" },
];
// Real system metrics
const memoryUsage = (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2);
const uptimeSeconds = process.uptime();
const uptime = new Date(uptimeSeconds * 1000).toISOString().substr(11, 8); // HH:MM:SS
// Real activity logs
const activityLogs = getRecentLogs();
const content = `
<div class="dashboard-grid">
@@ -44,31 +47,38 @@ export function dashboardRoute(): Response {
<span class="badge live">LIVE</span>
</div>
<ul class="activity-feed">
${mockedActivity.map(log => `
${activityLogs.length > 0 ? activityLogs.map(log => `
<li class="activity-item ${log.type}">
<span class="time">${log.time}</span>
<span class="message">${log.message}</span>
</li>
`).join('')}
<li class="activity-item info"><span class="time">--:--:--</span> <span class="message">Waiting for events...</span></li>
`).join('') : `
<li class="activity-item info"><span class="time">--:--:--</span> <span class="message">No recent activity.</span></li>
`}
</ul>
</div>
<div class="panel metrics-panel">
<div class="panel-header">
<h2>System Metrics</h2>
<h2>System Health</h2>
</div>
<div class="mock-chart-container">
<div class="mock-chart-bar" style="height: 40%"></div>
<div class="mock-chart-bar" style="height: 60%"></div>
<div class="mock-chart-bar" style="height: 30%"></div>
<div class="mock-chart-bar" style="height: 80%"></div>
<div class="mock-chart-bar" style="height: 50%"></div>
<div class="mock-chart-bar" style="height: 90%"></div>
<div class="mock-chart-bar" style="height: 45%"></div>
</div>
<div class="metrics-legend">
<span>CPU Load (Mock)</span>
<div class="metrics-grid">
<div class="metric-item">
<span class="metric-label">Uptime</span>
<span class="metric-value">${uptime}</span>
</div>
<div class="metric-item">
<span class="metric-label">Memory (Heap)</span>
<span class="metric-value">${memoryUsage} MB</span>
</div>
<div class="metric-item">
<span class="metric-label">Node Version</span>
<span class="metric-value">${process.version}</span>
</div>
<div class="metric-item">
<span class="metric-label">Platform</span>
<span class="metric-value">${process.platform}</span>
</div>
</div>
</div>
</div>

View File

@@ -1,38 +0,0 @@
# 2026-01-07-move-status-to-footer
**Status:** Done
**Created:** 2026-01-07
**Tags:** ui, layout, enhancement
## 1. Context & User Story
* **As a:** User of the Web Interface
* **I want to:** see the system status and uptime information in the footer of every page
* **So that:** the main content area is less cluttered and status information is globally available.
## 2. Technical Requirements
### Data Model Changes
- [ ] N/A
### API / Interface
- [x] **Home Page:** Remove the "Status" card from the main content.
- [x] **Layout:** Update `BaseLayout` (or `layout.ts`) to accept or calculate uptime/status information and render it in the `<footer>`.
## 3. Constraints & Validations (CRITICAL)
- **Visuals:** The footer should remain clean and not be overcrowded.
- **Functionality:** The existing client-side uptime counter (via `#uptime-display` in `script.js`) must continue to work. Ensure the ID or data attributes it relies on are preserved in the new location.
## 4. Acceptance Criteria
1. [x] The "Status" card is removed from the Home page content.
2. [x] The Footer displays "System Operational" and the running Uptime counter.
3. [x] navigation to other pages (if any) still shows the status in the footer.
## 5. Implementation Plan
- [x] Edit `src/web/routes/home.ts` to remove the Status card.
- [x] Edit `src/web/views/layout.ts` to add the Status HTML structure to the footer.
- [x] Verify `script.js` selector targets the new element correctly.
## Implementation Notes
- Moved Status/Uptime logic from `home.ts` to `layout.ts` (footer).
- Calculated server-side uptime for initial rendering to prevent flash.
- Preserved `id="uptime-display"` and `data-start-timestamp` for `script.js` compatibility.
- Updated tests to verify uptime presence in global layout.

View File

@@ -0,0 +1,52 @@
# 2026-01-07-replace-mock-dashboard-data.md: Replace Mock Dashboard Data with Live Telemetry
**Status:** Done
**Created:** 2026-01-07
**Tags:** dashboard, telemetry, logging, database
## 1. Context & User Story
* **As a:** Bot Administrator
* **I want to:** see actual system logs, real-time resource usage, and accurate database statistics on the web dashboard
* **So that:** I can monitor the true health and activity of the Aurora application without checking the terminal or database manually.
## 2. Technical Requirements
### Data Model Changes
- [ ] No strict database schema changes required, but may need a cohesive `LogService` or in-memory buffer to store recent "Activity" events for the dashboard history.
### API / Interface
- **Dashboard Route (`src/web/routes/dashboard.ts`):**
- [x] Replace `mockedActivity` array with a fetch from a real log buffer/source.
- [x] Replace `userCount` approximation with a precise count from `UserService` or `AuroraClient`.
- [x] Replace "System Metrics" mock bars with real values (RAM usage, Uptime, CPU load if possible).
- **Log Source:**
- [x] Implement a mechanism (e.g., specific `Logger` transport or `WebServer` static buffer) to capture the last ~50 distinct application events (commands, errors, warnings) for display.
- [ ] (Optional) If "Docker Compose Logs" are strictly required, implement a file reader for the standard output log file if accessible, otherwise rely on internal application logging.
### Real Data Integration
- **Activity Feed:** Must show actual commands executed, system errors, and startup events.
- **Top Stats:** Ensure `Servers`, `Users`, `Commands`, and `Ping` come from the live `AuroraClient` instance.
- **Metrics:** Display `process.memoryUsage().heapUsed` converted to MB. Display `process.uptime()`.
## 3. Constraints & Validations (CRITICAL)
- **Performance:** Fetching logs or stats must not block the event loop. Avoid heavy DB queries on every dashboard refresh; cache stats if necessary (e.g., via `setInterval` in background).
- **Security:** Do not expose sensitive data (tokens, raw SQL) in the activity feed.
- **Fallbacks:** If data is unavailable (e.g., client not ready), show "Loading..." or a neutral placeholder, not fake data.
## 4. Acceptance Criteria
1. [x] The "Activity Feed" on the dashboard displays real, recent events that occurred in the application (e.g., "Bot started", "Command /ping executed").
2. [x] The "System Metrics" section displays a visual representation (or text) of **actual** memory usage and uptime.
3. [x] The hardcoded `mockedActivity` array is removed from `dashboard.ts`.
4. [x] Refreshing the dashboard page updates the metrics and feed with the latest data.
## 5. Implementation Plan
- [x] Step 1: Create a simple in-memory `LogBuffer` in `src/lib/logger.ts` (or similar) to keep the last 50 logs.
- [x] Step 2: Hook this buffer into the existing logging system (or add manual pushes in `command.handler.ts` etc).
- [x] Step 3: Implement `getSystemMetrics()` helper to return formatted RAM/CPU data.
- [x] Step 4: Update `src/web/routes/dashboard.ts` to import the log buffer and metrics helper.
- [x] Step 5: Replace the HTML template variables with these real data sources.
## Implementation Notes
- **Log Buffer**: Added a 50-item rolling buffer in `src/lib/logger.ts` exposing `getRecentLogs()`.
- **Dashboard Update**: `src/web/routes/dashboard.ts` now uses `AuroraClient` stats and `process` metrics (Uptime, Memory) directly.
- **Tests**: Added `src/lib/logger.test.ts` to verify buffer logic.

View File

@@ -1,50 +0,0 @@
# 2026-01-07-web-interface-feature-expansion
**Status:** Draft
**Created:** 2026-01-07
**Tags:** product-design, feature-request, ui
## 1. Context & User Story
* **As a:** Bot Administrator
* **I want to:** have more useful features on the web dashboard
* **So that:** getting insights into the bot's performance and managing it becomes easier than using text commands.
## 2. Technical Requirements
### Proposed Features
1. **Live Console / Activity Feed:**
* Stream abbreviated logs or important events (e.g., "User X joined", "Command Y executed").
2. **Metrics Dashboard:**
* Visual charts for command usage (Top 5 commands).
* Memory usage and CPU load over time.
* API Latency gauge.
3. **Command Palette / Control Panel:**
* Buttons to clear cache, reload configuration, or restart specific services.
4. **Guild/User Browser:**
* Read-only list of top guilds or users by activity/economy balance.
### Data Model Changes
- [ ] May require exposing existing Service data to the Web module.
### API / Interface
- [ ] `GET /api/stats` or `WS` subscription for metrics.
- [ ] `GET /api/logs` (tail).
## 3. Constraints & Validations (CRITICAL)
- **Security:** Modifying bot state (Control Panel) requires strict authentication/authorization (Future Ticket). For now, read-only/safe actions only.
- **Privacy:** Do not expose sensitive user PII in the web logs or dashboard without encryption/masking.
## 4. Acceptance Criteria
1. [ ] A list of prioritized features is approved.
2. [ ] UI Mockups (code or image) for the "Dashboard" view.
3. [ ] Data sources for these features are identified in the codebase.
## 5. Implementation Plan
- [x] **Phase 1:** Brainstorm & Mockup (This Ticket).
- [ ] **Phase 2:** Create individual implementation tickets for selected features (e.g., "Implement Metrics Graph").
## Implementation Notes
- Created `/dashboard` route with a code-based mockup.
- Implemented responsive CSS Grid layout for the dashboard.
- Integrated real `AuroraClient` data for Server Count, User Count, and Command Count.
- Added placeholder UI for "Live Activity" and "Metrics".
- Next steps: Connect WebSocket "HEARTBEAT" to the dashboard metrics and implement real logger streaming.

View File

@@ -1,42 +0,0 @@
# 2026-01-07-websocket-realtime-data
**Status:** Done
**Created:** 2026-01-07
**Tags:** feature, websocket, realtime, research
## 1. Context & User Story
* **As a:** Developer
* **I want to:** implement a WebSocket connection between the frontend and the Aurora server
* **So that:** I can stream real-time data (profiling, logs, events) to the dashboard without manual page refreshes.
## 2. Technical Requirements
### Data Model Changes
- [ ] N/A
### API / Interface
- [x] **Endpoint:** `/ws` (Upgrade Upgrade: websocket).
- [x] **Protocol:** Define a simple JSON message format (e.g., `{ type: "UPDATE", data: { ... } }`).
## 3. Constraints & Validations (CRITICAL)
- **Bun Support:** Use Bun's native `Bun.serve({ websocket: { ... } })` capabilities if possible.
- **Security:** Ensure that the WebSocket endpoint is not publicly abusable (consider simple token or origin check if necessary, though internal usage is primary context for now).
- **Performance:** Do not flood the client. Throttle updates if necessary.
## 4. Acceptance Criteria
1. [x] Server accepts WebSocket connections on `/ws`.
2. [x] Client (`script.js`) successfully connects to the WebSocket.
3. [x] Server sends a "Hello" or "Ping" packet.
4. [x] Client receives and logs the packet.
5. [x] (Stretch) Stream basic uptime or heartbeat every 5 seconds.
## 5. Implementation Plan
- [x] Modify `src/web/server.ts` to handle `websocket` upgrade in `Bun.serve`.
- [x] Create a message handler object/function to manage connected clients.
- [x] Update `src/web/public/script.js` to initialize `WebSocket`.
- [x] Test connection stability.
## Implementation Notes
- Enabled `websocket` in `Bun.serve` within `src/web/server.ts`.
- Implemented a heartbeat mechanism broadcasting `HEARTBEAT` events every 5s.
- Updated `script.js` to auto-connect, handle reconnects, and update a visual "online" indicator.
- Added `src/web/websocket.test.ts` to verify protocol upgrades and messaging.