Skip to content

Repository files navigation

Student Dormitory

Student Dormitory

Role-based dormitory intake, onboarding, submission review, and room selection platform.

Java 21 Spring Boot 4.0.3 React 19.1 PostgreSQL 16 Docker Compose

Overview

This repository contains a working full-stack implementation of a student dormitory move-in workflow:

  • super admins configure admission cycles, dormitories, room inventory, employees, and document requirements
  • accepted students are imported from CSV and receive onboarding emails
  • students activate accounts, upload profile photos, upload documents and fee proofs, and submit their package
  • employees review every uploaded item, request corrections, approve, or reject submissions
  • students can self-select and temporarily hold beds when the dormitory allows direct room selection

Current state: this is a strong local/demo environment for the end-to-end workflow. It is not yet production-hardened.

What Is Implemented Right Now

  • JWT-based authentication with refresh cookie support
  • First-time student account activation from onboarding email links
  • Role-specific React dashboards for SUPER_ADMIN, EMPLOYEE, and STUDENT
  • Admission cycle, dormitory, block, room, and document requirement management
  • CSV-based acceptance import with duplicate handling and onboarding email delivery
  • Employee account management
  • Student profile photo upload with image validation
  • Student document upload, fee proof upload, exemption support upload, and final package submission
  • Employee queue, item-by-item review, final decisioning, and audit history
  • Self-service bed hold and release workflow for enabled dormitories
  • Docker Compose stack with PostgreSQL, backend, frontend, and Mailpit
  • Flyway-backed database schema migrations and backend integration tests

Workflow Snapshot

flowchart LR
    A[Super Admin Setup] --> B[Import Accepted Students CSV]
    B --> C[Onboarding Email Sent]
    C --> D[Student Activates Account]
    D --> E[Student Uploads Photo, Documents, Fees]
    E --> F[Student Holds Bed if Self-Selection Is Enabled]
    F --> G[Student Submits Package]
    G --> H[Employee Reviews Each Item]
    H --> I{Decision}
    I -->|Correction Required| E
    I -->|Approved| J[Approved for Move-In]
    I -->|Rejected| K[Rejected Package]
Loading

Architecture

flowchart TB
    Browser[Browser]
    Frontend[React 19 + Vite + Bootstrap]
    Nginx[Nginx SPA Container]
    Backend[Spring Boot API]
    Db[(PostgreSQL)]
    Mail[Mailpit or SMTP]

    Browser --> Frontend
    Frontend -->|Local dev| Backend
    Browser -->|Docker| Nginx
    Nginx -->|/api proxy| Backend
    Backend --> Db
    Backend --> Mail
Loading

Tech Stack

Layer Current choice
Backend Java 21, Spring Boot 4.0.3, Spring Security, Spring Web, Spring Data JPA
Database PostgreSQL, Flyway migrations
Authentication JWT access token + HTTP-only refresh cookie
Frontend React 19.1, React Router 7.4, Bootstrap 5.3, Vite 7.1
Local infrastructure Docker Compose, Mailpit, Nginx
Testing JUnit integration tests on the backend, frontend production build validation

Repository Layout

.
├── src/main/java/                  Spring Boot application code
├── src/main/resources/             application properties + Flyway migrations
├── src/test/java/                  backend integration tests
├── frontend/                       React/Vite application
├── docker/backend-entrypoint.sh    backend container bootstrap
├── compose.yaml                    full local stack
├── compose.mailpit.yaml            Mailpit-only helper stack
├── acceptance-import-example.csv   sample student import file
├── .env.example                    backend + compose environment template
└── frontend/.env.example           frontend environment template

Product Surface By Role

