Skip to content

Classroom Service API

Current Endpoints

  • GET /healthz
  • GET /readyz
  • GET /v1
  • PUT /v1/classrooms/{classroomId}/snapshot
  • GET /v1/classrooms
  • POST /v1/classrooms
  • GET /v1/classrooms/{classroomId}
  • PATCH /v1/classrooms/{classroomId}
  • PATCH /v1/classrooms/{classroomId}/status
  • DELETE /v1/classrooms/{classroomId}
  • GET /v1/classrooms/{classroomId}/delete-impact
  • DELETE /v1/classrooms/{classroomId}/purge
  • GET /v1/classrooms/{classroomId}/members
  • POST /v1/classrooms/{classroomId}/members
  • PUT /v1/classrooms/{classroomId}/members/{userId}
  • DELETE /v1/classrooms/{classroomId}/members/{userId}
  • GET /v1/classrooms/{classroomId}/students
  • POST /v1/classrooms/{classroomId}/students
  • DELETE /v1/classrooms/{classroomId}/students/{studentId}
  • POST /v1/classrooms/{classroomId}/join
  • GET /v1/classrooms/{classroomId}/progress

Native Classroom Foundation

Phase 8 classroom-service starts with classroom and classroom-member ownership. This is an internal /v1 foundation, not a public /api/classrooms* or /api/admin/classrooms* cutover.

Legacy evidence:

  • apps/api/src/modules/classrooms/classrooms.controller.ts:32-204 maps legacy classroom list/detail/create/update/status/delete/join/student/progress routes.
  • apps/api/src/modules/classrooms/classrooms.controller.ts:803-1430 maps admin classroom list/create/update/detail/member/purge routes.
  • apps/api/src/modules/app-data/app-data.classrooms-core.ts:38-520 implements legacy classroom list/detail/create/update/status rules, teacher membership creation, manager checks, and response counters.
  • apps/api/src/modules/app-data/app-data.classrooms-support.ts:50-150 defines classroom manager, teacher-managed-classroom, reference, and membership assertions.
  • apps/api/src/modules/app-data/app-data.public.ts:707-980 implements delete impact, soft archive vs hard delete, purge, join, remove student, and student list behavior.
  • apps/api/src/modules/app-data/app-data.progress-overview.ts:17-48 implements classroom progress as a composition of classroom detail, student members, assignments, attempts, and weak topics.
  • apps/api/prisma/schema.prisma:551-604 defines Classroom and ClassroomMember with unique code, unique publicSlug, unique (classroomId,userId), and ACTIVE/ARCHIVED status.
  • packages/shared/src/index.ts:593-610 and packages/shared/src/index.ts:1160-1178 define public slug, visibility, grade-level, and classroom input validation.
  • apps/web/components/classroom/classroom-crud-client.tsx:168-336 consumes /classrooms, status, delete-impact, delete, and admin purge.
  • apps/web/app/join/class/[code]/join-class-link-client.tsx:30-39 consumes /classrooms/{code}/join.

Native contract:

  • PUT /v1/classrooms/{classroomId}/snapshot upserts service-owned rows from legacy backfill, including timestamps, status, visibility, counters, and teacher/member data when supplied.
  • GET /v1/classrooms supports organizationId, teacherId, studentId, status, visibility, q, page, and limit; X-Actor-Id/X-Actor-Role scopes non-admin reads.
  • POST /v1/classrooms creates a classroom, generates a unique uppercase join code, and upserts the primary teacher as a TEACHER member.
  • GET /v1/classrooms/{classroomId} accepts id or code, preserving the legacy join-link lookup path.
  • PATCH /v1/classrooms/{classroomId} preserves partial update rules for name, description, summary, cover image, visibility, public slug, featured flag, grade level, subject id, and teacher id.
  • PATCH /v1/classrooms/{classroomId}/status sets ACTIVE or ARCHIVED.
  • DELETE /v1/classrooms/{classroomId} hard deletes only when there is no owned usage beyond the teacher membership; otherwise it archives and returns {deleted:false, archived:true}.
  • GET /v1/classrooms/{classroomId}/delete-impact returns service-owned counts immediately and zeroes deferred lesson/material/assignment/tuition counters until those slices are native.
  • DELETE /v1/classrooms/{classroomId}/purge hard deletes the service-owned classroom and members for admin-only adapters.
  • Member routes preserve upsert by (classroomId,userId), role updates, student join by id or code, student member listing, and primary-teacher reassignment when admin removes a teacher member.
  • GET /v1/classrooms/{classroomId}/progress returns the classroom, current student member rows, and zero assignment/weak-topic metrics until exam/analytics adapters provide native data.

