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áze | Scope (stručně) | Závislost | Dopad na live user |
|---|---|---|---|
| F0 | UC-10008 marže do účtování | — nezávislá | žádný (marže 0 = no-op) |
| F1 | Entita environment + lazy default „TalkIDE” | — foundation | žádný (čistě additivní) |
| F2 | Billing read-path + postpaid akruál + měsíční faktura per-env řádky + SOFT enforcement | F1 hotová | minimální (trial DP-1; žádný suspend) |
| F3 | Create/Manage Environment UC (SHARED, user-created) | F2 hotová | žádný (opt-in) |
| F4 | Deployment wiring (namespace routing podle prostředí) + cut-over živých tenantů na nový ns tvar → UC-10014 | F3 hotová | citlivá (živý todo-list.talkide.app — řešeno maintenance oknem) |
| F5 | HARD 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-workerdo samostatného repa/podu) NENÍ fáze Environment konceptu. Je to souběžný projekt druhého týmu (talkide-workerrepo, be#213–be#218). F4 vůči workeru garantuje jen to, že DEFAULT namespace{tenant-slug}-talkideexistuje 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 environmentpro 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_eventsINSERT senvironment_id→hosting_credit_ledgerDEBIT řá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_accountentita (UC-10009 DESIGN datový model, beze změny struktury). - FE billing breakdown:
GET /api/v1/billing/hosting/estimatevrátí per-env řádky (accrued + projected). „Next invoice on 1st” jazyk (DP-6). - Trial (DP-1):
hosting_billing_account.trial_ends_atnastaven při 1. Publish; nulové akruály v trial periódě;trial_dayszapplication.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_usdsloupec nauser_budget(NEreuse UC-10005spending_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 →SUSPENDEDnahosting_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
- OpenCost scrape běží periodicky a plní
hosting_cost_eventss korektnímenvironment_idpro všechny aktivní tenanty. - Měsíční faktura (1. v měsíci) vygenerována a odeslána Stripe pro tenanty mimo trial periodu.
- Faktura obsahuje per-environment line items (alespoň 1 řádek „TalkIDE”).
- FE breakdown zobrazuje aktuální accrued + projected s disclaimerem.
- Trial: tenant v trial periódě nedostane fakturu; trial konec = příští 1.
- Dunning: neuhrazená faktura projde 3 retry →
PAST_DUE→ grace →SUSPENDEDzáznamu v DB; živé pody/namespace nedotčeny. - Hosting spend cap: při překročení
hosting_spending_limit_usdse akruál zastaví (cap enforcement); alert email odeslan. todo-list.talkide.appstále běží bez přerušení po celé F2.
Klíčové závislosti
- F1 hotová (entita
environmentexistuje, každý tenant má DEFAULT „TalkIDE”). - OpenCost nasazen v K8s clusteru (talkide-infra).
hosting_billing_account,hosting_invoice,hosting_credit_ledger,hosting_cost_eventstabulky 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).
| Soubor | Obsah |
|---|---|
0032-add-environment-id-to-hosting-cost-events.xml | ALTER TABLE hosting_cost_events ADD COLUMN environment_id BIGINT NULL REFERENCES environment(id) |
0033-add-environment-id-to-hosting-credit-ledger.xml | analogicky pro hosting_credit_ledger |
0034-create-hosting-billing-account.xml | nová tabulka dle UC-10009 DESIGN |
0035-create-hosting-invoice.xml | nová tabulka dle UC-10009 DESIGN |
0036-add-hosting-spending-limit-to-user-budget.xml | ALTER 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íNamespaceProvisionermá hardcodedtenant-{slug}signaturu).environment.namespace_refse nastaví na nové jméno. - Delete Environment: odmítne
deletable=falses409 CONFLICT_ENVIRONMENT_NOT_DELETABLE. Prodeletable=true(USER_CREATED): deprovision namespace (ADR-015 teardown), hard-delete environment záznamu (DELETE FROM environment; FKprojects.environment_id→ NULL přesON 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:
projectstabulka dostaneenvironment_idFK (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=falseguardem).
Acceptance kritéria F3
- User vytvoří prostředí „TEST” (SHARED) → vznikne namespace
{tenant}-tests ResourceQuota; environment záznam v DB snamespace_ref. - Nasazení projektu do „TEST” funguje (Publish target volba v UI).
- Delete „TEST” → namespace deprovisionován; environment
DEPROVISIONING → smazán; projekt bez deployment-targetu fallback na DEFAULT. - Delete DEFAULT „TalkIDE” → 409 CONFLICT_ENVIRONMENT_NOT_DELETABLE.
- env-slug validace: rezervované (
talkide,www,api, …) → 409/400. todo-list.talkide.appa DEFAULT environment nedotčeny.- 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í).
EnvironmentProvisionerwrapper (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
0037je 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).
| Soubor | Obsah |
|---|---|
0040-add-environment-id-to-projects.xml | ALTER 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-slugtalkide→{tenant-slug}-talkide. Nový tvar je bez prefixutenant-(dnešní tvartenant-{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). Nahrazujeapp-{slug}-dev/app-{slug}-prod. project.environment_idrouting + backfill:NULL→ fallback na DEFAULT prostředí tenanta. Backfill migrace nastaví existující projekty sNULL.- Cut-over živých tenantů (
popelkam,h): jednorázová koordinovaná operace v maintenance okně (ruční runbook). Součástí je normalizace slugupopelkam-892950971785850→popelkam. Žá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
- Published deploy routuje do namespace prostředí projektu (
{tenant}-{env-slug}). - Preview deploy/build routuje vždy do DEFAULT namespace
{tenant}-talkide. - Resource naming
{slug}(published) /{slug}-preview(preview). - Cost attribution funguje pro nový tvar namespace.
- Backfill: projekty s NULL
environment_idnavázány na DEFAULT prostředí. - Cut-over:
popelkamahsrovnány na nový namespace tvar;todo-list.talkide.appfunkční po cut-overu (řešeno maintenance oknem, projekty jsou scale-to-zero). - Namespace
{tenant}-{env}garantovaně ≤ 63 znaků —TenantSlugValidator.MAX_LENGTHzpří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→ K8sscale --replicas=0pro 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=DEDICATEDzpří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
- 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.
- User zvolí DEDICATED pro „PROD” → dedikovaný DO PG cluster provisionován do ~5 minut; app mluví přes dedikovaný PgBouncer endpoint.
- SHARED prostředí nedotčena (DEDICATED je ortogonální).
- Downgrade DEDICATED → SHARED: app secret přepnut; žádná data ztracena (data zůstávají v DEDICATED clusteru; migrace dat = separátní operace).
- 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 (
ProvisionDedicatedDbUseCasenebo rozšíření existujícíhoProjectDatabaseProvisioner). - 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.
Thanks for the feedback.