Role Current UI/API surface What the role can do
SUPER_ADMIN /super-admin, /api/admin/setup/**, /api/admin/employees/**, /api/admin/acceptance-imports/** manage cycles, dormitories, blocks, rooms, document requirements, employees, onboarding accounts, and CSV imports
EMPLOYEE /employee, /api/employee/submissions/** search queue, inspect submission detail, download files, review documents and fee items, request correction, approve, reject
STUDENT /student, /api/student/** see dormitory offer, upload profile photo, upload documents and fees, download requirement templates, hold/release bed, submit or resubmit package
Shared /guide, /process-flow, /api/auth/** sign in, activate account, review role instructions, follow the end-to-end process map

Quick Start

Option A: Docker Compose

This is the best way to run the current project exactly as it is wired today.

docker compose up --build

Services

Service URL Notes
Frontend http://localhost:5173 Nginx-served SPA
Backend API http://localhost:8080 Spring Boot API
Mailpit UI http://localhost:8025 inspect onboarding emails
Mailpit SMTP localhost:1025 backend mail target in local/dev
PostgreSQL localhost:5432 database exposed to host

Docker-specific behavior

  • if JWT_SECRET is not provided, the backend container generates an ephemeral development secret on startup
  • the frontend container uses same-origin /api calls and proxies them to the backend through Nginx
  • Mailpit is enabled by default in the full stack

Stop the stack:

docker compose down

Stop the stack and remove the Postgres volume:

docker compose down -v

Option B: Run Services Manually

Prerequisites

Tool Version expected by the repo
Java 21
Node.js 22+
npm current Node-compatible npm
PostgreSQL 16-compatible

1. Configure the backend environment

Create a JWT secret:

openssl rand -base64 32

Copy the template:

cp .env.example .env

Important values:

JWT_SECRET=<base64 secret with at least 32 decoded bytes>
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/dormitory_db?currentSchema=public
SPRING_DATASOURCE_USERNAME=<your database username>
SPRING_DATASOURCE_PASSWORD=<your database password>
APP_FRONTEND_BASE_URL=http://localhost:5173
APP_SECURITY_ALLOWED_ORIGINS=http://localhost:5173,http://127.0.0.1:5173

The backend automatically imports .env because application.properties contains:

spring.config.import=optional:file:.env[.properties]

2. Start PostgreSQL

Create the database if needed:

createdb dormitory_db

3. Run the backend

./mvnw spring-boot:run

The API will be available at http://localhost:8080.

4. Configure and run the frontend

cp frontend/.env.example frontend/.env.local
cd frontend
npm ci
npm run dev

By default the frontend points to:

VITE_API_BASE_URL=http://localhost:8080

The frontend dev server will be available at http://localhost:5173.

5. Optional mail helpers

Run Mailpit only:

docker compose -f compose.mailpit.yaml up -d

Then run the backend with the Mailpit profile:

SPRING_PROFILES_ACTIVE=mailpit ./mvnw spring-boot:run

Or write emails to disk instead of SMTP:

SPRING_PROFILES_ACTIVE=mailpreview ./mvnw spring-boot:run

Mail previews are written to target/mail-preview by default.

Configuration Reference

The full template lives in .env.example. The most important variables are grouped below.

Backend, Auth, and CORS

Variable Default Purpose
JWT_SECRET none required outside Docker; must be Base64 and decode to at least 32 bytes
JWT_REFRESH_COOKIE_SECURE false marks the refresh cookie as Secure
SPRING_DATASOURCE_URL jdbc:postgresql://localhost:5432/dormitory_db?currentSchema=public JDBC URL
SPRING_DATASOURCE_USERNAME empty database username
SPRING_DATASOURCE_PASSWORD empty database password
SPRING_JPA_SHOW_SQL true SQL logging
SPRING_JPA_HIBERNATE_DDL_AUTO update Hibernate schema mode
APP_FRONTEND_BASE_URL http://localhost:5173 base URL used in onboarding emails
APP_SECURITY_ALLOWED_ORIGINS http://localhost:5173,http://127.0.0.1:5173 CORS allow-list

Seed and bootstrap behavior

Variable Default Purpose
APP_SEED_ENABLED false forces a destructive re-seed of the focused demo dataset
APP_BOOTSTRAP_SUPERADMIN_USERNAME empty optional local bootstrap admin username
APP_BOOTSTRAP_SUPERADMIN_PASSWORD empty optional local bootstrap admin password
APP_BOOTSTRAP_SUPERADMIN_FULL_NAME Local Super Admin display name for the bootstrap admin

Important current behavior:

  • if the database is completely empty, the focused demo dataset is seeded automatically once
  • APP_SEED_ENABLED=true wipes and recreates that focused dataset
  • the APP_BOOTSTRAP_SUPERADMIN_* variables are only used when startup skips the empty-database seed path and there are still no users

Mail delivery

Variable Default Purpose
APP_MAIL_FROM no-reply@student-dormitory.local sender address
APP_MAIL_PREVIEW_ENABLED false writes emails to disk instead of SMTP
APP_MAIL_PREVIEW_DIRECTORY target/mail-preview preview output directory
APP_MAIL_LOCAL_DETECTION_HOSTS 127.0.0.1,localhost,host.docker.internal,mailpit hosts checked for local Mailpit
SPRING_MAIL_HOST empty explicit SMTP host
SPRING_MAIL_PORT 1025 SMTP port
SPRING_MAIL_USERNAME empty SMTP auth username
SPRING_MAIL_PASSWORD empty SMTP auth password
SPRING_MAIL_SMTP_AUTH false SMTP auth toggle
SPRING_MAIL_SMTP_STARTTLS false STARTTLS toggle
SPRING_MAIL_SMTP_STARTTLS_REQUIRED false require STARTTLS
DOCKER_SPRING_MAIL_HOST mailpit backend container SMTP host
DOCKER_SPRING_MAIL_PORT 1025 backend container SMTP port

Mail resolution order in the current backend:

  1. explicit SMTP via SPRING_MAIL_HOST
  2. auto-detected local Mailpit host
  3. filesystem preview when preview mode is enabled

Frontend

Variable Default Purpose
VITE_API_BASE_URL http://localhost:8080 in local dev backend base URL for the Vite app

Seeded Demo Dataset

Warning: APP_SEED_ENABLED=true deletes existing application data and recreates the focused demo environment.

What gets created

When the database is empty, the application seeds a focused dataset for the 2026/2027 move-in cycle.

Area Current seeded value
Admission cycle 2026/2027 Вселување во студентски домови
Dormitory Гоце Делчев in Скопје
Blocks А, Б, В, Г
Floors per block 15
Rooms per floor 24
Beds per room 2
Total beds 2880
Employees employee, reviewer1, reviewer2, reviewer3, reviewer4
Super admin superadmin
Students student001 through student100
Bed hold duration 20 minutes
Roommate group size 2

Seeded documents and fees

Document requirements:

  • MOVE_IN_PACKAGE with a downloadable text template
  • BIRTH_CERTIFICATE_COPY
  • CURRENT_SEMESTER_VERIFICATION
  • INDEX_COPY
  • PHOTOS

Fee items:

  • DOCUMENT_PACKAGE_FEE - 500.00 MKD
  • ACCOMMODATION_FEE - 3490.00 MKD, supports exemption evidence
  • MAINTENANCE_FEE - 1200.00 MKD

Seeded submission distribution

The demo students are intentionally spread across workflow states:

Status Count
DRAFT 45
SUBMITTED 27
CORRECTION_REQUIRED 12
APPROVED 11
REJECTED 5

Demo credentials

Username Password Role
superadmin superadmin123 Super Admin
employee employee123 Employee
reviewer1 to reviewer4 employee123 Employee
student001 to student100 student123 Student

CSV Acceptance Import Format

Use acceptance-import-example.csv as the source of truth for the current import contract.

Expected header:

username,fullName,email,personalIdentifier,indexNumber,cycleName,dormitoryName,acceptancePreference,submissionDeadline

Column reference

Column Meaning
username student account username
fullName display name stored on the student profile and offer
email onboarding destination and student profile email
personalIdentifier student identifier
indexNumber student academic index number
cycleName must match an existing admission cycle name
dormitoryName must match an existing dormitory name
acceptancePreference PRIMARY or ALTERNATIVE
submissionDeadline ISO date, for example 2026-11-15

Current import behavior

  • empty files are rejected
  • duplicate rows inside the uploaded CSV are reported
  • duplicate cycle + user offers already stored in the database are reported
  • new student usernames create inactive student accounts with activation tokens
  • existing active student accounts can be linked to new acceptance offers
  • onboarding email delivery status is stored per imported offer

API Overview

This is not a Swagger-generated list. It is the practical API surface that is clearly implemented today.

Route group Purpose
POST /api/auth/login authenticate and return access token
POST /api/auth/refresh rotate the access session using refresh cookie
POST /api/auth/logout revoke refresh token and clear cookie
GET /api/auth/me return the current authenticated user
POST /api/auth/activate activate first-time student account
GET/POST/PUT/DELETE /api/admin/setup/... manage cycles, dormitories, blocks, rooms, and document requirements
GET/POST/PUT/DELETE /api/admin/employees... manage employee accounts
POST /api/admin/acceptance-imports import accepted students CSV
GET /api/admin/acceptance-imports/accounts onboarding account overview
POST /api/admin/acceptance-imports/accounts/{id}/resend-email resend onboarding mail
GET /api/employee/submissions/queue employee queue and filtering
GET /api/employee/submissions/{id} detailed review workspace
POST /api/employee/submissions/{id}/documents/{requirementId}/review review one document
POST /api/employee/submissions/{id}/fees/{feeItemId}/review review one fee item
POST /api/employee/submissions/{id}/request-correction request correction
POST /api/employee/submissions/{id}/approve approve submission
POST /api/employee/submissions/{id}/reject reject submission
GET /api/student/acceptance-offer student dormitory offer
GET /api/student/profile student profile summary
POST /api/student/profile/photo upload profile photo
GET /api/student/profile/photo fetch profile photo
GET /api/student/submission submission workspace
POST /api/student/submission/documents/{requirementId}/upload upload one document
POST /api/student/submission/fees/{feeItemId}/upload upload payment proof or exemption support
POST /api/student/submission/submit submit or resubmit the package
GET /api/student/submission/documents/{requirementId}/template download requirement template
GET /api/student/room-selection room and bed availability
POST /api/student/room-selection/beds/{bedId}/hold hold a bed
DELETE /api/student/room-selection/current release the current hold
GET /api/faculty/... separate smaller public faculty endpoint still present in the backend

Upload and Auth Rules

Authentication model

  • access token lifetime: 900 seconds
  • refresh token lifetime: 2592000 seconds
  • refresh token is stored in an HTTP-only cookie
  • the frontend stores the access token in browser local storage and refreshes it automatically

Upload constraints implemented today

Upload type Current rule
Student profile photo max 2 MB, must be a valid PNG, JPEG, or GIF image
Student documents max 5 MB per file
Student fee proof / exemption file max 5 MB per file

Uploaded files are stored in the database in the current implementation.

Database and Migrations

Flyway migrations currently cover:

Migration Focus
V1 auth foundation
V2 master data foundation
V3 employee scope and permissions
V4 acceptance offers
V5 submission workflow
V6 review workflow
V7 bed selection workflow
V8 student profile photo
V9 student email and staff member updates
V10 acceptance-offer onboarding fields

Current default persistence notes:

  • Hibernate is configured with ddl-auto=update
  • Flyway runs against the public schema
  • PostgreSQL is the only supported database in the current project configuration

Testing and Verification

Backend

./mvnw test

These are integration tests, not an in-memory test suite. The current test setup expects a reachable PostgreSQL database. If your local PostgreSQL roles differ from the repo defaults, override the datasource settings before running the suite or point the tests at the Compose database.

Current backend tests cover:

  • auth controller
  • CORS
  • admin employee management
  • admin setup
  • acceptance import
  • student profile
  • student submission workflow
  • student room selection workflow
  • employee review workflow

Frontend

cd frontend
npm ci
npm run build

Current reality:

  • there is no dedicated frontend automated test suite in package.json yet
  • the frontend verification path today is a production build

Operational Notes and Known Gaps

  • The frontend stores access tokens in localStorage; that should be reviewed before any public deployment.
  • File uploads and profile photos are stored directly in PostgreSQL rather than external object storage.
  • SPRING_JPA_HIBERNATE_DDL_AUTO=update is convenient for local development but usually not what you want in production.
  • The app auto-seeds the focused demo dataset whenever it starts against a completely empty database.
  • Docker Compose settings are tuned for local development, not for hardened deployment.
  • The login page still includes a legacy quick-fill student demo account, while the current focused seed creates student001 through student100.
  • Employee permission profiles currently only expose STAFF_MEMBER.
  • Backend tests currently depend on a real PostgreSQL connection instead of an embedded test database.
  • There is no generated OpenAPI or Swagger document in the current repo.

Useful Commands

# Start the full local stack
docker compose up --build

# Start only Mailpit
docker compose -f compose.mailpit.yaml up -d

# Run the backend locally
./mvnw spring-boot:run

# Run backend tests
./mvnw test

# Package the backend jar
./mvnw -DskipTests package

# Run the frontend locally
cd frontend
npm ci
npm run dev

# Validate the frontend production build
cd frontend
npm ci
npm run build

Additional Project Documents

  • EMAIL_SETUP.md
  • DORMITORY_SYSTEM_REQUIREMENTS.md
  • IMPLEMENTATION_PLAN.md
  • frontend/README.md

Built for a full dormitory intake workflow: setup, onboarding, submission, review, and room assignment.

About

Built for a full dormitory intake workflow: setup, onboarding, submission, review, and room assignment. Making the enrolling in the student dormitories each year easier and faster for the students and the staff.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages