Threadmark is the working name for a focused web reader with EPUB import,
automatic resume, bookmarks, content-weighted navigation, and spoiler-safe
recaps. The name and public metadata live in config/product.json so they can
be changed in one place when the final product name is chosen.
- Node.js 22.13 or newer
- npm
- Docker with Compose, for the production/Portainer deployment
npm install
npm run devThe development server is available at http://localhost:3000 by default.
npm test
npm run lint
npm run build
npm run test:integrationRun the full sequence with npm run validate.
The production build is a static export served by nginx. The stack pulls
published Node and nginx images; Portainer does not build a custom image.
Instead, the updater container clones this repository, validates and builds a
new commit, and publishes out/ to a shared volume while nginx continues to
serve the last successful build.
Start the same stack locally with:
docker compose up -d
docker logs -f threadmark-updaterFor Portainer, create a stack from this Git repository and select compose.yml
as the Compose path. Set THREADMARK_PORT if port 3000 is already occupied and
set NEXT_PUBLIC_SITE_URL to the externally visible URL. The initial site
appears after the updater's first successful build. See docs/deployment.md
for the full handoff.
app/contains the thin Next.js route and global document shell.features/reader/contains reader components, domain logic, EPUB parsing, and browser persistence.content/contains book-specific application content such as recaps.public/books/contains generated, deployable book assets.config/product.jsonis the single place for working product identity and built-in book URLs.tests/unit/covers reader calculations and behavioral source contracts.tests/integration/verifies the static production export and bundled assets.
More detail is available in docs/architecture.md.
Pass the source manuscript explicitly; the project no longer depends on a sibling repository:
npm run book:generate -- path/to/manuscript.mdSet BOOK_AUTHOR when the author name should differ from the current default.
The script writes book.json and book.epub under
public/books/before-we-were-us/.