This guide provides a streamlined setup for running the LEARN-Hub server locally with a Docker-based PostgreSQL database.
LEARN-Hub has three moving parts that you run locally:
| Part | Tech | Runs at | Started by |
|---|---|---|---|
| Client | React + Vite | http://localhost:3001 | npm run dev (hot reload) |
| Server | Spring Boot (Java 21) | http://localhost:5001 | make dev |
| Database | PostgreSQL 17 | localhost:5432 | Docker Compose |
The typical loop is:
- Once: install prerequisites, copy
example.env→.env, start PostgreSQL in Docker, run migrations, (optionally) seed demo data. - Every day:
make devfrom the repo root to run client + server together. The Vite client hot-reloads on save; restart the server to pick up Java changes. - Before committing:
make formatandmake test.
If you prefer to run everything in containers instead of locally, jump to Docker-based Development.
Ensure you have the following tools installed:
- Java 21 or higher - Required for running the server
- Maven 3.9+ - Required for building (or use included wrapper
./mvnw) - npm - Required for running the client locally
- Docker - Required for running PostgreSQL locally
- LibreOffice - Required when running the Spring Boot server locally because DOCX generation uses
soffice
# Check Java version
java -version # Should show version 21 or higher
# Check npm version
npm -version
# Check Docker version
docker --version
# Check LibreOffice / soffice availability
soffice --versionOn macOS, install LibreOffice with:
brew install --cask libreofficeThe local development profile expects LibreOffice at /Applications/LibreOffice.app/Contents/MacOS/soffice.
Create a .env file in the project root based on example.env:
cp example.env .envexample.env already ships with working defaults for local development – ports (SERVER_PORT=5001, CLIENT_PORT=3001), the PostgreSQL connection, and a TUM-hosted LLM endpoint. The minimum you should set before the first run:
PDF_PATH- an existing folder on your machine where uploaded PDFs are storedLLM_API_KEY- API key for the OpenAI-compatible chat endpoint (needed for activity creation; leave the defaultLLM_BASE_URL/LLM_MODEL_NAMEunless you use your own model)INITIAL_ADMIN_EMAIL/INITIAL_ADMIN_PASSWORD- a known admin login created by the seeder (see Database Seeding)
Required only if you need teacher email verification / credential emails:
EMAIL_ADDRESS- the from address on login emailsEMAIL_USERNAME/EMAIL_PASSWORD- SMTP credentialsSMTP_SERVER/SMTP_PORT- SMTP host and port (default:postout.lrz.de:587)
Optional variables (add to .env manually – not all are listed in example.env):
LLM_IMAGE_MODEL_NAME- image model for exercise illustrations; reusesLLM_BASE_URL/LLM_API_KEYand is enabled when setADOBE_PDF_SERVICES_CLIENT_ID/ADOBE_PDF_SERVICES_CLIENT_SECRET- Adobe PDF Services for PDF-to-DOCX conversionDOCX_CACHE_PATH- cache directory for converted DOCX filesSESSION_TIMEOUT/SESSION_COOKIE_MAX_AGE- session and persistent-cookie lifetime overridesVERBOSE_LOGGING- settruefor more detailed server logs
make setupThis will:
- Resolve Java dependencies for the Spring Boot server
- Install npm dependencies for the React client
make setup does not install LibreOffice. Install that separately before starting the server locally.
Start the PostgreSQL database using Docker Compose:
docker compose -f docker/compose.yml up postgres -dRun migrations (create db tables):
make db-migrateTo populate the database with demo data, set this in your .env:
DB_SEED_ENABLED=trueThen start the server (next step). The seeder will:
- Load the full dataset if
dataset/dataset.csvanddataset/pdfs/are present, otherwise fall back to a handful of demo activities - Create an initial admin user so you can log in immediately
Set a known admin login so you don't have to dig through the logs. Add these to your .env before the first start:
INITIAL_ADMIN_EMAIL=admin@learnhub.com
INITIAL_ADMIN_PASSWORD=choose-a-strong-passwordIf you leave them blank, the seeder generates a random admin password and prints it to the server logs on first startup. Either way, log in via the Password Login tab at http://localhost:3001/login.
Run both client and server locally:
make devThis starts:
- Server on http://localhost:5001
- React client on http://localhost:3001
To run just the server:
cd server
make devTo run just the client:
cd client
npm run devOnce the server is running, verify the setup:
-
API Health Check: Visit http://localhost:5001/api/hello
- Should return:
{"message": "Hello, world!"}
- Should return:
-
API Documentation: Visit http://localhost:5001/api/openapi/swagger
- Should show the Swagger UI with all available endpoints
-
Client UI: Visit http://localhost:3001
- Should display the LEARN-Hub landing page
- Browse as a guest, or sign in at /login with your
INITIAL_ADMIN_EMAIL/INITIAL_ADMIN_PASSWORD(Password Login tab) to reach the admin features (user management, drafts) - Use the controls in the top-right to switch language (English / German) and theme (light / dark)
To stop the database:
docker compose -f docker/compose.yml downTo stop the server, press Ctrl+C in the terminal where it's running.
If port 5001 is already in use, change it in .env:
SERVER_PORT=5002Check if PostgreSQL is running:
docker compose -f docker/compose.yml psIf not running, start it:
docker compose -f docker/compose.yml up postgres -dIf you encounter migration errors, you can clean and reapply:
make db-clean
make db-migrateWarning: This will delete all data in the database.
Ensure you have Java 21 or higher:
java -versionIf you have multiple Java versions, set JAVA_HOME:
export JAVA_HOME=/path/to/java21To run the entire stack (PostgreSQL + Spring Boot + React) in Docker:
docker compose -f docker/compose.yml up --buildThe server Docker image already installs LibreOffice (libreoffice-writer), so no extra host setup is required for containerized runs.
Access:
- Client: http://localhost:3001
- Server: http://localhost:5001
- API Docs: http://localhost:5001/api/openapi/swagger
- Review the Server README for detailed server documentation
- Check the API Documentation for available endpoints
- Read the Main README for project architecture and design decisions