Commit Graph
100 Commits
Author SHA1 Message Date
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
XingfenD 8fbc58eaaa fix(redis,scanner): atomic IncrWindow Lua, lock rand/ctx fixes, ScanLock renewal, single-flight, error logging (B1,B2,B3,B9,B10,B11) 2026-09-14 19:40:53 +08:00
XingfenD 2c2f6d3116 chore: gofmt content_test.go 2026-09-14 19:38:33 +08:00
XingfenD 26111e73af docs: changelog + README updates for batch A (migrations, CI, B14/B15/B17) 2026-09-14 19:38:16 +08:00
XingfenD b63d50e04b fix(smoke): drop ignored root_path field, align with API contract (B17) 2026-09-14 19:37:42 +08:00
XingfenD f26aac103b fix(config): validate DATABASE_URL required and parseable, log redis disabled (B15) 2026-09-14 19:37:26 +08:00
XingfenD f0437139f3 fix(main): channel-based serve error instead of log.Fatalf in goroutine (B14) 2026-09-14 19:36:57 +08:00
XingfenD 161128cac0 ci: add GitHub Actions workflow (Gitea Actions compatible) 2026-09-14 19:36:31 +08:00
XingfenD 6d3d23c3f9 feat(db): ordered migration system with advisory lock and baseline detection 2026-09-14 19:36:21 +08:00
XingfenD c9b32db592 docs(plan): backend hardening implementation plan — 29 tasks across 3 batches 2026-09-14 19:33:30 +08:00
XingfenD 942a9952ca docs(spec): clarify batch attribution for B8/B9-2 (depend on batch-C packages) 2026-09-14 19:14:45 +08:00
XingfenDandCommandCodeBot 2cf842af9e docs(spec): backend hardening design — migrations, 17 bug fixes, ports/internal restructure, CI
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-14 16:55:44 +08:00
XingfenD a22b44be06 Merge branch 'fix/cbz-end-chapter-jump' 2026-09-08 22:45:20 +08:00
XingfenD 2e43cb2423 fix(web): stop CBZ reader snapping/bouncing at chapter end on mixed-orientation books 2026-09-08 22:42:05 +08:00
XingfenD 90b39d4f97 Merge branch 'feat/ui-redesign' 2026-09-08 21:48:41 +08:00
XingfenD fd227c1f00 feat(web): table-style 库管理, admin entries under avatar 系统管理, shelf-view upload button 2026-09-08 21:45:03 +08:00
XingfenD 3178c2802f refactor(web): extract prefetch slider into reusable RdSlider component 2026-09-08 21:31:20 +08:00
XingfenD 472e58bec9 fix(web): unify 更多 menu text size, add 0-3 tick anchors under prefetch slider 2026-09-08 21:30:26 +08:00
XingfenD d2c852d6f0 feat(web): iconify reader chrome, move 连读/预读 into 更多 menu with slider 2026-09-08 21:29:01 +08:00
XingfenD 9c2b7e2074 feat(web): collapse reader toc/bookmark buttons into single 导航 toolbar button 2026-09-08 21:11:16 +08:00
XingfenD 65e07a0890 chore: ignore tsc buildinfo artifact 2026-09-08 21:08:52 +08:00
XingfenD 48161ea1ff feat(web): unify reader TOC and bookmarks into one left nav drawer with tabs 2026-09-08 21:08:42 +08:00
XingfenD 4f4c7e5434 chore: gitignore playwright artifacts 2026-09-08 20:48:38 +08:00
XingfenD 6fbe3b0794 fix(web): active lib highlight, rail a11y names, card focus ring, AA accent + destructive tokens, touch-reachable menu, brand wordmark, chrome unify 2026-09-08 20:37:20 +08:00
XingfenD 7e0847815d docs(changelog): phase-1 modern redesign — shadcn tokens, dual theme, app shell, rebuilt public surfaces 2026-09-08 19:37:38 +08:00
XingfenD 7727baa25b fix(web): theme menu items fire on keyboard select (onSelect) 2026-09-08 19:19:45 +08:00
XingfenD dcaf502de6 feat(ui): admin pages on shadcn table/card/alert-dialog; drop TopBar, trim icons/ui.ts to reader-compat surface 2026-09-08 19:14:41 +08:00
XingfenD 273f35a42f fix(web): shelf search debounce merges against live searchParams (no lost sort/group clicks) 2026-09-08 19:08:05 +08:00
XingfenD b1c0db6c03 feat(ui): shelf rebuilt — sticky toolbar (search/sort/group in URL), rail, menu cards, alert-dialog delete 2026-09-08 18:58:16 +08:00
XingfenD d9e9e95ece feat(ui): login rebuilt on shadcn card/label/input, theme toggle available pre-auth 2026-09-08 17:47:17 +08:00
XingfenD 52e95a48d8 fix(ui): gate app sidebar to md+ and use onSelect for logout (keyboard path) 2026-09-08 17:41:29 +08:00
XingfenD 7957e5cee5 feat(ui): AppShell layout route — desktop rail, tablet icon rail, mobile tabs, theme toggle 2026-09-08 17:35:14 +08:00
XingfenD 913f3286bb feat(lib): shelf sort/section pure helpers + formatSize extraction, table tests 2026-09-08 17:29:07 +08:00
XingfenD 03bc537308 feat(ui): semantic light/dark tokens, ThemeProvider with FOUC guard, token-restyle Toaster/Cover 2026-09-08 17:17:44 +08:00
XingfenD 87b7545a94 feat(ui): shadcn/radix toolchain — deps, @ alias, cn, generated primitives 2026-09-08 17:07:28 +08:00
XingfenD ee676c2d2e docs(plan): modern redesign phase-1 implementation plan — 8 tasks from toolchain to acceptance walkthrough 2026-09-08 17:02:02 +08:00
XingfenD b8a5b3deb6 docs(design): phase-1 modern redesign spec — shadcn/radix foundation, dual theme, app shell, shelf/admin rebuild; readers deferred to phase 2 2026-09-08 16:49:46 +08:00
XingfenD 2721df8ea9 fix(web): upload toast always showed 0 files (live FileList read after input reset); snapshot before upload 2026-09-08 16:22:12 +08:00
XingfenD e5dacc0a77 fix(cbz): clamp locked cur at chapter end, hide 连读 on flat packs, silent restore, tighten prefetch storage 2026-09-08 15:28:27 +08:00
XingfenD 60c4ccf26f fix(cbz): window-relative scroll geometry locks head boundary; default prefetch 2 when key absent 2026-09-08 15:15:42 +08:00
XingfenD f63b639f64 feat(cbz): chapter-scoped continuous reading — lock scroll at chapter end, screen paging, prefetch next N chapters; drop 连读/整页/适高 modes 2026-09-08 15:01:28 +08:00
XingfenD cd251b940c feat(cbz): pure chapter-window helpers (chapterIndexAt/chapterWin) with table tests 2026-09-08 14:56:46 +08:00
XingfenD bba82e5529 docs(plan): correct container names to podman compose underscores 2026-09-08 14:54:34 +08:00
XingfenD 497dc16604 fix(deploy): COPY paths in web Dockerfiles still referenced old web/ dir after web->frontend rename — dev image build failed 2026-09-08 14:53:29 +08:00
XingfenD 37ddff89a5 docs(cbz): chapter-scoped reading implementation plan — 3 tasks, virt helpers TDD first 2026-09-08 14:51:03 +08:00
XingfenD a39ddf7b57 docs: add cbz chapter-scoped reading design spec 2026-09-08 14:45:15 +08:00
XingfenD ec3f2c587e feat(reader): remove admin delete button from reader header; shelf card hover remains the only delete entry 2026-09-08 13:08:46 +08:00
XingfenD a43b73dcef fix(cbz): attach resize observer via callback ref + drop vh from scroll-mode geometry deps — fixes constant per-page gaps and refetch storm on mobile 2026-09-08 13:05:58 +08:00
XingfenD 32b9d3a136 feat(ui): content-first shelf redesign — responsive cover grid, hover overlays, format badges, skeletons, sticky blurred top bar, brand login, SVG icon set, animated toasts 2026-09-08 13:05:40 +08:00
XingfenD 02ac3e5f7f Merge branch 'feat/bookmarks' 2026-09-08 12:33:32 +08:00
XingfenD 40e9999e6a chore(bookmarks): changelog + e2e verification (create/jump/patch/delete against live api, seek page serves real jpeg) 2026-09-08 12:32:36 +08:00
XingfenD d989668650 feat(bookmarks): shared useBookmarks panel + wired into all four readers 2026-09-08 01:06:39 +08:00
XingfenD b2c5c4a445 feat(bookmarks): client plumbing — saver capture + bookmark api 2026-09-08 01:04:44 +08:00
XingfenD 0fe3bc3057 feat(bookmarks): api+store — per-user CRUD, owner-scoped 404, percent-ordered list 2026-09-08 01:03:44 +08:00