1. 19 Jul, 2026 3 commits
    • Administrator's avatar
      test: seam coverage for auth/authService/endpoints/lanAccess — Candidate 4 · 4bca327d
      Administrator authored
      
      
      Five new spec files take the test count 113 → 178 (+65). Zero
      production code changes; all coverage gain.
      
      - src/__tests__/utils/jwtFactory.js           — base64url JWT maker
      - src/__tests__/utils/authGuard.spec.js       — 21 tests on checkAuth()
                                                     (LAN bypass, already-authed,
                                                      refresh-failed, etc.)
      - src/__tests__/utils/lanAccess.spec.js       — 17 tests on real CIDR
                                                     parser (jsdom hostname
                                                     patching)
      - src/__tests__/api/endpoints.spec.js         — 10 tests, structural
                                                     lock for apiEndpoints
      - src/__tests__/api/authService.spec.js       — 5 tests, login +
                                                     refreshAccessToken HTTP
                                                     shape
      - src/__tests__/stores/authStore.spec.js      — 33 tests, first Pinia
                                                     spec; covers axios
                                                     interceptor 8-branch
                                                     decision tree including
                                                     the LAN GET-bypass that
                                                     had 0 coverage before
      
      Footnotes for future explorers:
      - auth.js reads localStorage at module-eval time to seed its initial
        ref values — vi.stubGlobal('localStorage', ...) installed in
        beforeEach is too late. Manipulate jsdom's real localStorage and
        clear() it in beforeEach instead.
      - The axios response interceptor's logout() call is closure-captured
        at setup time, so external reassignment of auth.logout won't
        intercept it. Assert logout side effects via state changes
        (auth.accessToken === null, etc.) instead.
      Co-Authored-By: default avatarClaude <noreply@anthropic.com>
      4bca327d
    • Administrator's avatar
      refactor(task): decompose TaskView 2294→310 lines — Candidate 2 · 5975ab07
      Administrator authored
      
      
      TaskView was a god-view doing filter wiring, calendar rendering,
      edit-dialog state, image carousel, and image grid all inline. Pulled
      into focused modules:
      
      - src/components/task/TaskFilters.vue      — filter panel + emits update:*-id
      - src/components/task/TaskCalendar.vue     — FullCalendar wrapper
      - src/components/task/TaskEditDialog.vue   — create/edit dialog
      - src/components/task/TaskImageCarousel.vue — full-screen carousel
      - src/components/task/TaskImageGrid.vue    — thumbnail grid + upload
      - src/composables/useTaskFilters.js        — pure filter state + apply logic
      - src/utils/taskDisplay.js                 — completion/status display helpers
      
      Filter state now lives in useTaskFilters (covered by 20-test spec);
      TaskView is an orchestrator that mounts the children and forwards
      events. Closes the longest-standing "this file is too big to review"
      pain point.
      Co-Authored-By: default avatarClaude <noreply@anthropic.com>
      5975ab07
    • Administrator's avatar
      refactor(api): extract apiError/boolCodec/logger/paginate helpers — Candidate 1 · c5d94b56
      Administrator authored
      
      
      Five thin service adapters (student/subject/term/story/task) now route
      through three pure helpers:
      
      - apiError.js  — normalize axios errors (status, message, detail, original)
      - boolCodec.js — parse DRF Y/N/true/false/etc. into strict booleans
      - logger.js    — tag-prefixed console output (swap to no-op in tests)
      - paginate.js  — DRF paginated-list walker with page_size:100 + 100-page cap
      
      apiEndpoints lifted from src/api/index.js (was stale) into its own
      endpoints.js single source of truth. Service tests gain 4 new spec
      files (apiError/boolCodec/logger/paginate).
      
      The duplicated fetchAllPages() copy in studentService and taskService
      is now a single import; either delete the old code or accept the
      temporary duplication until a follow-up candidate collapses it.
      Co-Authored-By: default avatarClaude <noreply@anthropic.com>
      c5d94b56
  2. 18 Jul, 2026 1 commit
    • Administrator's avatar
      feat(task): spec 0004 — task images migrated to stdt_task_images sub-resource · 8925331e
      Administrator authored
      
      
      Task images were stored as a JSON-ish field on stdt_tasks. Spec 0004 (see
      docs/task-images-migration.md) splits them into a dedicated sub-resource
      stdt_task_images so each image is its own row with mime_type / file_name /
      etag / size_bytes, accessed via /api/tasks/<id>/images/.
      
      Frontend changes:
      - new useTaskImages composable owning image state per edit dialog, with
        eager-load priming in load() so thumbnails render and are clickable in
        the grid (fixes v-if branch gated on populated imageCache).
      - taskService refactored: listTaskImages / createTaskImage / deleteTaskImage
        / getTaskImageContent (blob fetch with responseType: 'blob' to dodge 406s).
      - apiEndpoints.TASKS.IMAGES added for documentation purposes only — services
        still hardcode paths (CLAUDE.md flags apiEndpoints as stale).
      - TaskView.vue: switched from inline task.images to useTaskImages(); image
        upload / preview / delete / carousel wired to the new composable. Explicit
        taskId passed to load() and commit() since useTaskImages is instantiated
        without a taskIdRef at module scope.
      - locales en/zh-CN: new image keys (addImage, pendingUpload, clickToLoad,
        imagePartialFailure, imageLimitReached, etc.).
      
      Tests:
      - src/__tests__/api/taskService.test.js
      - src/__tests__/composables/useTaskImages.test.js
      - src/__tests__/composables/useTaskImages.network.test.js
      
      Also: .claude/ added to .gitignore (Claude Code local permissions, per-dev).
      Co-Authored-By: default avatarClaude <noreply@anthropic.com>
      8925331e