Stack és architektúra
| Réteg | Döntés |
|---|---|
| Frontend | React + TypeScript, Tailwind + shadcn/ui (Radix UI primitívekre és class-variance-authority-ra épül; a komponensek forráskódja bemásolódik a repóba). Nem DaisyUI. |
| Állapotkezelés | Zustand, domain-enkénti store-okban |
| Backend | Strapi (Node.js headless CMS) + PostgreSQL — online igazságforrás (auth, admin, entitlement, Lemon Squeezy webhook); NEM íródik át Go-ra |
| Kliens | Kizárólag Electron desktop app (Win/Mac/Linux) — a webes SPA-nak nincs önálló publikus üzemelése, l. Termékdöntések "Desktop-elsődleges" sora |
| Offline/sync réteg | Egy natív Go sidecar processz, amit az Electron main indít — EGYSÉGES titkosított lokális tárolóval minden tartalomtípusra: kurzusvideó, szöveges kurzus (markdown), jegyzet, kvíz-válasz, fórum téma/hozzászólás. Nincs Dexie/IndexedDB — a korábbi (2026-11-03 kora esti) Dexie-alapú jegyzet-megoldás migrálás alatt a sidecar-ra. |
| Fizetés | Lemon Squeezy (Merchant of Record — az ÁFA/adó kérdéseket is kezeli); egyszeri kurzus és visszatérő membership is ezen megy. Ez az EGYETLEN webes lépés a felhasználói útban (hosted checkout) — utána minden a desktop appban folytatódik. |
| Videó tárolás | Azure Blob Storage (Bunny Stream kivezetve, l. lentebb) — a Strapi media library upload providerén keresztül |
| Infra | Docker / Docker Compose most; Azure (App Service/Container Apps a Strapi backendnek, Blob Storage a videónak, Postgres managed DB) |
| Tesztelés | Vitest (backend unit) + Playwright (E2E, Flow-onként legalább egy spec, Electron build ellen is) |
Miért nem kell már Bunny Stream? (2026-11-03, késő esti döntés)
A korábbi (2026-09-13-i) Bunny Stream döntés azon alapult, hogy a kurzusvideó élőben, böngészőben streamelve működik. Miután a cél tisztán offline-first, letöltős lejátszás lett (a hallgató mindig a teljes fejezetet tölti le, sosem néz élő streamet), Bunny adaptív HLS/CDN rétegére nincs szükség:
- Tárolás: a nyers videófájl egyszerűen Azure Blob Storage-ban van, mint bármelyik más média a Strapi media library-jában — nincs külön videó-CDN integráció.
- Letöltés: a Go sidecar HTTP Range fejlécekkel, darabokban (chunked) tölti le a fájlt egy rövid élettartamú, aláírt (SAS token) URL-ről — ugyanaz a "darabolt letöltés" elv, mint korábban a HLS-szegmenseknél, csak más forrásformátum.
- Lejátszás: saját, egyszerű videólejátszó az appban (nem Bunny iframe) — a letöltött, titkosított darabokat csak az app tudja visszafejteni és lejátszani.
- Titkosítás: a lemezen AES-256-GCM-mel titkosítva tárolódik, géphez kötött kulccsal — ez nem valódi DRM (egy debuggerrel felszerelt támadó ellen nem védene), csak a véletlenszerű/könnyű másolás ellen.
- Jogosultság-újraellenőrzés: legalább 14 naponta online kapcsolat szükséges, különben a letöltött prémium tartalom hozzáférése felfüggesztődik.
Részletek a Craftingtable BC-013 specifikációjában; a kódban még nincs implementálva (a backend src/utils/bunny-stream.ts → azure-blob.ts migráció dokumentum-szintű döntés, külön Work Package-et igényel).