Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ public/videos/*

# Local environment files may contain deployment secrets.
.env*

# Never package applicant documents or local test credentials
private
.local-verification
.career-tests-*
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ jobs:
- name: Run TypeScript checks
run: yarn tsc --noEmit

- name: Test career applications
run: yarn test:career

container:
name: Build Docker image
needs: quality
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:
- name: Run TypeScript checks
run: yarn tsc --noEmit

- name: Test career applications
run: yarn test:career

build:
name: Build and publish image
needs: quality
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,7 @@ yarn-error.log*
next-env.d.ts
/.idea/
/yarn.lock
public/videos
public/videos
# Private applicant documents and local verification artifacts
/private/
/.local-verification/
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,36 @@ See [docs/deployment.md](docs/deployment.md) for environment setup, required sec
- Theming and reusable UI components

If you have questions or want to contribute, feel free to open an issue or PR.

### Szerkeszthető űrlap és önéletrajzok

A **Karrier oldal → Űrlap kérdései** fülön szerkeszthetők a magyar/angol feliratok,
segédszövegek, sorrend, kötelezőség és láthatóság. Új kérdésként rövid vagy hosszú
szöveg, egy- vagy többválasztós mező és jelölőnégyzet adható hozzá. A név, e-mail
és hozzájárulás kötelező; a csoport és pozíció mező megőrzi az automatikus kitöltést.
A hozzájárulás mindig az űrlap végén jelenik meg. A kérdés- és opcióazonosítók
állandók. A jelentkezések a beküldéskori kérdéseket, opciókat és válaszokat is tárolják.
Ha kitöltés közben módosul az űrlap, a beküldés frissíti a kérdéseket és újraellenőrzést
kér, miközben a beírt válaszok és a kiválasztott CV megmaradnak.

Az opcionális CV egy érvényes, nem titkosított PDF lehet, maximum **5 MiB**.
A fájl a privát `application-cvs` kollekcióba kerül, csak bejelentkezett admin
olvashatja vagy töltheti le. A jelentkezés törlése a hozzá tartozó fájlt is törli.
A nyilvános médiatárba nem kerül önéletrajz. Helyi tárolási útvonal:
`private/cvs`; a `CV_STORAGE_DIR` változóval felülírható. Dockerben külön,
környezetenként elkülönített `applicant_cvs` kötet tárolja a fájlokat.

Állítsd be a **`NEXT_PUBLIC_SERVER_URL`** változót az adott környezet nyilvános
HTTPS címére (helyben például `http://localhost:3107`). A Google-táblázat a
korábbi tíz oszlop után a **További válaszok** és **Jelentkezés az adminban**
oszlopokat kapja. A második linkről adminbelépés után tölthető le a CV.
Ha a K–L oszlopban már saját adatok vannak, az export hibát jelez, és nem írja
felül őket: előbb helyezd át ezeket, majd használd az újraszinkronizálás gombot.
A jelentkezés és CV táblázathiba esetén is megmarad.

A **Kapcsolat** bejegyzésben szerkeszthető a kiállítási gomb HTTPS linkje és
magyar/angol felirata. Üres linknél a gomb nem jelenik meg. Ezeket a beállításokat
csak bejelentkezett admin módosíthatja.

Ellenőrzések: `yarn test:career`, `yarn tsc --noEmit`, `yarn eslint <érintett fájlok>`.
Adatbázis-frissítés: `yarn payload:migrate`; generált típusok: `yarn payload:generate-types`.
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
dockerfile: Dockerfile
volumes:
- frt:/app/media
- applicant_cvs:/app/private/cvs
- ./public/videos:/app/public/videos
depends_on:
postgres:
Expand All @@ -47,6 +48,7 @@ services:
volumes:
postgres:
frt:
applicant_cvs:

networks:
postgres:
Expand Down
31 changes: 31 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,34 @@ cd /srv/frt-preview
```

Ez sem végez helyi Docker buildet.

## Privát önéletrajzok mentése és helyreállítása

A Compose `applicant_cvs` kötete az `/app/private/cvs` könyvtárra csatlakozik.
A staging és production külön Compose projektnevét továbbra is kötelező használni.
A helyi CV-ket és tesztadatokat a Docker build és a Git figyelmen kívül hagyja.
A `NEXT_PUBLIC_SERVER_URL` az adott környezet publikus címe legyen, hogy a
Google-táblázatban szereplő adminhivatkozások teljes URL-ek legyenek.

A production telepítési script az adatbázismentés mellé `postgres-<id>-cvs.tar.gz`
fájlt is készít. Sikertelen fájlmentés esetén a migráció nem indul el. Mindkét
mentés személyes adatokat tartalmazhat; a script 600-as fájljogosultságot állít be.
Az adatbázis és a CV-archívum együtt kezelendő. Konzisztens kézi mentéshez és
helyreállításhoz állítsd le az alkalmazás írásait/alkalmazáskonténerét.

Helyreállítás próbája kizárólag elkülönített környezetben:

1. Az adatbázis dumpját állítsd vissza egy külön PostgreSQL-adatbázisba.
2. Az azonos időpontú archívumot bontsd ki az elkülönített privát kötetbe
(`tar -xzf <archívum> -C <privát-könyvtár>`; az archívumban `cvs/` szerepel).
3. Indítsd el az alkalmazást ezzel az adatbázissal és `CV_STORAGE_DIR` útvonallal.
4. Adminbelépéssel tölts le egy önéletrajzot, és hasonlítsd össze az eredeti
SHA-256 lenyomatával. Belépés nélkül ugyanez a URL legyen elutasítva.
5. Újraindítás után ismételd meg a letöltést. Az eredeti környezetet a próba nem módosíthatja.

A korábbi migrációs snapshotok már tartalmazták a Kapcsolat-táblát, de az
üres adatbázist felépítő migrációs lánc nem. A `contact_baseline` migráció ezt
`IF NOT EXISTS` műveletekkel pótolja, meglévő kapcsolati adatok megőrzésével.
Visszavonása szándékosan nem törli a táblát. A következő migráció az új kérdéseket,
CV-kapcsolatot és kiállítási gombmezőket adja hozzá; éles adatokat tartalmazó
adatbázison visszavonás helyett előre javító migrációt használj.
3 changes: 3 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const eslintConfig = [
ignores: [
".next/**",
"coverage/**",
".local-verification/**",
".career-tests-*/**",
"private/**",
"next-env.d.ts",
"node_modules/**",
"src/payload-types.ts",
Expand Down
32 changes: 32 additions & 0 deletions karrier-ellenorzes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Karrierfejlesztés – helyi ellenőrzés

