Přeskočit obsah

Katalog aplikací & Distribuce — Specifikace

Přehled

Katalog obsahuje ekonomické aplikace dostupné na platformě AVAX. Aplikace jsou buď veřejné (dostupné všem firmám po zakoupení) nebo na míru. Binárky jsou uloženy na S3 jako kolekce souborů (ne monolitický instalátor). Launcher stahuje pouze soubory které se od předchozí verze změnily.

Formát distribuce aplikací — Portable App Folder

Aplikace nejsou distribuovány jako klasický .exe instalátor, ale jako správovaná složka souborů. Launcher ji udržuje aktuální.

Výhody oproti klasickému instalátoru:
  • Launcher stahuje jen změněné soubory (ne celou aplikaci)
  • Žádné generování patch souborů na serveru
  • Snadný rollback (zachovat předchozí soubory)
  • Launcher plně kontroluje instalaci (žádný cizí installer.exe)

Launcher zajišťuje za aplikaci:
  • Vytvoření zástupce na ploše / v Start menu
  • Registrace v "Přidat nebo odebrat programy" (Windows)
  • Správa lokálního app adresáře
  • Čistá odinstalace

Lokální adresářová struktura aplikace

Windows: %LOCALAPPDATA%\Avaxis\apps\{app-slug}\
  current\          ← aktivní verze (symlink nebo přímá složka)
    app.exe         ← hlavní spustitelný soubor
    lib\
    assets\
    config\
  previous\         ← předchozí stable verze (pro rollback)
  manifest.json     ← aktuálně nainstalovaná verze + checksums

Linux: ~/.local/share/avaxis/apps/{app-slug}/
  current/
  previous/
  manifest.json

Release kanály a nasazení verzí

1. ALPHA ── testovací firma Avaxis
   • Nahraná nová verze (catalog_admin v portálu)
   • Nasazena POUZE na interní testovací firmu Avaxis
   • Tým Avaxis provede funkční testy
   • Pokud OK → povýšit na Beta

2. BETA ── vybrané beta firmy
   • Nasazena na explicitně přiřazené beta firmy
   • Monitoring chybových logů (viz sekce Error Logs)
   • Minimální doba v beta: default 3 dny (konfigurovatelné)
   • Firma může kdykoli přepnout zpět na stable
   • Pokud OK → povýšit na Stable

3. STABLE ── všechny firmy s předplatným
   • Automatický rollout všem oprávněným firmám
   • Tray notifikace "dostupná aktualizace"

Udržované verze

Per aplikace jsou vždy dostupné v S3:
  stable-current    → nasazena všem (launcher ji stahuje)
  stable-previous   → záloha pro rollback
  beta              → jen pro beta firmy
  alpha             → jen pro Avaxis test firmu

Starší verze → po 90 dnech přesun do S3 archivu

Rollback

catalog_admin klikne [Rollback] v portálu:
  → stable-previous se označí jako stable-current
  → launcher při příštím startu detekuje nižší verzi v kanálu
  → stáhne pouze soubory které se liší (manifest diff)
  → Tray notifikace: "Aplikace vrácena na předchozí verzi"
  → Chybná verze zůstane v S3 pro analýzu

Manifest-based update (klíčový mechanismus)

Launcher nikdy nestahuje celý instalátor znovu. Vždy porovná manifest nové verze s lokálně nainstalovanými soubory a stáhne jen soubory které se změnily.

Manifest verze (version-manifest.json)

{
  "app": "fakturace-pro",
  "version": "2.1.4",
  "channel": "stable",
  "released_at": "2026-04-15T12:00:00Z",
  "changelog": "Oprava tisku sestav, nové exporty do ISDOC.",
  "min_os_win": "Windows 10 1903",
  "min_os_linux": "Ubuntu 20.04",
  "files": [
    {
      "path": "app.exe",
      "checksum": "sha256:a1b2c3...",
      "size": 5242880,
      "platform": "win"
    },
    {
      "path": "lib/runtime.dll",
      "checksum": "sha256:d4e5f6...",
      "size": 1048576,
      "platform": "win"
    },
    {
      "path": "assets/logo.png",
      "checksum": "sha256:g7h8i9...",
      "size": 51200,
      "platform": "any"
    }
  ],
  "total_size_win": 52428800,
  "total_size_linux": 48000000
}

