DokumentaceArchitektura

Architektura

Eutepio stojí na třech rozhodnutích: lokální databáze jako jediný zdroj pravdy, synchronizace pouze v lokální síti a striktní oddělení sdílených a osobních dat.

Offline-first

Každé zařízení má vlastní úplnou kopii knihovny. Neexistuje server, který by data vlastnil, ani účet, pod kterým by byla vedená. Synchronizace je způsob, jak během zkoušky nebo koncertu držet kapelu na stejné stránce — ne záloha a ne cloudové úložiště.

Důsledky:

  • Aplikace funguje bez internetu
  • Kvalita připojení nemá vliv na chování na pódiu
  • Zálohu si musíš udělat sám — slouží k tomu formát .eutbackup
  • Když přijdeš o telefon bez zálohy, přijdeš o knihovnu

Úložiště

Databází je Isar (komunitní fork verze 3), vestavěná databáze běžící přímo v procesu aplikace.
Od verze 0.2.0 nejde o jednu databázi, ale o jednu databázi na knihovnu plus samostatný registr:
KdeCo v tom je
RegistrSeznam knihoven a tvůj uživatelský profil — jméno, nástroj, vzhled pódia, mapování pedálu a MIDI
KnihovnaPísně, setlisty, anotace a stav té konkrétní knihovny
Profil je proto globální: když přepneš knihovnu, pódium ani ovládání se ti nepřenastaví. Podrobnosti v Víc knihoven.
PlatformaUmístění databáze
Android, iOSadresář dokumentů aplikace
Windows, Linux, macOSadresář podpory aplikace
Binární přílohy v databázi neleží. PDF, MusicXML a obrázky se ukládají jako soubory do podsložek pdfs/, musicxml/ a images/; v databázi je uložená jen relativní cesta. Každá knihovna má vlastní kořen pro přílohy.

Odolnost

  • Pokud se databázi nepodaří otevřít, poškozený soubor se odloží stranou pod jménem s příponou .corrupt-<časové razítko> a aplikace nastartuje s čerstvou databází místo toho, aby spadla.
  • Databáze si pamatuje verzi schématu, se kterou do ní bylo naposledy zapsáno. Když otevřeš starší build aplikace nad novější databází, aplikace se zamkne na varovné obrazovce místo toho, aby data poškodila.
  • Aplikace rozlišuje zamčenou databázi (jiný proces ji drží — zkusí to znovu) od poškozené (odloží ji stranou). Zamčený soubor se tedy neodkládá zbytečně.

Datový model

Píseň

Sdílená část, kterou má smysl znát celá kapela:

PoleTypPoznámka
title, artisttextpovinné
variantNametextvolitelná varianta, součást identity písně
keytexttónina
bpmčíslotempo
timeSignaturetexttaktové označení
capočíslovýchozí 0
tagsseznam textůindexované pro vyhledávání
chordProContenttextvlastní obsah písně v ChordPro
durationSecondsčíslodélka
versiončíslozvyšuje se při úpravě sdílených polí
createdAt, updatedAt, deletedAtčasmazání je měkké — záznam zůstane a jen se označí
K tomu tři identifikátory používané při synchronizaci a zálohách: syncId (unikátní), matchKey (odvozený z názvu, interpreta a varianty) a contentHash (SHA-256 sdílených polí).

Setlist

name, eventDate, venue, startTime, estimatedDurationMin, songIds (seřazený seznam), breaks, songNotes, customFieldsJson, version, createdAt, deletedAt a lokální sortOrder.
Setlist nemá syncId — mezi zařízeními se páruje jen podle názvu a data akce. Když stejný setlist na jednom zařízení přejmenuješ, na druhém z něj po synchronizaci vznikne duplicita.

Sdílená a lokální pole

Píseň má vedle sdílených polí i řadu per-device hodnot, které se nikdy nesynchronizují a nikdy je nepřepíše nikdo jiný:
  • privateNotes — tvoje osobní poznámky k písni
  • localTranspose, localTransposeXml — transpozice akordů a MusicXML
  • fontSizeScale — velikost textu
  • rychlosti autoscrollu zvlášť pro každý z pěti režimů zobrazení
  • defaultViewMode, pdfStartPage, pdfFitWidth, musicXmlZoom
  • cesty k přílohám (pdfPath, musicXmlPath, imagePaths) a odložené alternativní verze
  • midiJson — MIDI příkaz odeslaný při otevření písně

Anotace jsou lokální úplně — do synchronizace nevstupují vůbec, byť je najdeš v záloze.

Tohle rozdělení je důvod, proč ti kytarista nemůže přepsat transpozici ani poznámky. Zpěvák může mít stejnou píseň o tercii výš a nikoho to neruší.

Vrstvy synchronizace

1. Objevování

Leader se ohlásí v lokální síti přes mDNS/Bonjour pod službou _eutepio._tcp. Souběžně běží záložní sken lokálního rozsahu adres, aby relace šla najít i v sítích, kde multicast nefunguje. Připojit se dá i naskenováním QR kódu nebo ručním zadáním IP adresy.

2. Přenos

Leader spustí HTTP server na portu 8765. Pokud je port obsazený, zkusí postupně 8766 až 8769. Server nabízí čtyři endpointy — ohlášení relace, připojení, WebSocket upgrade a health check. Vlastní komunikace pak jede po WebSocketu.

3. Aplikační protokol

Zprávy jsou JSON objekty s klíčem command. Leader je vysílá, členové je vykonávají; člen, který chce něco poslat ostatním, pošle zprávu leaderovi a ten ji přerazítkuje a rozešle dál. Každá zpráva nese razítko leaderových hodin a čas executeAt (standardně o 300 ms v budoucnosti), aby všechna zařízení akci provedla ve stejný okamžik.
Kompletní seznam příkazů je v Leader/member modelu.

Co opouští zařízení

Aby bylo jasno, protože „data nikdy neopustí zařízení" by nebyla pravda:

SituaceCo se posíláKam
SynchronizacePísně, setlisty a přílohy, které si členové vyžádajíOstatním zařízením ve stejné lokální síti
Automatická zálohaCelá záloha knihovnyDo složky, kterou sám vybereš — může být i složka synchronizovaná do cloudu
Import z URLJen HTTP GET požadavek na adresu, kterou sám zadášNa server, který jsi zadal
První export setlistu do PDFStažení písma Noto SansGoogle Fonts
Co se neposílá nikdy a nikam: žádná analytika, žádné crash reporty, žádná telemetrie, žádný účet. V aplikaci není Firebase, Supabase, Sentry ani jiná podobná služba.