fix: critical bugs from code review (data corruption, error contract, HTTP hardening) #5

Merged
frx merged 7 commits from refactor/code-review-fixes into master 2026-06-28 14:04:25 +00:00

7 Commits

Author SHA1 Message Date
ca63e04e7d refactor: move mocks and NotImplemented stubs out of domain package
- Move domain/mocks/ → adapters/mocks/ (update imports + mockery directives)
- Extract NotImplementedOrganizationRepository + NotImplementedLearningCategory
  from domain/repository.go into adapters/not_implemented.go
- Remove cerrors import from domain/repository.go (domain now has no
  dependency on internal/common/errors)
- nullable stays in domain: used by entity structs and interface Params

Addresses review comments #2 (domain deps) and #3 (mocks in domain) on PR #5.
2026-06-28 12:57:17 +00:00
0d2c4a7c3a fix: remove error types from domain package completely
domain/error.go deleted — errors do not belong in domain.
All ErrNotImplemented stubs in repository.go now reference
common/errors.ErrNotImplemented via cerrors alias.
2026-06-28 10:19:33 +00:00
bd4a066d10 fix: remove domain->common/errors import — domain must be dependency-free
Review #3 comment: domain package shouldn't depend on any other package.
Replace common/errors.ErrNotImplemented alias with stdlib errors.New
so domain has zero internal dependencies.
2026-06-28 10:02:35 +00:00
9088caf600 fix: unify ErrNotFound — remove domain.ErrNotFound, use errors.ErrNotFound everywhere
Responds to PR #5 review comment: consolidate on common/errors.ErrNotFound
instead of having two separate error types (domain.PlainError and
common/errors.SimpleError) for the same sentinel.

- Remove domain.ErrNotFound and domain.PlainError type
- Keep domain.ErrNotImplemented as alias to common/errors.ErrNotImplemented
- Update sqlite_organization_repository to return cerrors.ErrNotFound
- Update sqlite_learning_category_repository to return cerrors.ErrNotFound
- Update server.go handleError to check only errors.ErrNotFound
- Update test to assert errors.ErrNotFound
- Remove unused domain import from server.go
2026-06-28 07:56:13 +00:00
4f89f59232 fix(cluster-3): http hardening (M15/M16/M14/C2)
- pagination: clamp per_page to [1,100] and page to >=1 in the parser,
  guard the TotalPages division against per_page=0 (panic), and clamp the
  current page to [1,totalPages]; preserves cursor (next-token) mode
- middleware: add panic-recovery as the outermost middleware so handler
  panics return a 500 instead of crashing the process; re-panics
  http.ErrAbortHandler to keep file serving intact
- index: bound the index page query (Limit:200) so it no longer drains
  the entire courses table in 1000-row batches
2026-06-28 04:31:21 +00:00
40e5621eb9 fix(cluster-2): error contract unification (C1/M10/M11/M12)
- http: handleError now recognizes domain.ErrNotFound in addition to the
  common errors.ErrNotFound sentinel, so repo-not-found maps to 404
  instead of 500 (the two packages use distinct error types)
- sqlite_course_repository: propagate listCount errors instead of logging
  and swallowing them, which left callers with a silent Count=0
- synchandler: collect course/organization insert failures into a
  function-scoped error via errors.Join and return it; previously the
  loop-local err was overwritten and the handler always returned nil,
  hiding all insert failures
2026-06-28 04:28:48 +00:00
23c29aba1d fix(cluster-1): data corruption fixes (C4/C5/C8)
- synchandler: combine course date with clock time via time.Date instead
  of adding two absolute Unix epochs, which produced corrupt start times
- tracing: make DeploymentEnvironment configurable via config.Trace
  (defaults to development instead of hardcoded production)
- http: align course handler tracer name to 'kuriweb.http' to match the
  request middleware instrument so spans share the same tracer
2026-06-27 23:54:07 +00:00