# 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,
  visitor_id TEXT NOT NULL,    -- daily HMAC; raw IP addresses are not stored
  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 visitor_id) 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;
```

## 3. Optional Event Relay

Set `ADMIN_DASH_URL` to receive same-origin website events as JSON:

```json
{ "path": "/blog", "visitorId": "daily-hmac-id", "timestamp": 1770000000000 }
```

If `ADMIN_DASH_KEY` is set, the website sends it as a bearer token. The relay is disabled when `ADMIN_DASH_URL` is empty.

## 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:
```