Update flow (launcher)

Launcher detekuje dostupnou aktualizaci:
  1. Stáhne version-manifest.json nové verze (malý soubor, ~10 KB)
  2. Načte lokální manifest.json (aktuálně nainstalovaná verze)
  3. Porovná checksumy souborů:

  Pro každý soubor v novém manifestu:
    lokální checksum == nový checksum → PŘESKOČIT (soubor beze změny)
    lokální checksum != nový checksum → STÁHNOUT
    soubor lokálně chybí             → STÁHNOUT

  Soubory v lokálu ale ne v novém manifestu → SMAZAT

  4. Sestaví seznam souborů ke stažení + jejich celkovou velikost
  5. Zobrazí uživateli: "Aktualizace 2.1.4 — ke stažení 3,2 MB z 50 MB"
     (nebo "Ke stažení 2 soubory — 3,2 MB")

  6. Vyžádá od API presigned URL pro každý změněný soubor
  7. Stahuje soubory paralelně přímo ze S3
  8. Každý soubor po stažení: ověří checksum → nahradí lokální
  9. Zapíše nový manifest.json lokálně
  10. Aplikace je aktuální — bez restartu launcheru (jen restartuje appku)

Vizuální progress při update

┌──────────────────────────────────────────────────────┐
│  Aktualizace Fakturace Pro 2.1.3 → 2.1.4            │
│                                                      │
│  Ke stažení: 3 soubory (3,2 MB z celkových 50 MB)   │
│                                                      │
│  app.exe              [████████████░░░░] 68%  2.1 MB │
│  lib/vypocty.dll      [████████████████] hotovo      │
│  assets/sablony.zip   [░░░░░░░░░░░░░░░░] čeká        │
│                                                      │
│  Celkem: ████████░░░░░░░░  52%                       │
└──────────────────────────────────────────────────────┘

Datový model

apps (
  id           UUID PRIMARY KEY,
  slug         VARCHAR(100) UNIQUE,
  name         VARCHAR(255),
  description  TEXT,
  category     VARCHAR(100),
  publisher_id UUID REFERENCES companies,
  visibility   VARCHAR(20),        -- 'public' | 'custom'
  client_id    UUID REFERENCES companies,
  icon_url     TEXT,
  is_active    BOOLEAN DEFAULT true,
  created_at   TIMESTAMPTZ
)

app_versions (
  id              UUID PRIMARY KEY,
  app_id          UUID REFERENCES apps(id),
  version         VARCHAR(50),         -- semver: '2.1.4'
  channel         VARCHAR(20),         -- 'alpha' | 'beta' | 'stable'
  changelog       TEXT,
  min_os_win      VARCHAR(20),
  min_os_linux    VARCHAR(20),
  manifest_s3_key TEXT,                -- cesta k version-manifest.json v S3
  total_size_win  BIGINT,              -- součet všech souborů (Win)
  total_size_linux BIGINT,
  is_current      BOOLEAN DEFAULT false,
  is_rolled_back  BOOLEAN DEFAULT false,
  released_at     TIMESTAMPTZ,
  created_at      TIMESTAMPTZ
)

-- Soubory verze (pro server-side přehled, manifest je source of truth)
app_version_files (
  id          UUID PRIMARY KEY,
  version_id  UUID REFERENCES app_versions(id),
  path        VARCHAR(500),            -- relativní cesta v app složce
  platform    VARCHAR(10),             -- 'win' | 'linux' | 'any'
  s3_key      TEXT,
  checksum    VARCHAR(64),             -- SHA-256
  size        BIGINT,
  created_at  TIMESTAMPTZ
)

