Launcher 2 — Roadmap a plán implementace¶
Aktuální stav (2026-05-04)¶
Nově dokončeno ✅ (od 2026-04-28)¶
| Fáze | Datum | Co bylo implementováno |
|---|---|---|
| v0.3.1 | 2026-04-29 | Company switcher, ARES, pamatovat heslo/auto-login, AVAX menu, GDPR fix |
| v0.3.2 | 2026-04-29 | Multi-company zálohy per firma, company-specifický token |
| v0.3.3 | 2026-05-03 | Správa uživatelů (UsersScreen), employee self-registration, pending login |
| v0.3.4 | 2026-05-04 | Fix 500 pending users (lazy-load), editace uživatele (heslo/role/email) |
| v0.3.5 | 2026-05-04 | Fix remember_password (chybí v DEFAULTS), autostart, tray, auto-update URL |
| v0.3.6 | 2026-05-04 | BackupScreen: registrace zařízení, subscribed sync UI, _SubscribeFolderDialog |
| v0.3.7 | 2026-05-04 | Fix Fernet key v root .env → storage/usage 500 opraveno, správa plánů firem |
Spec: Launcher auto-update¶
Přehled¶
Při každém startu launcher zkontroluje S3 endpoint latest.json. Pokud je dostupná novější verze, zobrazí banner s nabídkou stažení. Stažení a instalace proběhne bez nutnosti administrátorských práv přes .bat skript spuštěný po ukončení procesu.
Tok aktualizace¶
Start launcheru
│
├─► [5 s] GET https://s3.avaxis.cz/app-avax/latest.json
│ { "version": "0.3.5", "url": "...exe", "notes": "..." }
│
├─► Porovnat verze: _parse("0.3.5") > _parse(VERSION)
│
├─► [ano] Zavolat on_update(info) → zobrazit banner v LoginWindow / MainWindow
│ Banner: "Dostupná aktualizace v0.3.5 [Stáhnout]"
│
├─► [klik Stáhnout] download_update(url)
│ Stream do %TEMP%\avax-launcher2-update.exe
│ Progres: tlačítko zobrazuje "37 %"
│
├─► Bezpečnostní kontrola: soubor > 5 MB (jinak 403/404 stránka)
│
└─► install_and_restart(tmp_path)
Vytvoří %TEMP%\avax-update.bat:
timeout 2
copy /y "<tmp>" "<exe>"
start "" "<exe>"
del "%~f0"
os.startfile(bat) → launcher se ukončí → bat nahradí exe → spustí nový
S3 latest.json formát¶
{
"version": "0.3.5",
"filename": "avax-launcher2-0.3.5.exe",
"url": "https://s3.avaxis.cz/app-avax/versions/0.3.5/files/win/avax-launcher2.exe",
"notes": "Fix pamatovat heslo, tray, autostart",
"published_at": "2026-05-04T10:00:00Z"
}
Nahrávání nové verze (CI/manuálně)¶
# Po buildu PyInstaller:
python upload_release.py --version 0.3.X --file dist/avax-launcher2.exe
# nebo manuálně přes boto3 na dev serveru (S3 user: N0ZWGSW26GENWNQ1UDKD)
Bezpečnost¶
- URL v
latest.jsonmusí začínathttps://s3.avaxis.cz/claudeai/— jinak ignorovat - Stažený soubor musí být > 5 MB (ochrana proti HTML chybovým stránkám)
- Podpis exe: v budoucnu Authenticode (aktuálně self-signed / bez podpisu)
Omezení / edge cases¶
| Situace | Chování |
|---|---|
| Launcher není zmrazený (.py dev) | install_and_restart() vrátí False, restart neproběhne |
| Offline / S3 nedostupné | Tichý fail — žádný banner, žádná chyba |
| Verze identická | Banner se nezobrazí |
| Uživatel ignoruje banner | Aktualizace se nenaistaluje, příště banner znovu |
| Stahování při aktivní záloze | Stahování probíhá na pozadí, záloha není přerušena |
Implementační soubory¶
| Soubor | Role |
|---|---|
updater.py |
check_for_update(), download_update(), install_and_restart() |
main.py |
Banner v LoginWindow._show_update_banner() |
main_window.py |
Banner _show_update_banner() v hlavním okně (TODO) |
version.py |
VERSION = "0.3.X", BUILD_DATE |
Spec: Autostart + Tray + Pamatovat heslo¶
Autostart při spuštění Windows¶
settings.set_startup(True)
└─► winreg HKCU\Software\Microsoft\Windows\CurrentVersion\Run
AVAX = "C:\...\avax-launcher2.exe"
settings.set_startup(False)
└─► winreg DeleteValue("AVAX")
- Funguje pouze pro zmrazený
.exe(sys.frozen) - V dev módu registruje
python main.py— méně čisté, info label v nastavení
Chování při zavření okna¶
on_close == "tray":
MainWindow.withdraw()
tray.notify("AVAX Launcher", "Launcher běží na pozadí.")
(sync agent, zálohy, IPC socket stále aktivní)
on_close == "quit":
_logout() → LoginWindow
Tray menu:
Stavy ikony:
Modrá — online, vše OK (state="online")
Světle — sync probíhá (state="syncing")
Žlutá — update / notifikace (state="warning")
Červená — offline / chyba (state="offline")
Pamatovat si heslo + auto-login¶
Nastavení (settings.json):
remember_password: bool — ukládat heslo
saved_password: str — heslo v plaintextu (TODO: DPAPI encrypt)
auto_login: bool — přihlásit se automaticky po 600 ms
Závislosti:
auto_login = True vyžaduje remember_password = True
remember_password = False → smaže saved_password + vypne auto_login
TODO (bezpečnost): Uložení hesla v plaintextu je dočasné řešení.
Finálně: Windows DPAPI (win32crypt.CryptProtectData) nebo keyring.
Aktuální stav (2026-04-28)¶
Hotovo ✅¶
| Fáze | Datum | Co bylo implementováno |
|---|---|---|
| L2.0 | 2026-04-23 | LoginWindow — login form, registrace, threading auth |
| L2.1 | 2026-04-24 | MainWindow — menu lišta, dropdowny, 13 obrazovek, screen cache |
| L2.1 | 2026-04-24 | LibraryScreen, HelpScreen, flow login ↔ main, PyInstaller build |
| L2.S | 2026-04-25 | Settings, 6 témat, live přepínání, autostart registry |
| L2.2 | 2026-04-25 | Offline SQLite + JWT, grace period 7 dní |
| L2.3 | 2026-04-25 | Stažení/spuštění/odinstalace aplikací, progress bar, checksum diff |
| L2.4 | 2026-04-25 | Tray ikona (pystray), minimize to tray, notify, 4 stavy |
| L2.5 | 2026-04-25 | CalculationEngine + PluginRegistry, mzdy 2024/2025, DPH |
| L2.6 | 2026-04-26 | DSL engine (simpleeval), uživatelské vzorce, editor, live preview |
| L2.7 | 2026-04-26 | Audit log výpočtů, 40 testů (pytest + hypothesis) |
| L2.8 | 2026-04-26 | IPC (TCP/Unix socket) + AVAX SDK, 14 testů |
| F7 | 2026-04-27 | BackupScreen, SharedDirsScreen, StorageUsageScreen, záložka Úložiště |
| F8 | 2026-04-27 | SyncAgent: startup diff, scheduled sync, file watcher, NewerFilesDialog |
| FB | 2026-04-28 | Soubory dialog: vyloučení ze syncu, označení/smazání ze serveru |
| FC | 2026-04-28 | Verze souborů: badge, rozbalovací seznam, Stáhnout (presigned URL) |
| Fix | 2026-04-28 | Fix limit_bytes, zálohovací plán → Obchod/Knihovna, MinIO versioning Enabled |
Opravené chyby¶
| Chyba | Příčina | Řešení |
|---|---|---|
_draw() got unexpected keyword argument 'no_color_updates' |
Název metody koliduje s CTkFrame._draw |
Přejmenovat na _render |
can't invoke "destroy" command: application has been destroyed |
callback volán před self.destroy() |
Swap pořadí: destroy → pak callback |
NameError: cannot access free variable 'exc' |
Python 3.13 maže exc po except bloku |
msg = str(exc) před lambda |
Plán — co zbývá¶
L2.2 — Offline SQLite + JWT (střední priorita)¶
%LOCALAPPDATA%\Avaxis\launcher2\local.db
├── installed_apps — slug, verze, cesta, installed_at
├── cached_license — offline_jwt, exp, device_id
└── sync_state — last_synced per app per device
Offline JWT ověření:
1. Načíst offline_jwt z local.db
2. Ověřit RS256 podpis veřejným klíčem (bundlován v exe)
3. exp > now() → přístup OK
4. exp < now() → varování, grace 7 dní
5. grace > 7 dní → read-only, žádné instalace
Závislosti: PyJWT, SQLAlchemy (sync), bundlovaný jwt_public.pem
L2.3 — Knihovna: instalace a spuštění aplikací (vysoká priorita)¶
Stav aplikace (per slug, ukládáno v local.db):
not_installed → [Stáhnout]
downloading → [Progress bar — MB/s, %]
installed → [Spustit] [Odinstalovat]
update_avail → [Aktualizovat] [Spustit]
Stažení (GET presigned URL):
POST /apps/{slug}/file-urls → seznam URL souborů
Stáhnout jen změněné soubory (checksum diff)
Uložit do: %LOCALAPPDATA%\Avaxis\apps\{slug}\
Spuštění:
subprocess.Popen([app_exe_path])
Registrovat PID → heartbeat monitoring
Odinstalace:
Potvrzovací dialog
shutil.rmtree(app_path)
Smazat z installed_apps v DB
L2.4 — Tray ikona (střední priorita)¶
Závislost: pystray + Pillow
Chování při zavření X (settings.on_close == "tray"):
→ MainWindow.withdraw() (neskrýt, nechat v tray)
→ Tray ikona aktivní
Tray menu (pravý klik):
Otevřít AVAX
Chat (N nepřečtených)
Zálohy: OK / Probíhá / Chyba
─────────────────────────
Ukončit AVAX
Stavy tray ikony:
Zelená — online, vše OK
Modrá — sync/stahování probíhá
Žlutá — čeká aktualizace nebo nepřečtené zprávy
Červená — offline / chyba
Implementace:
- pystray.Icon v separátním daemonic vlákně
- Komunikace přes queue.Queue (thread-safe)
- Ikona: PNG 64×64 generovaná PIL.ImageDraw
L2.5 — CalculationEngine + PluginRegistry¶
desktop/launcher2/plugins/
├── registry.py — PluginRegistry, vybere plugin podle data
├── mzdy/
│ ├── v2024.py — výpočet mezd 2024
│ └── v2025.py — výpočet mezd 2025
└── dph/
├── v2024.py
└── v2025.py
Plugin rozhraní:
PLUGIN_ID = "mzdy.v2025"
VALID_FROM = date(2025, 1, 1)
VALID_TO = None
class MzdyInput(BaseModel): ...
class MzdyOutput(BaseModel): ...
async def calculate(inputs, rates) -> MzdyOutput: ...
PluginRegistry.get(plugin_type, date) → správný plugin pro dané datum
RateStore — sazby z DB (temporal DATERANGE):
SELECT value FROM tax_rates
WHERE code = :code AND :date <@ valid_range
L2.6 — DSL engine (uživatelské vzorce)¶
Závislost: simpleeval
Příklady vzorců (firma si definuje vlastní bonusy):
"hruby_prijem * 0.05"
"max(0, hruby_prijem - 50000) * 0.1"
"pocet_deti * 500 if pocet_deti > 0 else 0"
Validace: testovací výpočet s dummy hodnotami před uložením
Bezpečnost: simpleeval sandboxuje exec (žádné importy, žádné builtins)
L2.7 — Audit log + testy¶
Audit log výpočtů (JSONB v PostgreSQL):
plugin_id, inputs, outputs, rate_snapshot, calculated_at, calculated_by
Testy:
pytest + hypothesis (property-based)
Golden files: tests/golden/*.json (vstup + očekávaný výstup)
Regresní test:
@given(hruby_prijem=st.decimals(min_value=0, max_value=1_000_000))
def test_cisty_prijem_nikdy_zaporne(hruby_prijem): ...
L2.8 — IPC / Named pipe (AVAX SDK)¶
Launcher ↔ Aplikace komunikace:
Windows: Named pipe \\.\pipe\avaxis-{slug}
Linux: Unix socket /tmp/avaxis-{slug}.sock
Zprávy launcher → app:
{ "type": "shutdown", "reason": "user_request" }
{ "type": "update_pending", "version": "2.1.4" }
{ "type": "sync_complete", "status": "ok" }
Zprávy app → launcher:
{ "type": "ready", "version": "1.0.0", "pid": 1234 }
{ "type": "heartbeat" }
{ "type": "shutdown_ok" }
{ "type": "sync_request" }
{ "type": "log", "level": "ERROR", "message": "..." }
Python SDK: desktop/launcher2/sdk/avaxis_sdk.py
class AvaxApp:
connect(), ready(), shutdown_ok()
log.error(), log.warn(), log.info()
sync.request()
on_shutdown, on_update_pending (decorators)
Závislostní graf fází¶
L2.0–L2.8 ✅ (vše hotovo)
└─► F7 BackupScreen / SharedDirs / StorageUsage ✅
└─► F8 SyncAgent (file watcher, smart sync) ✅
└─► FB Soubory dialog (exclude/delete) ✅
└─► FC Verze souborů (S3 versioning) ✅
└─► F9 Full restore workflow ← PŘÍŠTÍ
Příští kroky¶
| Priorita | Fáze | Popis |
|---|---|---|
| 1. | F9 Full restore | Obnovení konkrétní verze souboru na disk (UI flow) |
| 2. | Subscribed sync | Synchronizace subscribed složek v sync_agent |
| 3. | F4 Chat | WebSocket gateway, Redis Pub/Sub fan-out |
| 4. | F5 Support+AI | Tikety, Ollama RAG, Claude fallback |
| 5. | F6 Portál | Admin správa, registrace firem, billing |
| 6. | Prod VM | vm-gateway, vm-api, vm-db, Nginx + SSL |
Aktualizováno: 2026-04-28