Internal Documentation internal
TalkIDE internal documentation

Přehled zbývajících fází Environment first-class konceptu (ADR-026). Každá fáze je samostatně nasaditelná; plné sekvence / finální API kontrakty se dopíšou per-fáze před implementací.

Toto není implementovatelná UC — je to scope dokument s acceptance kritérii a závislostmi. Každá fáze dostane vlastní implementovatelnou UC před zahájením implementace příslušné fáze. Foundation je UC-10010 F1. Zamčená rozhodnutí viz ADR-026 LOCKED DECISIONS.


Fázový přehled

FázeScope (stručně)ZávislostDopad na live user
F0UC-10008 marže do účtování— nezávislážádný (marže 0 = no-op)
F1Entita environment + lazy default „TalkIDE”— foundationžádný (čistě additivní)
F2Billing read-path + postpaid akruál + měsíční faktura per-env řádky + SOFT enforcementF1 hotováminimální (trial DP-1; žádný suspend)
F3Create/Manage Environment UC (SHARED, user-created)F2 hotovážádný (opt-in)
F4Deployment wiring (namespace routing podle prostředí) + cut-over živých tenantů na nový ns tvar → UC-10014F3 hotovácitlivá (živý todo-list.talkide.app — řešeno maintenance oknem)
F5HARD enforcement (scale-to-zero) + DEDICATED resource_mode (ADR-023 §7 jako produkt)F4 hotovámírná (hard enforcement jen pro nezaplacené); DEDICATED opt-in premium

