100% Self-HostedFree to Install, Free to Get HostedYour School, Your DataOpen Source ForeverNo Per-Student Fees, Ever100% Self-HostedFree to Install, Free to Get HostedYour School, Your DataOpen Source ForeverNo Per-Student Fees, Ever
OpenRegistro
All docs

Server actions reference

OpenRegistro has no general-purpose REST/JSON API - apps/web is a single Next.js App Router application that reads data in React Server Components and mutates it through Server Actions (functions marked 'use server', called directly from forms/client components, compiled by Next.js into POST handlers under the hood). There is intentionally no OpenAPI spec here: documenting one would describe internal actions as a stable public contract they are not. Two real HTTP endpoints do exist for cases a Server Action genuinely can't serve (binary responses) - see "Route handlers" below.

Every action follows the same shape: it re-derives the session with auth(), calls requirePermission(session, permission) from lib/authz.ts (and, where relevant, a scope check from packages/core's RBAC module), validates FormData/arguments with a Zod schema, performs the mutation through the active StorageDriver, and calls revalidatePath() for every page whose data it affects. See Architecture for the full request-flow diagram.

If you need programmatic access to OpenRegistro data from outside the app (an integration, a script), the backing StorageDriver interface in packages/core/src/storage/driver.ts is the stable contract to build against directly - see apps/web/scripts/migrate-json-to-postgres.ts for an example of a standalone script driving a StorageDriver without going through the web app at all.

Action inventory (by file)

FileActionsPurpose
app/setup/driver/actions.tstestStorageConnectionVerifies the configured storage driver can connect/write during the setup wizard.
app/setup/school/actions.tssaveSchoolDetailsCreates/updates the school and current school year during setup.
app/setup/admin/actions.tscreateAdminAccountCreates the first school_admin user during setup.
app/setup/smtp/actions.tssubmitSmtpForm, skipSmtpSetupPersists SMTP settings, or skips the step.
app/setup/demo/actions.tsfinishSetupOptionally seeds demo data, then permanently locks the installer.
app/login/actions.tsauthenticateCredentials + optional TOTP sign-in.
app/dashboard/actions.tslogOutSigns the current session out.
app/dashboard/school/classes/actions.tscreateClassCreates a class.
app/dashboard/school/classes/[classId]/actions.tsenrollStudent, assignTeacherEnrolls a student in a class; assigns a teacher to a class/subject.
app/dashboard/school/subjects/actions.tscreateSubjectCreates a subject.
app/dashboard/school/people/actions.tscreatePersonCreates a teacher/student/guardian/staff account.
app/dashboard/school/terms/actions.tscreateTermCreates a term for the active school year.
app/dashboard/register/[classId]/actions.tssaveLessonLog, saveAttendanceRecords a signed lesson log entry; saves the attendance grid for a class/date.
app/dashboard/gradebook/[classId]/[subjectId]/actions.tscreateGradeRecords a grade for a student.
app/dashboard/attendance/actions.tssubmitJustification, reviewJustificationSubmits an absence justification; approves/rejects a pending one.
app/dashboard/homework/[classId]/[subjectId]/actions.tscreateHomework, deleteHomeworkAssigns/removes a homework assignment.
app/dashboard/announcements/actions.tscreateAnnouncement, markAnnouncementReadPublishes an announcement; records a read receipt.
app/dashboard/report-cards/[classId]/[subjectId]/actions.tssaveTermEvaluationRecords a term's final per-subject evaluation.
app/dashboard/school/people/actions.tscreatePerson, setUserActiveCreates an account; deactivates/reactivates one (blocks sign-in, keeps history).
app/dashboard/account/actions.tsstartTotpEnrollment, confirmTotpEnrollment, disableTotpTOTP 2FA enrollment for the signed-in user's own account.
app/dashboard/discipline/[classId]/actions.tscreateDisciplinaryNoteRecords an immutable disciplinary note for a student.
app/dashboard/timetable/[classId]/actions.tsaddTimetableSlot, removeTimetableSlotAdds/removes a weekly timetable slot for a class.
app/dashboard/calendar/actions.tscreateCalendarEvent, deleteCalendarEventPublishes/removes a school-wide calendar entry (test, event, or holiday).
app/dashboard/meetings/actions.tscreateMeetingSlot, deleteMeetingSlot, bookMeetingSlotOffers/removes a parent-teacher meeting slot; books one for a child.

app/dashboard/grades/page.tsx and app/dashboard/audit-log/page.tsx are read-only - they have no actions.ts, since nothing on those pages mutates data.

This table reflects the actions present as of this writing - new dashboard features add their own actions.ts following the same pattern described above rather than a shared generic handler (see the "dialogs must be fully self-contained Client Components" and revalidatePath() conventions noted in the codebase's own working notes for why).

Route handlers

Two real HTTP endpoints exist, both GET-only, both returning a binary response a Server Action cannot:

RouteReturnsAccess control
/api/report-cards/[studentId]/[termId]A PDF report cardThe student themselves, a guardian of that student, or staff with reports:read.
/api/account/exportA JSON export of the caller's own dataAny signed-in user, always scoped to their own session - there is no id parameter.

Both re-derive the session with auth() independently of whatever page links to them, so neither trusts the UI that happened to render the link.

Found an issue with this page? Edit it on GitHub.