company_channel_assignments (
  company_id  UUID REFERENCES companies(id),
  app_id      UUID REFERENCES apps(id),
  channel     VARCHAR(20),             -- 'alpha' | 'beta' | 'stable'
  assigned_by UUID REFERENCES users(id),
  assigned_at TIMESTAMPTZ,
  PRIMARY KEY (company_id, app_id)
)

company_subscriptions (
  id                   UUID PRIMARY KEY,
  company_id           UUID REFERENCES companies(id),
  app_id               UUID REFERENCES apps(id),
  plan                 VARCHAR(50),
  status               VARCHAR(50),
  current_period_start TIMESTAMPTZ,
  current_period_end   TIMESTAMPTZ,
  stripe_sub_id        VARCHAR(255),
  UNIQUE (company_id, app_id)
)

app_installs (
  id           UUID PRIMARY KEY,
  user_id      UUID REFERENCES users(id),
  app_id       UUID REFERENCES apps(id),
  version      VARCHAR(50),
  channel      VARCHAR(20),
  platform     VARCHAR(20),
  device_id    VARCHAR(255),
  installed_at TIMESTAMPTZ
)

S3 struktura — aplikace

s3://avaxis/apps/

catalog/
└── {app-slug}/
    ├── channels/
    │   ├── alpha.json          ← { version, manifest_key }
    │   ├── beta.json
    │   └── stable.json         ← launcher čte tento soubor
    └── versions/
        └── {version}/
            ├── version-manifest.json   ← seznam všech souborů + checksums
            └── files/
                ├── win/
                │   ├── app.exe
                │   ├── lib/runtime.dll
                │   └── assets/logo.png
                └── linux/
                    ├── app
                    ├── lib/libruntime.so
                    └── assets/logo.png

logs/
└── {app-slug}/
    └── {rok}/{měsíc}/{den}/
        └── {device_id}-{timestamp}.log.gz

custom/
└── {client-id}/
    └── {app-slug}/
        └── versions/{version}/ ...

Chybové logy (Error Logs → S3)

Launcher zachytí logy z běžící aplikace a uploaduje přímo na S3 přes presigned PUT URL (nezatěžuje API server).

Aplikace/launcher zapíše chybu do lokálního bufferu
  → max 5 MB nebo 1 hodina → komprimuj (gzip)
  → POST /apps/{slug}/log-upload-url → presigned PUT URL
  → Upload přímo na S3
  → Pokud offline → čeká v bufferu, upload při připojení

Obsah logu: timestamp, level, stack trace, verze, kanál,
            OS, device_id — ŽÁDNÁ osobní data uživatele

Zobrazení v portálu (catalog_admin)

Detail aplikace → záložka Chybové logy
Filtr: kanál / verze / datum

Automatický alert: stejná chyba > 5× za hodinu → notifikace

Retention

Alpha: 14 dní  |  Beta: 30 dní  |  Stable: 90 dní → smazáno

Download & Update API

GET  /catalog?company_id={id}
     Vrátí: aplikace s aktuálním kanálem firmy

GET  /catalog/{slug}/check-update
     Body: { installed_version, platform }
     Vrátí: { update_available, version, channel,
              manifest_url (presigned), changelog,
              changed_files_count, changed_files_size }

POST /apps/{slug}/file-urls
     Body: { version, platform, files: ["app.exe", "lib/runtime.dll"] }
     Vrátí: { files: [{ path, presigned_url, expires_at }] }
     ← launcher vyžádá URL jen pro soubory které potřebuje stáhnout

POST /apps/{slug}/install-report
     Body: { version, channel, platform, device_id }

POST /apps/{slug}/log-upload-url
     Body: { platform, version, channel }
     Vrátí: { presigned_put_url, expires_at }

Admin API (catalog_admin, super_admin)

POST /admin/apps
     Vytvoří novou aplikaci

POST /admin/apps/{slug}/versions
     Nahraje manifest + soubory nové verze do kanálu alpha
     → server vygeneruje Ed25519 podpisy souborů

