______ ________ _ __ __
/ ____/___ ____ ____/ / ____/ __ | | / /__ / /_
/ /_ / __ \/ __ \/ __ / __/ | |/_/____| | /| / / _ \/ __ \
/ __/ / /_/ / /_/ / /_/ / /____> </_____/ |/ |/ / __/ /_/ /
/_/ \____/\____/\__,_/_____/_/|_| |__/|__/\___/_.___/
Full-stack FoodEx app: Spring Boot backend (apps/backend) + Next.js frontend (apps/frontend).
| Service | Default URL |
|---|---|
| Backend | http://localhost:8080 |
| Frontend | http://localhost:3000 |
| Swagger | http://localhost:8080/swagger-ui/index.html |
- JDK 25
- IntelliJ IDEA (Ultimate recommended for Spring Boot run configs)
- pnpm 10 (frontend)
- AuthSCH OAuth client (auth.sch.bme.hu console)
Work from apps/backend (Gradle project root).
- Create an OAuth client at auth.sch.bme.hu.
- Set Átirányítási cím (redirect URI) to:
http://localhost:8080/login/oauth2/code/authsch - Create
apps/backend/src/main/resources/config/application-local.propertiesusing the config below and update it with your AuthSCH credentials:
### SPECIFY AUTHSCH
spring.security.oauth2.client.registration.authsch.client-id=YOUR_CLIENT_ID
spring.security.oauth2.client.registration.authsch.client-secret=YOUR_SECRET_CLIENT_KEY
spring.jpa.show-sql=trueOptional: enable the H2 console only for local debugging:
spring.h2.console.enabled=trueTo grant SUPERUSER on login (admin pages plus granting/revoking ADMIN), edit:
apps/backend/src/main/resources/config/superusers.properties
# key = AuthSCH internalId (OIDC subject)
# value = note (documentation only)
your-uuid-here=Your Name (backend)Re-login after changing this file. AuthSCH FoodEx executives still become ADMIN without being listed here.
cd apps/backend
# local profile (loads application-local.properties)
./gradlew bootRun --args='--spring.profiles.active=local'
# local + demo seed data (TestConfig)
./gradlew bootRun --args='--spring.profiles.active=local,test'API: http://localhost:8080 After AuthSCH login you are redirected to the SPA: http://localhost:3000
- Open the project from
apps/backend(or open the monorepo and import the Gradle module). - Link Gradle: open
build.gradle.ktsand refresh (Gradle elephant icon). - Run / Debug Configuration → Spring Boot:
- Main class:
hu.kirdev.foodex.FoodExApplication - JDK: 25
- Active profiles:
localFor demo data:local,test
- Main class:
- Debug / Run.
Open:
http://localhost:8080/oauth2/authorization/authsch
On success the backend redirects to foodex.frontend-url (default http://localhost:3000).
Public smoke endpoint (no login): http://localhost:8080/api/homepage
Session user (login required): GET /api/users/me — returns the current user’s DetailedUserDto (id, role, profile, …). 401 if not logged in.
From apps/backend:
# all tests
./gradlew test
# single class
./gradlew test --tests 'hu.kirdev.foodex.shift.ShiftServiceCapacityTest'
# single method
./gradlew test --tests 'hu.kirdev.foodex.security.SecuritySmokeTest.homepage is public'
# HTML report
# apps/backend/build/reports/tests/test/index.htmlTests use an in-memory H2 DB and do not need AuthSCH credentials or application-local.properties.
In IntelliJ: right-click a test class/method or src/test/kotlin → Run.
Most /api/** routes need a logged-in Spring session. Mutating methods also need CSRF.
| Status | Typical meaning |
|---|---|
| 401 Unauthorized | Missing/invalid JSESSIONID (not logged in to the backend) |
| 403 Forbidden | Often missing/wrong CSRF header; or authenticated but not allowed (e.g. not club leader / admin) |
| 201 / 200 | Success |
After AuthSCH login, DevTools will show cookies on several domains. Only http://localhost:8080 cookies are used by this API:
| Cookie | Domain | Use it? |
|---|---|---|
JSESSIONID |
localhost:8080 | Yes — backend session |
XSRF-TOKEN |
localhost:8080 | Yes — CSRF (send again as header) |
PHPSESSID |
auth.sch.bme.hu | No — AuthSCH only; useless for /api/** |
How to copy them:
- Sign in via http://localhost:8080/oauth2/authorization/authsch (must complete against the backend).
- Browser DevTools → Application → Cookies → select
http://localhost:8080(notauth.sch.bme.hu). - Copy
JSESSIONIDandXSRF-TOKEN. IfXSRF-TOKENis missing, open http://localhost:8080/api/homepage or Swagger once while logged in.
Restarting the backend invalidates in-memory sessions — log in again and copy new cookies.
# Values from DevTools → Cookies → http://localhost:8080
SESSION='paste-JSESSIONID-here'
TOKEN='paste-XSRF-TOKEN-here'
curl -X POST 'http://localhost:8080/api/requests' \
-H 'Content-Type: application/json' \
-H "X-XSRF-TOKEN: $TOKEN" \
-H "Cookie: JSESSIONID=$SESSION; XSRF-TOKEN=$TOKEN" \
-d '{
"cookingClubId": 403,
"opening": "2026-08-03T13:00:00",
"closing": "2026-08-03T18:00:00",
"place": "nagykonyha",
"description": "example"
}'Requirements for POST / PUT / PATCH / DELETE:
Cookie: JSESSIONID=...— real session fromlocalhost:8080(not a placeholder, not AuthSCH’sPHPSESSID).Cookie: XSRF-TOKEN=...andHeader: X-XSRF-TOKEN: ...— same token value from theXSRF-TOKENcookie.
Swagger: http://localhost:8080/swagger-ui/index.html
- Use it in the same browser after backend login so
JSESSIONIDis sent automatically. - Swagger does not add
X-XSRF-TOKENfor you. Prefer curl (above) for POSTs, or inject the header via browser tooling. - “Authorize” in Swagger does not replace session + CSRF for this cookie-based setup.
- CORS allows
http://localhost:3000with credentials. - Frontend must send cookies (
credentials: 'include') and on mutating requests set headerX-XSRF-TOKENfrom theXSRF-TOKENcookie. - After login, call
GET /api/users/mewithcredentials: 'include'to load the current user (id,role, profile fields). Use that instead of guessing the user id. Safe GETs only need the session cookie; CSRF is for mutating methods.
From the repository root:
pnpm installpnpm start:frontend
# → http://localhost:3000Run the backend at the same time so the SPA can call the API.
pnpm lint
# or
pnpm lint:fixpnpm format:check
# or
pnpm formatpnpm build:frontendCI is expected to fail if pnpm lint or pnpm format:check fails.
# terminal 1 — backend
cd apps/backend
./gradlew bootRun --args='--spring.profiles.active=local,test'
# terminal 2 — frontend (repo root)
pnpm install # once
pnpm start:frontend- Visit http://localhost:3000
- Sign in via http://localhost:8080/oauth2/authorization/authsch
- Use the app; API session + CSRF apply as above
cd apps/backend
docker build . -t harbor.sch.bme.hu/org-kir-dev/foodex-backend:latestcd apps/frontend
docker build . -t harbor.sch.bme.hu/org-kir-dev/foodex-frontend:latestdocker login harbor.sch.bme.hudocker push harbor.sch.bme.hu/org-kir-dev/foodex-backend:latestdocker push harbor.sch.bme.hu/org-kir-dev/foodex-frontend:latestdocker run -p 8080:8080 harbor.sch.bme.hu/org-kir-dev/foodex-backend:latestdocker run -p 3000:3000 harbor.sch.bme.hu/org-kir-dev/foodex-frontend:latestkubectl config current-context
kubectl get pods -Ak9s ________ __ _______ __ __ __
/\ _____\ /\ \/\ ____\ /\ \ __/\ \ /\ \
\ \ \_____ ____ ____ \_\ \ \ \____ __ _ \ \ \/\ \ \ \ __\ \ \____
\ \ ____\/ __`\ / __`\ /'_` \ \ ___\ /\ \/ \ _______\ \ \ \ \ \ \ /'__`\ \ '__`\
\ \ \ /\ \_\ \/\ \_\ \/\ \_\ \ \ \____ \/> <//\______\\ \ \_/ \_\ \/\ __/\ \ \_\ \
\ \_\ \ \____/\ \____/\ \___,_\ \_____\ /\_/\_\/______/ \ `\___x___/\ \____\\ \_,__/
\/_/ \/___/ \/___/ \/__,_ /\/_____/ \/_/\/_/ '\/__//__/ \/____/ \/___/