2026. szeptember 6. Helyi alkalmazás: http://127.0.0.1:3107/karrier

- `yarn build`: sikeres (187 másodperc). Két meglévő, az érintett funkcióktól független lintfigyelmeztetés maradt a `car-section.tsx` és `image-gallery.tsx` fájlokban.
- `yarn tsc --noEmit`: sikeres. Célzott ESLint, `git diff --check`, a telepítési script szintaxisellenőrzése és a staging Compose konfiguráció ellenőrzése sikeres.
- `yarn test:career`: 12/12 teszt sikeres. Kötelező alapmezők, választós mezők, hosszkorlát, hibás PDF és feltöltési méret, JSON/multipart bemenet, fejlécütközés, szinkronhiba és teljes 12 oszlopos RAW export.
- Valódi helyi HTTP-próbák: régi JSON beküldés; dinamikus kötelező kérdés és hamis opció; konfigurációváltozás (409); PDF mentés/letöltés; névtelen fájlhozzáférés (403); hiányzó adminjog és hibás kiállítási URL; zárt/külső jelentkezés; honeypot és kéréskorlát (429).
- Kényszerített adatbázishiba után a feltöltött CV takarítása sikeres. Jelentkezés törlésekor a CV rekordja és fájlja is eltűnik. A konfigurációból törölt kérdés válaszai és eredeti feliratai a korábbi jelentkezésben megmaradnak.
- Látható Chromium-böngésző: 1440 px asztali, 390 px mobil és 420 px magas képernyő; magyar/angol cím és menü; kilenc csoport; GYIK a jelentkezés előtt; pozíció-előtöltés; HU beküldés CV-vel és EN beküldés CV nélkül. A panel és az első csoport felső éle azonos, a GYIK-ugrás a felső menü alá érkezik. Nem volt JavaScript-oldalhiba.
- Adminból új, kötelező, kétnyelvű kérdés létrehozása és mentése sikeres. Egy korábban megnyitott űrlap beküldése jelezte a változást, megőrizte a válaszokat és a CV-t; az új kérdés kitöltése után sikeres volt a beküldés. A jelentkezés az adminban CV-vel és olvasható válaszösszesítővel jelenik meg.
- A buildből indított standalone alkalmazáson az üres GYIK, a zárt/külső jelentkezési mód, a billentyűzetes szakasznavigáció és az újraindítás utáni privát CV-letöltés is sikeresen ellenőrizve.
- A kiállítási gomb új lapon megnyitotta a megadott Google-űrlapot, címe: „BME FRT - Rendezvényen való kiállítási igény”.
- Adatbázis- és CV-mentés visszaállítása külön adatbázisba és könyvtárba sikeres. A CV-hivatkozás és a fájl SHA-256 lenyomata egyezik. A visszaállított adatbázison az új migráció visszavonása és ismételt futtatása sikeres; a régi jelentkezés és a kapcsolati tartalom megmaradt.

