Ugrás a fő tartalomhoz

Build, futtatás, Azure üzemeltetés

BC-087 döntés óta (2026-11-03, késő este) a Forrás-Code desktop-elsődleges: az Electron app az egyetlen tényleges kliens, a web app csak marketing + vásárlás. A kurzusvideó Azure Blob Storage-ban van (l. BC-013, Craftingtable), a Strapi saját media library-ján keresztül feltöltve, aláírt (SAS) URL-lel kiszolgálva — ugyanazt az URL-t használja az online lejátszás (<video>) és a Go sidecar offline letöltése is.

1. Előfeltételek​

EszközVerzióMire kell
Node.js20+ (a repo 22-t használ)backend, web, desktop
pnpmcorepack enable elégmonorepo package manager
Go1.22+a desktop Go sidecar fordításához (apps/desktop/sidecar)
Docker—Postgres, Adminer, Azurite (lokális Azure Blob emulátor)
cd business-apps/forras-code
pnpm install

Backend env: másold apps/backend/.env.example-t apps/backend/.env-re, és töltsd ki (l. 3. és 4. pont a konkrét Azure/Azurite értékekhez).

2. Lokális fejlesztői futtatás (mind a három app egyszerre)​

pnpm run dev

Ez (package.json gyökér predev/dev szkriptje):

  1. docker compose up -d — elindítja a Postgres-t (és az Adminer-t, Azurite-ot, ha fel van véve a docker-compose.yml-be, l. 4. pont).
  2. Párhuzamosan (concurrently) elindítja:
    • a Strapi backend-et (:1337),
    • a web app Vite dev szerverét (:5173),
    • és — amint a :5173 felállt (wait-on) — az Electron desktop appot, ami a Vite dev szerverre töltődik be (FORRAS_CODE_WEB_DEV_URL, alapértelmezetten http://localhost:5173).

Az Electron dev szkriptje (apps/desktop/package.json) minden indításkor lefordítja a Go sidecar-t (go build) — ezért kell lokálisan telepített Go. Sikeres bejelentkezés után a renderer elindítja a sidecar-t (sidecar:start IPC), ami egy helyi, csak localhost-on figyelő, Bearer-tokennel védett HTTP szervert indít (l. a SKL-electron-desktop-csomagolas-es-offline-first-eloirasok Craftingtable skillt).

Csak egy-egy app külön:

pnpm run dev:backend # Strapi :1337
pnpm run dev:web # Vite :5173
pnpm run dev:desktop # Electron (a web dev szerverre csatlakozik)

3. Lokális Azure Blob reprodukálás Docker-ben (Azurite)​

Nem kell valós Azure fiók a fejlesztéshez — a docker-compose.yml tartalmaz egy Azurite szolgáltatást, ami a Blob Storage API-t pontosan úgy emulálja, mint a valós Azure. A backend kódja (src/utils/azure-blob.ts, strapi-provider-upload-azure-storage-v5) változtatás nélkül, ugyanazokkal az env-kulcsokkal megy Azurite ellen, mint valós Azure ellen — csak az URL-ek különböznek.

docker compose up -d azurite

apps/backend/.env (l. .env.example "Opció A" blokk — ez Azurite publikus, mindenki gépén azonos fejlesztői alapértelmezése, NEM titok):

AZURE_STORAGE_ACCOUNT=devstoreaccount1
AZURE_STORAGE_ACCOUNT_KEY=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==
AZURE_STORAGE_CONTAINER=forras-code-videos
AZURE_STORAGE_URL=http://127.0.0.1:10000/devstoreaccount1

Indítsd újra a backendet — a konténer automatikusan létrejön (a provider createIfNotExists()-et hív induláskor). Ha a Strapi admin panelen (Platform Settings) a videoMockMode be van kapcsolva, kapcsold ki, különben a chapter controller mindig mock módban marad (l. isVideoMockModeEnabled()), és sosem próbál tényleges Azure/Azurite hívást.

Két buktató, amire a bevezetés közben derült fény (mindkettő már megoldva a kódban/compose-ban, csak dokumentálva, hogy miért van úgy, ahogy van):

  1. Azurite API-verzió — az @azure/storage-blob SDK újabb API-verziót küld, mint amit egy adott Azurite image ismer, ezért a docker-compose.yml-ben az Azurite parancs --skipApiVersionCheck flaggel fut. Nélküle minden kérés "API version ... is not supported by Azurite" hibával esik el.
  2. SAS protokoll — a valós Azure Blob Storage mindig HTTPS, de Azurite lokálisan sima HTTP-n fut. A generateSignedVideoUrl() (src/utils/azure-blob.ts) ezért a SAS protocol paraméterét a serviceBaseURL alapján választja: https:// esetén SASProtocol.Https, minden más esetén (pl. Azurite http://127.0.0.1:10000/...) SASProtocol.HttpsAndHttp. Éles Azure ellen ez nem változtat semmit (a serviceBaseURL ott mindig https://).

Végig tesztelve (2026-11-03): Strapi upload → Azurite → aláírt SAS URL → teljes fájl letöltés (byte-exact) → Range (206 Partial Content) kérés → Go sidecar /downloads végpontja ugyanerről a SAS URL-ről darabolva letölt, AES-256-GCM-mel titkosítva tárol, és dekódolva, byte-exact módon szolgál ki.

Blobok megtekintése Azurite-ban (opcionális, hibakereséshez): Azure Storage Explorer → "Attach to a local emulator", vagy Azure CLI-vel:

az storage container list \
--connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;"

4. Teljes (production-szerű) build​

pnpm run build:backend # Strapi admin + TS build (apps/backend/dist)
pnpm run build:web # Vite production build (apps/web/dist)
pnpm run build:desktop # Go sidecar build + Electron TS build

Desktop csomagolás (telepítő előállítása az adott OS-re):

cd apps/desktop
pnpm run package # electron-builder — mac: .dmg, win: nsis .exe, linux: AppImage/.deb

A kimenet apps/desktop/release/ alatt jön létre. Az electron-builder konfig (package.json "build" blokk) a lefordított web app-ot (../web/dist) és a lefordított Go sidecar binárist (sidecar/dist) is becsomagolja — tehát előbb build:web és a sidecar build (build:desktop ezt már megcsinálja) kell, hogy lefusson.

Docker image-ek (backend + web — a web image jelenleg nem a tényleges futó klienshez kell, hiszen a web app csak marketing+vásárlás, de CI-ban leteszteli, hogy a build reprodukálható):

docker build -t forras-code-backend -f apps/backend/Dockerfile apps/backend
docker build -t forras-code-web -f apps/web/Dockerfile apps/web

CI-ban ez már megy (forras-code-backend-ci.yml, forras-code-web-ci.yml) — jelenleg szándékosan nem push-olnak sehová (nincs még konfigurált éles registry/hoszt, l. 5.2 pont).

5. Mit kell létrehozni/konfigurálni Azure-ban (éles üzemhez)​

5.1. Azure Storage Account + Blob Container (kurzusvideó) — ez kell feltétlenül​

Azure Portal:

  1. Create a resource → Storage account → Standard performance, LRS (vagy GRS, ha több régiós redundancia kell) → hozd létre.
  2. A resource → Containers → + Container → név (pl. forras-code-videos) → Access level: Private (fontos — a videó sosem publikus, csak a saját SAS-tokenünkkel kiszolgált).
  3. A resource → Access keys → key1 → Show → ez lesz AZURE_STORAGE_ACCOUNT_KEY, a resource neve AZURE_STORAGE_ACCOUNT.

Vagy Azure CLI-vel egyszerűbben:

az group create -n forras-code-prod -l westeurope

az storage account create \
-n <storage-account-neve> -g forras-code-prod -l westeurope \
--sku Standard_LRS --kind StorageV2

az storage container create \
--account-name <storage-account-neve> \
--name forras-code-videos --public-access off

az storage account keys list \
--account-name <storage-account-neve> -g forras-code-prod -o table

A kapott értékeket töltsd a (production) .env-be:

AZURE_STORAGE_ACCOUNT=<storage-account-neve>
AZURE_STORAGE_ACCOUNT_KEY=<key1 értéke>
AZURE_STORAGE_CONTAINER=forras-code-videos
# AZURE_STORAGE_URL nincs megadva → a kód a https://<account>.blob.core.windows.net
# alapértelmezést használja, ami éles Azure-nál mindig helyes.

CORS-ot NEM kell beállítani a Storage Account-on. A videó lejátszás egy sima <video src="..."> tag-gel megy (VideoPlayer.tsx) — ehhez a böngésző nem követeli meg CORS header-t (az csak fetch()/canvas/XHR-szintű hozzáféréshez kellene). A Go sidecar letöltése sem böngészőből megy, hanem natív Go HTTP kliensből — a CORS egy tisztán böngésző-oldali mechanizmus, oda nem vonatkozik.

5.2. Hol fusson a Strapi backend éles üzemben (javasolt, külön munka)​

Ehhez a session-höz nem tartozott hozzá — a backend jelenleg csak CI-ban buildelődik (push: false), nincs még élesben futó hosztja. A monorepóban már van egy bevált minta hasonló (stateful, Postgres-hez kötött) szolgáltatásra — a Fider (infra/azure-deploy.md 5. pont) Azure Container Apps-ra megy. Javasolt ugyanez a Strapi backendnek is:

  • Azure Container Apps — a meglévő apps/backend/Dockerfile image-et futtatja, HTTPS-t, scale-to-zero-t és custom domaint ad natívan.
  • Azure Database for PostgreSQL – Flexible Server (legkisebb Burstable tier) — DATABASE_HOST/DATABASE_PASSWORD ide mutat, DATABASE_SSL=true.
  • Image push: Azure Container Registry (ACR) vagy GitHub Container Registry — a meglévő forras-code-backend-ci.yml workflow-t egy docker/build-push-action + az containerapp update lépéssel kellene kiegészíteni.
  • A feltöltött fájlok (public/uploads) ÉRDEMES volume-ba tenni Container Apps-nál is — bár videó már nem oda megy (Azure Blob-ba), a Strapi admin média (pl. kurzus thumbnail) helyben tárolódna konténer-újraindításkor elveszve, ha nincs volume. Alternatíva: állítsd az upload provider-t MINDEN médiatípusra Azure Blob-ra, ne csak a chapter videóra (jelenleg csak a video mezőn megy keresztül a custom controller logika, de a config/plugins.ts globálisan konfigurálja a providert, tehát a thumbnail/materialsFile is Azure-ba menne, ha be van állítva).

Ez egy önálló, külön átgondolást igénylő feladat (registry választás, Container Apps env/scaling, CI workflow bővítés) — szólj, ha ezt is lépésről lépésre végig akarod vinni, az egy új munkamenet/session legyen.

5.3. M365 SMTP — nem Azure resource, hanem a tenant beállítása​

Ez a Microsoft 365 admin center-ben van, nem az Azure Portalon: Postafiók → Beállítások → SMTP AUTH engedélyezve. Utána:

SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_USERNAME=<az M365 postafiók email címe>
SMTP_PASSWORD=<az M365 postafiók jelszava, vagy app password, ha MFA van>
SMTP_DEFAULT_FROM=<ugyanaz, mint SMTP_USERNAME>

Amíg ez üres, a rendszer jsonTransport/mock módban fut (l. config/plugins.ts email blokk) — nem küld valós emailt, csak logol. Production-ban (NODE_ENV=production) a bootstrap (src/index.ts) hard-fail-t dob, ha ez hiányzik — szándékosan, hogy a jelszó-visszaállítás sose tűnjön "sikeresnek" anélkül, hogy valódi emailt küldene.

5.4. Lemon Squeezy — nem Azure resource​

A fizetés/előfizetés külső szolgáltatás (LEMONSQUEEZY_* env-ek, app.lemonsqueezy.com) — ehhez nincs Azure-oldali teendő, csak a webhook endpoint-nak kell élesben elérhetőnek lennie (l. 5.2 — ha a backend nincs hostolva, a webhook sem tud megérkezni).

6. Ismert korlátok / nyitott pontok (ezt a build/deploy leírást nem érintik, de ide tartoznak)​

  • A Go sidecar letöltött videójának lejátszása közvetlenül a lokális cache-ből (<video> elem a sidecar lokális szerverét érje el, auth token nélkül a renderer-ben) még nincs bekötve — jelenleg csak a letöltés/tárolás kész, l. apps/web/src/lib/offlineDownload.ts megjegyzése.
  • A feliratok (captions) .vtt tartalma még nincs tárolva, csak jelző mezők (hasCaptions/captionsLang) — l. uploadCaptions controller megjegyzése.
  • Chapter.video (a media reláció) jelenleg nincs populate-elve a fetchChapters lista-hívásban — ezért a tartalomjegyzék "▶" jelzése azure-videós fejezeteknél nem jelenik meg (csak mock-nál). Nem biztonsági probléma (a video.url amúgy sem lenne SAS-aláírt, tehát nem kellene publikusan populate-elni élesben sem) — ha a jelzés fontos, egy külön, entitlement-mentes "van-e videó" boolean mezőt érdemes felvenni, NEM populate-elni a teljes media relációt.