Steven
Steven5 min čtení

Jedna codebase, dvě aplikace: jak na white-label bez forku

GeekBye a Pavleur jsou dvě desktopové aplikace s odlišným brandem, postavené z jediného repozitáře — žádný fork, žádná duplicitní codebase. Tady je mašinerie fungující v čase buildu, díky které se jedna codebase zkompiluje do dvou produktů, a jednořádková chyba, kvůli které se naše druhá aplikace představovala špatným jménem.

Inženýrství
Architektura
Build
Vydání GeekBye
Jedna codebase, dvě aplikace: jak na white-label bez forku

GeekBye je zapisovatel schůzek. Pavleur je AI aplikace na trénink pohovorů. Vypadají jako dva různé produkty, protože to jsou dva různé produkty — ale staví se z jedné codebase, bez forku a bez větve, která se rozjíždí. Tohle je inženýrská strana white-labelingu: ne „proč prodávat brandovanou aplikaci" (to je jiný článek), ale jak vlastně zkompilujete jeden repozitář do dvou aplikací — a ta neatraktivní chyba, která se skrývá v každém white-label systému, dokud ji nezačnete aktivně hledat.

Generujte, nevětvěte

Špatný způsob, jak provozovat dva produkty z jedné codebase, je rozesít po aplikaci if (product === 'pavleur'), nebo udělat fork a modlit se, aby se ty dvě kopie nikdy nerozešly. Obojí rychle hnije.

Přístup GeekBye je generování kódu v čase buildu. Každý produkt má konfigurační soubor — configs/geekbye/config.ts, configs/pavleur/config.ts — s jeho identitou: název, bundle id, URL protokol, repozitář vydání pro automatické aktualizace a tak dále. Před buildem se spustí jeden script:

node scripts/build-product.js pavleur

Ten script přečte konfiguraci zvoleného produktu a udělá tři konkrétní věci:

  1. Vygeneruje dva konfigurační moduly — jeden pro renderer (src/config/product.ts), jeden pro main proces (electron/config/product.ts) — každý orazítkovaný hlavičkou „NEUPRAVOVAT RUČNĚ — změny budou přepsány". Zbytek aplikace si prostě importuje productName, applicationId a protocol z konfigurace a nikdy nepřemýšlí, kterým brandem je.
  2. Zkopíruje jen assety daného brandu — ikony, malé logo, ikonu toast notifikací. Build GeekBye fyzicky neobsahuje ani pixel grafiky Pavleuru a naopak. Není co uniknout.
  3. Přepíše package.json (u release buildů) — app id, název produktu, URL protokol, GitHub repozitář vydání, kam se publikuje, a — což potěší — brandovaný text žádosti o přístup k mikrofonu, takže se macOS zeptá „Pavleur žádá o přístup k mikrofonu", ne špatný brand.

Celá aplikace je brand-agnostická; brand se injektuje v čase buildu. Neexistuje žádný runtime přepínač produktů, který by šlo pokazit, protože za běhu je vždycky zapečený jen jeden produkt.

Jeden backend, dva brandy

Obě aplikace mluví se stejným backendem. Jak tedy server pozná, ke kterému produktu — a ke kterým cenám, promptům a limitům — požadavek patří?

Dva signály, oba nastavené v čase buildu. Zaprvé application id (geekbye nebo pavleur) zapečené v konfiguraci a posílané s požadavky, aby backend uměl směrovat na chování správného produktu. Zadruhé User-Agent, který klient připojuje ke každému volání backendu, ve tvaru Product/version (platform) — např. Pavleur/1.2.5 (win32) nebo GeekBye/1.7.3 (darwin). Tahle jedna hlavička dává backendu atribuci podle produktu i podle operačního systému zadarmo, bez samostatného analytického pole. Automatické aktualizace mezitím zůstávají izolované: každý produkt publikuje do vlastního repozitáře vydání, takže aktualizace GeekBye nikdy nemůže být naservírována instalaci Pavleuru.

Onboarding se také liší podle produktu — průvodce GeekBye je o přepisu schůzek, průvodce Pavleuru o tréninku pohovorů — a ten správný se vybírá za běhu podle jediného zapečeného application id. Stejná mašinerie, dvoje vstupní dveře.

Ta chyba: když si Pavleur říkal GeekBye

Tady je historka z fronty — a je to ta, jejíž verzi má každý white-label systém.

Generování konfigurace fungovalo. Ikony se přepínaly. Dotaz na mikrofon byl brandovaný. Protokoly i bundle id seděly. Podle všech viditelných měřítek build Pavleuru byl Pavleur. A přesto se po nějakou dobu každý build Pavleuru hlásil backendu pod jménem GeekBye.

