No description
Find a file
Michal Kozák 6f6ddff6de
refactor: bump to Go 1.26 and adopt os.Root for safe file I/O
Bumps go.mod from 1.23 to 1.26 to match the installed toolchain.

Refactors store to use os.Root (Go 1.24+) for file operations:
- Split filePath into rootDir + fileName
- load() opens the directory as a root and reads within it
- save() creates the directory if needed, then writes via root
- Prevents path traversal attacks (e.g. DATA_FILE=../../../etc/passwd)

Updates README and docs to reference Go 1.26 and document os.Root
and range-over-func iterators (slices.All, maps.All).
2026-04-24 23:56:45 +02:00
docs refactor: bump to Go 1.26 and adopt os.Root for safe file I/O 2026-04-24 23:56:45 +02:00
.gitignore Initial commit 2025-09-14 22:26:16 +02:00
go.mod refactor: bump to Go 1.26 and adopt os.Root for safe file I/O 2026-04-24 23:56:45 +02:00
LICENSE Initial commit 2025-09-14 22:26:16 +02:00
main.go refactor: bump to Go 1.26 and adopt os.Root for safe file I/O 2026-04-24 23:56:45 +02:00
main_test.go refactor: modernize to Go 1.23 with docs and tests 2026-04-24 23:50:00 +02:00
README.md refactor: bump to Go 1.26 and adopt os.Root for safe file I/O 2026-04-24 23:56:45 +02:00

▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
▓▓                                                                    ▓▓
▓▓   ░▒▓ D̷O̷C̷H̷A̷Z̷K̷O̷T̷R̷O̷N̷-̷5̷0̷0̷0̷ ▓▒░                              ▓▓
▓▓                                                                    ▓▓
▓▓   [ K I N D E R G A R T E N   A T T E N D A N C E   S Y S T E M ] ▓▓
▓▓                                                                    ▓▓
▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓

Simple web application for tracking kindergarten attendance with a parent excuse feature (must be submitted before 08:00).

Built as a modern Go 1.26 reference — structured logging, method-aware routing, graceful shutdown, slices generics, middleware, and table-driven tests.

Features

  • Two classes (16 children each)
  • Absence excuses accepted until 08:00 on the given day
  • Attendance list per class
  • Parent authorization — only the assigned parent can excuse their child
  • Health endpoint for load-balancer / k8s probes
  • Graceful shutdown on SIGINT / SIGTERM
  • Persistent JSON file storage

Requirements

Installation & Running

git clone <your-repo-url>
cd dochazkotron-5000
go mod tidy
go run main.go

Open http://localhost:8080 (or set PORT env variable).

Environment Variables

Variable Default Description
PORT 8080 HTTP server port
DATA_FILE attendance.json Path to the JSON data file

API Endpoints

Health Check (GET)

curl http://localhost:8080/health

Response:

{"status":"ok"}

Excuse a Child (POST)

curl -X POST http://localhost:8080/excuse \
  -H "Content-Type: application/json" \
  -d '{"child_id":"child_0_0","parent_id":"parent1"}'

Parameters:

  • child_id — Child ID (e.g. child_0_0)
  • parent_id — Parent ID (must match the child's assigned parent)

Constraints:

  • Excuses are accepted only until 08:00 on the given day.
  • A parent can only excuse their own children.

Success Response:

{"status":"excused"}

Error Responses:

  • 400 Bad Request — Invalid JSON, missing fields, or excuse time expired
  • 403 Forbidden — Parent does not match child or unknown parent
  • 404 Not Found — Child not found

Get Class Attendance (GET)

curl "http://localhost:8080/attendance/class1"

Path Variable:

  • class_id — Class ID (class1 or class2)

Response:

{
  "Dítě 1-1": true,
  "Dítě 1-2": false
}
  • true — Child is absent and not excused (needs attention)
  • false — Child is excused

Modern Go Patterns Used

This project is intentionally kept small to serve as a learning reference. Key modern patterns:

Feature Where Why
slog main() Structured, leveled logging instead of log
http.ServeMux method + path matching main() Go 1.22+: POST /excuse, GET /attendance/{class_id}
r.PathValue("class_id") handleAttendance Extract route variables without third-party routers
signal.NotifyContext main() Graceful shutdown with context cancellation
http.Server timeouts main() Production-hardened server config
http.MaxBytesHandler main() Request body size limits
os.Root store Go 1.24+: sandboxed file I/O prevents path traversal
slices.All / maps.All store Go 1.23+: range-over-func iterators
slices.IndexFunc store Generic slice search
range over integers newStore for j := range 16
cmp.Or main() Default-value fallback
time.DateOnly store "2006-01-02" constant
errors.Is sentinel errors handlers + tests Clean error classification
sync.RWMutex store Many concurrent readers, one writer
Middleware chaining app.chain Composable recoverPanic + logRequest
t.Parallel() + table-driven tests main_test.go Fast, scalable test suite
httptest through ServeMux main_test.go Tests routing + path values together
Injected clock function app struct Deterministic time in tests

Data Storage

All data is stored in attendance.json (override with DATA_FILE).

Example structure:

{
  "classes": [
    {
      "id": "class1",
      "name": "Třída 1",
      "children": [
        {
          "id": "child_0_0",
          "name": "Dítě 1-1",
          "class_id": "class1",
          "parent_id": "parent1"
        }
      ]
    }
  ],
  "attendances": [],
  "parents": ["parent1", "parent2"]
}

Data Model

Children

  • Each class contains 16 children.
  • Every child has:
    • id — Unique identifier (e.g. child_0_0)
    • name — Display name
    • class_id — Class identifier
    • parent_id — Parent ID used for excuse authorization

Testing

go test -v -race ./...

Tests cover:

  • Store logic (excuse, attendance, validation, persistence)
  • HTTP handlers (routing, status codes, JSON responses)
  • Middleware (panic recovery, request logging)
  • Time constraint logic

Production Notes

  • The server runs with read/write timeouts and graceful shutdown.
  • For HTTPS, place a reverse proxy (Nginx, Caddy, Traefik) or a cloud load balancer in front.
  • The JSON file uses 0600 permissions. For production workloads, migrate to a real database.
  • Authentication is parent-ID-based in this demo. Add OAuth2 / JWT for real deployments.

License

MIT