Commit Graph
180 Commits
Author SHA1 Message Date
XingfenD cea2414371 refactor(frontend): shared reader chrome to shadcn/radix (header, nav Sheet, bookmarks) 2026-09-16 15:46:07 +08:00
XingfenD 1f9d7e7572 feat(frontend): cbz page/spread view math (TDD) 2026-09-16 15:22:59 +08:00
XingfenD 996f492083 feat(frontend): reading stats store (TDD) + session heartbeat hook (B0) 2026-09-16 15:22:38 +08:00
XingfenD 6aefe62a9f feat(frontend): unified reader settings bar with theme linkage (B0) 2026-09-16 15:20:18 +08:00
XingfenD 8283d66db6 feat(frontend): shadcn sheet/tabs/slider primitives (B0) 2026-09-16 15:17:26 +08:00
XingfenD 655b77c2b7 feat(frontend): reading theme token group + useGlobalDark for auto linkage (B0) 2026-09-16 15:15:53 +08:00
XingfenD 64cc293878 feat(frontend): readerPrefs v2 unified structure (TDD) 2026-09-16 15:15:08 +08:00
XingfenD 72cf13c8c3 chore(frontend): extend tsc coverage to e2e/configs, tighten vitest include (B0) 2026-09-16 15:13:35 +08:00
XingfenD 154ef11c90 docs: reader revamp implementation plan (18 tasks, 6 batches) 2026-09-16 15:10:02 +08:00
XingfenD 043b7fc480 docs: reader revamp spec (subproject ②) 2026-09-16 14:53:59 +08:00
XingfenD cc18822c97 Merge remote-tracking branch 'origin/feat/frontend-quality'
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
2026-09-16 12:16:40 +08:00
XingfenD 2fccf3f2b3 docs: record TS side-by-side + legacy-peer-deps conventions (AGENTS.md + .npmrc)
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
2026-09-16 11:43:21 +08:00
XingfenD caacaf9c30 docs: changelog for component testing + bundle review (B4 done, spec ④ complete) 2026-09-16 11:28:12 +08:00
XingfenD 5ba522753a docs: README frontend gates (lint/e2e/analyze), bilingual 2026-09-16 11:21:35 +08:00
XingfenD 8f4c34c949 docs: bundle-review — align dependency sizes to source-level caliber, rewrite epubjs finding 2026-09-16 11:18:44 +08:00
XingfenD 0bf8129f6e docs: bundle review findings (B4) 2026-09-16 11:06:58 +08:00
XingfenD f5c33f538e chore(frontend): bundle analyzer via npm run analyze (B4) 2026-09-16 11:00:22 +08:00
XingfenD cd02a88b59 ci(e2e): render configs from templates before compose up 2026-09-16 10:56:47 +08:00
XingfenD 4ba55fcf2a ci: e2e workflow (workflow_dispatch) + changelog (B3 done) 2026-09-16 10:53:23 +08:00
XingfenD f2f06a516b test(frontend): e2e admin smoke (create library + scan) 2026-09-16 10:48:23 +08:00
XingfenD 9c6339d35e test(frontend): e2e main flow (login→shelf→cbz→bookmark→logout) + axe scans 2026-09-15 17:29:20 +08:00
XingfenD 217adf5914 test(frontend): e2e api/axe helpers 2026-09-15 14:13:58 +08:00
XingfenD ba28fe9037 test(frontend): tiny 3-page CBZ fixture for e2e 2026-09-15 14:11:24 +08:00
XingfenD b65ea93984 test(frontend): playwright e2e scaffolding (config + scripts) 2026-09-15 12:00:45 +08:00
XingfenD a3755bcfab test(frontend): sample component tests for button/dialog/theme-toggle (B2) 2026-09-15 11:54:56 +08:00
XingfenD 38957b4c2c fix(frontend): install @testing-library/dom (missing peer under legacy-peer-deps) 2026-09-15 11:50:44 +08:00
XingfenD ca419410b4 test(frontend): component testing infra (jsdom + testing-library + vitest projects) 2026-09-15 11:46:20 +08:00
XingfenD 147339083b chore(frontend): wire lint+format into check gate, changelog (B1 done) 2026-09-15 11:44:21 +08:00
XingfenD a427aa1c4a fix(frontend): resolve all eslint errors to zero (B1) 2026-09-15 11:39:21 +08:00
XingfenD 29167d3cea style(frontend): prettier baseline format (no logic change) 2026-09-15 11:27:54 +08:00
XingfenD 09a02fa0d7 chore(frontend): eslint flat config + prettier baseline config 2026-09-15 11:22:02 +08:00
XingfenD 24c5d42531 docs: frontend quality implementation plan (16 tasks, 4 batches) 2026-09-15 11:12:38 +08:00
XingfenD 42a39ceef8 docs: frontend engineering quality spec (subproject ④) 2026-09-15 10:59:43 +08:00
XingfenD b3a207a5d2 Merge remote-tracking branch 'origin/fix/backend-hardening'
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
2026-09-15 00:42:26 +08:00
XingfenD 8305af9d5c docs: changelog + README backend structure for batch C (Task 29)
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
- CHANGELOG [Unreleased]: consolidated the duplicated Added/Changed/Fixed
  groups left by earlier batches into one group each (no entry dropped);
  added batch C entries — port-based restructure, media/upload domain
  packages, sweep moved to scanner ticker (B16), router contract test,
  portsfake unit-test layer. Upload-sweep wording no longer promises the
  old 24h opportunistic request-path behaviour.
