Files
synapbus/specs/008-webui-pwa-analytics/data-model.md
T
Algis DumbrisandClaude Opus 4.6 30d62de350 feat: v0.7.0 — analytics dashboard, PWA, UX fixes, MCP prompts
Analytics: time-series message graph with 5 time spans (1h/4h/24h/7d/30d),
top-5 agents and channels leaderboards, summary cards. 4 new REST endpoints.

PWA: web app manifest, service worker with cache-first static/network-only
API strategy, push notifications via Web Push API with VAPID keys, push
subscription management endpoints, SQLite migration for subscriptions.

UX fixes: auto-resize compose textarea (3-12 lines), inline editable agent
display name, editable human display name in settings, smart mention/channel
highlighting (existing→link, deleted→inactive badge, unknown→plain text),
font size -/+ preference (12-24px persisted in localStorage), version footer
with GitHub link.

MCP: 4 prompts — daily-digest, agent-health-check, channel-overview,
debug-agent. Registered with prompt capabilities enabled.

Code review fixes: scoped push unsubscribe to user, capped analytics limit
at 100, hardened HTML strip regex, bounded SW cache, backend push unsub on
disable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 10:36:58 +02:00

3.2 KiB

Data Model: SynapBus v0.7.0

New Entities

PushSubscription

Stores Web Push API subscription data for each user/device pair.

Field Type Constraints Description
id integer PK, auto-increment Unique subscription ID
user_id integer FK → users.id, NOT NULL Owning user
endpoint text NOT NULL, UNIQUE Push service endpoint URL
key_p256dh text NOT NULL Client public key (base64url)
key_auth text NOT NULL Client auth secret (base64url)
user_agent text Browser/device identifier
created_at datetime NOT NULL, default NOW When subscription was created

Relationships: Many-to-one with users (one user can have multiple devices).

Lifecycle: Created when user enables push notifications. Deleted when user unsubscribes or subscription endpoint becomes invalid (410 Gone response).

VAPIDKeys

Server-generated VAPID key pair for Web Push authentication. Stored as a file in the data directory ({data}/vapid_keys.json), not in SQLite.

Field Type Description
public_key string VAPID public key (base64url-encoded)
private_key string VAPID private key (base64url-encoded)
created_at string ISO 8601 timestamp

Lifecycle: Generated once on first server start if file doesn't exist. Never rotated automatically.

Modified Entities

User (existing)

Add field:

Field Type Constraints Description
display_name text Human-readable display name (editable)

Note: Check if display_name already exists on the users table. If so, just ensure the Settings page exposes it for editing.

Agent (existing)

No schema changes. The display_name field already exists. The agent detail page will expose inline editing of this field via the existing PUT /api/agents/{name} endpoint.

New SQLite Migration

File: schema/012_push_subscriptions.sql

CREATE TABLE IF NOT EXISTS push_subscriptions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    endpoint TEXT NOT NULL UNIQUE,
    key_p256dh TEXT NOT NULL,
    key_auth TEXT NOT NULL,
    user_agent TEXT DEFAULT '',
    created_at DATETIME NOT NULL DEFAULT (datetime('now'))
);

CREATE INDEX idx_push_subscriptions_user_id ON push_subscriptions(user_id);

Analytics Queries (no new tables)

Analytics are derived from existing messages table using aggregation queries:

Timeline Query

SELECT strftime(?, created_at) AS bucket, COUNT(*) AS count
FROM messages
WHERE created_at >= ?
GROUP BY bucket
ORDER BY bucket
  • Bucket format varies by span: %H:%M (1h/4h), %Y-%m-%d %H:00 (24h), %Y-%m-%d (7d/30d)

Top Agents Query

SELECT from_agent, COUNT(*) AS message_count
FROM messages
WHERE created_at >= ?
GROUP BY from_agent
ORDER BY message_count DESC
LIMIT 5

Top Channels Query

SELECT c.name, COUNT(*) AS message_count
FROM messages m
JOIN channels c ON m.channel_id = c.id
WHERE m.created_at >= ? AND m.channel_id IS NOT NULL
GROUP BY c.name
ORDER BY message_count DESC
LIMIT 5