← Späť na blog

Prečo som si postavil vlastný 'druhý mozog' namiesto poznámkového bloku (a čo ma to naučilo o dátach)

25. júla 2026 · 5 min čítania

self-hostedhomelab

Nie appka pre iných — nástroj postavený čisto na to, aby vlastná práca naprieč desiatkami projektov a dvoma strojmi nezabúdala, čo už bolo urobené a prečo.

Problém, ktorý appka rieši

Keď spravuješ desiatky projektov naraz — homelab služby, vlastné appky, klientsku prácu, na viacerých strojoch — vzniká špecifický druh problému: kontext sa stráca. K projektu sa vrátiš o týždeň a nevieš, čo presne sa vtedy robilo, prečo bolo niečo urobené presne tak a nie inak, a čo ešte čaká na dokončenie. Bežné riešenie — "zapisuj si priebežne poznámky do .md súborov" — znie rozumne, ale v praxi má jednu slabinu: je to krok navyše, ktorý nemá žiadnu mechanickú väzbu na samotnú prácu. Pri kratšej úlohe sa dodrží. Pri dlhšom, rozbehnutom kole práce sa postupne vytráca.

Presne to sa aj potvrdilo — audit ukázal, že pri type záznamov, ktoré mali ísť zapisovať priebežne, chýbalo až 10 z 16 očakávaných záznamov za jeden deň. Pravidlo existovalo, bolo aj zrozumiteľné, no nebolo ničím vynútené — a tak sa jednoducho vynechávalo.

Prvý pokus: zapisuj na dve miesta naraz

Prvá reakcia bola logická — ak sa .md zápis vynecháva, pridaj druhé, redundantné miesto zápisu (dual-write): appka s API, ktorá si zároveň drží aj vlastnú databázu. Zápis by mal ísť na oba ciele naraz.

Problém je, že "zapisuj na dve miesta" má presne tú istú slabinu ako pôvodné pravidlo — je to znova krok navyše bez mechanickej väzby. Chvíľu to fungovalo lepšie, no nakoniec šlo o rovnaký typ krehkosti, len s jedným miestom zápisu naviac.

Rozhodnutie: jeden smer zápisu, jeden zdroj pravdy

Riešenie napokon nebolo "zapisuj dôslednejšie", ale zmeniť, čo je vôbec zdroj pravdy. Namiesto dvoch rovnocenných miest zápisu vznikol jeden jediný — appka s API — a pôvodné .md súbory sa zmenili na čisto generovaný, čitateľný backup, obnovovaný automaticky raz za hodinu skriptom bežiacim opačným smerom, než pôvodný importér.

Dôsledok je jednoduchý, ale dôležitý: teraz existuje presne jedno miesto, kde môže zápis chýbať — a keď chýba, dá sa to jednoducho overiť (posledný timestamp zápisu cez vlastný sync-status endpoint), nie dohadovať sa, či to náhodou nie je len v tom druhom súbore.

Cesta k tomu nebola priamočiara — dátové bugy, ktoré sa objavili cestou

Prechod na jediný zdroj pravdy odhalil sériu reálnych chýb, ktoré predtým jednoducho neboli vidieť, lebo dáta boli rozdelené na viacero miest naraz:

  • Case-sensitive duplicita projektov. Vlastný zápisový kód si pri zakladaní nového projektu robil lookup podľa mena bez ohľadu na veľkosť písmen inak, než pri neskoršom vyhľadávaní — výsledkom boli dva samostatné projekty Mimir a mimir, ktoré mali obsahovať to isté. Presne ten istý typ bugu sa neskôr našiel ešte raz, na inom mieste kódu (živé zapisovanie z paralelnej relácie na inom stroji), čo potvrdilo, že nešlo o jednorazový preklep, ale o vzorec — všade, kde sa robí lookup-alebo-vytvor podľa textového mena, treba explicitne riešiť veľkosť písmen.
  • SQLite schema poradie. Pridanie nového stĺpca do existujúcej tabuľky zhavarovalo backend hneď pri štarte s "no such column" — hoci príkaz na jeho pridanie bol v kóde prítomný. Príčina: SQLite vykoná celý blok príkazov v poradí, v akom sú napísané, a CREATE INDEX na novom stĺpci sa pokúsil spustiť skôr, než samostatná funkcia stihla dobehnúť ALTER TABLE ADD COLUMN. V systéme bez poriadneho migračného frameworku musí byť poradie explicitné: najprv nemenená schéma, potom idempotentný backfill nových stĺpcov, až potom čokoľvek, čo na tých stĺpcoch závisí.
  • Príliš veľké API odpovede. Zoznam projektov vracal pri každom volaní aj plné poznámkové texty ku každému — pri niektorých projektoch až 70+ KB. Pri bežnom čítaní appky to nevadilo, ale pri čítaní cez API to prekračovalo rozumný limit na jedno načítanie a bolo to nakoniec nepohodlnejšie, než len otvoriť jeden .md súbor. Riešenie: odľahčený zoznamový endpoint (len príznak "má poznámky", nie ich obsah), plný text len na vyžiadanie pre konkrétny záznam. Rovnaký princíp neskôr aplikovaný aj na zoznam záznamov (voliteľné orezanie textu na pár stoviek znakov).