- README.md / README_zh.md: new 'Backend structure' section documenting
  the port/fake layout (cmd/webui composition root, handlers as HTTP-only,
  internal/ports + portsfake, media/upload/store/scanner/bookfile
  responsibilities) and the two-tier testing approach (real PG+Redis
  integration vs fake-injected unit, route table pinned by contract test)

Gate: gofmt clean, go vet clean, go test -p 1 all pass (0 skip),
scripts/smoke.sh ALL SMOKE TESTS PASSED against a live webui on :18080
2026-09-14 23:37:36 +08:00
XingfenD 85c61d9f24 refactor: consolidate isUnique and path validation helpers (Task 28)
- seed.Admin: hand-rolled pgconn.PgError 23505 check → store.IsUniqueViolation
  (single predicate for unique violations across the codebase)
- books.absBookPath: local hasPrefixDir (filepath.Rel-based) removed in favor
  of bookfile.Contains, which also resolves symlinks — stricter escape check
- handlers isUnique alias + libraries.go local prefix check were already
  folded into ports.IsUniqueViolation / bookfile.Contains in Task 25;
  scanner.inside was folded in Task 24 — this commit closes the last two

Full gate green: gofmt, vet, go test -p 1 (real PG+Redis, 0 skip)
2026-09-14 23:26:16 +08:00
XingfenD cc1470f6e4 test: portsfake + router contract test + handler unit tests (Task 27)
- internal/ports/portsfake: hand-written in-memory fakes for all 9 ports
  (Users/Libraries/Books/Progress/Bookmarks/RateLimiter/Scanner/Media/Uploads);
  error semantics mirror the real store exactly — pgx.ErrNoRows for misses,
  store.ErrLastAdmin guard, and *pgconn.PgError{Code:23505} for unique
  violations (ports.IsUniqueViolation only accepts the PgError shape, so the
  fakes must produce it to exercise the 409 branch without touching prod code)
- Media/Uploads fakes are hook-programmable: one field per error branch, so a
  test can force e.g. CompleteErr=ErrIncomplete without stubbing the rest
- Scanner fake is mutex-guarded + WaitForScan: handler fires ScanLibraryByID
  in a goroutine, tests stay deterministic
- router_test.go: TestRouterContract pins all 27 routes — any route table
  change now fails the test explicitly
- handler unit tests (~30 cases, no PG/Redis): users CRUD branches (self-delete
  400, last-admin 400, dup 409, 204 ok), library reserved names (contract:
  code=bad_request message=reserved_name, per original impl), upload sentinel
  mapping (413/400/404 per branch)
- NewRouter takes pure port interfaces; main.go distributes *store.Store
  across the 5 store ports at the composition root