A helyi adatbázis `frt_career`, külön Docker-konténerben, az 55439-es porton fut.
A kilenc csoport, a kapcsolati szöveg és a jelentkezések helyi tesztadatok.
A helyi admin adatai a Gitből és a Docker buildből kizárt
`.local-verification/admin.json` fájlban vannak. Az eredeti `.env` változatlan;
a helyi környezet külön `.env.local` beállításokat használ, üres Google-szolgáltatásfiókkal.

A Google Sheets-exportot szimulált API-válaszokkal ellenőriztük, valódi táblázatba
nem írtunk. Élesítéskor a dokumentált publikus URL-beállítás és a tartós privát
CV-kötet szükséges. Az ellenőrzés helyi környezetben történt; push és élesítés nem történt.

## Világos téma kontrasztjavítása

- A karrieroldal külön szemantikus színkészletet használ. Világos módban semleges kártyák, sötét szövegek, jól látható mezőkeretek és piros, fehér feliratú gombok jelennek meg. A korábbi globális színfelülírások nem érintik ezeket az elemeket.
- Látható Chromium: világos magyar 1440/390 px, világos angol 1440 px, sötét magyar 1440 px és sötét angol 390 px. Összesen 38 állapotellenőrzés: alapnézet, nyitott csoport/pozíció, oldalsáv, GYIK, hover, mezőfókusz, hibás és sikeres beküldés. Nem volt vízszintes túlcsordulás vagy JavaScript-oldalhiba.
- A helyi teszttartalom megjelenített szövegeinek legkisebb mért kontrasztja 5,34:1. A normál mezőkeretek kontrasztja a környező kártyán világos módban 4,02:1, sötét módban 4,56:1. A sikerpipa kontrasztja világos módban 6,40:1. Ez a vizsgált tartalomra és állapotokra vonatkozó mérés, nem teljes webhely-audit.
- A beküldési állapotokat szimulált HTTP-válaszokkal ellenőriztük; ez az ellenőrzés nem hozott létre jelentkezéseket. Részletes mérések és képek: `.local-verification/career-contrast-results.json`, `career-light-form.png`, `career-light-success.png` és a témánkénti képernyőképek.
- `yarn tsc --noEmit`, a karrieroldal célzott ESLint-ellenőrzése és `git diff --check`: sikeres. A helyi fejlesztői szerver továbbra is a 3107-es porton fut.
18 changes: 18 additions & 0 deletions karrier-visszajelzesek-terv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Karrieroldal és kiállítási igény – javítási terv

Megvalósítva 2026. szeptember 6-án. Az alkalmazás és az admin ellenőrzése elkülönített helyi PostgreSQL-adatbázissal és tesztadatokkal történt. A build, a típusellenőrzés és a 12 célzott teszt sikeres; éles környezetet nem módosítottunk.

Javasolt alapbeállítás: adminból szerkeszthető kérdések; opcionális, egyetlen PDF önéletrajz, legfeljebb 5 MiB; angol főcím: „Join our team!”. Ezek a jóváhagyott terv szerinti alapbeállítások.

