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>
This commit is contained in:
Shivam Patel
2026-02-09 00:50:40 -05:00
parent 4416e35580
commit d5ab2db926
9 changed files with 259 additions and 47 deletions

View File

@@ -10,14 +10,9 @@ interface ServiceStatus {
latency: number;
uptime24h?: number;
uptime7d?: number;
history?: Array<{ hour: string; up: boolean }>;
}
// We'd ideally fetch stats from API, but for now we calculate from live data or mock
// To do this properly, we need an API endpoint returning stats.
// Let's update `api/status` to also return stats or create `api/status/stats`.
// For this step, I'll update the visual to SHOW where stats would be,
// and we'll implement the backend stats aggregation in the next step.
export function UptimeCard() {
const [services, setServices] = useState<ServiceStatus[]>([]);
const [loading, setLoading] = useState(true);
@@ -72,11 +67,20 @@ export function UptimeCard() {
<span className="text-xs text-neutral-500 font-mono w-10 text-right">{service.latency}ms</span>
</div>
</div>
{/* Mini bars visualization for history - Mocked visual for now until API is ready */}
<div className="flex gap-[2px] h-1.5 opacity-50">
{[...Array(20)].map((_, i) => (
<div key={i} className={`flex-1 rounded-full ${Math.random() > 0.95 ? 'bg-red-500' : 'bg-emerald-500'}`} />
))}
{service.history && service.history.length > 0 ? (
service.history.slice(-24).map((h, i) => (
<div
key={i}
className={`flex-1 rounded-full ${h.up ? 'bg-emerald-500' : 'bg-red-500'}`}
title={h.hour}
/>
))
) : (
[...Array(24)].map((_, i) => (
<div key={i} className="flex-1 rounded-full bg-neutral-700" />
))
)}
</div>
<div className="flex justify-between text-[10px] text-neutral-600 font-mono">
<span>24h: {service.uptime24h ?? 100}%</span>