PUT  /admin/apps/{slug}/versions/{version}/promote
     Body: { to_channel: "beta"|"stable" }

PUT  /admin/apps/{slug}/rollback
     Označí stable-previous jako stable-current

POST /admin/apps/{slug}/beta-companies
     Body: { company_ids: [...] }

GET  /admin/apps/{slug}/logs
     ?channel=beta&version=2.1.4&from=...&to=...

GET  /admin/apps/{slug}/stats


AVAX App SDK

Každá aplikace distribuovaná přes AVAX musí integrovat SDK. SDK je malá knihovna která zajišťuje komunikaci s launcherem.

Dostupné implementace

avaxis-sdk-dotnet   → .NET / C# (NuGet balíček)
avaxis-sdk-java     → Java / Kotlin (Maven / Gradle)
avaxis-sdk-python   → Python (pip balíček)

Ekonomické aplikace jsou typicky psány v těchto jazycích — pokrývají 99 % případů. Nový jazyk → nová SDK implementace dle tohoto protokolu.

IPC — komunikace launcher ↔ aplikace

Launcher a aplikace komunikují přes lokální socket:

Windows: Named Pipe  \\.\pipe\avaxis-{app-slug}
Linux:   Unix Socket /tmp/avaxis-{app-slug}.sock

Protokol: JSON zprávy oddělené newline (\n)
Launcher naslouchá, aplikace se připojí při startu.

SDK API (co aplikace volá)

# Python příklad — ostatní jazyky mají identické API

from avaxis_sdk import AvaxApp

app = AvaxApp(slug="fakturace-pro")

# --- POVINNÉ při startu ---
app.connect()          # Připojí se k launcheru přes IPC
app.ready()            # Oznámí launcheru "jsem spuštěna a připravena"

# --- CESTY (aplikace MUSÍ používat tyto cesty) ---
app.paths.data         # Adresář pro klientská data (zálohováno)
app.paths.settings     # Adresář pro nastavení (zálohováno)
app.paths.temp         # Dočasné soubory (nezálohováno)
app.paths.logs         # Lokální logy před uploadem

# --- LOGOVÁNÍ ---
app.log.error("Chyba při tisku", exception=e, context={"doklad_id": 123})
app.log.warn("Pomalý dotaz do DB", duration_ms=3200)
app.log.info("Uživatel otevřel modul fakturace")

# --- SYNC (požádá launcher o okamžitou synchronizaci dat) ---
app.sync.request()              # Spustí sync ihned (např. po uložení dokladu)
app.sync.request(priority=HIGH) # Prioritní sync

# --- LIFECYCLE (co aplikace musí zpracovat) ---
@app.on_shutdown
def handle_shutdown():
    db.close()          # Uložit, zavřít spojení
    app.shutdown_ok()   # Potvrdit launcheru že lze ukončit

@app.on_update_pending
def handle_update(new_version):
    # Launcher stáhl update a čeká na souhlas aplikace
    if db.has_unsaved_changes():
        app.update_defer()   # Požádám o odložení — uživatel má neuložená data
    else:
        app.update_ok()      # Aplikace souhlasí s okamžitým restartem

# --- HEARTBEAT (automatické, SDK posílá každých 10s) ---
# Pokud launcher nedostane heartbeat 30s → aplikace považována za zamrzlou

Zprávy které launcher posílá aplikaci

{ "type": "shutdown",        "reason": "user_request" }
{ "type": "shutdown",        "reason": "update_ready", "version": "2.1.4" }
{ "type": "update_pending",  "version": "2.1.4", "changelog": "..." }
{ "type": "sync_complete",   "app": "fakturace-pro", "status": "ok" }
{ "type": "license_expiring","days_remaining": 5 }

Zprávy které aplikace posílá launcheru

