Skip to content

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 @Autowired fields)
  • 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)

Document Path
Sample module guide Sample Guide
Root PRD index docs/PRD.md
Backend system README backend/README.md