Torna alla documentazione
Guida 00

Quotas e costi — limiti d'uso e di spesa

Il motore di quota copre tre generi: quota token e quota storage (Phase 207) più la quota costo (Phase 216, hold-and-settle sulla matematica del denaro reale). Le quote sono lo strumento di operatore per i tetti d'uso su installazioni multi-utente; vinco…

4 min di lettura

Il motore di quota copre tre generi: quota token e quota storage (Phase 207) più la quota costo (Phase 216, hold-and-settle sulla matematica del denaro reale). Le quote sono lo strumento di operatore per i tetti d'uso su installazioni multi-utente; vincolano ogni utente con una quota configurata — amministratori inclusi — e una quota non impostata significa illimitato (fail-open: zero cambi di comportamento per le installazioni esistenti).

Funzione Community (operator tool). Fonti: docs/QUOTAS.md (Phase 207 + 216), docs/MODEL_COSTS.md, docs/API.md (la sezione Costs, quotas, and per-user model policy). Righe di provenienza: FACT-CENSUS.md F-QUOTA-1.

Invarianti fondamentali

  • Niente secondo misuratore. La verità del consumo (token/costo) resta nel ledger esistente WorkspaceTokenUsage (packages/server/src/services/quotaService.ts). QuotaBalance / QuotaHold / QuotaReset sono stato derivato e ancore, mai una tabella di conteggio.
  • Reset = ancora di ledger. Un reset scrive ancora QuotaReset(kind, at) che delimita la finestra rollante — la cronologia d'uso/costo non viene mai cancellata o azzerata.
  • Gate a livello di servizio, pre-turn — NON middleware di auth (il check serve dati di dominio, non la forma della richiesta). I gate partono prima della prima chiamata LLM nell'orchestratore e prima dell'ingest nei percorsi di upload.
  • Fail-open per quote non impostate. La catena di risoluzione termina su "illimitato" quando nulla è configurato (D-08).
  • La matematica del denaro è Decimal→cents. TUTTA l'aritmetica dei costi passa per Prisma.Decimal e atterra a cents interi — mai float (costQuotaService.ts, dottrina COST-01).

La catena di risoluzione (D-08)

LivelloFonteNote
1Override per-utenteUser.tokenQuotaLimit / User.storageQuotaGb / righe costo per-utente — via PUT /api/quota/:userId (admin)
2Preset d'installazioneChiavi SystemConfig (sotto) — DB > ENV > default
3IllimitatoSentinela "0" / "" / unset = non configurato → fail-open

Chiavi di configurazione (SystemConfig, editabili da Settings)

ChiaveDefaultSignificato
QUOTA_TOKEN_DEFAULTsentinela unsetTetto token d'installazione per ogni utente senza override
QUOTA_STORAGE_GB_DEFAULTsentinela unsetTetto storage d'installazione (GB)
QUOTA_COST_EUR_DEFAULTsentinela unset ("0"/"" = illimitato)Tetto COSTO d'installazione — stringa decimale EUR
QUOTA_COST_FALLBACK_INPUT_CENTS_PER_1Mfloor built-in non-zeroTariffa di fallback SC-4 per modelli SENZA prezzo — input, cents interi per 1M token
QUOTA_COST_FALLBACK_OUTPUT_CENTS_PER_1Mfloor built-in non-zeroTariffa di fallback SC-4 per modelli SENZA prezzo — output

Dottrina SC-4: un modello senza prezzo non bypassa MAI la quota costo — le tariffe fallback si applicano con warn-once (warnFallbackOnce): un modello senza prezzo non può mai risultare gratis.

Quote token (quotaService.ts)

  • resolveTokenQuota(userId) → { limit, source } — limit: null = illimitato; source dice quale livello del D-08 ha deciso.
  • La finestra rollante parte dall'ultima ancora QuotaReset per (userId, kind: "token") (o dall'epoca se mai resettato); l'uso in finestra si somma dal ledger WorkspaceTokenUsage.
  • Superare la quota lancia QuotaError (status + payload) — il campo quota del payload è il contratto che frontend, widget e handler dei connettori leggono. Non c'è middleware da bypassare: il gate gira dentro il percorso del servizio.

Quote costo (costQuotaService.ts, Phase 216) — hold-and-settle

