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¶
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