# retoor <retoor@molodetz.nl>

from .._shared import endpoint, field

GROUP = {
        "slug": "admin",
        "title": "Admin API",
        "admin": True,
        "intro": """
# Admin API

Site administration endpoints for users, news curation, and settings. Every call requires an
**admin** account. Background service management lives on the
[Background Services](/docs/services.html) page.

Every endpoint follows the shared [Conventions & Errors](/docs/conventions.html) (auth, content
negotiation, pagination, status codes); see [Authentication](/docs/authentication.html) for the
four ways to sign requests.
""",
        "endpoints": [
            endpoint(
                id="admin-users",
                method="GET",
                path="/admin/users",
                title="List users",
                summary="Paginated user management page. Returns HTML.",
                auth="admin",
                interactive=True,
                params=[field("page", "query", "int", False, "1", "Page number.")],
            ),
            endpoint(
                id="admin-media",
                method="GET",
                path="/admin/media",
                title="Media trash",
                summary=(
                    "Moderation view of deleted media. When a member or admin deletes an "
                    "attachment it is soft-deleted: hidden from the gallery and from its parent "
                    "object, but the row and file are kept and the relation to the parent is "
                    "preserved. This page lists every soft-deleted attachment, newest first, with "
                    "its uploader, so an admin can restore or permanently purge it. Returns HTML."
                ),
                auth="admin",
                interactive=True,
                params=[field("page", "query", "int", False, "1", "Page number.")],
            ),
            endpoint(
                id="media-restore",
                method="POST",
                path="/media/{uid}/restore",
                title="Restore media",
                summary=(
                    "Restore a soft-deleted attachment. Because the parent relation is never "
                    "cleared, it reappears in the owner's Media tab and on its original post, "
                    "project, or gist immediately."
                ),
                auth="admin",
                destructive=True,
                params=[
                    field(
                        "uid", "path", "string", True, "", "Soft-deleted attachment uid."
                    ),
                ],
                sample_response={"ok": True, "redirect": "/admin/media"},
            ),
            endpoint(
                id="admin-revoke-award",
                method="POST",
                path="/admin/awards/{uid}/revoke",
                title="Revoke award",
                summary=(
                    "Soft-delete a published award and its linked attachments, then recompute "
                    "receiver stats. Restorable from admin trash."
                ),
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "", "Award uid to revoke."),
                ],
                sample_response={"ok": True, "redirect": "/profile/receiver?tab=awards"},
            ),
            endpoint(
                id="admin-media-purge",
                method="POST",
                path="/admin/media/{uid}/purge",
                title="Purge media",
                summary=(
                    "Permanently delete a soft-deleted attachment: removes the database row and "
                    "deletes the file from disk. This cannot be undone and is the only way media "
                    "is hard-deleted from the UI."
                ),
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "", "Attachment uid to purge."),
                ],
                sample_response={"ok": True, "redirect": "/admin/media"},
            ),
            endpoint(
                id="admin-audit-log",
                method="GET",
                path="/admin/audit-log",
                title="Audit log",
                summary=(
                    "Paginated, filterable audit event list (newest first, 25 per page). "
                    "Negotiates HTML or JSON. Every state-changing action on the platform "
                    "is recorded here with actor, origin, target, change, and result."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field("page", "query", "int", False, "1", "Page number."),
                    field("event_key", "query", "string", False, "post.create", "Filter by exact event key."),
                    field("category", "query", "string", False, "admin", "Filter by category (auth, content, admin, container, ...)."),
                    field("actor_role", "query", "string", False, "admin", "Filter by actor role at action time."),
                    field("actor_uid", "query", "string", False, "", "Filter by acting user uid."),
                    field("origin", "query", "string", False, "web", "Filter by origin (web, api, devii, cli, service, scheduler)."),
                    field("result", "query", "string", False, "denied", "Filter by result (success, failure, denied)."),
                    field("q", "query", "string", False, "", "Free-text search over summary, event key, and target."),
                    field("date_from", "query", "string", False, "", "ISO date lower bound (inclusive)."),
                    field("date_to", "query", "string", False, "", "ISO date upper bound (inclusive)."),
                ],
                sample_response={
                    "entries": [
                        {
                            "uid": "AUDIT_UID",
                            "created_at": "2026-06-11T20:00:00+00:00",
                            "event_key": "admin.setting.update",
                            "category": "admin",
                            "actor_username": "ADMIN",
                            "actor_role": "admin",
                            "origin": "web",
                            "via_agent": 0,
                            "target_type": "setting",
                            "old_value": "0",
                            "new_value": "1",
                            "result": "success",
                        }
                    ],
                    "pagination": {"page": 1, "total": 1, "total_pages": 1},
                    "filters": {},
                    "options": {"category": ["admin", "auth", "content"]},
                },
            ),
            endpoint(
                id="admin-audit-event",
                method="GET",
                path="/admin/audit-log/{uid}",
                title="Audit event",
                summary="A single audit event with its full row and every related-object link.",
                auth="admin",
                interactive=True,
                params=[field("uid", "path", "string", True, "AUDIT_UID", "Audit event uid.")],
                sample_response={
                    "event": {"uid": "AUDIT_UID", "event_key": "container.instance.start", "result": "success"},
                    "links": [
                        {"relation": "actor", "object_type": "user", "object_uid": "USER_UID"},
                        {"relation": "instance", "object_type": "instance", "object_uid": "INSTANCE_UID"},
                    ],
                },
            ),
            endpoint(
                id="admin-analytics",
                method="GET",
                path="/admin/analytics",
                title="Site analytics",
                summary=(
                    "One-call aggregate analytics, returned as JSON: total members, active users "
                    "in the last 24h/7d/30d, signed_in_now, new signups (24h/7d/30d), content "
                    "totals (posts, comments, gists, projects, news), and top authors. Use this "
                    "instead of paging the user list to count or measure activity."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field(
                        "top_n",
                        "query",
                        "int",
                        False,
                        "10",
                        "How many top authors to include (1-50).",
                    )
                ],
                notes=[
                    "`signed_in_now` counts members holding an unexpired session (logged in within the session lifetime, default 7-30 days), not a real-time online/presence count; the response carries a `signed_in_definition` explaining this. `active_*` means created content in the window (`active_definition`).",
                    "This is the endpoint the Devii assistant calls as `site_analytics`; see [Devii internals](/docs/devii-internals.html).",
                ],
            ),
            endpoint(
                id="admin-statistics",
                method="GET",
                path="/admin/statistics/data",
                title="Platform statistics",
                summary=(
                    "Tabbed platform statistics with KPI cards, period-over-period deltas, "
                    "time-series data for charts, and breakdown tables. Covers visitors, members, "
                    "content, engagement, social, AI, Devii, services, containers, game, awards, "
                    "moderation, tools, and storage."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field(
                        "tab",
                        "query",
                        "string",
                        False,
                        "overview",
                        "Tab key (overview, visitors, members, content, ...).",
                    ),
                    field(
                        "hours",
                        "query",
                        "int",
                        False,
                        "168",
                        "Lookback window in hours (24, 168, 720, 2160, or 0 for all time).",
                    ),
                    field(
                        "compare",
                        "query",
                        "int",
                        False,
                        "1",
                        "Include previous-period comparison (1 or 0).",
                    ),
                    field(
                        "top_n",
                        "query",
                        "int",
                        False,
                        "10",
                        "Rows in breakdown tables (1-50).",
                    ),
                ],
                notes=[
                    "The HTML dashboard lives at `/admin/statistics`. Visitor metrics require the statistics tracking middleware (hourly aggregation, 90-day retention).",
                ],
            ),
            endpoint(
                id="admin-statistics-page",
                method="GET",
                path="/admin/statistics",
                title="Statistics dashboard",
                summary="Admin HTML dashboard for platform statistics with charts and tabs.",
                auth="admin",
                interactive=False,
                params=[
                    field(
                        "tab",
                        "query",
                        "string",
                        False,
                        "overview",
                        "Initial tab to render.",
                    ),
                    field(
                        "hours",
                        "query",
                        "int",
                        False,
                        "168",
                        "Initial time window in hours.",
                    ),
                ],
            ),
            endpoint(
                id="admin-issues-planning",
                method="GET",
                path="/admin/issues/planning",
                title="Ticket planning report",
                summary=(
                    "Admin page listing every open Gitea ticket so an admin can pick a subset "
                    "and generate a grouped, ordered planning document for a coding agent."
                ),
                auth="admin",
                interactive=False,
                sample_response={
                    "configured": True,
                    "tickets": [
                        {"number": 42, "title": "Fix login redirect", "labels": ["bug"]},
                    ],
                    "tickets_error": False,
                },
                notes=[
                    "`configured` is false when the issue tracker (Gitea) has not been set up in Services yet - `tickets` is then empty.",
                    "`tickets_error` is true when the tracker is configured but the live fetch failed - retry shortly.",
                ],
            ),
            endpoint(
                id="admin-ai-usage",
                method="GET",
                path="/admin/ai-usage/data",
                title="AI gateway usage analytics",
                summary=(
                    "One-call AI gateway metrics, returned as JSON for a bounded time window: request "
                    "volume and throughput, token usage with averages and percentiles (p50/p90/p95/p99), "
                    "latency (upstream, gateway overhead, queue wait, connection establishment), error "
                    "rates by category, cost in USD (per model, per caller, input vs output, projected "
                    "monthly burn, caching savings), caller behavior, and an hourly breakdown. Cost is "
                    "taken from the upstream native cost when present (OpenRouter) and computed from the "
                    "configured per-million pricing otherwise (DeepSeek)."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field(
                        "hours",
                        "query",
                        "int",
                        False,
                        "48",
                        "Lookback window in hours (1-168).",
                    ),
                    field(
                        "top_n",
                        "query",
                        "int",
                        False,
                        "10",
                        "How many rows in each top-N breakdown.",
                    ),
                ],
                notes=[
                    "TTFT and inter-token latency (latency.ttft_ms/latency.inter_token_ms) are measured only for calls that requested streaming (stream: true); a zero count means no streaming calls occurred in the window, not that the metric is unavailable."
                ],
            ),
            endpoint(
                id="admin-user-ai-usage",
                method="GET",
                path="/admin/users/{uid}/ai-usage",
                title="Per-user AI usage",
                summary=(
                    "One user's AI gateway usage over the last 24 hours, returned as JSON: request "
                    "volume, success and error rates, token totals, cost (window, per hour, per request, "
                    "and a 30-day projection from the full 24h spend), average latency and throughput, a "
                    "per-model breakdown, and an hourly cost series. Because Devii operates a signed-in "
                    "user's account with that user's own API key, this is the user's complete gateway "
                    "spend, whether driven through Devii or direct API calls. Shown admin-only on the "
                    "user's profile page."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field(
                        "uid", "path", "string", True, "USER_UID", "Target user UID."
                    ),
                    field(
                        "hours",
                        "query",
                        "int",
                        False,
                        "24",
                        "Lookback window in hours (1-168).",
                    ),
                ],
                sample_response={
                    "owner_id": "USER_UID",
                    "window_hours": 24,
                    "requests": 42,
                    "success": 41,
                    "failed": 1,
                    "success_pct": 97.6,
                    "error_pct": 2.4,
                    "tokens": {"prompt": 120000, "completion": 38000, "total": 158000},
                    "cost": {
                        "window_usd": 0.214,
                        "per_hour_usd": 0.0089,
                        "per_request_usd": 0.0051,
                        "projected_30d_usd": 6.42,
                    },
                    "latency": {"avg_ms": 1830.0, "avg_tps": 41.2},
                    "by_model": [
                        {
                            "key": "molodetz",
                            "requests": 42,
                            "total_tokens": 158000,
                            "cost_usd": 0.214,
                        }
                    ],
                    "hourly": [
                        {
                            "hour": "2026-06-08T16",
                            "requests": 6,
                            "cost_usd": 0.031,
                            "total_tokens": 22000,
                        }
                    ],
                },
            ),
            endpoint(
                id="admin-user-role",
                method="POST",
                path="/admin/users/{uid}/role",
                title="Set a user role",
                summary="Promote or demote a user. You cannot change your own role.",
                auth="admin",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "uid", "path", "string", True, "USER_UID", "Target user UID."
                    ),
                    field(
                        "role",
                        "form",
                        "enum",
                        True,
                        "member",
                        "New role.",
                        ["member", "admin"],
                    ),
                ],
            ),
            endpoint(
                id="admin-user-password",
                method="POST",
                path="/admin/users/{uid}/password",
                title="Reset a user password",
                summary="Set a new password for a user.",
                auth="admin",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "uid", "path", "string", True, "USER_UID", "Target user UID."
                    ),
                    field(
                        "password",
                        "form",
                        "string",
                        True,
                        "newpassword",
                        "New password, 6+ characters.",
                    ),
                ],
            ),
            endpoint(
                id="admin-user-toggle",
                method="POST",
                path="/admin/users/{uid}/toggle",
                title="Enable or disable a user",
                summary="Toggle a user's active state. You cannot disable yourself.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "USER_UID", "Target user UID.")
                ],
            ),
            endpoint(
                id="admin-news-list",
                method="GET",
                path="/admin/news",
                title="List news articles",
                summary="Paginated news management page. Returns HTML.",
                auth="admin",
                interactive=True,
                params=[field("page", "query", "int", False, "1", "Page number.")],
            ),
            endpoint(
                id="admin-news-toggle",
                method="POST",
                path="/admin/news/{uid}/toggle",
                title="Toggle featured",
                summary="Toggle an article's featured flag and lock it from the news service's auto-rotation.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "NEWS_UID", "Article UID.")
                ],
            ),
            endpoint(
                id="admin-news-publish",
                method="POST",
                path="/admin/news/{uid}/publish",
                title="Toggle published",
                summary="Switch an article between draft and published.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "NEWS_UID", "Article UID.")
                ],
            ),
            endpoint(
                id="admin-news-landing",
                method="POST",
                path="/admin/news/{uid}/landing",
                title="Toggle landing",
                summary="Toggle whether an article shows on the landing page and lock it from the news service's auto-rotation.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "NEWS_UID", "Article UID.")
                ],
            ),
            endpoint(
                id="admin-news-delete",
                method="POST",
                path="/admin/news/{uid}/delete",
                title="Delete a news article",
                summary="Delete an article and its images.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "NEWS_UID", "Article UID.")
                ],
            ),
            endpoint(
                id="admin-settings-get",
                method="GET",
                path="/admin/settings",
                title="Read site settings",
                summary="Return the current site and operational settings. Negotiates HTML or JSON.",
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-settings",
                method="POST",
                path="/admin/settings",
                title="Save site settings",
                summary="Update operational and site settings. Empty fields are skipped.",
                auth="admin",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "site_name", "form", "string", False, "DevPlace", "Site name."
                    ),
                    field(
                        "rate_limit_per_minute",
                        "form",
                        "string",
                        False,
                        "60",
                        "Requests per window.",
                    ),
                    field(
                        "registration_open",
                        "form",
                        "enum",
                        False,
                        "1",
                        "Allow signups.",
                        ["1", "0"],
                    ),
                    field(
                        "maintenance_mode",
                        "form",
                        "enum",
                        False,
                        "0",
                        "Maintenance gate.",
                        ["1", "0"],
                    ),
                ],
                notes=[
                    "Accepts every field on the admin settings form; only non-empty values are written."
                ],
            ),
            endpoint(
                id="admin-notification-default",
                method="POST",
                path="/admin/notifications",
                title="Set a notification default",
                summary="Set the platform-wide default for one notification type on one channel. Applies to users who have not customized that notification; explicit user choices are unaffected.",
                auth="admin",
                encoding="form",
                destructive=True,
                params=[
                    field(
                        "notification_type",
                        "form",
                        "string",
                        True,
                        "vote",
                        "One of: comment, reply, mention, vote, follow, message, badge, level, issue, reminder, harvest_stolen.",
                    ),
                    field(
                        "channel",
                        "form",
                        "string",
                        True,
                        "push",
                        "One of in_app, push or telegram (telegram is off by default and requires a paired Telegram account).",
                    ),
                    field(
                        "value",
                        "form",
                        "boolean",
                        False,
                        "1",
                        "1 to enable this notification by default, 0 to disable.",
                    ),
                ],
                sample_response={
                    "ok": True,
                    "redirect": "/admin/notifications",
                    "data": {
                        "notification_type": "vote",
                        "channel": "push",
                        "value": False,
                    },
                },
            ),
            endpoint(
                id="admin-user-reset-ai-quota",
                method="POST",
                path="/admin/users/{uid}/reset-ai-quota",
                title="Reset user AI quota",
                summary="Delete a specific user's AI gateway ledger rows, resetting their quota.",
                auth="admin",
                destructive=True,
                params=[
                    field(
                        "uid", "path", "string", True, "USER_UID", "Target user UID."
                    ),
                ],
            ),
            endpoint(
                id="admin-ai-quota-reset-guests",
                method="POST",
                path="/admin/ai-quota/reset-guests",
                title="Reset guest AI quotas",
                summary="Reset AI quota for all anonymous guest users.",
                auth="admin",
                destructive=True,
            ),
            endpoint(
                id="admin-ai-quota-reset-all",
                method="POST",
                path="/admin/ai-quota/reset-all",
                title="Reset all AI quotas",
                summary="Reset AI quota for every user (members and guests).",
                auth="admin",
                destructive=True,
            ),
            endpoint(
                id="admin-gateway-page",
                method="GET",
                path="/admin/gateway",
                title="Gateway routing dashboard",
                summary="Admin HTML page for managing AI gateway providers and per-model routing.",
                auth="admin",
                interactive=False,
            ),
            endpoint(
                id="admin-gateway-providers",
                method="GET",
                path="/admin/gateway/providers",
                title="List AI gateway providers",
                summary="List every configured upstream provider plus the default provider summary.",
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-gateway-provider-set",
                method="POST",
                path="/admin/gateway/providers",
                title="Create or update an AI gateway provider",
                summary="Save an upstream provider (base URL, model, and API key) by name. Pass name to update an existing provider.",
                auth="admin",
                params=[
                    field("name", "json", "string", True, "openrouter", "Provider name; existing name updates in place."),
                    field("base_url", "json", "string", True, "https://openrouter.ai/api/v1", "Upstream chat completions base URL."),
                    field("model", "json", "string", True, "x-ai/grok-4.3", "Default model for this provider."),
                    field("api_key", "json", "string", False, "", "Upstream API key. Blank keeps the current key."),
                ],
            ),
            endpoint(
                id="admin-gateway-provider-delete",
                method="DELETE",
                path="/admin/gateway/providers/{name}",
                title="Delete an AI gateway provider",
                summary="Delete a configured upstream provider by name.",
                auth="admin",
                destructive=True,
                params=[
                    field("name", "path", "string", True, "openrouter", "Provider name."),
                ],
            ),
            endpoint(
                id="admin-gateway-models",
                method="GET",
                path="/admin/gateway/models",
                title="List AI gateway model routes",
                summary="List every source-to-target model route plus the configured provider names.",
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-gateway-model-set",
                method="POST",
                path="/admin/gateway/models",
                title="Create or update an AI gateway model route",
                summary="Route a source model name to a target model, optionally on a specific provider. Pass source_model to update an existing route.",
                auth="admin",
                params=[
                    field("source_model", "json", "string", True, "gpt-4", "Model name callers request."),
                    field("target_model", "json", "string", True, "x-ai/grok-4.3", "Model actually sent upstream."),
                    field("provider", "json", "string", False, "openrouter", "Provider name to route through. Blank = the default provider."),
                    field("fallback_model", "json", "string", False, "molodetz-pro", "Another already-configured source_model of the same kind, tried once automatically when this route fails after its own retries are exhausted. Blank = no fallback."),
                ],
            ),
            endpoint(
                id="admin-gateway-model-delete",
                method="DELETE",
                path="/admin/gateway/models/{source_model}",
                title="Delete an AI gateway model route",
                summary="Delete a source-to-target model route by source model name.",
                auth="admin",
                destructive=True,
                params=[
                    field("source_model", "path", "string", True, "gpt-4", "Source model name."),
                ],
            ),
            endpoint(
                id="admin-gateway-quota-rules",
                method="GET",
                path="/admin/gateway/quota-rules",
                title="List AI gateway quota rules",
                summary=(
                    "List every rolling-24h USD quota rule on /openai/v1/*, each scoped by any "
                    "combination of role, specific user uid, and app_reference label, plus the "
                    "global per-role default caps that apply when no rule matches."
                ),
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-gateway-quota-rule-set",
                method="POST",
                path="/admin/gateway/quota-rules",
                title="Create or update an AI gateway quota rule",
                summary=(
                    "Caps rolling-24h USD spend on /openai/v1/*. At least one of owner_kind, "
                    "owner_id, app_reference must be set; leaving a dimension blank makes it a "
                    "wildcard, and the most specific active match wins over other rules and over "
                    "the global default. Pass uid to update an existing rule."
                ),
                auth="admin",
                params=[
                    field("uid", "json", "string", False, "", "Existing rule uid to update; omit to create a new rule."),
                    field("owner_kind", "json", "string", False, "user", "internal, key, user, admin, or anonymous. Blank = any role."),
                    field("owner_id", "json", "string", False, "", "Specific user uid. Blank = any caller of the matched role."),
                    field("app_reference", "json", "string", False, "devplace-bots-v-1-0-0", "App label (the X-App-Reference header). Blank = any app."),
                    field("limit_usd", "json", "number", True, "2.5", "Rolling 24h USD cap. 0 = unlimited."),
                    field("is_active", "json", "boolean", False, "true", "Whether the rule is enforced."),
                    field("label", "json", "string", False, "", "Optional admin-facing note."),
                ],
            ),
            endpoint(
                id="admin-gateway-quota-reset",
                method="POST",
                path="/admin/gateway/quota-resets",
                title="Reset the AI gateway 24h spend",
                summary=(
                    "Clear the counted rolling-24h spend for a scope so a capped caller can call "
                    "again, without deleting any usage history (the cost analytics stay intact). "
                    "Scope it exactly like a quota rule; leaving all three dimensions blank resets "
                    "every caller. Only spend recorded before the reset is cleared - new calls "
                    "count again immediately against the same limit."
                ),
                auth="admin",
                destructive=True,
                params=[
                    field("owner_kind", "json", "string", False, "user", "internal, key, user, admin, or anonymous. Blank = every role."),
                    field("owner_id", "json", "string", False, "", "Specific user uid. Blank = every caller."),
                    field("app_reference", "json", "string", False, "typosaurus", "App label (the X-App-Reference header). Blank = every app."),
                ],
            ),
            endpoint(
                id="admin-gateway-quota-rule-delete",
                method="DELETE",
                path="/admin/gateway/quota-rules/{uid}",
                title="Delete an AI gateway quota rule",
                summary="Delete a quota rule; callers it covered fall back to the next most specific rule or the global default.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "RULE_UID", "Quota rule uid."),
                ],
            ),
            endpoint(
                id="admin-bots-monitor",
                method="GET",
                path="/admin/bots",
                title="Bot monitor page",
                summary="Live low-quality screenshot grid of every running bot persona, one frame per bot.",
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-bots-data",
                method="GET",
                path="/admin/bots/data",
                title="Bot monitor data",
                summary="JSON of every running bot slot with its label, persona, current action/status, and latest frame URL for polling.",
                auth="admin",
                sample_response={
                    "enabled": True,
                    "service_status": "running",
                    "frames": [
                        {
                            "slot": 0,
                            "username": "bytewren",
                            "persona": "grumpy_senior",
                            "action": "POST: rant [3]",
                            "status": "page load",
                            "url": "https://example.com/feed",
                            "label": "bytewren",
                            "captured_at": 1718366400,
                            "age_seconds": 2,
                            "has_image": True,
                            "active": True,
                            "frame_url": "/admin/bots/0/frame.jpg?t=1718366400",
                        }
                    ],
                },
            ),
            endpoint(
                id="admin-bots-frame",
                method="GET",
                path="/admin/bots/{slot}/frame.jpg",
                title="Bot frame image",
                summary="The latest low-quality JPEG screenshot for one bot slot (no-store).",
                auth="admin",
                encoding="none",
                interactive=False,
                params=[
                    field(
                        "slot",
                        "path",
                        "integer",
                        True,
                        "0",
                        "Bot fleet slot index.",
                    )
                ],
            ),
            endpoint(
                id="admin-devii-tasks",
                method="GET",
                path="/admin/devii-tasks",
                title="Scheduled Devii tasks",
                summary=(
                    "Every scheduled Devii task across all owners with its schedule, run count, "
                    "expiry, failure streak, and whether its owner may still schedule, plus the "
                    "configured automation bounds. Returns HTML (or JSON with "
                    "Accept: application/json)."
                ),
                auth="admin",
                interactive=True,
                params=[
                    field(
                        "state",
                        "query",
                        "string",
                        False,
                        "active",
                        "One of active, inactive, all.",
                    )
                ],
            ),
            endpoint(
                id="admin-devii-task-disable",
                method="POST",
                path="/admin/devii-tasks/{uid}/disable",
                title="Disable a scheduled task",
                summary="Stop one scheduled task. The row is kept and stays auditable.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "", "Uid of the task."),
                ],
            ),
            endpoint(
                id="admin-devii-task-delete",
                method="POST",
                path="/admin/devii-tasks/{uid}/delete",
                title="Delete a scheduled task",
                summary="Soft-delete one scheduled task; it moves to the admin trash.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "", "Uid of the task."),
                ],
            ),
            endpoint(
                id="admin-backups",
                method="GET",
                path="/admin/backups",
                title="Backups dashboard",
                summary=(
                    "Storage usage, every backup archive, and every backup schedule. Returns HTML "
                    "(or JSON with Accept: application/json)."
                ),
                auth="admin",
                interactive=True,
            ),
            endpoint(
                id="admin-backups-data",
                method="GET",
                path="/admin/backups/data",
                title="Backups data",
                summary=(
                    "JSON dashboard payload: per-path storage usage, total data and backup size, "
                    "disk usage, the backup list, and the schedule list."
                ),
                auth="admin",
            ),
            endpoint(
                id="admin-backups-run",
                method="POST",
                path="/admin/backups/run",
                title="Create backup",
                summary=(
                    "Enqueue an async backup job for a target (database, uploads, keys, full). "
                    "Returns the job uid and a status_url."
                ),
                auth="admin",
                params=[
                    field(
                        "target",
                        "form",
                        "string",
                        True,
                        "full",
                        "One of database, uploads, keys, full.",
                    )
                ],
                sample_response={
                    "ok": True,
                    "uid": "JOB_UID",
                    "backup_uid": "BACKUP_UID",
                    "status_url": "/admin/backups/jobs/JOB_UID",
                },
            ),
            endpoint(
                id="admin-backups-job",
                method="GET",
                path="/admin/backups/jobs/{uid}",
                title="Backup job status",
                summary="Status of one backup job (pending, running, done, failed) with archive stats.",
                auth="admin",
                params=[field("uid", "path", "string", True, "", "Backup job uid.")],
                sample_response={
                    "uid": "JOB_UID",
                    "kind": "backup",
                    "status": "done",
                    "target": "full",
                    "backup_uid": "BACKUP_UID",
                    "download_url": "/admin/backups/BACKUP_UID/download",
                    "bytes_out": 10485760,
                    "file_count": 1240,
                    "sha256": "…",
                },
            ),
            endpoint(
                id="admin-backups-download",
                method="GET",
                path="/admin/backups/{uid}/download",
                title="Download backup",
                summary="Stream a completed backup archive as a tar.gz file. Restricted to the primary administrator (the first user created with the Admin role); every other administrator receives 403 Forbidden.",
                auth="admin",
                encoding="none",
                params=[field("uid", "path", "string", True, "", "Backup uid.")],
            ),
            endpoint(
                id="admin-backups-delete",
                method="POST",
                path="/admin/backups/{uid}/delete",
                title="Delete backup",
                summary="Permanently delete a backup archive and reclaim its disk space.",
                auth="admin",
                destructive=True,
                params=[field("uid", "path", "string", True, "", "Backup uid.")],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-backups-schedule-create",
                method="POST",
                path="/admin/backups/schedules/create",
                title="Create backup schedule",
                summary=(
                    "Create a recurring backup. kind=interval uses every_seconds; kind=cron uses a "
                    "5-field cron expression. keep_last rotates older backups of the schedule."
                ),
                auth="admin",
                params=[
                    field("name", "form", "string", True, "Nightly full", "Schedule name."),
                    field("target", "form", "string", True, "full", "Backup target."),
                    field("kind", "form", "string", True, "interval", "interval or cron."),
                    field("every_seconds", "form", "int", False, "86400", "Seconds between runs (kind=interval)."),
                    field("cron", "form", "string", False, "0 3 * * *", "Cron expression (kind=cron)."),
                    field("keep_last", "form", "int", False, "7", "Keep only the newest N (0 = all)."),
                ],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-backups-schedule-edit",
                method="POST",
                path="/admin/backups/schedules/{uid}/edit",
                title="Edit backup schedule",
                summary="Update a backup schedule's target, trigger, and retention.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "", "Schedule uid."),
                    field("name", "form", "string", True, "Nightly full", "Schedule name."),
                    field("target", "form", "string", True, "full", "Backup target."),
                    field("kind", "form", "string", True, "interval", "interval or cron."),
                    field("every_seconds", "form", "int", False, "86400", "Seconds between runs (kind=interval)."),
                    field("cron", "form", "string", False, "0 3 * * *", "Cron expression (kind=cron)."),
                    field("keep_last", "form", "int", False, "7", "Keep only the newest N (0 = all)."),
                ],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-backups-schedule-toggle",
                method="POST",
                path="/admin/backups/schedules/{uid}/toggle",
                title="Toggle backup schedule",
                summary="Enable or disable a backup schedule.",
                auth="admin",
                params=[field("uid", "path", "string", True, "", "Schedule uid.")],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-backups-schedule-run",
                method="POST",
                path="/admin/backups/schedules/{uid}/run",
                title="Run backup schedule now",
                summary="Immediately enqueue a backup for a schedule without waiting for its next run.",
                auth="admin",
                params=[field("uid", "path", "string", True, "", "Schedule uid.")],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-backups-schedule-delete",
                method="POST",
                path="/admin/backups/schedules/{uid}/delete",
                title="Delete backup schedule",
                summary="Delete a backup schedule. Existing archives are kept.",
                auth="admin",
                destructive=True,
                params=[field("uid", "path", "string", True, "", "Schedule uid.")],
                sample_response={"ok": True, "redirect": "/admin/backups"},
            ),
            endpoint(
                id="admin-game",
                method="GET",
                path="/admin/game",
                title="Code Farm Era management",
                summary="View the current Code Farm Era status.",
                auth="admin",
                sample_response={"era_active": False, "era_name": ""},
            ),
            endpoint(
                id="admin-game-era-start",
                method="POST",
                path="/admin/game/era/start",
                title="Start an Era",
                summary="Start a new Code Farm Era: resets every farm's visible Era coins/harvests counters to zero. Real coins, prestige, stars, Legacy, and Mastery are never touched.",
                auth="admin",
                params=[
                    field("name", "form", "string", True, "Genesis", "Era name."),
                    field("duration_days", "form", "int", False, "28", "Planned Era length in days."),
                ],
                sample_response={"ok": True, "redirect": "/admin/game"},
            ),
            endpoint(
                id="admin-game-era-end",
                method="POST",
                path="/admin/game/era/end",
                title="End the running Era",
                summary="End the current Era: ranks every participating farm by Era score, awards Stars to the top 10 (and an Era-exclusive cosmetic when available), and permanently records the results.",
                auth="admin",
                destructive=True,
                sample_response={"ok": True, "redirect": "/admin/game"},
            ),
            endpoint(
                id="admin-workspaces-page",
                method="GET",
                path="/admin/workspaces",
                title="Workspaces dashboard",
                summary="Admin HTML page listing every dev workspace across all projects, with owner, project, and moderation flags.",
                auth="admin",
                interactive=False,
            ),
            endpoint(
                id="admin-workspaces-data",
                method="GET",
                path="/admin/workspaces/data",
                title="List workspaces",
                summary="Every dev workspace across all projects plus open moderation flags, as JSON.",
                auth="admin",
                interactive=True,
                sample_response={"workspaces": [], "flags": []},
            ),
            endpoint(
                id="admin-workspaces-suspend",
                method="POST",
                path="/admin/workspaces/{uid}/suspend",
                title="Suspend a workspace",
                summary="Suspend a workspace with a reason shown to its owner. The owner is notified.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                    field("reason", "form", "string", True, "Excessive resource usage", "Shown to the workspace owner."),
                ],
            ),
            endpoint(
                id="admin-workspaces-unsuspend",
                method="POST",
                path="/admin/workspaces/{uid}/unsuspend",
                title="Unsuspend a workspace",
                summary="Lift a suspension. The owner is notified the workspace is available again.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                ],
            ),
            endpoint(
                id="admin-workspaces-stop",
                method="POST",
                path="/admin/workspaces/{uid}/stop",
                title="Stop a workspace",
                summary="Stop the workspace container. Files and tunnels are kept.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                ],
            ),
            endpoint(
                id="admin-workspaces-start",
                method="POST",
                path="/admin/workspaces/{uid}/start",
                title="Start a workspace",
                summary="Resume a stopped workspace container.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                ],
            ),
            endpoint(
                id="admin-workspaces-delete",
                method="POST",
                path="/admin/workspaces/{uid}/delete",
                title="Delete a workspace",
                summary="Remove a workspace and its tunnels.",
                auth="admin",
                destructive=True,
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                ],
            ),
            endpoint(
                id="admin-workspaces-flag",
                method="POST",
                path="/admin/workspaces/{uid}/flag",
                title="Flag a workspace",
                summary="Raise a moderation flag on a workspace. The owner is notified.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                    field("kind", "form", "string", False, "manual", "Flag kind."),
                    field("severity", "form", "string", False, "warn", "Flag severity."),
                    field("detail", "form", "string", False, "", "Detail shown to the owner."),
                ],
            ),
            endpoint(
                id="admin-workspaces-flag-resolve",
                method="POST",
                path="/admin/workspaces/flags/{flag_uid}/resolve",
                title="Resolve or dismiss a workspace flag",
                summary="Set a moderation flag's status.",
                auth="admin",
                params=[
                    field("flag_uid", "path", "string", True, "FLAG_UID", "Flag uid."),
                    field("status", "query", "string", False, "resolved", "resolved or dismissed."),
                ],
            ),
            endpoint(
                id="admin-workspaces-editor",
                method="POST",
                path="/admin/workspaces/{uid}/editor",
                title="Set a workspace owner's editor preferences",
                summary="Change the workspace owner's editor preferences on their behalf, or reset them. Subject to admin seniority.",
                auth="admin",
                params=[
                    field("uid", "path", "string", True, "INSTANCE_UID", "Workspace instance uid."),
                    field("theme", "form", "string", False, "devplace-dark", "devplace-dark, devplace-light or system."),
                    field("layout", "form", "string", False, "standard", "standard, terminal-focus or zen."),
                    field("panel_preset", "form", "string", False, "tall", "short, normal, tall or maximized."),
                    field("font_size", "form", "integer", False, "14", "Editor font size in pixels."),
                    field("terminal_font_size", "form", "integer", False, "13", "Terminal font size in pixels."),
                    field("zoom_level", "form", "integer", False, "0", "Window zoom, -5 to 5."),
                    field("boot_agent", "form", "string", False, "dpc", "dpc or none."),
                    field("boot_shell", "form", "integer", False, "1", "1 opens a shell on boot, 0 skips it."),
                    field("window_mode", "form", "string", False, "tab", "tab, window or fullscreen."),
                    field("window_width", "form", "integer", False, "1600", "Editor window width in pixels."),
                    field("window_height", "form", "integer", False, "1000", "Editor window height in pixels."),
                    field("reset", "form", "boolean", False, "false", "Drop every preference for this owner."),
                ],
            ),
            endpoint(
                id="admin-workspaces-quota",
                method="POST",
                path="/admin/workspaces/quota",
                title="Set a user's workspace quota override",
                summary="Set or update a per-user override of the workspace count/disk/egress/idle/retention/CPU/memory limits.",
                auth="admin",
                params=[
                    field("owner_id", "form", "string", True, "USER_UID", "Target user uid."),
                    field("label", "form", "string", False, "", "Optional admin-facing note."),
                    field("max_workspaces", "form", "int", False, "0", "0 = use the site default."),
                    field("max_tunnels", "form", "int", False, "0", "0 = use the site default."),
                    field("disk_quota_mb", "form", "int", False, "0", "0 = use the site default."),
                    field("egress_quota_mb", "form", "int", False, "0", "0 = use the site default."),
                    field("idle_stop_minutes", "form", "int", False, "0", "0 = use the site default."),
                    field("retention_days", "form", "int", False, "0", "0 = use the site default."),
                    field("cpu_millicores", "form", "int", False, "0", "0 = use the site default."),
                    field("memory_mb", "form", "int", False, "0", "0 = use the site default."),
                ],
            ),
            endpoint(
                id="admin-trash-list",
                method="GET",
                path="/admin/trash",
                title="Trash",
                summary="Admin HTML page listing soft-deleted rows for one table, with restore/purge controls per row.",
                auth="admin",
                interactive=True,
                params=[
                    field("table", "query", "string", False, "posts", "Trash table key (posts, comments, gists, projects, news, awards, quizzes, project_files, attachments)."),
                    field("page", "query", "int", False, "1", "Page number."),
                ],
            ),
            endpoint(
                id="admin-trash-restore",
                method="POST",
                path="/admin/trash/{table}/{uid}/restore",
                title="Restore a soft-deleted row",
                summary="Restore every row soft-deleted under the same event timestamp as the given row (a whole delete cascade at once).",
                auth="admin",
                params=[
                    field("table", "path", "string", True, "posts", "Trash table key."),
                    field("uid", "path", "string", True, "ROW_UID", "Row uid."),
                ],
            ),
            endpoint(
                id="admin-trash-purge",
                method="POST",
                path="/admin/trash/{table}/{uid}/purge",
                title="Purge a soft-deleted row",
                summary="Permanently delete every row soft-deleted under the same event timestamp as the given row, unlinking any attachment/project-file blobs.",
                auth="admin",
                destructive=True,
                params=[
                    field("table", "path", "string", True, "posts", "Trash table key."),
                    field("uid", "path", "string", True, "ROW_UID", "Row uid."),
                ],
            ),
        ],
}