ADR-024 worker extraction (přesun talkide-worker do samostatného repa/podu) NENÍ fáze Environment konceptu. Je to souběžný projekt druhého týmu (talkide-worker repo, be#213–be#218). F4 vůči workeru garantuje jen to, že DEFAULT namespace {tenant-slug}-talkide existuje a má správné jméno — tam druhý tým worker deployne.


F2 — Billing read-path + postpaid akruál + SOFT enforcement

Scope

  • C.2 namespace→environment mapování: OpenCost aggregate=namespace → mapování namespace name → environment.namespace_ref → tenant. V F2 je vždy 1:1 „TalkIDE” = tenant-{slug} (bezpečné, attribution jednoznačná).
  • hosting_cost_events.environment_id: nový nullable sloupec FK → environment.id. Backfill historických řádků: environment_id = id DEFAULT environment pro daného tenanta. Nové events plněny okamžitě.
  • hosting_credit_ledger.environment_id: analogicky nullable FK + backfill.
  • Postpaid akruál pipeline (UC-10009 DESIGN sekvence 2, přizpůsobeno per-env): C.2 OpenCost scrape → hosting_cost_events INSERT s environment_idhosting_credit_ledger DEBIT řádek.
  • Měsíční Stripe faktura (anchor 1. v měsíci, DP-5): jedna faktura per tenant, per-env line items (OD-6). hosting_invoice + hosting_billing_account entita (UC-10009 DESIGN datový model, beze změny struktury).
  • FE billing breakdown: GET /api/v1/billing/hosting/estimate vrátí per-env řádky (accrued + projected). „Next invoice on 1st” jazyk (DP-6).
  • Trial (DP-1): hosting_billing_account.trial_ends_at nastaven při 1. Publish; nulové akruály v trial periódě; trial_days z application.yaml (config property, default 14, 0 = trial vypnut). Trial granularita = per tenant (OD-5), NE per-env.
  • Hosting spend cap (DP-2): nový hosting_spending_limit_usd sloupec na user_budget (NEreuse UC-10005 spending_limit_usd). Cap agregovaný přes všechna prostředí tenanta (OD-1).
  • Enforcement v F2 = SOFT only (OD-2, LOCKED): při neuhrazené faktuře po dunning (DP-3) → stav PAST_DUE → grace → SUSPENDED na hosting_billing_account. Žádný hard scale-to-zero žádného podu/namespace. Hard enforcement přichází až ve F4 (OD-2).
  • Dunning (DP-3): 3 retry (+0/+2/+5 dní) → email notifikace v každém kroku → PAST_DUE → 7 dní grace s eskalačními e-maily → SUSPENDED (jen záznam v DB, žádná infra akce v F2).

Acceptance kritéria F2

  1. OpenCost scrape běží periodicky a plní hosting_cost_events s korektním environment_id pro všechny aktivní tenanty.
  2. Měsíční faktura (1. v měsíci) vygenerována a odeslána Stripe pro tenanty mimo trial periodu.
  3. Faktura obsahuje per-environment line items (alespoň 1 řádek „TalkIDE”).
  4. FE breakdown zobrazuje aktuální accrued + projected s disclaimerem.
  5. Trial: tenant v trial periódě nedostane fakturu; trial konec = příští 1.
  6. Dunning: neuhrazená faktura projde 3 retry → PAST_DUE → grace → SUSPENDED záznamu v DB; živé pody/namespace nedotčeny.
  7. Hosting spend cap: při překročení hosting_spending_limit_usd se akruál zastaví (cap enforcement); alert email odeslan.
  8. todo-list.talkide.app stále běží bez přerušení po celé F2.

Klíčové závislosti

  • F1 hotová (entita environment existuje, každý tenant má DEFAULT „TalkIDE”).
  • OpenCost nasazen v K8s clusteru (talkide-infra).
  • hosting_billing_account, hosting_invoice, hosting_credit_ledger, hosting_cost_events tabulky z UC-10009 DESIGN datového modelu.
  • Mailgun (ADR-025) funkční (pro dunning e-maily).

Nové Liquibase changesety (F2)

⚠️ Tato čísla jsou zastaralá a informativní. Přesná čísla changesetů a kompletní seznam viz implementovatelná UC-10012 (F2 changesety = 0034–0039).

SouborObsah
0032-add-environment-id-to-hosting-cost-events.xmlALTER TABLE hosting_cost_events ADD COLUMN environment_id BIGINT NULL REFERENCES environment(id)
0033-add-environment-id-to-hosting-credit-ledger.xmlanalogicky pro hosting_credit_ledger
0034-create-hosting-billing-account.xmlnová tabulka dle UC-10009 DESIGN
0035-create-hosting-invoice.xmlnová tabulka dle UC-10009 DESIGN
0036-add-hosting-spending-limit-to-user-budget.xmlALTER TABLE user_budget ADD COLUMN hosting_spending_limit_usd NUMERIC(10,2) NULL

F3 — Create/Manage Environment UC (SHARED, user-created)

Scope

  • Create Environment: user vytvoří nové prostředí (kind=USER_CREATED, resource_mode=SHARED). Validace: env-slug RFC-1123, délka ≤ 20, unikátní v rámci tenanta, not-in reserved list (talkide + globální reserved slugs).
  • Nový SHARED namespace: při Create Environment se provisionuje nový K8s namespace {tenant}-{env-slug} (idempotentní, ADR-015 vzor, EnvironmentProvisioner — nový wrapper zavedený v UC-10013, protože existující NamespaceProvisioner má hardcoded tenant-{slug} signaturu). environment.namespace_ref se nastaví na nové jméno.
  • Delete Environment: odmítne deletable=false s 409 CONFLICT_ENVIRONMENT_NOT_DELETABLE. Pro deletable=true (USER_CREATED): deprovision namespace (ADR-015 teardown), hard-delete environment záznamu (DELETE FROM environment; FK projects.environment_id → NULL přes ON DELETE SET NULL, changeset 0040).
  • Get Environment detail: GET /api/v1/environments/{id}.
  • List Environments: rozšíření existujícího GET /api/v1/environments (z F1) — nyní může vrátit víc než 1 prostředí.
  • Project deployment-target: projects tabulka dostane environment_id FK (nullable pro F3 rollout — F1/F2 projekty bez explicitní volby = implicitně DEFAULT „TalkIDE”). Create Project UI dostane volitelný selector prostředí.
  • FE Environment management: nová sekce „Environments” v nastavení tenantu. Seznam prostředí, tlačítko Create, Delete (chráněno deletable=false guardem).

Acceptance kritéria F3

  1. User vytvoří prostředí „TEST” (SHARED) → vznikne namespace {tenant}-test s ResourceQuota; environment záznam v DB s namespace_ref.
  2. Nasazení projektu do „TEST” funguje (Publish target volba v UI).
  3. Delete „TEST” → namespace deprovisionován; environment DEPROVISIONING → smazán; projekt bez deployment-targetu fallback na DEFAULT.
  4. Delete DEFAULT „TalkIDE” → 409 CONFLICT_ENVIRONMENT_NOT_DELETABLE.
  5. env-slug validace: rezervované (talkide, www, api, …) → 409/400.
  6. todo-list.talkide.app a DEFAULT environment nedotčeny.
  7. Faktura (F2) ukáže 2 řádky (TalkIDE + TEST) při aktivním TEST prostředí.

Klíčové závislosti

  • F2 hotová (billing napojení funguje pro přibývající prostředí).
  • EnvironmentProvisioner wrapper (nový, ADR-014/ADR-015 vzor) — kompletní kontrakt + K8s/Noop implementace viz UC-10013.
  • FE komponenta „Environments” (nová stránka/sekce).

Nové Liquibase changesety (F3)

⚠️ Číslo 0037 je zastaralé a informativní. Přesná čísla changesetů a kompletní XML obsah viz implementovatelná UC-10013 (F3 changeset = 0040, sekvenčně za F2 changesety 0034–0039).

SouborObsah
0040-add-environment-id-to-projects.xmlALTER TABLE projects ADD COLUMN environment_id BIGINT NULL REFERENCES environment(id) ON DELETE SET NULL + index idx_projects_environment_id

F4 — Deployment wiring + cut-over živých tenantů

Rozpracováno do UC-10014 — plně implementovatelná UC pro F4.

Scope F4 byl po sladění s druhým týmem (2026-05-20) zúžen: F4 = deployment wiring + cut-over. ADR-024 worker extraction je práce druhého týmu (talkide-worker), HARD enforcement je odsunut do F5.

Scope (high-level)

  • Jednotný namespace tvar {tenant-slug}-{environment-slug} pro všechna prostředí. DEFAULT „TalkIDE” má env-slug talkide{tenant-slug}-talkide. Nový tvar je bez prefixu tenant- (dnešní tvar tenant-{slug}).
  • Deployment routing podle prostředí: deployment a build pipeline (K8sAppDeployer, K8sIngressProvisioner, KanikoBuildService, KanikoBuildLogStreamService, K8sNamespaceProvisioner) dnes hardcodují tenant-{slug}. F4 zavádí NamespaceResolver — published deploy routuje do namespace prostředí projektu, preview deploy vždy do DEFAULT „talkide”.
  • Resource naming: preview {project-slug}-preview, published {project-slug} (bez suffixu). Nahrazuje app-{slug}-dev / app-{slug}-prod.
  • project.environment_id routing + backfill: NULL → fallback na DEFAULT prostředí tenanta. Backfill migrace nastaví existující projekty s NULL.
  • Cut-over živých tenantů (popelkam, h): jednorázová koordinovaná operace v maintenance okně (ruční runbook). Součástí je normalizace slugu popelkam-892950971785850popelkam. Žádná automatizovaná služba.
  • F4 nemění DB schéma (backfill je data, ne schema; cut-over UPDATE jsou data pro 2 konkrétní tenanty).

Acceptance kritéria F4

  1. Published deploy routuje do namespace prostředí projektu ({tenant}-{env-slug}).
  2. Preview deploy/build routuje vždy do DEFAULT namespace {tenant}-talkide.
  3. Resource naming {slug} (published) / {slug}-preview (preview).
  4. Cost attribution funguje pro nový tvar namespace.
  5. Backfill: projekty s NULL environment_id navázány na DEFAULT prostředí.
  6. Cut-over: popelkam a h srovnány na nový namespace tvar; todo-list.talkide.app funkční po cut-overu (řešeno maintenance oknem, projekty jsou scale-to-zero).
  7. Namespace {tenant}-{env} garantovaně ≤ 63 znaků — TenantSlugValidator.MAX_LENGTH zpřísněn na 42.

Klíčové závislosti

  • F3 hotová (mechanika prostředí ověřena na throwaway prostředích).
  • Sladění s druhým týmem (talkide-worker) — žádná souběžná změna namespaces.
  • NamespaceResolver (nový BE komponent) — kontrakt viz UC-10014.

F5 — HARD enforcement + DEDICATED resource_mode (post-alfa)

F5 se implementuje post-alfa (OD-4, LOCKED). Tento scope je informativní a nezávazný — finalizuje se až ve správný čas.

Scope — HARD enforcement (scale-to-zero)

  • HARD scale-to-zero (OD-2, LOCKED): při neuhrazené infra faktuře po PLNÉ dunning sekvenci (F2 SOFT enforcement → DB stav SUSPENDED) → skutečný scale(0) všech Deploymentů tenanta. Implementačně: HostingEnforcementService → K8s scale --replicas=0 pro všechny Deployments ve všech namespaces tenanta; obnovení platby → scale zpět na 1.
  • EnvironmentStatus.SUSPENDED (enum hodnota už existuje z F1) — F5 ji začne aktivně používat pro infra akci. Případný auditní sloupec (suspended_at) se rozhodne při F5 implementaci.
  • Tenant-wide enforcement (OD-2 LOCKED) — platí i pro DEFAULT „TalkIDE” prostředí.
  • Pozn.: HARD enforcement byl původně plánován pro F4; po sladění scope (2026-05-20) přesunut do F5, aby F4 zůstalo soustředěné na deployment wiring.

Scope — DEDICATED resource_mode

  • resource_mode=DEDICATED zpřístupněno v Create Environment UI (gated plánem / feature flag — jen pro oprávněné tenanty).
  • Per-env dedikovaný DO Managed PG cluster (ADR-023 §7 escape hatch jako produkt): provisioner vytvoří nový DO PG cluster, per-app roli a schéma, napojí PgBouncer. App secret přepnut na dedikovaný endpoint.
  • Downgrade path: DEDICATED → SHARED = re-point app secret na sdílený pooler (ADR-023 §6 invariant — aplikační kód se nemění, jen secret).
  • Billing: DEDICATED prostředí nese vyšší cost (dedikovaný cluster) → reflektováno na per-env faktura řádku.
  • ResourceQuota: DEDICATED prostředí může mít vlastní node pool nebo předdefinované třídy (S/M/L dle konfigurace).

Acceptance kritéria F5

  1. HARD enforcement: simulace SUSPENDED tenant → všechny Deploymenty na 0 replik; obnovení platby → scale zpět na 1. Test na throwaway prostředí, NIKDY na „TalkIDE” produkce.
  2. User zvolí DEDICATED pro „PROD” → dedikovaný DO PG cluster provisionován do ~5 minut; app mluví přes dedikovaný PgBouncer endpoint.
  3. SHARED prostředí nedotčena (DEDICATED je ortogonální).
  4. Downgrade DEDICATED → SHARED: app secret přepnut; žádná data ztracena (data zůstávají v DEDICATED clusteru; migrace dat = separátní operace).
  5. Faktura ukáže správnou cenu za DEDICATED (vyšší než SHARED).

Klíčové závislosti

  • F4 hotová (per-env ns invariant plně živý).
  • ADR-023 §7 provisioner implementován (ProvisionDedicatedDbUseCase nebo rozšíření existujícího ProjectDatabaseProvisioner).
  • DO API pro cluster provisioning (DO Managed PG cluster create/delete).

be#125 disposition (informativní — přenést do GitLab)

ADR-026 §6 (be#125 disposition) navrhuje text pro PM → GitLab issue update. Stručně:

  • Původní problém be#125 (worker + build Joby + user-app pody nerozlišitelné v tenant-{slug}) z velké části zaniká pod ADR-026 F4+.
  • Reziduum (přechodné): dočasný label/ns split jen pro migrační F2–F4 období.
  • Reziduum (trvalé): orphan-namespace safety net v C.2 (namespace bez mapování → WARN + NEfakturovat).
  • Issue scope uzavřít po F4 migraci.

Was this page helpful?

Thanks for the feedback.