synops/docs/infra/brukerklasser.md
vegard 68d8fff2dd Spec: brukerklasser og AI-budsjettering
Konfigurerbare brukerklasser (Basis, Proff(ish), Superduper ultra
premium, Admin) med token-budsjett per dag, modellnivå-tilgang og
feature-gates. Budsjettsjekk før hvert LLM-kall. Admin-forbruk
vises med kostnadsestimat. Automatiske triggere teller mot
brukerens budsjett. Klasser og brukere som noder i grafen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 01:21:44 +00:00

13 KiB
Raw Blame History

Brukerklasser og AI-budsjettering

Konsept

Brukerklasser styrer tilgang til AI-ressurser. Hver klasse definerer token-budsjett, tilgjengelige modellnivåer og hvilke AI-features brukeren kan trigge. Admin konfigurerer klasser og tildeler brukere.

Brukerklasser som noder

node_kind: 'user_class'
title: "Proff(ish)"
metadata: {
  budget_tokens_per_day: 500000,
  model_access: ["synops/low", "synops/medium"],
  features: ["chat_bot", "summarize", "suggest_edges", "ai_process"],
  priority: 2,           // høyere = finere (for sortering)
  description: "For de som mener alvor. Noen ganger."
}

Default-klasser

Klasse Budsjett/dag Modeller Features
Basis 50k tokens low chat-bot
Proff(ish) 500k tokens low, medium chat-bot, oppsummering, suggest-edges, ai-prosessering
Superduper ultra premium 5M tokens low, medium, high alt unntatt modellvalg og konfig
Admin ubegrenset alle inkl. extreme alt + modellvalg (/claude, /grok) + konfig

Klassenavnene er konfigurerbare. Default-navnene er selvironiske i tråd med plattformens tone. Admin kan opprette, endre, slette og omdøpe klasser fritt.

Tildeling

Bruker → klasse via edge:

person_node --[has_class]--> user_class_node

Én klasse per bruker. Default for nye brukere: "Basis" (eller konfigurerbar i admin). Admin kan endre klasse per bruker.

Budsjettsjekk

Maskinrommet sjekker budsjett før hvert LLM-kall:

async fn check_budget(user_node_id: Uuid, pool: &PgPool) -> Result<bool> {
    // Hent brukerens klasse
    let class = get_user_class(user_node_id, pool).await?;

    // Ubegrenset? Alltid OK.
    if class.budget_tokens_per_day == 0 { return Ok(true); }

    // Hent forbruk siste 24 timer
    let used = sqlx::query_scalar!(
        "SELECT COALESCE(SUM(input_tokens + output_tokens), 0)
         FROM ai_usage_log
         WHERE user_node_id = $1
         AND created_at > now() - interval '1 day'",
        user_node_id
    ).fetch_one(pool).await?;

    Ok(used < class.budget_tokens_per_day)
}

Ved overskridelse:

  • LLM-kall avvises
  • Bruker får melding: "Daglig budsjett brukt opp. Tilbakestilles kl. 00:00."
  • Admin varsles hvis ønskelig
  • Jobber som trigger for brukeren køes til neste dag (eller droppes)

Modellnivå-gate

I tillegg til token-budsjett: brukerens klasse bestemmer hvilke modellnivåer (synops/low, medium, high, extreme) de kan bruke.

async fn check_model_access(user_node_id: Uuid, model_alias: &str, pool: &PgPool) -> bool {
    let class = get_user_class(user_node_id, pool).await.unwrap();
    class.model_access.contains(model_alias)
}

"Basis"-brukere får alltid synops/low. Prøver de en feature som krever synops/high, downgrades modellen automatisk til det høyeste nivået de har tilgang til — med varsel om at resultatet kan være dårligere.

Automatiske triggere og budsjett

Når en orkestrering (som suggest-edges) trigger på en brukers handling, teller kostnadene mot brukerens budsjett:

