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
XingfenD and CommandCodeBot
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
XingfenD
e117ad52d3
docs(bookmarks): implementation plan — 4 tasks, backend vertical slice first, shared useBookmarks panel wired into all readers
2026-09-08 00:59:46 +08:00
XingfenD
928e52c604
docs(bookmarks): design spec — per-user bookmarks table, REST CRUD with owner-scoped 404s, capture/seek reuse of progress locators, shared sidebar component
2026-09-08 00:40:00 +08:00
XingfenD
aa18eb66eb
Merge branch 'feat/cbz-chapters'
2026-09-08 00:24:40 +08:00
XingfenD
66466ec8d1
Merge branch 'feat/chunked-upload'
2026-09-08 00:24:40 +08:00
XingfenD
b8da9fd92e
feat(cbz): adapt reader to real archive structure — PageIndex skips macOS junk (__MACOSX/ and ._ AppleDouble were polluting pages with 163-byte blacks), pages endpoint derives chapters[{title,start}] from folder layout, imageless zip now lands state=error instead of an empty reader, CbzReader gains 目录 sidebar + prev/next chapter (TextReader pattern, rd-* classes); pagesidx cache key bumped for one-time invalidation; e2e on 311MB 調教開關:第二季.zip: 15048→7524 real pages, 52 chapters, all JPEGs
2026-09-08 00:22:13 +08:00
XingfenD
7d650107d2
feat(upload): resumable chunked upload protocol for large files — init(parts≤32MB)/status/complete endpoints with fingerprint-derived deterministic uploadId (same file resumes, no restart), sessions in BOOKS_DIR/.uploads with 24h sweep, frontend uploadBook auto-switches >16MB to 8MB parts (retry x3 in place, skip received); oversize single POST now reports honest 413 too_large instead of "multipart field 'file' required" (was MaxBytesReader abort mislabeled); UPLOAD_MAX_MB wired into both compose stacks (cap total, .env.example 2048), nginx body limit drops to 32m; testCfg limit 1MB, CJK/fullwidth-colon filename proven unaffected; e2e verified with 311MB real file (39 parts, sha1 match)
2026-09-07 23:56:40 +08:00
XingfenD
aba1e58fa6
Merge branch 'feat/reader-warm-theme'
2026-09-07 23:18:14 +08:00
XingfenD
c6dfb92c76
fix(cbz): smooth scrollbar/slider dragging — rAF-coalesce scroll handler, idle-debounced prefetch, frame-batched height corrections, PageHeights.setEst converges unseen pages to the first measured page size, page slider seeks instantly while scrubbing (no per-notch smooth-animation restart); restore lost ### Fixed header in changelog
2026-09-07 23:13:04 +08:00
XingfenD
065fde5b56
feat(reader): immersive chrome + WeChat-Read/Mihon-style bottom sheets — tap-center toggles header/toolbar, progress & page sliders seek anywhere, WYSIWYG theme swatches, A± font size; CBZ gains 连读/整页/适高 modes, edge-tap & arrow-key paging, persisted mode (seekChapter helper + test)
2026-09-07 23:03:26 +08:00
XingfenD
7e63c21902
feat(reader): stop detecting 卷 in txt splitting (volume lines stay body text, volume-only books fall back to pseudo-sections); replace chapter dropdown with a 目录 sidebar overlay (active row highlighted + centered, click-away/pick to close)
2026-09-07 22:42:10 +08:00
XingfenD
7fb01ce335
feat(ui): warm library palette (zinc+emerald -> stone+amber) with hover/focus feedback; text reader gains paper/sepia/night themes + persisted font-size (lib/readerPrefs.ts), serif justified measure; PDF drops emoji icons for 首页/末页, CBZ pill page counter, EPUB centered spread, blur reader header with format badge, aria labels on login/search/chapter select
2026-09-07 22:37:47 +08:00
XingfenD
2478da059b
Merge branch 'fix/txt-chapters-render'
2026-09-07 22:23:32 +08:00
XingfenD
f47f2a6199
fix(reader): split large txt into chapters (章 as boundaries, 卷 as optgroup labels, pseudo-sections when unmarked) rendered one at a time so the browser stops freezing; decode via strict-UTF-8-then-GB18030 with UTF-16 BOM sniffing to kill mojibake; progress locator {ch,scrollFraction} with old global-fraction fallback
2026-09-07 22:21:29 +08:00
XingfenD
991de0ef26
Merge branch 'feat/server-generated-library-root'
2026-09-07 21:59:48 +08:00
XingfenD
45eefd6741
feat(libs): create library by name only; root_path derived server-side as BOOKS_DIR/SafeName(name), validated at creation; drop root_path input from admin UI; align changelogs to bilingual template; trim AGENTS.md to rules not derivable from repo layout
2026-09-07 21:56:59 +08:00
XingfenD
ca64bc0d73
refactor(repo): conform structure to AGENTS.md (web->frontend, internal/api->cmd/webui/{api,handlers}, docs/README+CHANGELOGs, module .gitignores, drop stray library/ and committed debug bins)
2026-09-07 21:37:30 +08:00
XingfenD
961de429f9
fix(deploy): pin distinct image tags per compose (booklib/{api,web}:{dev,prod}); same project name shared default tags so dev up without --build ran the prod image
2026-09-07 21:24:33 +08:00
XingfenD
95317a0108
docs(readme): rewrite run/dev/migrate instructions for dev/release deploy spec
...
- scripts/smoke.sh: idempotent re-run (reuse existing member/library on 409)
- web client.ts: probe localStorage methods, not typeof (node 22+ stub regression)
2026-09-07 21:09:11 +08:00
XingfenD
0de824cc6a
feat(deploy): dev compose runs full stack with source mounts, delve, shared volumes; vite proxy target via env (dlv --accept-multiclient, GOPROXY=goproxy.cn in dev image)
2026-09-07 21:04:40 +08:00
XingfenD
0ea918fae6
feat(deploy): release compose under deploy/ with shared named volumes and rendered config mounts; drop root compose
2026-09-07 20:55:57 +08:00
XingfenD
67dc4bc2bf
feat(deploy): dev/prod Dockerfiles in service dirs (backend/,web/), templates live beside rendered outputs, entrypoint copies /etc/booklib conf before resolver injection
2026-09-07 20:53:41 +08:00
XingfenD
a78442da54
feat(deploy): prepare.sh + config templates, migrate env to deploy/, gitignore rendered outputs
2026-09-07 20:18:12 +08:00