diff --git a/backend/routes/admin.py b/backend/routes/admin.py index 4868a61..8be436c 100644 --- a/backend/routes/admin.py +++ b/backend/routes/admin.py @@ -709,13 +709,15 @@ async def get_analytics(user=Depends(require_mod)): today_start = now.replace(hour=0, minute=0, second=0, microsecond=0) week_start = today_start - timedelta(days=6) month_start = today_start - timedelta(days=29) + year_start = today_start - timedelta(days=364) now_ms = int(now.timestamp() * 1000) today_ms = int(today_start.timestamp() * 1000) week_ms = int(week_start.timestamp() * 1000) month_ms = int(month_start.timestamp() * 1000) + year_ms = int(year_start.timestamp() * 1000) async with httpx.AsyncClient(timeout=15) as c: - r_today, r_week, r_month, r_pv_month, r_pages, r_refs = await asyncio.gather( + r_today, r_week, r_month, r_pv_month, r_pv_year, r_pages, r_refs = await asyncio.gather( c.get(f"{url}/api/websites/{site_id}/stats", params={"startAt": today_ms, "endAt": now_ms}, headers=headers), c.get(f"{url}/api/websites/{site_id}/stats", @@ -725,6 +727,9 @@ async def get_analytics(user=Depends(require_mod)): c.get(f"{url}/api/websites/{site_id}/pageviews", params={"startAt": month_ms, "endAt": now_ms, "unit": "day", "timezone": "Europe/Berlin"}, headers=headers), + c.get(f"{url}/api/websites/{site_id}/pageviews", + params={"startAt": year_ms, "endAt": now_ms, + "unit": "month", "timezone": "Europe/Berlin"}, headers=headers), c.get(f"{url}/api/websites/{site_id}/metrics", params={"startAt": month_ms, "endAt": now_ms, "type": "url", "limit": 10}, headers=headers), @@ -733,6 +738,16 @@ async def get_analytics(user=Depends(require_mod)): "type": "referrer", "limit": 8}, headers=headers), ) + # Monatliche Neuanmeldungen aus lokaler DB (letzte 12 Monate) + with db() as conn: + reg_rows = conn.execute(""" + SELECT strftime('%Y-%m', created_at) AS month, COUNT(*) AS count + FROM users + WHERE created_at >= date('now', '-12 months') + GROUP BY month ORDER BY month ASC + """).fetchall() + monthly_registrations = [{"month": r["month"], "count": r["count"]} for r in reg_rows] + def _to_list(r): j = r.json() if isinstance(j, list): return j @@ -740,12 +755,14 @@ async def get_analytics(user=Depends(require_mod)): return [] return { - "today": r_today.json(), - "week": r_week.json(), - "month": r_month.json(), - "pageviews": r_pv_month.json(), - "top_pages": _to_list(r_pages), - "referrers": _to_list(r_refs), + "today": r_today.json(), + "week": r_week.json(), + "month": r_month.json(), + "pageviews": r_pv_month.json(), + "pageviews_year": r_pv_year.json(), + "monthly_registrations": monthly_registrations, + "top_pages": _to_list(r_pages), + "referrers": _to_list(r_refs), } diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 9f26609..247d544 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '478'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '479'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const App = (() => { diff --git a/backend/static/js/pages/admin.js b/backend/static/js/pages/admin.js index 8fab722..9452095 100644 --- a/backend/static/js/pages/admin.js +++ b/backend/static/js/pages/admin.js @@ -343,6 +343,68 @@ window.Page_admin = (() => { ${_dualChart(pv, ses)} + +