Full gate green: gofmt, vet, go test -p 1 (real PG+Redis, 0 skip)
2026-09-14 23:23:10 +08:00
XingfenD 7baadedeb4 refactor(handlers): consume port interfaces, wire media+upload assembly (Task 25+26)
- H now holds only small port interfaces (UserStore/LibraryStore/BookStore/
  ProgressStore/BookmarkStore/RateLimiter/Scanner/Media/UploadSessions);
  NewRouter is the composition root distributing *store.Store and *redispkg.R
- ports.Media gains EnsurePage; ChaptersOf returns ports.Chapter (media's
  local duplicate dropped); *media.M now provably satisfies ports.Media;
  ports.UploadSessions gains LibraryID for root validation before Complete
- content.go: duplicated page-index cache + cover self-heal + page extract
  logic removed in favor of media service — same redis keys, same contract;
  path traversal check stays in handler (403 semantics preserved)
- getLibrary/getLibRow merged into getLib(c, id); idParam helper dedupes
  :id parsing; isUnique replaced by ports.IsUniqueViolation (Task 28 partial)
- main.go assembles media + upload and passes upload.U as scanner Sweeper

Full gate green: gofmt, vet, go test -p 1 (real PG+Redis, 0 skip)
2026-09-14 22:56:15 +08:00
XingfenD b9b7022212 refactor(scanner): merge add/update into ingest, use shared utilities
- add/update consolidated into ingest(isNew) — persist branch differs,
  error handling and cover path fully shared (Task 24)
- zipIndex/cover use bookfile.OpenReaderAt instead of hand-rolled
  open+stat pairs
- root containment check uses bookfile.Contains (local inside removed)
- cover write goes through media.WriteAtomic (now exported, log-free —
  callers own context); media no longer logs inside the atomic helper
2026-09-14 22:12:30 +08:00
XingfenD fbd5cd243d feat(upload): extract upload subsystem + move sweep to scanner ticker (B16)
- internal/upload owns chunked-upload domain logic (fingerprint resume,
  part tmp+rename, assemble, session sweep) and the shared UniquePath
  helper used by both single-file and chunked completion paths
- handlers/uploads.go is now HTTP-only: bind params, call upload.U, map
  sentinel errors to the unchanged status/code/message contract
- B16: session sweep moved out of the UploadInit request path onto the
  scanner ticker via a Sweeper hook (upload.U satisfies it)
- unit tests for the package without PG/Redis; contract pinned by the
  existing handler integration tests (all green)
2026-09-14 22:00:25 +08:00
XingfenD 443f4acfa9 feat(media): Media service with EnsureCover, EnsurePage, PageIndex, ChaptersOf, writeAtomic
CI / backend (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
2026-09-14 19:50:34 +08:00
XingfenD 5ad277241c feat(bookfile): add Contains and OpenReaderAt utilities 2026-09-14 19:49:50 +08:00
XingfenD 18bd32e0f6 refactor(store): split into per-aggregate files, unexport pool, remove dead ListBookIDs 2026-09-14 19:49:18 +08:00
XingfenD 0c3b34c184 feat(ports): define consumer-side interfaces, sentinel errors, IsUniqueViolation 2026-09-14 19:47:27 +08:00
XingfenD f99f5a7878 docs: changelog for batch B (B1-B13 bug fixes); gofmt store.go 2026-09-14 19:46:16 +08:00
XingfenD 08b81fde60 fix(upload): retry on O_EXCL collision in single-file upload (B12) 2026-09-14 19:45:08 +08:00
XingfenD 8023a7ec5c fix(serve): check cover write errors, clean tmp only on failure path (B11) 2026-09-14 19:43:27 +08:00
XingfenD 0c5dfd4353 fix(library): reject reserved names (cache, .uploads) with 400 reserved_name (B8) 2026-09-14 19:42:52 +08:00
XingfenD 0e62d4aa18 fix(handlers): Upload io.Copy error → 500 not 413 (B6), Me distinguishes no-rows from DB errors (B7) 2026-09-14 19:42:25 +08:00
XingfenD b82a891c50 fix: upload part tmp+rename (B4), transactional last-admin DeleteUser (B5), RowsAffected order (B13) 2026-09-14 19:42:11 +08:00