Trond oppretter en innholds-node
  → orkestrering: suggest-edges triggers
  → budsjettsjekk: har Trond (Proff(ish)) tokens igjen?
  → ja: kjør suggest-edges, logg mot Trond
  → nei: dropp, logg "skipped:budget"

Systemjobber (RSS, rendering) som ikke er bruker-initiert kjører under et "system"-budsjett som admin styrer separat.

Feature-gate

Hver AI-feature har et navn brukt i feature-listen:

Feature-nøkkel Beskrivelse
chat_bot @bot i samtaler
summarize AI-oppsummering
suggest_edges Automatisk foreslåtte relasjoner
ai_process AI-prosessering (verktøy-panel)
transcribe Whisper-transkribering
tts Tekst-til-tale
clip Web clipper med AI-oppsummering
orchestration AI-steg i orkestreringer
model_select Eksplisitt modellvalg (/claude, /grok)
admin_config Konfigurasjon av klasser og ruting

Klassen lister hvilke features den har tilgang til. Maskinrommet sjekker feature-tilgang før det tillater operasjonen.

Admin-UI: Brukerpanel

Brukeroversikt (/admin/users)

┌─ Brukere ──────────────────────────────────────────┐
│                                                     │
│ Navn      Klasse                 Forbruk    Status │
│ Vegard    Admin                  1.2M i dag  ✅   │
│ Trond     Superduper ultra..     2.1M/5M     ✅   │
│ Arne      Proff(ish)            430k/500k    ⚠️   │
│ Lise      Basis                  48k/50k     ⚠️   │
│ Gjest     Basis                  0/50k       ✅   │
│                                                     │
│ Klikk bruker → detaljer med klasse-endring          │
└─────────────────────────────────────────────────────┘

Brukerdetaljer

┌─ Arne ─────────────────────────────────────────────┐
│                                                     │
│ Klasse: [Proff(ish) ▼]                             │
│                                                     │
│ Forbruk i dag:  430,000 / 500,000 tokens (86%)     │
│ Forbruk denne uken: 1.8M tokens                    │
│ ████████████████████░░░                             │
│                                                     │
│ Modellfordeling i dag:                              │
│   synops/low:    380k tokens (88%)                  │
│   synops/medium:  50k tokens (12%)                  │
│                                                     │
│ Siste AI-kall:                                      │
│   14:30  chat_bot (synops/low)     1.2k tokens     │
│   14:15  suggest_edges (synops/low) 800 tokens      │
│   13:50  summarize (synops/medium)  3.5k tokens     │
│                                                     │
│ [Overstyr budsjett]  [Deaktiver bruker]             │
└─────────────────────────────────────────────────────┘

Admin-forbruk

Admin har ubegrenset budsjett, men forbruket vises like fullt:

┌─ Vegard (Admin) ───────────────────────────────────┐
│                                                     │
│ Forbruk i dag: 1,200,000 tokens                    │
│ Forbruk denne uken: 8.3M tokens                    │
│ Forbruk denne måneden: 31M tokens                  │
│                                                     │
│ Estimert kostnad (basert på modellpriser):          │
│   synops/low:    800k × $0.10/M = $0.08            │
│   synops/medium: 300k × $0.50/M = $0.15            │
│   synops/high:   100k × $3.00/M = $0.30            │
│   ─────────────────────────────────                 │
│   Total i dag: ~$0.53                               │
│   Total denne uken: ~$3.70                          │
│   Total denne måneden: ~$14.20                      │
│                                                     │
│ Claude Code (abonnement, ikke tokens):              │
│   Sesjoner i dag: 3                                 │
│   Total tid: 4t 20min                               │
└─────────────────────────────────────────────────────┘

Klasse-konfigurasjon (/admin/classes)

┌─ Brukerklasser ────────────────────────────────────┐
│                                                     │
│ Navn                      Budsjett   Modeller       │
│ Basis                     50k/dag    low            │
│ Proff(ish)               500k/dag   low+medium     │
│ Superduper ultra premium  5M/dag     low+med+high  │
│ Admin                     ∞          alle           │
│                                                     │
│ [+ Ny klasse]                                       │
└─────────────────────────────────────────────────────┘