{ "type": "ready",           "version": "2.1.3", "pid": 12345 }
{ "type": "heartbeat",       "status": "ok" }
{ "type": "shutdown_ok"                          }
{ "type": "update_ok"                            }
{ "type": "update_defer",    "reason": "unsaved_data" }
{ "type": "sync_request",    "priority": "normal" }
{ "type": "log",             "level": "ERROR", "message": "...",
                             "stack": "...", "context": {} }

Povinné konvence pro distribuované aplikace

1. Datové cesty
   ✓ Aplikace MUSÍ ukládat data přes app.paths.*
   ✗ Aplikace NESMÍ zapisovat mimo svůj adresář (žádné %APPDATA% přímo)

2. Lifecycle
   ✓ Musí implementovat on_shutdown handler (uložit stav, zavřít DB)
   ✓ Musí potvrdit shutdown do 30 sekund (pak launcher ukončí násilně)
   ✓ Musí implementovat on_update_pending (update_ok nebo update_defer)

3. Logování
   ✓ Chyby a výjimky MUSÍ být logovány přes app.log.error()
   ✗ Žádná osobní data v logu (jméno, rodné číslo, částky)

4. Heartbeat
   ✓ SDK posílá automaticky každých 10s — aplikace neřeší

5. Spuštění
   ✓ app.connect() a app.ready() musí být voláno do 10s od startu
   → Pokud ne, launcher považuje start za selhání a restartuje aplikaci

Validace SDK integrace (při nahrání nové verze)

Catalog_admin nahraje novou verzi do kanálu alpha:
  → Portál automaticky spustí validační kontrolu:
      ✓ version-manifest.json obsahuje platná pole
      ✓ Hlavní spustitelný soubor je přítomen
      ✓ SDK závislost je přítomna v manifestu (avaxis-sdk-*)
  → Pokud validace selže → verze označena jako invalid, nelze povýšit
  → Funkční SDK integrace se ověří až při nasazení na alpha testovací firmu

Bezpečnost distribuce

Mechanismus Implementace
Šifrování přenosu HTTPS (TLS 1.3)
Integrita manifestu Ed25519 podpis celého manifestu (ne jednotlivých souborů)
Ověření souborů SHA-256 checksum každého souboru ověřen lancerem po stažení
S3 přístup Presigned URL TTL 15 min, write přístup jen pro Avaxis (IAM)
Manifest S3 Zapsán pouze catalog_adminem (IAM politika), HTTPS přenos
Oprávnění API ověří předplatné + přidělení + kanál firmy
Logy Žádná osobní data — pouze technické informace

Manifest se podepisuje jako celek — S3 je chráněný IAM politikami a HTTPS. Podpis přidává defense-in-depth pro případ kompromitace S3 write přístupu.


Rozhodnuté otázky

Otázka Rozhodnutí
Formát distribuce Portable app folder (ne monolitický installer.exe)
Aktualizační mechanismus Manifest-based: launcher stáhne jen změněné soubory
Patch generování Nepotřeba — manifest diff nahrazuje patch soubory
Delta velikost Zobrazena uživateli před stažením ("3,2 MB z 50 MB")
Rollback 2 stable verze, rollback stáhne jen změněné soubory zpět
Kanály Alpha (Avaxis) → Beta (vybrané firmy) → Stable (všichni)
Beta opt-out Firma může kdykoli přepnout zpět na stable
Chybové logy SDK volání → launcher buffer → S3 presigned PUT (bez zatížení API)
Log retention Alpha 14d / Beta 30d / Stable 90d
Log obsah Žádná osobní data — pouze technické informace
Podepisování Ed25519 podpis celého manifestu (ne každého souboru)
SDK logování Explicitní SDK volání (app.log.error/warn/info)
SDK jazyky .NET, Java, Python (pokrývají ekonomický software)
IPC protokol Named pipe (Win) / Unix socket (Linux), JSON zprávy
App konvence Povinné: datové cesty, lifecycle, logování, heartbeat
SDK validace Automatická při nahrání verze do portálu

Otevřené otázky

Všechny otázky k app-catalog.md jsou vyřešeny.


Poslední aktualizace: 2026-04-21