Přeskočit obsah

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.json musí začínat https://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:

▸ Otevřít AVAX         (default — dvojklik)
  ─────────────────────
  Ukončit

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