This setup gives every teammate:
- their own local Docker PostgreSQL database
- the same schema and seed data
- repeatable reset commands when data gets out of sync
- Docker + Docker Compose
make
git clone <repo-url>
cd academic-planner/academic-planner-api
make db-resetAfter make db-reset, your local DB is rebuilt from scratch and all SQL init scripts in db/ are applied.
If 5433 is already occupied on your machine, override the published Postgres port for that shell:
POSTGRES_HOST_PORT=5434 make db-resetmake app-upEndpoints:
- API:
http://localhost:8080 - Swagger:
http://localhost:8080/swagger - Keycloak Admin:
http://localhost:8180(admin/admin) - Health:
GET /health/liveGET /health/ready
make db-up: start PostgreSQL onlymake db-down: stop PostgreSQL (keep data)make db-reset: rebuild PostgreSQL and re-run all SQL scripts indb/make db-wait: wait until PostgreSQL is readymake db-seed: re-apply BBS + PM + student seed scripts and sync curriculamake db-logs: stream PostgreSQL logsmake db-shell: openpsqlin containermake app-up: start full stack (Postgres + Keycloak + API)make app-down: stop full stack
Run:
make db-resetThis is the team standard way to get back to a clean, shared baseline dataset.
Init scripts are in db/ (executed in filename order on fresh DB):
00_schema.sql: core ORDBMS schema (acad) with domains, enums, JSONB prereqs01_keycloak_db.sql: createskeycloak_dbfor identity server10_extensions.sql: concentrations/offerings/advisories extensions20_seed_bbs.sql: representative BBS seed30_curricula.sql:knowledge_blockcomposite type +curriculatable (ORDBMS array of composite types + JSONB course mapping)40_seed_bbs_students.sql: legacy bulk BBS student seed kept for reference; no longer part of the default init flow60_seed_fake_data.sql: curated benchmark seed with a small but diverse student mix across programs/cohortsseed_data.sql: legacy demo seed kept for reference, no longer part of the default init flow99_sync_curricula.sql: syncsacad.curriculafrom seeded requirements
seed_data_bbs.sql is kept for reference and is not part of the default Docker init flow.
JWT Bearer authentication via Keycloak with RBAC:
- Roles:
CVHT(Advisor),SV(Student),Admin(Training Admin) - Policies:
RequireAdvisor,RequireStudent,RequireAdmin - If
Keycloak:Authorityis empty, auth is bypassed (dev mode)
- Start services:
docker compose up --build - Open
http://localhost:8180, login asadmin/admin - Create realm
academic-planner - Create client
academic-planner(confidential, Standard flow) - Create roles:
CVHT,SV,Admin - Assign roles to users
/api/v1/programs— programs, cohorts, curriculum overview/api/v1/courses— course catalog, prerequisites, equivalencies/api/v1/students— student profiles, transcripts, latest attempts/api/v1/students/{studentId}/audit/*— full audit, summary, missing courses, eligibility, progress by category/api/v1/students/{studentId}/recommendations/*— next-term heuristic AI recommendations/api/v1/students/{studentId}/plans/*— CRUD for student term plans + validation/api/v1/curriculum/{programCode}/{cohortCode}— curriculum structure with knowledge blocks and course mapping/api/v1/curriculum/students/{studentId}/eligible-courses— eligible courses (prereqs checked)/api/v1/curriculum/students/search— paginated student search/api/v1/programs/{programCode}/concentrations/api/v1/students/{studentId}/concentration/api/v1/admin/*
- Backend: .NET 8 modular monolith
- Database: PostgreSQL 16 with ORDBMS features (composite types, JSONB, course_code[] arrays, GIN indexes)
- Auth: Keycloak 24 (JWT Bearer, realm roles mapped to .NET ClaimTypes.Role)
- Services:
PrerequisiteEvaluator— Parses JSONB prereq rules (none, course, english, and, or)StudentAuditService— Audit snapshot, progress by category, eligibilityRoadmapRecommendationService— Heuristic AI ranking (required core > concentration > elective)PlanValidationService— Credit limits, stage requirements, capstone checks
- Error format: ASP.NET ProblemDetails for failures,
ApiEnvelope<T>for success