Files
Admin_dash/ADMIN_DASH_INTEGRATION.md
Shivam Patel d5ab2db926 Wire up visitor metrics from webserver DB and fix uptime monitoring
- Read visitors from /server_storage/visitors.db (webserver's DB) instead of
  admin dash's own table; geoip lookups at query time for globe markers
- Globe card now shows 24h, 7d, and all-time unique visitor counts
- Uptime monitor: Nextcloud via host.docker.internal for Docker networking,
  Website and Gitea monitored on public domains
- UptimeCard uses real hourly history bars instead of Math.random() mock
- docker-compose: mount /server_storage:ro, add extra_hosts for Linux compat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 00:50:40 -05:00

107 lines
2.7 KiB
Markdown

# Admin Dashboard Integration
How to integrate with the website container from an external admin dashboard.
## 1. Uptime Check
**GET** `http://website-container:3000/api/health`
Returns:
```json
{ "status": "ok", "timestamp": "2026-02-09T05:19:53.468Z" }
```
- 200 = up, anything else (timeout, connection refused, non-200) = down
- Both containers must be on the same Docker network for hostname resolution:
```bash
docker network create app-net
docker network connect app-net website-container
docker network connect app-net admin-dash-container
```
Alternatively, use `http://host.docker.internal:8080/api/health` to go through the host port mapping (no shared network needed, but adds overhead).
## 2. Visitors Database
The website writes visitor data to a SQLite DB at `/server_storage/visitors.db`. Mount the same host volume in the admin dashboard container (read-only):
```bash
docker run -d \
--name admin-dash-container \
-v /server_storage:/server_storage:ro \
admin-dash:latest
```
### Schema
```sql
CREATE TABLE visits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip_address TEXT NOT NULL, -- e.g. "2600:6c65:6740:..." or "18.199.106.183"
path TEXT NOT NULL, -- e.g. "/", "/blog", "/resume"
visited_at TEXT NOT NULL -- UTC datetime, e.g. "2026-02-09 05:19:53"
);
```
### Reading from the DB
The DB uses WAL mode, so reads won't block the website's writes. Open in **read-only** mode to avoid conflicts:
```typescript
// Node.js with better-sqlite3
import Database from 'better-sqlite3';
const db = new Database('/server_storage/visitors.db', { readonly: true });
const visits = db.prepare('SELECT * FROM visits ORDER BY visited_at DESC LIMIT 100').all();
```
```python
# Python with sqlite3
import sqlite3
conn = sqlite3.connect('file:///server_storage/visitors.db?mode=ro', uri=True)
visits = conn.execute('SELECT * FROM visits ORDER BY visited_at DESC LIMIT 100').fetchall()
```
### Useful Queries
```sql
-- Unique visitors today
SELECT COUNT(DISTINCT ip_address) FROM visits
WHERE visited_at >= date('now');
-- Page view counts
SELECT path, COUNT(*) as views FROM visits
GROUP BY path ORDER BY views DESC;
-- Visits per hour (last 24h)
SELECT strftime('%Y-%m-%d %H:00', visited_at) as hour, COUNT(*) as views
FROM visits WHERE visited_at >= datetime('now', '-1 day')
GROUP BY hour ORDER BY hour;
```
## Docker Compose Example
```yaml
services:
website:
image: my-website:latest
ports:
- "8080:3000"
volumes:
- /server_storage:/server_storage
networks:
- app-net
admin-dash:
image: admin-dash:latest
ports:
- "3333:3000"
volumes:
- /server_storage:/server_storage:ro
networks:
- app-net
networks:
app-net:
```