
Üks koodibaas, kaks rakendust: white-label ilma forkimata
GeekBye ja Pavleur on kaks eri brändiga töölauarakendust, mis on ehitatud ühest repositooriumist — ilma forkita, ilma dubleeritud koodibaasita. Siin on ehitusaegne masinavärk, mis paneb ühe koodibaasi kompileeruma kaheks tooteks, ja üherealine viga, mille tõttu meie teine rakendus tutvustas end vale nimega.
GeekBye on koosolekute märkmete rakendus. Pavleur on AI-põhine intervjuuharjutamise rakendus. Nad näevad välja nagu kaks eri toodet, sest nad ongi kaks eri toodet — aga nad on ehitatud ühest koodibaasist, ilma forkita ja ilma haruta, mis laiali triivib. See on white-label-imise inseneripool: mitte "miks müüa brändiga rakendust" (see on teine postitus), vaid kuidas sa tegelikult kompileerid ühe repositooriumi kaheks rakenduseks — ja see ebaglamuurne viga, mis peidab end igas white-label-süsteemis, kuni sa seda otsima lähed.
Genereeri, ära hargne
Vale viis kahe toote jooksutamiseks ühest koodibaasist on puistata if (product === 'pavleur') üle kogu rakenduse või forkida ja loota, et kaks koopiat kunagi laiali ei triivi. Mõlemad mädanevad kiiresti.
GeekBye lähenemine on ehitusaegne koodigenereerimine. Igal tootel on konfiguratsioonifail — configs/geekbye/config.ts, configs/pavleur/config.ts — mis hoiab tema identiteeti: nime, bundle id-d, URL-protokolli, automaatuuenduste väljalasete repositooriumi ja nii edasi. Enne buildi jookseb üks skript:
node scripts/build-product.js pavleur
See skript loeb valitud toote konfiguratsiooni ja teeb kolm konkreetset asja:
- Genereerib kaks konfiguratsioonimoodulit — ühe rendererile (
src/config/product.ts), teise põhiprotsessile (electron/config/product.ts) — kumbki templiga "DO NOT EDIT MANUALLY — changes will be overwritten" päises. Ülejäänud rakendus lihtsalt impordib konfistproductName,applicationIdjaprotocolega mõtle kunagi sellele, milline bränd ta on. - Kopeerib ainult selle brändi varad — ikoonid, väikese logo, teavituste ikooni. GeekBye build ei sisalda füüsiliselt ühtegi Pavleur-i graafikat ja vastupidi. Pole midagi, mis saaks lekkida.
- Kirjutab
package.json-i üle (release-buildidel) — rakenduse id, tootenime, URL-protokolli, GitHubi väljalasete repo, kuhu avaldada, ja, mis kena, brändiga mikrofoniloa teksti, et macOS küsiks "Pavleur soovib ligipääsu mikrofonile", mitte vale brändiga.
Kogu rakendus on brändineutraalne; bränd süstitakse sisse ehitusajal. Pole käitusaegset tootelülitit, mida valesti seada, sest käitusajal on alati sisse küpsetatud ainult üks toode.
Üks backend, kaks brändi
Mõlemad rakendused suhtlevad sama backendiga. Kuidas server siis teab, millisele tootele — ja millisele hinnastusele, promptidele ja limiitidele — päring kuulub?
Kaks signaali, mõlemad määratud ehitusajal. Esiteks application id (geekbye või pavleur), mis on konfi sisse küpsetatud ja saadetakse päringutega kaasa, et backend saaks suunata õige toote käitumisele. Teiseks User-Agent, mille klient lisab igale backendi-kutsele, kujul Product/version (platform) — nt Pavleur/1.2.5 (win32) või GeekBye/1.7.3 (darwin). See üks päis annab backendile tasuta nii toote- kui ka OS-i-põhise atributsiooni, ilma eraldi analüütikaväljata. Automaatuuendused jäävad seejuures isoleerituks: kumbki toode avaldab oma väljalasete repositooriumisse, nii et GeekBye uuendust ei saa kunagi serveerida Pavleur-i installile.
Ka onboarding erineb tooteti — GeekBye viisard räägib koosolekute transkriptsioonist, Pavleur-i oma intervjuuharjutamisest — ja õige valitakse käitusajal selle ühe sisseküpsetatud application id põhjal. Sama masinavärk, kaks välisust.
Viga: kui Pavleur nimetas end GeekBye-ks
Siin on sõjalugu, ja see on just see, millest igal white-label-süsteemil on oma versioon.
Konfi genereerimine töötas. Ikoonid vahetusid. Mikrofoniküsimus oli brändiga. Protokollid ja bundle id-d olid õiged. Iga nähtava mõõdupuu järgi Pavleur-i build oligi Pavleur. Ja ometi helistas mõnda aega iga Pavleur-i build koju backendile, nimetades end GeekBye-ks.
Süüdlane oli üksainus kõvakodeeritud string ja see peitis end kõige ebaglamuursemas võimalikus kohas: User-Agenti ehitajas, pistetuna võrgu retry-abilise sisse. Kõik kasutajale nähtav oli konfi kaudu suunatud, aga sellel ühel sügava torustiku utiliidil oli sees ikka veel literaal `GeekBye/${version}`. Keegi ei mõtle retry-utiliidist kui "brändingust", nii et keegi polnud seda kontrollinud. Parandus oli neli rida — importida konfist dünaamiline productName ja interpoleerida see kõvakodeeritud brändi asemele — aga õppetund ongi kogu mõte:
White-label ei ole "kas logo vahetus ära". See on "kas iga identiteedistring käib konfi kaudu." Ja viimased vastupanijad ei ela kunagi UI-s, kust sa vaataksid. Nad elavad User-Agentis, deep-link-protokolli käsitlejas, loaküsimuste tekstides, veateadetes — torustikus, mida keegi ei liigita "brändi" alla. Ainus usaldusväärne kaitse on kohelda brändiliteraali kui midagi, mida aktiivselt jahid: grep-i koodibaasist kõvakodeeritud nime ja kukuta build läbi, kui see ilmub kuskil väljaspool konfi, mis peabki seda defineerima.
Kolm asja, mida white-label meile õpetas
- Genereeri, ära hargne. Kahe pisikese konfimooduli ehitusaegne genereerimine pluss valikuline varade kopeerimine võidab nii forkimist kui ka käitusaegset tootekontrollide padrikut. Rakendus jääb brändineutraalseks; bränd on buildi sisend.
- Identiteedistringid lekivad torustikku. UI on lihtne 90%. Raske 10% on User-Agent, URL-protokoll, mikrofoniloa string, veatekstid. Suuna nad kõik läbi ühe
productName/applicationIdekspordi — ja grep-i toorest brändinime CI-väravana, et hulkuv literaal ei saaks kunagi väljalaskesse jõuda. - Üks backend, mitu brändi, erista id ja päise järgi. Ehitusaegne application id pluss
Product/version (platform)User-Agent annab toote- ja platvormipõhise atributsiooni nulli dubleeritud infrastruktuuriga — eraldades puhtalt muutumatu ehitusaegse identiteedi käitusaegsest käitumisest.
Toote- ja privaatsuspoole kohta — kuidas jooksutada white-label-märkmerakendust oma brändi all — vaata white-label AI-märkmerakendust. See on kuues peatükk v1 loos, millest saab GeekBye v2 — eelmise peatüki jaoks vaata mis on tegelikult 127 commiti sisaldav väljalase (v1.7.0); ja kogu kaare jaoks tarkvara täiuslikkuseni tarnimise anatoomia.