Skip to content

PU College: institution type & academic setup

Pre-University (PU) colleges run classes 11 and 12 with Science / Commerce / Arts streams, and they're the institution type NEET and JEE aspirants belong to. Kwilo could already create a pu_college (via the Schools page) but couldn't set up its academics: every academic-setup surface routed pu_college into the higher-ed flow (Programs → Branches → Semesters), which PU has no concept of. This feature makes PU College a first-class type with a class-based, stream-aware setup (1st/2nd PU + combinations), so a PU admin can onboard end-to-end and enroll students by stream.

How it works

PU sits between K-12 and higher-ed and shares pieces of both: minors (face-consent required), NCERT-eligible, and class-based rather than semester-based. The structural unit a student enrolls into is a combination of exactly four electives (PCMB, PCMC, EBAC, HEPS, …), not a broad stream, because the combination drives subjects and exam track (NEET vs JEE).

PU College (org_unit_type = pu_college)   class-based, NOT semester
  Program "PU" (program_type=school, grades 11-12)
    └── Branch = combination (PCMB · PCMC · EBAC · HEPS · …)   ← the enrollable unit
          ├── AcademicLevel: Class 11, Class 12
          └── 4 elective subjects, assigned mandatory to each level

A student enrolls into a combination + year (e.g. 2nd PU PCMB). There are no sections in this model.

Routing keys off the class-vs-semester axis

The bug was that academic-setup surfaces keyed off isHigherEducation (HIGHER_ED_TYPES includes pu_college) instead of the class-vs-semester axis. Routing now keys off usesClasses / usesSemesters (already correct for PU in apps/web/src/utils/institutionType.ts), so pu_college lands in the class-based structure. HIGHER_ED_TYPES is left untouched so analytics, attendance, calendar, and enrollment surfaces that intentionally treat PU as "college" don't regress.

First-class onboarding type

Onboarding has a third PU College bucket (TInstitutionType = 'k12' | 'pu' | 'college') with its own setup step: pick combinations (curated presets grouped by stream, plus a custom-combination form), which creates Program(school, 11–12)Branch per combination → AcademicLevel Class 11/12, and creates and assigns each combination's four electives. The academic-setup view for pu_college reuses the hierarchical CollegeCurriculumPage, which is generic over orgUnitId.

The onboarding write-back is guarded so an existing pu_college is never overwritten to k12_school (the K-12 wizard's handleTypeNext hard-sets the type otherwise). On the hierarchical view, PU switches to class vocabulary (tab "Classes", "Add class", "Select class", empty/delete states) via hasSchoolProgram(programs) + getLevelTermKeys; colleges are unchanged. AcademicSetupPage shows a "PU College" badge.

No backend change was needed: the backend already accepts program_type=school, start_grade / end_grade, and level_type=class.

Non-goals

  • Not building NEET/JEE test-prep content or question banks. This is institution modeling + academic setup only.
  • Not reworking the higher-ed (Programs/Branches/Semesters) flow for degree/engineering colleges.
  • Not changing how pu_college is treated in analytics, attendance, calendar, or user-enrollment beyond correct structure. Those revisit deliberately, not wholesale.
  • Standalone NEET/JEE coaching centers that aren't PU colleges are a different org type (training_center), out of scope.

Where it lives

  • Routes: /admin/schools (institution type), /admin/academic-setup (structure), org-admin Institution Onboarding wizard.
  • apps/web/src/utils/institutionType.ts: HIGHER_ED_TYPES, CLASS_BASED_TYPES / SEMESTER_BASED_TYPES, usesClasses / usesSemesters, isHigherEducation.
  • apps/web/src/pages/school-admin/AcademicSetupPage/index.tsx: viewMode routing.
  • apps/web/src/pages/org-admin/InstitutionOnboardingPage/: deriveInstitutionType, handleTypeNext write-back, helpers/institutionRouting.ts.
  • apps/backend/src/models/academic.py: Program (start_grade/end_grade), Branch, Class. apps/backend/src/models/org_unit.py: OrgUnitType.PU_COLLEGE, K12_ORG_UNIT_TYPES, CONSENT_REQUIRED_ORG_UNIT_TYPES.