rebrand: MangaBM → BookmarkManager, add novel library support (#15)

Two intertwined changes — the rebrand and the novel library were developed on
the same branch because the novel UI plumbing is part of the new "Bookmark
Manager" wordmark in the web shell.

## What it does

- **Rebrand**: MangaBM → BookmarkManager across the Go module, compose stack,
  env vars, Traefik hostnames, container/image names, userscript storage
  prefixes (`mangabm:cache` → `bmgr:manga:cache`, `mangabm:queue` → `bmgr:manga:queue`),
  and docs.
- **Novel library**: same backend, two libraries. New `kind` column splits
  bookmarks into `manga` / `novel`; PUT validates it. Two userscripts:
  - `manga-bookmark.user.js` — unchanged behaviour, just stamps its own `kind`.
  - `novel-bookmark.user.js` — separate Violentmonkey install with adapters
    for **novelfull.com** (polled via headless browser — Cloudflare JS
    challenge) and **lightnovelworld.net** (polled via plain TLS).
- **Web UI**: library switch on the app shell. Login art, libswitch, and
  novel-site colours from the Cinder design snapshot.

## Plumbing

- `addedColumns` ALTER for `kind` runs on first start after upgrade; every
  pre-existing row is backfilled to `'manga'`. No manual SQL, no down-time.
- `ALLOWED_ORIGINS` gains the two novel sites.
- New `NOVEL_USERSCRIPT_PATH` env (default `/userscript/novel-bookmark.user.js`),
  bindmounted alongside the manga script.
- Traefik router names `mangabm*` → `bmapi*` / `bmweb*`.

## Test status

- `go test ./...` — green
- `node --test userscript/test/logic.test.js` — 34 pass
- `node --test userscript/test/novel-logic.test.js` — 11 pass
- `node --check` on both userscripts — clean

## Notes for the redeploy

.env keys were renamed (`MANGA_API_HOST` → `BOOKMARK_API_HOST`,
`MANGA_WEB_HOST` → `BOOKMARK_WEB_HOST`). Update DNS / Traefik labels on the
prod override before pulling, otherwise the public hostnames go dark.
See the redeploy instructions I'll post next to this PR.

Reviewed-on: #15
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #15.
This commit is contained in:
2026-08-06 03:58:23 +07:00
committed by sulthan
parent c445762244
commit 4229c179b0
40 changed files with 2948 additions and 347 deletions
+18 -15
View File
@@ -1,6 +1,6 @@
# Cinder — mangaBookmark design system
# Cinder — BookmarkManager design system
Source of truth: the Claude Design project **mangaBookmark Web UI**
Source of truth: the Claude Design project **BookmarkManager Web UI**
(`969ac210-fe02-4c01-ae1b-9a271dcc779a`, `index.html` + siblings
`archived.html`/`fav.html`/`finished.html`/`new.html`/`login.html`/`mobile.html`,
`style.css`, `filter.js`). This file records the rules that got implemented so
@@ -10,7 +10,7 @@ Implemented in:
| Surface | Files |
| --- | --- |
| Web UI (login, list, card, empty, errors) | `backend/static/style.css`, `backend/templates/{app,card,list,login,chrome,icons}.html`, `backend/static/filter.js` |
| Web UI (login, list, card, empty, errors) | `backend/internal/web/static/style.css`, `backend/internal/web/templates/{app,card,list,login,chrome,icons}.html`, `backend/internal/web/static/filter.js` |
| Userscript panel (Shadow DOM) | `userscript/manga-bookmark.user.js` — `TEMPLATE` and `CSS` at the bottom of the IIFE |
## 1. The one idea
@@ -41,7 +41,7 @@ Corollaries:
## 2. Tokens
Defined once in `backend/static/style.css` `:root`, mirrored in the userscript's
Defined once in `backend/internal/web/static/style.css` `:root`, mirrored in the userscript's
`:host`. **Never hardcode a hex outside those two blocks.**
| Token | Dark | Light | Use |
@@ -77,6 +77,8 @@ Defined once in `backend/static/style.css` `:root`, mirrored in the userscript's
| `--fav-line` | `#332b14` | `#e3d3a4` | desktop cell border, favourite when on |
| `--asura` | `#7d93a5` | `#4f6b80` | site tag |
| `--demonic` | `#a98a78` | `#8a6a55` | site tag |
| `--comix` | `#8a9a7d` | `#5f7250` | site tag |
| `--kagane` | `#9a8aa5` | `#6f5f7d` | site tag |
| `--hatch` / `--hatch-dim` | 135° 5px stripe | paper stripe | missing-cover slot |
`--slate`/`--moss`/`--clay`/`--brass` are held at the same weight deliberately:
@@ -95,7 +97,7 @@ dark, the hues are re-tuned.
| Sans | `DM Sans` → system UI | system UI |
The web UI **self-hosts** all three: five latin-subset woff2 files in
`backend/static/fonts/` (~120 KB total), declared by the `@font-face` block at
`backend/internal/web/static/fonts/` (~120 KB total), declared by the `@font-face` block at
the top of `style.css` and embedded in the binary by the existing
`//go:embed static`. There is no request to Google — this UI needs to survive
on a LAN with no internet route. `staticHandler()` in `web.go` registers the
@@ -116,7 +118,7 @@ root is at the mercy of the host site's CSP.
Recurring specs (copy these rather than inventing sizes):
- Brand: `400 26px/1 display` (`30px` ≥720px), inline SVG mark (§4) + `<em>` in
ember italic — `manga<em>Bookmark</em>`.
ember italic — `Bookmark<em>Manager</em>`.
- Row title: `400 21px/1.2 display` (`22px` ≥720px).
- Tab: `400 17px display` (`18px` ≥720px), active gets `border-bottom: 2px` in
`--paper` (`--ember` for Updated) plus `margin-bottom: -1px` so it lands on
@@ -141,18 +143,19 @@ Recurring specs (copy these rather than inventing sizes):
**Brand mark**: an inline `<svg class="mark">` (`viewBox="0 0 200 172"`),
defined once in `chrome.html`'s `mark` template and reused by `app.html` and
`login.html` so it takes the page's `--ink`/`currentColor`/`--ember` rather
than shipping as a static asset. The blade at its centre strokes
`var(--logo-blade, var(--ember))` — override that custom property, don't
duplicate the SVG, if a surface ever needs a different blade colour. Drawn at
a 5px stroke on a 200-unit grid; at brand size that thins out, so `.brand .mark
g` nudges `stroke-width` up to `6.5` rather than scaling the artwork down.
than shipping as a static asset. The blade at its centre strokes `var(--ember)`,
so a surface that needs a different blade colour re-points that token rather
than duplicating the SVG. Drawn at a 5px stroke on a 200-unit grid; at brand
size that thins out, so `.brand .mark g` nudges `stroke-width` up to `6.5`
rather than scaling the artwork down.
**Action key** (`.keyrow`): one permanent line under the tabs naming what
every icon in `.actions` does — Read / Fav / Chapter / Archive / Done /
Delete — so the icon strip on a card is never a guess. On a phone each pair
stacks icon-over-word (`flex-direction: column`) so the word gets the full
cell width and can stay in long form; ≥720px it lays out icon-beside-word and
switches the `.short`/`.full` label pair. `.pair.brass` and `.pair.trash`
Delete — so the icon strip on a card is never a guess. The key follows the tab,
not the row: Archive becomes Restore under Archived and Finished, and Finished
drops Done. On a phone each pair stacks icon-over-word
(`flex-direction: column`) so the word gets the full cell width; ≥720px it lays
out icon-beside-word at the same wording. `.pair.brass` and `.pair.trash`
carry their icon's resting accent so the key itself teaches the colour
vocabulary in §1/§2.