Prenotazione in due fasi:

  1. Reserve (prima della chiamata LLM) — reserveCostQuota(principal, estimateCents) gira UNA transazione interattiva: un updateMany condizionale il cui predicato (spentCents + estimate <= limitCents) Postgres valuta con row-lock, così N gate concorrenti si SERIALIZZANO invece di passare tutti su un check vecchio (SC-2) + insert di QuotaHold nella stessa transazione.
  2. Settle (alla sezione d'uso) — settleCostHold chiude l'hold e rimborsa estimate − actual. L'overshoot in volo (actual > estimate) è la finestra accettata — niente kill a stream in corso.
  3. A riposo vale l'invariante: settledSpent + Σ(lead aperte) ≤ limite.
  4. Fonte del prezzo per riga: lo snapshot FROZEN di Phase 203 dove esiste; altrimenti le tariffe fallback SC-4 (warn-once); le righe in valuta fuori dalla moneta dominante sono comunque prezzate (mai silenti gratis, mai escluse).
  5. Reset — resetCostQuota scrive l'ancora Quota(kind "cost") e RICOSTRUISCE il bilancio da ledger-sum + hold aperte (D-02).

Quote storage

checkStorageQuota / resolveStorageQuota enforcano l'override per-utente storageQuotaGb, il preset QUOTA_STORAGE_GB_DEFAULT o l'illimitato. I gate partono nei percorsi di upload prima del dispatch al collector.

Principal per i widget

I visitatori anonimi del widget non sono utenti — resolveWidgetQuotaPrincipal lega il traffico widget al principal dell'organizzazione del widget: il consumo del widget pesa sulla catena di quota dell'org, non su identità per-visitatore.

Dove partono i gate (siti di consumo)

SuperficieGateFile
Chat (JWT, widget proxy, connettori — un orchestrator)gate token + costo pre-turn / pre-LLMpackages/server/src/agent/orchestrator.ts
Upload documentogate storage pre-ingestpackages/server/src/routes/uploads.ts, routes/documents.ts
Sweep di resetreset orario delle quote token (pg-boss cron: initQuotaResetScheduler)services/quotaResetJob.ts
Letture self-serviceGET /api/quota/me, rollups, reset manualeroutes/quota.ts

Flusso operatore

  1. Default d'installazione — Settings UI → chiavi QUOTA_* (o PUT /api/system/settings).
  2. Override per-utente — PUT /api/quota/:userId (admin) o la UI di quota.
  3. Prezzi per-utente — la famiglia COSTS (Phase 209: /api/users/:userId/pricing, le chiavi own-provider sotto /api/me/provider-keys) alimenta lo stesso motore.
  4. Reset manuale in qualunque momento: POST /api/quota/:userId/reset; lo sweep orario regge lo stato stazionario.

Prezzi dei modelli (MODEL_COSTS)

Setup: Settings → Providers → seleziona il provider → azione pricing del modello → costo per-1M-token input/output (es. 1.50 e 6.00) + la valuta → Save. La formula: cost = tokens × rate, calcolata lato server a ogni scrittura d'uso, con snapshot congelato al run time (le modifiche successive alla tariffa non riscrivono la cronologia). Valute: USD, EUR, GBP, JPY, CNY, INR — totali per valuta, nessuna conversione in v1. N/A = prezzo non configurato (i modelli cloud unset; la UI mostra "N/A" — l'admin deve configurare); $0.00 = gratis esplicito (i modelli local/Ollama sono backfillati a 0 alla migrazione; override possibile). Limiti v1: niente conversione tra valute; costo dell'iterazione principale solo (le sub-pipeline tool/MCP/synthesis escluse); il costo è disponibile all'evento done (non a metà stream).

Riferimento endpoint

La tabella completa vive in API reference → Costs, quotas, and per-user model policy.

Vedi anche

  • Scaling — il comportamento delle quote sotto deployment multi-istanza

Questa guida copre la superficie operativa di quote e costi; l'approfondimento tecnico vive nel post gemello:

Provenance

SezioneFonte
Invarianti / catena di risoluzione / chiavidocs/QUOTAS.md (core invariants, D-08, le chiavi — Phase 207/203) — F-QUOTA-1
Quote costo / hold-and-settledocs/QUOTAS.md (§ Cost quotas — Phase 216) + costQuotaService.ts
Prezzi modellidocs/MODEL_COSTS.md (Phase 203/209/216)
Citi dei gatedocs/QUOTAS.md (§ Where the gates fire)

---

Riferimento operativo — Simmetric Chat v0.28.1 (docs aggiornate 2026-10-02, census SHA `aca5b8ff`).