Attendance Module — C3/C4 Architecture¶
Auto-generated by c4docgen on 2026-04-27. Do not edit manually — regenerate with
./gradlew generateC4Docs.
Component and code-level architecture for the Attendance module. For system-wide context (C1 — System Context, C2 — Container), see docs/c4-architecture.md.
C3 — Component¶
Internal components of the Attendance module, following the flat package structure established by the sample module.
C4Component
title Attendance Module — Component Diagram
Container_Boundary(attendance, "Attendance Module") {
Component(controllers, "Controllers", "@RestController", "REST endpoints for Attendance, AttendanceSetting, PickupPerson, SectionSchedule, StudentPickupPerson")
Component(services, "Services", "@Service", "Business logic, caching, event publishing")
Component(repositories, "Repositories", "JpaRepository", "Data access interfaces")
Component(mappers, "Mappers", "@Component", "Entity ↔ DTO conversion")
Component(producers, "Event Producers", "@Component", "Publishes domain events to Kafka")
Component(listeners, "Event Listeners", "@KafkaListener", "Consumes domain events from Kafka")
Component(entities, "Entities", "@Entity", "JPA entity classes")
ComponentDb(dtos, "DTOs", "Java Records", "Request/response data transfer objects")
Component(constants, "Constants", "static final", "API paths, Kafka topics, cache names")
}
Rel(controllers, services, "Delegates to")
Rel(controllers, mappers, "Converts via")
Rel(services, repositories, "Persists via")
Rel(services, mappers, "Converts via")
Rel(services, producers, "Emits events via")
Rel(listeners, services, "May trigger")
Rel(repositories, entities, "Manages")
Component → Package mapping¶
| Component | Package | Key classes |
|---|---|---|
| Controllers | controllers/ |
AttendanceController, AttendanceSettingController, PickupPersonController, SectionScheduleController, StudentPickupPersonController |
| Request DTOs | controllers/dto/request/ |
CreateAttendanceRequest, UpdateAttendanceRequest, CreateAttendanceSettingRequest, UpdateAttendanceSettingRequest, CreatePickupPersonRequest, UpdatePickupPersonRequest, CreateSectionScheduleRequest, UpdateSectionScheduleRequest, CreateStudentPickupPersonRequest, UpdateStudentPickupPersonRequest, etc. |
| Response DTOs | controllers/dto/response/ |
AttendanceResponse, AttendanceSettingResponse, PickupPersonResponse, SectionScheduleResponse, StudentPickupPersonResponse, etc. |
| Services | services/ |
AttendanceService, AttendanceSettingService, PickupPersonService, SectionScheduleService, StudentPickupPersonService |
| Repositories | repositories/ |
AttendanceRecordRepository, AttendanceSettingRepository, PickupPersonRepository, SectionScheduleRepository, StudentPickupPersonRepository |
| Entities | entities/ |
AttendanceRecord, AttendanceSetting, PickupPerson, SectionSchedule, StudentPickupPerson |
| Mappers | mappers/ |
AttendanceRecordMapper, AttendanceSettingMapper, PickupPersonMapper, SectionScheduleMapper, StudentPickupPersonMapper |
| Constants | constants/ |
Constants, KafkaTopics, CacheNames |
C3.1 — Entity Relationship Model¶
The 5 core entities and their relationships.
erDiagram
PickupPerson ||--o{ AttendanceRecord : "has many"
PickupPerson ||--o{ StudentPickupPerson : "has many"
AttendanceRecord {
UUID id PK
UUID schoolId FK
UUID studentId FK
UUID classroomId FK
LocalDate date
Instant checkInTime
UUID checkInPerformedById FK
String checkInPerformedByName
CheckMethod checkInMethod "SCAN, MANUAL"
Instant checkOutTime
UUID checkOutPerformedById FK
String checkOutPerformedByName
CheckMethod checkOutMethod "SCAN, MANUAL"
UUID dropoffPersonId FK
String dropoffPersonName
UUID pickupPersonId FK
String pickupPersonName
ArrivalClassification arrivalClassification "EARLY, ON_TIME, LATE"
DepartureClassification departureClassification "EARLY, ON_TIME, LATE"
AttendanceStatus status "PRESENT, ABSENT, LATE, EXCUSED"
String excuseReason
boolean isUnaccompanied
Instant createdAt
Instant updatedAt
}
AttendanceSetting {
UUID id PK
UUID schoolId FK
boolean parentSelfCheckInEnabled
AttendanceMode attendanceMode "SCAN, MANUAL, BOTH"
LocalTime selfCheckInStartTime
LocalTime selfCheckInEndTime
Instant createdAt
Instant updatedAt
}
PickupPerson {
UUID id PK
UUID schoolId FK
String fullName
String phoneNumber
String relationship
String photoUrl
Instant createdAt
Instant updatedAt
}
SectionSchedule {
UUID id PK
UUID schoolId FK
UUID sectionId FK
LocalTime startTime
LocalTime endTime
int lateThresholdMinutes
int pickupLateThresholdMinutes
int earlyDepartureThresholdMinutes
Instant createdAt
Instant updatedAt
}
StudentPickupPerson {
UUID id PK
UUID studentId FK
UUID pickupPersonId FK
AuthorisationMode authorisationMode "GENERAL, DAY_SPECIFIC"
PickupPermissionType permissionType "DROPOFF_ONLY, PICKUP_ONLY, BOTH"
boolean monday
boolean tuesday
boolean wednesday
boolean thursday
boolean friday
Instant createdAt
Instant updatedAt
}
Cross-module references¶
| Field | Source module | Purpose |
|---|---|---|
AttendanceRecord.schoolId |
School | Links to School |
AttendanceRecord.studentId |
School | Links to Student |
AttendanceRecord.classroomId |
School | Links to Classroom |
AttendanceSetting.schoolId |
School | Links to School |
PickupPerson.schoolId |
School | Links to School |
SectionSchedule.schoolId |
School | Links to School |
SectionSchedule.sectionId |
School | Links to Section |
StudentPickupPerson.studentId |
School | Links to Student |
C3.2 — REST API Structure¶
All endpoints follow the pattern established by the sample module.
| Entity | Base path | Operations |
|---|---|---|
| Attendance | /api/attendance/records |
GET /{id}, GET /by-class, POST /check-in, POST /check-out, PUT /mark-absent, PUT /mark-excused, POST /mass-check-in |
| AttendanceSetting | /api/attendance/settings |
GET (list, paginated), PUT `` |
| PickupPerson | /api/attendance/pickup-persons |
GET (list, paginated), GET /{id}, POST, PUT /{id}, GET /{id}/students |
| SectionSchedule | /api/attendance/section-schedules |
GET (list, paginated), GET /{sectionId}, PUT /{sectionId} |
| StudentPickupPerson | /api/attendance/students/{studentId}/pickup-persons |
GET (list, paginated), POST, DELETE /{pickupPersonId}, PUT /{pickupPersonId} |
All list endpoints support page (default: 0) and size (default: 20) query parameters, returning PagedResponse<T> from modules/shared/.
C3.3 — Event Flow¶
No Kafka events defined for this module.
C3.4 — Caching Strategy¶
No caching defined for this module.
C4 — Code Patterns¶
Implementation follows the conventions from the sample module.
Request flow¶
HTTP Request
→ Controller (validates, delegates)
→ Mapper.toEntity(request)
→ Service (business logic)
→ Repository.save(entity)
→ Mapper.toEvent(entity, CREATED)
→ EventProducer.publish(event)
→ Redis cache updated
→ Mapper.toResponse(entity)
→ HTTP Response (JSON)
Shared utilities (reuse from modules/shared/)¶
| Class | Usage |
|---|---|
PagedResponse<T> |
Wrap all paginated list responses |
ResourceNotFoundException |
Throw on entity-not-found (auto-mapped to 404 ProblemDetail) |
Conventions¶
- All DTOs are immutable Java records
- Constructor injection only (no
@Autowiredfields) - OpenAPI annotations on all controllers and DTOs (
@Tag,@Operation,@Schema) - Constants for API paths, Kafka topics, and cache names (no magic strings)
- Integration tests with Testcontainers (real Postgres, Kafka, Redis)
Related documents¶
| Document | Path |
|---|---|
| Sample module guide | Sample Guide |
| Root PRD index | docs/PRD.md |
| Backend system README | backend/README.md |