- [x] **1. Oldalszerkezet és főcím.** A `career-page-client.tsx` címét és bevezetőjét a teljes tartalmi konténert átfogó sorba emelni. Alatta közös kéthasábos elrendezés: balra csoportok → GYIK → jelentkezés, jobbra az első csoport felső éléhez igazított panel. A főcím „Csatlakozz csapatunkhoz!”, a magyar menüfelirat „Karrier”. A fordításokat a `translations.ts` kezeli. Mobilon egyhasábos tartalom marad. Elfogadás: hosszabb bevezetővel is az első csoport mellett kezdődik a panel.
- [x] **2. Oldalsáv és szakasznavigáció.** A `career-sidebar.tsx` három eleme: alapból csukott „Csoportok” lenyíló, „Gyakran ismételt kérdések” ugrólink, jelentkezési gomb. A lista a CMS aktuális csoportjait használja, nincs beégetett kilences darabszám. Csoportválasztáskor a célcsoport kinyílik és odagörgetünk; a listát visszacsukjuk. A GYIK stabil `gyik` horgonyt kap, linkje csak az adott nyelven megjelenő GYIK esetén látszik. A `use-career-page.ts` görgetése és a sticky távolság a felső menü alá igazodik; alacsony képernyőn minden panelvezérlő elérhető. Billentyűzet, fókuszjelzés, `aria-expanded`, csökkentett mozgás támogatása. A zárt jelentkezés és a külső Google-űrlap mód viselkedése megmarad.
- [x] **3. Menüsorrend.** A `src/config/navigation.ts` listában a Karrier a Rólunk után kerül. Elfogadás: asztali és mobilmenüben, magyarul és angolul is ez az utolsó tartalmi menüpont; a láthatósági beállítás tovább működik.
- [x] **4. Szerkeszthető jelentkezési kérdések.** A `CareerSettings.ts` új „Űrlap kérdései” fülén a meglévő mezők felirata, súgója és sorrendje szerkeszthető; az opcionális mezők elrejthetők vagy kötelezővé tehetők. Név, e-mail és hozzájárulás kötelező alapmező marad, a csoport/pozíció automatikus kitöltése megmarad. Új kérdésként rövid/hosszú szöveg, egy- vagy többválasztós kérdés és jelölőnégyzet adható hozzá, HU/EN felirattal és opciókkal. Stabil kérdés- és opcióazonosítók; az `application-form.tsx` és a szervervalidáció ugyanazt a konfigurációt követi. A `JobApplications.ts` az új válaszok mellé a beküldéskori kérdésszöveget, opciókat, nyelvet és konfigurációverziót is menti. Kérdés törlése a régi válaszokat nem törli; beküldés közbeni konfigurációváltozásnál érthető hibajelzés, adatvesztés nélkül. Elfogadás: adminban hozzáadott kérdés megjelenik, validálódik és visszaolvasható.
- [x] **5. CV-feltöltés.** A kérdések után, a hozzájárulás és beküldés előtt fájlmező: fájlnév, eltávolítás/csere, típus- és mérethatár jelzése. A `/api/karrier/jelentkezes` multipart beküldést fogad, szerveroldalon is ellenőrzi a méretet és PDF-tartalmat; a korábbi JSON beküldés támogatása megmarad. Új privát upload-kollekció és kapcsolat a jelentkezéshez: beküldés kizárólag az ellenőrzött API-n át, olvasás/letöltés csak belépett adminnak. Külön tartós Docker-kötet, például `/app/private/cvs`, környezetenként elkülönítve, mentéssel és helyreállítási próbával. Hibás jelentkezés után ne maradjon árva fájl; jelentkezéstörlés a CV-t is takarítsa. Meglévő botvédelem megtartása, teljes kérésméret korlátozása. Elfogadás: CV-vel és nélküle is sikeres beküldés, hibás/túlméretes fájl elutasítása, névtelen letöltés tiltása, újraindítás után elérhető dokumentum. A jogosultsági megoldást a [Payload feltöltési dokumentációja](https://payloadcms.com/docs/upload/overview) támogatja.
- [x] **6. Google Sheets és adatmigráció.** A `karrier-sheet-sync.ts` / `google-sheets.ts` a meglévő tíz oszlop után „További válaszok” és „Jelentkezés az adminban” oszlopot kap; utóbbiból érhető el a CV is belépés után. Az összesítő a beküldéskori kérdés–válasz párokat tartalmazza. A jelenlegi fejléc csak üres táblánál jön létre, ezért ellenőrzött fejlécbővítés kell, idegen oszlop felülírása nélkül. Sheets-hiba nem akadályozhatja a jelentkezés/CV mentését; adminból újraszinkronizálható marad. Payload-migrációk, típusgenerálás és README-frissítés; a régi rekordok új mezői opcionálisak, a jelenlegi űrlap az induló konfiguráció.
- [x] **7. Kiállítási igény gomb.** A `Contact.ts` kollekcióban szerkeszthető URL és HU/EN gombfelirat, a `kapcsolat/page.tsx` innen olvas. A megadott [Google-űrlap](https://docs.google.com/forms/d/e/1FAIpQLSdrA3VX3YpxQB3uZ1ojXov8-J3LPawAt4ip_Aj4k8FNbNOCrA/viewform?usp=dialog) legyen az induló cél, a meglévő rekordot is kitöltő migrációval; üres URL-nél nincs gomb. HTTPS URL-validáció, új lapos megnyitás. A jelenlegi `Contact` nyilvános létrehozási/frissítési hozzáférését bejelentkezett adminra kell szűkíteni, hogy a publikus API-n se lehessen átírni a linket. Elfogadás: adminból módosított link jelenik meg, névtelen írás tiltott. A böngészős próba megnyitotta a „BME FRT - Rendezvényen való kiállítási igény” űrlapot.
- [x] **8. Végső ellenőrzés.** Elkülönített tesztadatbázison migráció és visszaolvasás régi jelentkezésekkel; TypeScript (`yarn tsc --noEmit`), célzott ESLint (`yarn eslint …`), build. Célzott API-tesztek a dinamikus validációra, fájlhozzáférésre és hibák utáni takarításra; Sheets-próba kizárólag teszttáblán. Böngészős próba HU/EN nyelven, mobilon és asztali/ alacsony képernyőn: sorrend, paneligazítás, csoport/ GYIK ugrás, pozíció-előtöltés, üres GYIK, zárt/külső jelentkezés, teljes beküldés és adminos CV-letöltés. Élesítés külön egyeztetett lépés.

Megvalósítási sorrend: 1–3. megjelenés → 4–6. szerkeszthető űrlap és CV teljes adatútja → 7. kapcsolati gomb → 8. ellenőrzés. A megjelenési rész önállóan is szállítható; az űrlap, tárolás, export és migráció együtt alkot teljes változtatást.

Ellenőrzési részletek: [karrier-ellenorzes.md](./karrier-ellenorzes.md). A Google Sheets-kéréseket izolált, szimulált teszttáblával ellenőriztük; valódi Google-táblázatba nem írtunk.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"lint": "next lint",
"payload:migrate": "node --import ./css-loader-register.mjs ./node_modules/.bin/payload migrate",
"payload:migrate-status": "node --import ./css-loader-register.mjs ./node_modules/.bin/payload migrate:status",
"payload:generate-types": "node --import ./css-loader-register.mjs ./node_modules/.bin/payload generate:types"
"payload:generate-types": "node --import ./css-loader-register.mjs ./node_modules/.bin/payload generate:types",
"test:career": "node scripts/test-career.mjs"
},
"dependencies": {
"@fullcalendar/core": "^6.1.19",
Expand All @@ -32,6 +33,7 @@
"lucide-react": "^0.511.0",
"next": "15.5.9",
"payload": "^3.80.0",
"pdf-lib": "^1.17.1",
"react": "19.2.1",
"react-dom": "19.2.1",
"tailwind-merge": "^3.3.0",
Expand Down
10 changes: 10 additions & 0 deletions scripts/deploy-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ if [[ "$backup_database" == "true" ]]; then
rm -f "$backup_tmp"
exit 1
fi
cv_backup_path="${backup_path%.dump}-cvs.tar.gz"
echo "Creating private CV backup at $cv_backup_path"
if compose_with "$candidate_env" run --rm -T --no-deps --entrypoint tar app \
-C /app/private -czf - cvs > "$cv_backup_path.tmp"; then
mv "$cv_backup_path.tmp" "$cv_backup_path"
chmod 600 "$backup_path" "$cv_backup_path"
else
rm -f "$cv_backup_path.tmp"
exit 1
fi
fi

echo "Running Payload migrations with the candidate image"
Expand Down
22 changes: 22 additions & 0 deletions scripts/test-career.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { build } from "esbuild";
import { mkdtemp, rm } from "node:fs/promises";
import { spawnSync } from "node:child_process";
import path from "node:path";
const directory = await mkdtemp(path.join(process.cwd(), ".career-tests-"));
try {
const outfile = path.join(directory, "career.test.cjs");
await build({
entryPoints: ["tests/career.test.ts"],
outfile,
bundle: true,
platform: "node",
format: "cjs",
packages: "external",
});
const result = spawnSync(process.execPath, ["--test", outfile], {
stdio: "inherit",
});
process.exitCode = result.status ?? 1;
} finally {
await rm(directory, { recursive: true, force: true });
}
1 change: 1 addition & 0 deletions src/app/(app)/globals.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import "tailwindcss";
@import "tw-animate-css";
@import "./karrier/career-theme.css";
@tailwind utilities;

@plugin "@tailwindcss/typography";
Expand Down
Loading
Loading