config je daň
Každý B2B produkt pro SMB začíná stejným malým kompromisem. Klient chce, aby schvalování faktur fungovalo trochu jinak, nebo potřebuje jeden stav navíc mezi „draft“ a „sent“, nebo trvá na tom, že account manageři mají vidět jeden tab, který nikdo jiný neuvidí. Tým kývne, protože je to levnější než se hádat, levnější než tlačit změnu procesu, levnější než riskovat deal. O půl roku později máte stránku Settings se 43 přepínači, třemi vnořenými accordiony, čtyřmi úrovněmi role overrides a test suite, která projde jen tehdy, když na nic nesáhnete.
Tenhle vzorec jsem viděl pořád dokola v ERP i CRM projektech, včetně toho, co stavíme ve Steezr pro startupy a SMB, hlavně v customer portálech, kde se od adminů čeká, že budou „konfigurovat systém“, místo aby ho používali. Tahle formulace by vás měla znervóznit. Ve většině případů jen znamená, že produktový tým vzdal těžká rozhodnutí a engineering pak kóduje lokální politiku každého zákazníka do databázového schématu.
Konfigurovatelnost něco stojí a týmy ji skoro vždycky podcení. Každá nová volba rozšiřuje prostor stavů, každá podmínka prosákne do oprávnění, UI textů, exportů, onboarding flow, dokumentace, seed dat, QA plánů i support skriptů. Nepřidáváte jedno checkbox políčko. Přidáváte další vesmír, který váš software musí navždy respektovat. Nejhorší je, že zákazníci to většinou nevnímají jako větší moc nad systémem. Vnímají to jako nejistotu. Nevědí, které nastavení je důležité, které kombinace vůbec podporujete, proč po zapnutí jednoho flagu zmizel report nebo proč se stejný workflow chová jinak ve dvou tenantech.
Jeden správný admin workflow je lepší než dvacet napůl konfigurovatelných workflow. Ostrý default s rozumnými omezeními shipuje rychleji, zaučuje rychleji, méně se rozbíjí a support má konečně něco, o čem se dá normálně přemýšlet. Většina SMB zákazníků nepotřebuje workflow engine. Potřebují software, který se bude chovat předvídatelně v úterý odpoledne, když office manažerka potřebuje před obědem uzavřít faktury.
test matrix lže
Obvyklá obhajoba těžké konfigurace je, že „core zůstává stejné“ a mění se jen povrch. To je pohádka. Jakmile settings ovlivňují oprávnění, automatizaci nebo přechody mezi stavy, žádné core už nemáte. Postavili jste generátor produktů.
Vezměte si úplně běžný Django admin backend s tenant-scoped settings uloženými v PostgreSQL JSONB, něco jako account.settings -> 'approvals' -> 'require_second_signoff'. Na začátku v pohodě. Pak další zákazník chce signoff jen nad amount > 5000, další chce jiné thresholdy podle oddělení, další chce výjimku pro manažery, další chce notifikace přes email a Slack, další nechce, aby approval blokoval generování PDF, protože jejich finance tým to „řeší ručně bokem“. Za chvíli se z původně čisté service metody stane tohle:
1if settings.require_second_signoff:2 if invoice.total_cents >= settings.signoff_threshold_cents:3 if settings.exempt_manager_role and user.role == "manager":4 pass5 elif settings.department_thresholds_enabled:6 threshold = settings.department_thresholds.get(invoice.department_id)7 if threshold and invoice.total_cents >= threshold:8 require_approval()9 else:10 require_approval()
Teď to ještě napojte na Next.js 14 admin UI, server actions, cache invalidation, audit logy a permission matici. Pak si užijte bug report: TypeError: Cannot read properties of undefined (reading 'enabled'), protože jeden tenant má částečně migrovaný settings objekt z loňského srpna. QA pak položí úplně logickou otázku: které kombinace vlastně podporujeme? Nikdo neví.
Tady neumírá velocity. Ne ve velkých rewrites, ale v deseti tisících lokálních výjimek. Cypress suite naroste z 30 minut na 95. Produkt neumí odhadovat delivery, protože každý estimate začíná větou „záleží, jaké settings to musí respektovat“. Support otevírá tickety, které vypadají triviálně, ale zaberou dva dny, protože je potřeba zrekonstruovat tenant-specific ruleset z přepínačů rozlezlých po čtyřech obrazovkách. Týmy tomu říkají flexibilita. Ve skutečnosti je to entropie s hezkou nálepkou.
kde config dává smysl
Nějaká konfigurace dává smysl. Jen jí do hlavního admin workflow patří opravdu málo.
Dobrá konfigurace obvykle spadá do pár kategorií. Branding, protože loga, barvy, jméno odesílatele v emailu nebo custom domény nerozbijí business logiku. Externí integrace, protože napojení na QuickBooks, Stripe, S3 nebo SMTP relay je ze své podstaty specifické pro konkrétní prostředí. Access control v rozumné míře, protože přiřazování lidí do předem definovaných rolí je normální a očekávané. Bezpečné bývají i číselné thresholdy, pokud jen ladí chování a nemění tvar samotného workflow, třeba retry limity, cadence připomínek k fakturám nebo session timeout.
Ta hranice je jednoduchá. Pokud setting mění, kdo může něco udělat, kdy se spustí background job nebo jaký label se objeví v headeru, většinou se to dá uřídit. Pokud mění pořadí hlavních akcí, vkládá tenant-specific stavy do lifecycle nebo vytváří alternativní interpretace stejného záznamu, stavíte pod jedním logem paralelní produkty.
Pro PM a foundery se hodí jedno jednoduché pravidlo: konfigurace, která systém ladí, je levná. Konfigurace, která definuje proces, je drahá. Ta první často může žít jako typed settings s validací. Ta druhá potřebuje produktového ownera, migrační strategii, dokumentaci, školení a trvalý engineering budget. Když obojí házíte do pytle jako „další admin volbu“, skončíte s monstrózní obrazovkou Settings, které nikdo nerozumí.
Klienty obvykle tlačíme k úzkému admin surface, hlavně v ERP a systémech na zpracování dokumentů, protože admini už tak mají dost kognitivní zátěže. Nechtějí navrhovat chování softwaru. Chtějí spravovat uživatele, řešit výjimky, opravit špatná data a jít dál. Produkt proto musí zakódovat proces. Admin panel má ukázat hrany systému, ne celé vnitřnosti.
feature flags, ne customer knobs
Spousta tenant settings by vůbec neměla být nastavení pro admina, ale feature flags pod kontrolou produktového týmu. To je výrazně čistší kontrakt.
Jestli variantní workflow potřebují tři zákazníci, nenuťte dalších 300, aby mu rozuměli. Dejte ho za server-side flag, scopeujte ho podle tenant ID, mějte ho podchycený v kódu a napište si exit plan. Záměrně na to používáme nudné nástroje, někdy Django s django-waffle==4.1.0, jindy obyčejnou tabulku account_features s explicitními sloupci, protože SQL je lepší než záhadné JSON bláto ve chvíli, kdy na tom záleží chování systému. Tohle úplně stačí:
1class AccountFeature(models.Model):2 account = models.OneToOneField(Account, on_delete=models.CASCADE)3 invoice_dual_approval = models.BooleanField(default=False)4 custom_export_v2 = models.BooleanField(default=False)5 ai_salesperson_beta = models.BooleanField(default=False)
Pak v kódu držte podmínku co nejblíž hranici:
1if account.features.invoice_dual_approval:2 return dual_approval_flow(invoice, user)3return standard_flow(invoice, user)
Vypadá to až moc jednoduše, a přesně o to jde. Produkt zapíná feature záměrně, support okamžitě vidí stav flagu, engineeři si podmínku najdou grepem a odstranění je reálné, protože každá výjimka má jméno i ownera. Srovnejte si to s obecným settings.workflow.mode = "advanced" plus pěti podvolbami, které novému vývojáři nic neřeknou a mají tendenci hromadit mrtvé kombinace.
Settings viditelné pro zákazníka mají být stabilní, nudné a bezpečné. Interní feature flags klidně můžou být ostré. Zákazník nepotřebuje přístup k ostrým nástrojům. Když se variantní workflow osvědčí u dost tenantů, povyšte ho na default produktu nebo ho formalizujte jako plugin. Pokud zůstane okrajové, držte ho bokem a naceněte ho podle toho.
pluginy pro skutečné odchylky
Některé firmy opravdu potřebují reálné rozdíly v procesech. Tam pluginy porážejí hlubokou konfiguraci pokaždé.
Plugin boundary vás donutí být upřímní. Musíte definovat extension pointy, event kontrakty, validační pravidla a to, co se stane při chybě. Přestanete předstírat, že každý workflow patří do jednoho admin formuláře. V Django systému to může znamenat třeba to, že signals jsou zakázané pro core doménovou logiku, protože skrytý control flow je jed, a místo toho vystavíte explicitní hooky jako before_invoice_finalize, after_payment_reconciled nebo build_export_rows. Plugin si může registrovat callables, nebo když potřebujete izolaci, pustíte samostatný worker, který konzumuje doménové eventy z PostgreSQL nebo Redis a zapisuje zpět přes úzké API.
Dobře funguje i jednoduchý Python registry:
1PLUGIN_HOOKS = {2 "build_export_rows": [],3}45def register(hook_name, fn):6 PLUGIN_HOOKS[hook_name].append(fn)
Custom podivnosti pak žijí na jednom místě, mají verze, review a dají se testovat samostatně. Výchozí admin workflow zůstává nedotčený. Dokumentace core produktu zůstává čitelná. Support může říct „tenant ACME má zapnutý export plugin acme_export_v3“ místo prolézání settings, které z poloviny řídí transformaci dat a z poloviny viditelnost v UI.
U SMB produktů je to důležité dvojnásob, protože jeden trochu enterprise zákazník snadno ohne roadmapu pro všechny ostatní. Plugin model vám dovolí říct ano, aniž by vám shnil střed produktu. Čistí to i pricing. Custom proces, custom rozpočet. Core workflow, pevné chování produktu. To lidé chápou. Čemu nerozumí, je situace, kdy kliknutí na náhodný checkbox v Advanced Settings ve stejném releasu rozbije webhook a zároveň změní schvalování.
jak ten bordel rozmotat
Jestli už dnes máte v produktu bažinu admin settings, vyrvat ji naráz je skvělý způsob, jak vyvolat zákaznickou vzpouru. Potřebujete pomalou migraci a tvrdá data.
Nejdřív si udělejte inventuru všech settings a rozdělte je do čtyř skupin: nechat jako user-facing config, přesunout na interní feature flag, nahradit plugin hookem, úplně odstranit. Buďte nemilosrdní. Vytáhněte reálná usage data z databáze, ne historky od sales. Viděl jsem settings obrazovky, kde byla půlka přepínačů zapnutá u méně než 2 % tenantů a tři se za dva roky nikdy nezměnily z defaultu. Ty mají zmizet.
Pak zmrazte nové settings, pokud neprojdou vysokou laťkou. Tu laťku si napište. Stačí jednostránkové RFC: účel, owner, očekávaná životnost, zasažené části kódu, migrační plán. Když to nikdo nechce sepsat, ten setting nemá existovat.
Potom zjednodušte UI dřív než backend. Označte málo hodnotné settings jako deprecated, schovejte je za rozbalení „starší možnosti“, doplňte inline text s vysvětlením nového defaultního chování a pak tenanty migrujte po dávkách. U rizikovějších změn ukažte tenant-specific oznámení s daty a konkrétními dopady, ne vágní produktový marketing. „Od 15. 4. 2026 bude schvalování faktur používat standardní dvoukrokový flow. Váš současný threshold 10 000 CZK zůstane zachovaný.“ Přesně takový text zabraňuje panice.
Dále logujte všechno. Audit záznamy, supportem viditelné souhrny feature flags, stav migrace, efektivní popis workflow. Support panel s generovaným shrnutím jako Approval flow: standard, dual approval: off, export plugin: none šetří absurdní množství času.
Poslední část, které se týmy vyhýbají, je zavolat zákazníkům a změnu s nimi projít. Foundeři a PM rádi mluví abstraktně o flexibilitě, dokud nesedí na telefonu s ops manažerkou, která přizná, že na advanced settings stránku nikdo rok nesáhl, protože se jí báli. Právě tenhle hovor bývá moment, kdy se produkt konečně zjednoduší.