Authorization model:

  • Native service accepts X-Actor-Id, X-Actor-Role, and X-Organization-Id; X-User-Id and X-User-Role are accepted as fallbacks for gateway-injected headers. Gateway remains responsible for JWT verification and public route RBAC.
  • ADMIN may manage any classroom in the requested organization scope.
  • TEACHER may manage classrooms where teacherId equals the actor or where the actor has a TEACHER classroom member row.
  • TEACHER cannot create or transfer a classroom to another teacher.
  • STUDENT list/detail access is membership-scoped and join may only add the actor as a student.
  • PARENT cannot read or manage classroom-service foundation routes.

Envelope:

json
{
  "success": true,
  "data": {
    "id": "class_local_math_6",
    "name": "Toan 6",
    "code": "A1B2C3",
    "status": "ACTIVE",
    "visibility": "PRIVATE",
    "gradeLevel": 6,
    "subjectId": "math",
    "teacherId": "teacher_1",
    "studentCount": 0,
    "_count": {
      "members": 1,
      "lessons": 0,
      "materials": 0,
      "assignments": 0
    }
  },
  "message": "OK"
}

Database:

  • services/classroom-service/migrations/000002_classrooms.sql creates classrooms and classroom_members.
  • classrooms.organization_id, unit_id, subject_id, teacher_id, and created_by_id store public ids from other services; classroom-service does not query other service databases.
  • classrooms.code is unique and stores the legacy uppercase join code.
  • classrooms.public_slug uses a partial unique index so null slugs are allowed.
  • classroom_members enforces unique (classroom_id,user_id) and stores only user ids plus role.

Validation queries:

sql
SELECT id, legacy_id, organization_id, name, code, status, teacher_id
FROM classrooms
ORDER BY created_at DESC
LIMIT 20;

SELECT classroom_id, user_id, role, joined_at
FROM classroom_members
ORDER BY joined_at DESC
LIMIT 20;

SELECT c.id, c.code, count(m.id) AS member_count
FROM classrooms c
LEFT JOIN classroom_members m ON m.classroom_id = c.id
GROUP BY c.id, c.code
ORDER BY c.id;

Rollback for this native slice:

  • Keep /api/classrooms* and /api/admin/classrooms* routed to legacy.
  • Disable gateway callers for /v1/classrooms*.
  • Run make test-classroom-route-guard after route-table edits to prove public/admin classroom routes still stay legacy-proxied.
  • Keep lessons, materials, announcements, tuition, exam assignments, dashboard, leaderboard, and public catalog routes on legacy until their dedicated slices land.
  • Drop classroom-service local classroom_members and classrooms tables with the migration down step if local test data must be reset.

Non-goals for P8-004:

  • Public gateway adapter/cutover for /api/classrooms* or /api/admin/classrooms*.
  • Lesson, material, video, announcement, tuition, notification, dashboard, leaderboard, exam, or exam-assignment ownership.
  • Subject, teacher, organization, and student existence checks against other service databases.
  • Full admin search hydration for teacher, organization, and subject names; gateway/user/school/question-bank adapters can hydrate later.
  • Derived analytics, weak topics, attempt scores, and assignment completion.

Go-platform documentation is generated from repository Markdown.