Klikk en klasse → rediger:

┌─ Rediger: Proff(ish) ─────────────────────────────┐
│                                                     │
│ Navn:     [Proff(ish)                  ]           │
│ Beskrivelse: [For de som mener alvor.  ]           │
│                                                     │
│ Budsjett: [500000] tokens per [dag ▼]              │
│                                                     │
│ Modellnivåer:                                       │
│   ☑ synops/low                                     │
│   ☑ synops/medium                                  │
│   ☐ synops/high                                    │
│   ☐ synops/extreme                                 │
│                                                     │
│ Features:                                           │
│   ☑ chat_bot       ☑ summarize                     │
│   ☑ suggest_edges  ☑ ai_process                    │
│   ☐ transcribe     ☐ tts                           │
│   ☐ model_select   ☐ admin_config                  │
│                                                     │
│ Brukere i denne klassen: 2 (Arne, Lise)            │
│                                                     │
│ [Lagre]  [Avbryt]                                   │
└─────────────────────────────────────────────────────┘

Systembudsjett

Jobber som ikke tilhører en spesifikk bruker (RSS-generering, planlagt publisering, system-orkestreringer) kjører under et eget systembudsjett:

metadata på system-config-node: {
  system_budget_tokens_per_day: 1000000,
  system_model_level: "synops/low"
}

Vises i admin-panelet under "Systemforbruk".

Implementering

Database

Ingen ny tabell — brukerklasser er noder:

-- Opprett default-klasser (seed)
INSERT INTO nodes (node_kind, title, visibility, metadata) VALUES
('user_class', 'Basis', 'readable', '{"budget_tokens_per_day":50000,"model_access":["synops/low"],"features":["chat_bot"],"priority":1,"description":"Grunnpakken. Du får en bot. Vær takknemlig."}'),
('user_class', 'Proff(ish)', 'readable', '{"budget_tokens_per_day":500000,"model_access":["synops/low","synops/medium"],"features":["chat_bot","summarize","suggest_edges","ai_process"],"priority":2,"description":"For de som mener alvor. Noen ganger."}'),
('user_class', 'Superduper ultra premium', 'readable', '{"budget_tokens_per_day":5000000,"model_access":["synops/low","synops/medium","synops/high"],"features":["chat_bot","summarize","suggest_edges","ai_process","transcribe","tts","clip","orchestration"],"priority":3,"description":"Alt du kan drømme om. Nesten."}'),
('user_class', 'Admin', 'readable', '{"budget_tokens_per_day":0,"model_access":["synops/low","synops/medium","synops/high","synops/extreme"],"features":["chat_bot","summarize","suggest_edges","ai_process","transcribe","tts","clip","orchestration","model_select","admin_config"],"priority":99,"description":"Hersker over alt. Betaler regningen."}');

(budget_tokens_per_day: 0 = ubegrenset for Admin)

Maskinrommet

  • check_ai_budget(user_node_id, estimated_tokens) — kall før LLM
  • check_model_access(user_node_id, model_alias) — kall før LLM
  • check_feature_access(user_node_id, feature_key) — kall før feature
  • Alle bruker get_user_class() som cacher i minne (invalideres ved endring)

Frontend

  • /admin/users — utvidet med klasse, forbruk, statusindikator
  • /admin/classes — ny side for klasse-konfigurasjon
  • Brukerens egen profil viser forbruk og gjenstående budsjett

Modellpris-tabell

For å estimere kostnad i admin-UI:

CREATE TABLE model_pricing (
  model_alias TEXT PRIMARY KEY,
  input_price_per_m NUMERIC,   -- pris per million input-tokens
  output_price_per_m NUMERIC,  -- pris per million output-tokens
  updated_at TIMESTAMPTZ DEFAULT now()
);

Admin oppdaterer priser manuelt (de endres sjelden). Brukes kun for visning — ikke for faktisk fakturering.