Veľké upratovanie: keď duplicita vôbec nevyzerá ako duplicita

Najzaujímavejšia časť prišla pri hľadaní duplicitných záznamov, ktoré vznikli tak, že tá istá udalosť sa počas prechodového obdobia zapísala dvakrát — raz živým zápisom, raz spätným importom z .md zálohy toho istého obdobia.

Prvý, najjednoduchší prístup — presná zhoda dátumu a názvu — našiel len časť z nich, pretože formulácie sa medzi dvomi zápismi tej istej udalosti mierne líšili (interpunkcia, diakritika). Rozšírenie na "fuzzy" porovnanie normalizovaných názvov našlo ďalšie páry, no stále nie všetky.

Skutočné riešenie prišlo až s porovnaním obsahu, nie len názvu — jaccard podobnosť (prekryv slov) medzi telami všetkých záznamov v rámci toho istého dňa, naprieč celým súborom dát, nie len v tej časti, kde sa duplicity nahlásili. Tento prístup našiel výrazne viac skutočných duplicít, no priniesol aj dôležitú pascu, ktorej sa bolo treba vyhnúť: pri jednej obzvlášť hustej sage (viacero pokusov o opravu tej istej chyby za sebou) mali susedné, ale skutočne odlišné záznamy ("test úspešný" vs. "test mylne označený za vyriešený — oprava") natoľko podobný text, že hrubší prístup by ich nesprávne spojil ako duplicitu. Až kontrola pomocou dostatočne vysokého prahu podobnosti (a chápania obsahu, nie len povrchnej zhody) dokázala spoľahlivo odlíšiť "toto je to isté zapísané dvakrát" od "toto je tvrdenie a jeho neskoršia oprava".

Celkovo sa takto postupne našlo a vyčistilo 46 duplicitných záznamov naprieč viacerými kolami — presný názov, fuzzy názov, obsahová podobnosť, a napokon jeden úplne identický pár, ktorý bol artefaktom pôvodného spôsobu parsovania starých súborov.

Čo z toho zostáva ako poučenie

  • Pravidlo bez mechanickej väzby na prácu sa v dlhšej relácii vytráca — bez ohľadu na to, aké je rozumné. Dual-write nie je výnimka, má presne tú istú slabinu ako pôvodné manuálne pravidlo.
  • Jeden zdroj pravdy je jednoduchšie overiť než dva synchronizované zdroje. Namiesto "dúfajme, že oba súhlasia" stačí jedna otázka: zapísalo sa to tam, kde sa má?
  • Rozdelenie dát na viacero miest skrýva chyby. Case-duplicita, schema poradie aj duplicitné záznamy boli prítomné už predtým — vyplavili sa na povrch až vtedy, keď dáta museli žiť na jednom mieste a byť interne konzistentné.
  • Pri hľadaní duplicít nestačí porovnávať povrch (názov). Skutočný obsah je spoľahlivejší signál, ale treba nastaviť dostatočne opatrný prah, aby sa "to isté dvakrát" nezamieňalo s "podobné, ale zámerne odlišné".

Appka, ktorá vznikla len na to, aby som si nemusel pamätať kontext naprieč desiatkami rozbehnutých projektov, sa nakoniec stala aj malým cvičením v dátovej integrite — presne v tom rozsahu, aký si takýto osobný nástroj zaslúži: dosť poriadne na to, aby sa dalo dôverovať, že to, čo tam je, je aj naozaj pravda.