A modern, intuitive dashboard designed originally for Goethe Gymnasium Lichterfelde (GGL) to transform the lobby information display into a comprehensive school information hub.
The School Dashboard was created to replace the outdated and clumsy substitution plan display in the lobby of Goethe Gymnasium Lichterfelde. Built with React and Spring Boot, it provides a centralized hub for students, teachers, and staff to access critical updates throughout the school day with a clean, responsive design.
While developed specifically for GGL, this application is designed to be adaptable for any school using the DSBmobile system for substitution plans.
-
π Substitution Plan Integration
- Real-time connection to DSBmobile API
- Clear, organized display of class changes
- Cached updates for performance optimization
-
π€οΈ Weather Forecasts
- Current conditions and temperature
- Daily forecast visualization
- Open-Meteo API integration for accurate data
-
π Transportation Schedules
- Real-time bus and train departures
- Route information and delays
- Nearest stop information
- BVG API integration for Berlin transportation data
-
β° Live Clock
- Current time and date display
- Visual time tracking
-
π School Event Calendar
- Upcoming events visualization
- Important dates and deadlines
- Integration of any iCal calendar
-
ποΈ Upcoming Holiday display
- Display of upcoming holidays for Berlin
- Data provided by "Senatsverwaltung fΓΌr Bildung, Jugend und Familie Berlin"
-
π± Mobile Responsiveness
- Optimize display for various device sizes
- Touch-friendly interface for tablets
-
π Notification System
- Important announcements and alerts
- Customizable notifications based on user preferences
-
π¨ Customizable Themes
- Light/dark mode toggle
- School color integration
- TanStack Start (React 19) with TypeScript
- TanStack Router (file-based routing)
- Tailwind CSS for styling
- Vite + Nitro adapter for development and production builds
- Spring Boot 3.2 Java backend
- RESTful API design
- Caching for performance optimization
The integration with DSBmobile API was a significant challenge in this project. We initially attempted implementation using various Python libraries, which resulted in:
- 8+ hours of troubleshooting authentication issues
- Inconsistent data payloads
- Undocumented API changes
After these frustrations, we discovered and implemented a 6-year-old Java library that perfectly handles the DSBmobile integration. This discovery was a breakthrough moment for our project, enabling us to finally move forward with the core functionality.
π‘ Lesson Learned: Sometimes the best solution isn't the newest one. The robust Java implementation from 2018 outperformed modern alternatives.
Working with DSBmobile has been an exercise in frustration due to heinekingmedia's approach to their platform:
- No Public API: Despite being used by thousands of schools, there's no official, documented API for developers
- Zero Transparency: Changes to the backend occur without warning, breaking third-party integrations
- Artificial Barriers: Simple data that should be easily accessible is obscured behind proprietary interfaces
This opacity has forced us to rely on reverse-engineered solutions, creating unnecessary technical debt and development delays for what should be a straightforward integration.
- JDK 21
- Node.js 24+ and pnpm (enable via
corepack enable) - Maven (only needed once to bootstrap Maven Wrapper if wrapper files are missing)
TL;DR:
git clone https://github.com/Zzacklack/school-dashboard.git
cd school-dashboard
pnpm run setup
pnpm run devpnpm run setup now includes an interactive credential/URL bootstrap and writes:
Backend/.env(backend secrets and Spring env overrides)Frontend/.env(frontend backend target URL)
These files are local-only and must never be committed.
The monorepo helper scripts prefer Maven Wrapper (Backend/mvnw / Backend/mvnw.cmd) and fall back to system Maven if wrapper files are missing.
Backend uses a single committed config file: Backend/src/main/resources/application.properties.
Every runtime value is read from environment variables (with safe defaults where appropriate).
-
Install dependencies + local env bootstrap
pnpm run setup
If you need to regenerate credentials/URLs later, run:
pnpm run setup:env
You can override any Spring property using environment variables (Spring Boot relaxed binding). Examples:
-
DSB_USERNAME->dsb.username -
DSB_PASSWORD->dsb.password -
CALENDAR_ICS_URL->calendar.ics-url -
SPRING_DATASOURCE_URL->spring.datasource.url -
SERVER_SERVLET_SESSION_COOKIE_SECURE->server.servlet.session.cookie.secureSession timeout/cookie notes:
-
SECURITY_SESSION_IDLE_TIMEOUTcontrols app-level idle invalidation. -
SERVER_SERVLET_SESSION_TIMEOUToptionally sets container session timeout; the shorter timeout effectively applies. -
If
SECURITY_CORS_ALLOWED_ORIGINSincludeshttp://localhost, setSERVER_SERVLET_SESSION_COOKIE_SECURE=falsefor local HTTP cookie-based auth. -
Database migrations β Flyway runs automatically on startup. Production PostgreSQL migrations live under
Backend/src/main/resources/db/migration/postgresql, local H2 migrations underBackend/src/main/resources/db/migration/h2. To apply schema changes, add matchingV{next}__description.sqlfiles and restart the backend. -
Start the dev server (hot reload, no jar required)
mvn spring-boot:run
-
Run tests
mvn test -
Build an executable jar (skips tests for faster iteration)
mvn clean package -DskipTests
The local H2 database persists plan snapshots under
Backend/data/.
All endpoints are served from the backend base URL (default: http://localhost:8080).
GET /health- Lightweight health response with status + timestamp.GET /api/substitution/plans- Substitution plan data (cached fallback on errors).GET /api/dsb/timetables- Raw DSBmobile timetables list.GET /api/dsb/news- DSBmobile news payload.GET /api/calendar/events?limit=5- Parsed calendar events (epoch millis +allDay).GET /error- Error page handler (HTML).
If actuator endpoints are enabled (see management.endpoints.web.exposure.include), you can also use:
GET /actuator/healthGET /actuator/infoGET /actuator/metricsGET /actuator/env
-
Install dependencies
pnpm install --frozen-lockfile
Frontend/.envis generated bypnpm run setupand used automatically by Vite. -
Start the dev server
pnpm --dir Frontend run dev
-
Run checks
pnpm --dir Frontend run build # production bundle pnpm --dir Frontend run lint # optional lint pass pnpm --dir Frontend run test:unit pnpm --dir Frontend run test:integration pnpm --dir Frontend run test:web
- Formatting
- Backend: Spotless (
mvn -f Backend/pom.xml spotless:check) - Frontend: Prettier (
pnpm --dir Frontend run format:check)
- Backend: Spotless (
- Linting
- Frontend: ESLint (
pnpm --dir Frontend run lint)
- Frontend: ESLint (
- CI/CD
- GitHub Actions workflows for CI, CodeQL, and Docker image publishing
Monorepo helpers from the repo root:
pnpm run format:check
pnpm run format
pnpm run lint
pnpm run test
pnpm run build- Frontend: http://localhost:3000
- Backend API: http://localhost:8080
This repository now supports deploying only Frontend/ with Wrangler (Cloudflare Workers static assets):
- Wrangler config:
Frontend/wrangler.toml - Production domain:
goethe-dashboard.zacklack.de - Preview URLs: enabled via
preview_urls = trueandworkers_dev = true
Cloudflare-managed build/deploy (Workers Builds):
- In Cloudflare Workers, connect the GitHub repository.
- Build settings:
- Root directory: repository root (
/) - Build command:
pnpm --dir Frontend run build:workers - Deploy command:
pnpm --dir Frontend run deploy:workers - Non-production branch deploy command:
pnpm --dir Frontend run deploy:workers:preview
- Root directory: repository root (
- Docker
- Docker Compose
- Configure the Backend:
- Provide required credentials through environment variables (e.g. add a
.envfile in theDocker/directory or inject values in your CI/CD system). Typical variables includeDSB_USERNAME,DSB_PASSWORD, and any optional Spring overrides. - Configure PostgreSQL connectivity for backend:
SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/school_dashboardSPRING_DATASOURCE_USERNAME=school_dashboardSPRING_DATASOURCE_PASSWORD=<strong-password>SPRING_FLYWAY_LOCATIONS=classpath:db/migration/postgresql
- Persistent storage for PostgreSQL is wired via the
postgres-datavolume. Create regular backups of that volume (or pg dumps).
- Configure the Frontend:
- Set
BACKEND_URLfor the frontend runtime (for examplehttp://backend:8080in Docker Compose). The TanStack Start server routes under/api/*forward requests to this backend origin.
- Optional: import legacy H2 data into PostgreSQL:
-
For legacy backups, run:
PG_URL="postgresql://localhost:5432/school_dashboard" \ PG_USER="school_dashboard" \ PG_PASSWORD="<strong-password>" \ H2_PASSWORD="" \ ./scripts/prod/import-h2-legacy-to-postgres.bash Backend/data/backup/20260307-181933
-
The script imports
SUBSTITUTION_PLAN_DOCUMENTSand (if present)API_RESPONSE_CACHE.
- Build the Docker Images:
cd Docker
docker compose -f docker-compose.yaml build- Run the Application with Docker Compose:
docker compose -f docker-compose.yaml up -dThis command builds the images and starts the containers in detached mode.
- Check Container Status:
docker compose -f docker-compose.yaml psVerify that both the frontend and backend containers are running without issues.
- Access the Application:
Open your browser and navigate to the domain or IP address where your application is deployed.
This project is currently under active development. The core functionality is implemented, but we're working on:
- Design refinements and UI/UX improvements
- Additional feature implementations
- Performance optimizations
- Comprehensive testing
The existing solution for displaying the substitution plan at GGL was:
- Visually outdated and difficult to read
- Limited to showing only substitution information
- Not responsive or adaptable to different screen sizes
- Unable to display other important information for students and staff
Our dashboard solves these problems by providing a modern, readable interface that combines substitution plans with weather, transportation, and other useful information in one unified display.
| Phase | Focus | Status |
|---|---|---|
| 1 | Core API Integration & Basic UI | β Done |
| 2 | Enhanced UI & Additional Features | π In Progress |
| 3 | Testing & Performance Optimization | π In Progress |
| 4 | Deployment & Documentation | π§© Partially done |
| 5 | User Feedback & Iteration | π Planned |
| 6 | Final Review & Launch | π Planned |
Contributions are welcome! While this project was created for GGL, we've designed it to be adaptable for any school. Please feel free to submit a Pull Request.
See CONTRIBUTING.md for detailed guidelines.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
- DSBmobile-API by Sematre for the Java implementation
- BVG-API for the Berlin transportation data
- Open-Meteo for the weather data
- Weather-Sense/Icons by Leftium for the weather icons
- All contributors who have invested their time into making this project better
- Special thanks to Saloking (Nikolas) for giving me the idea to use the Java API instead of Python ones
- Goethe Gymnasium Lichterfelde for the opportunity to improve the school's information system
Made with β€οΈ for improving school information systems, starting with GGL