Viníkem byl jediný natvrdo zapsaný string a schovával se na tom nejméně okouzlujícím místě, jaké si dovedete představit: v sestavovači User-Agentu, zastrčeném uvnitř síťového retry pomocníka. Všechno, co viděl uživatel, procházelo konfigurací, ale tahle jedna hluboko zahrabaná instalatérská utilita v sobě pořád měla literál `GeekBye/${version}`. Nikoho nenapadne přemýšlet o retry utilitě jako o „brandingu", takže ji nikdo nezkontroloval. Oprava měla čtyři řádky — naimportovat dynamický productName z konfigurace a interpolovat ho místo natvrdo zapsaného brandu — ale poučení je celá pointa:

White-labeling není „změnilo se logo". Je to „prochází každý identitní string konfigurací". A poslední opozdilci nikdy nežijí v UI, kde byste hledali. Žijí v User-Agentu, v obsluze deep-link protokolu, v textu žádosti o oprávnění, v chybových hláškách — v instalatérské vrstvě, kterou nikdo neřadí pod „brand". Jediná spolehlivá obrana je zacházet s brandovým literálem jako s něčím, co aktivně lovíte: grepněte codebase na natvrdo zapsané jméno a shoďte build, pokud se objeví kdekoli mimo konfiguraci, která ho definovat.

Tři věci, které nás white-labeling naučil

  1. Generujte, nevětvěte. Codegen dvou drobných konfiguračních modulů v čase buildu plus selektivní kopírování assetů poráží jak fork, tak runtime houštinu produktových kontrol. Aplikace zůstává brand-agnostická; brand je vstup buildu.
  2. Identitní stringy prosakují do instalatérské vrstvy. UI je snadných 90 %. Těžkých 10 % je User-Agent, URL protokol, string žádosti o mikrofon, texty chyb. Protáhněte je všechny jedním exportem productName / applicationId — a grepujte na syrové jméno brandu jako CI bránu, aby zbloudilý literál nikdy nemohl doputovat k uživatelům.
  3. Jeden backend, mnoho brandů, rozlišujte pomocí id a hlavičky. Application id z času buildu plus User-Agent ve tvaru Product/version (platform) dává atribuci podle produktu i podle platformy s nulovou duplicitní infrastrukturou — a čistě odděluje neměnnou identitu z času buildu od chování za běhu.

Produktovou a soukromí se týkající stránku provozování white-label zapisovatele pod vlastním brandem najdete v white-label AI zapisovateli. Tohle je šestá kapitola příběhu v1, který se stane GeekBye v2 — předchozí kapitolu najdete v co ve skutečnosti znamená vydání se 127 commity (v1.7.0); a celý oblouk v anatomii dodávání softwaru k dokonalosti.

Související články

Jedna proměnná CSS, pět kol revize a Swift toolchain, který lhal
Steven
Steven6 min čtení

Jedna proměnná CSS, pět kol revize a Swift toolchain, který lhal

GeekBye v2.0.7 udělal celý overlay nastavitelně průsvitným — což zní jako jednořádková změna v CSS a rozhodně nebylo. Skutečný příběh je to, co odhalila revize kódu: dvě plochy, které odmítaly zprůhlednět, nahrávací lišta, jež vypadala špatně při stejné neprůhlednosti, a zkompilovaná binárka, která poskočila o 672 bajtů, protože naše vlastní dokumentace řekla revidujícímu špatnou verzi Swiftu.

Inženýrství
Design
Build
Smazali Jsme 5 000 Řádků Zvukového Kódu — a Přepisy Se Začaly Zobrazovat Dvakrát
Steven
Steven6 min čtení

Smazali Jsme 5 000 Řádků Zvukového Kódu — a Přepisy Se Začaly Zobrazovat Dvakrát

GeekBye v1.6 vytrhlo dva zařízení běžící Swift transkriptory a nahradilo je jedním sjednoceným řetězcem — čistý úbytek přes 5 000 řádků, provedený zatímco lidé byli uprostřed schůzky přímo v aplikaci. Pak se přepisy začaly objevovat dvakrát, protože chyba se přesunula do jediné vrstvy, která si pořád myslela, že existují dva engine.

Inženýrství
Přepis
Architektura
Co ve skutečnosti znamená vydání se 127 commity
Steven
Steven5 min čtení

Co ve skutečnosti znamená vydání se 127 commity

GeekBye v1.7.0 bylo 127 commitů za jedenáct dní. Zvenčí to vypadá jako sto drobností. Zevnitř to byly dvě velké funkce spletené dohromady — a jedna z nich vznikla na špatném místě, pak byla vytržena a uprostřed vydání znovu postavena. Tady je anatomie velkého vydání.

Inženýrství
Vydání
Architektura