This document captures the authoritative product definition, architecture, and delivery rules for do EPUB Studio. It mirrors the final decisions from the latest planning thread and supersedes older scattered notes.
- Product:
do EPUB Studio - Repository:
do-epub-studio - GitHub repo target:
d-oit/do-epub-studio
do EPUB Studio is a web-based EPUB reading and editorial workspace for self-publishing, controlled distribution, and annotated review.
It is not just a reader.
It combines:
- EPUB reading
- gated access by email
- optional password protection
- public or private distribution
- offline reading as a PWA
- bookmarks and highlights
- editorial comments and threaded discussion
- audit logging and permission management
- author shares a manuscript EPUB with selected readers
- editor reviews EPUB with comments and discussion
- proofreaders access a protected draft
- selected readers get read-only access
- public sample books are exposed without grant approval
- readers continue offline and sync later
| Layer | Choice | Why |
|---|---|---|
| Frontend | TypeScript + Vite + PWA | fast, modern, strong offline path |
| Reader engine | EPUB.js first | pragmatic browser-first MVP |
| Backend/API | Cloudflare Workers | simple secure edge runtime |
| Database | Turso | good fit for syncable SQLite-style app state |
| Object storage | Cloudflare R2 | proper file storage for EPUB bytes |
| Local browser storage | IndexedDB + Cache Storage | offline reading and queued sync |
| State management | Zustand | matches your stack preference |
| Validation | Zod | strong boundary validation |
| Testing | Vitest + Playwright | unit/integration/E2E |
| Styling | Tailwind CSS | fast, responsive UI system |
| CI/CD | GitHub Actions | practical default |
| Frontend hosting | Cloudflare Pages | free tier, native CDN, easy Worker rewrites |
Do not treat Turso as the primary EPUB file store.
Use Turso for:
- users
- book metadata
- grants
- sessions
- reading progress
- bookmarks
- highlights
- comments
- audit logs
- sync state
Use R2 for:
- EPUB file bytes
- covers
- derived file assets if needed
That separation is simpler, cheaper, and safer.
- admin creates a book record
- admin uploads EPUB to R2
- admin grants access by email
- optional password on grant
- reader authenticates by email and optional password
- reader opens EPUB in browser
- reader position persists
- offline reading works after initial authenticated fetch
- bookmarks work
- highlights work
- comments work for editorial mode
- threaded comments and resolution
- expiring invites and revocation flows
- reviewer activity dashboard
- public catalog mode
- versioned manuscript releases
- export comments
- compare editions
- AI-assisted editorial workflows
Use explicit roles and capability flags.
admineditorreader
privatepassword_protectedreader_onlyeditorial_reviewpublic
can_readcan_commentcan_highlightcan_download_offlinecan_export_notescan_manage_access
| Mode | Read | Comment | Offline | Password | Public |
|---|---|---|---|---|---|
| private | yes | optional | optional | optional | no |
| password_protected | yes | optional | optional | yes | no |
| reader_only | yes | no | optional | optional | no |
| editorial_review | yes | yes | yes/no | optional | no |
| public | yes | optional by policy | optional | no | yes |
Do not rely on R2 visibility or storage permissions as the app’s main authorization system.
Private and restricted books must still be gated by application-level access rules and short-lived signed URLs.
-
admin logs in
-
admin creates a book
-
admin uploads EPUB
-
system stores file in R2
-
system extracts metadata if possible
-
admin creates access grants
-
admin sets:
- optional password
- access mode
- comments allowed
- offline allowed
- expiry date
-
system optionally sends invite email
-
audit log records changes
- reader opens invite or book URL
- reader enters email
- reader enters password if required
- backend validates grant
- backend creates short-lived session
- backend returns capabilities
- reader requests signed EPUB URL
- reader opens EPUB
- app stores reading state locally first
- when online, local state syncs
- reviewer selects passage
- app creates locator anchor
- reviewer adds comment
- if offline, comment enters sync queue
- when online, comment syncs to backend
- other reviewers or admin see thread
- comment can be resolved or moderated
Use a pragmatic normalized schema.
usersbooksbook_filesbook_access_grantsreader_sessionsreading_progressbookmarkshighlightscommentsaudit_log
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
display_name TEXT,
global_role TEXT NOT NULL DEFAULT 'reader',
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);CREATE TABLE books (
id TEXT PRIMARY KEY,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
author_name TEXT,
description TEXT,
language TEXT,
visibility TEXT NOT NULL DEFAULT 'private',
cover_image_url TEXT,
published_at TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
archived_at TEXT
);CREATE TABLE book_files (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
storage_provider TEXT NOT NULL,
storage_key TEXT NOT NULL,
original_filename TEXT NOT NULL,
mime_type TEXT NOT NULL,
file_size_bytes INTEGER NOT NULL,
sha256 TEXT,
epub_version TEXT,
manifest_json TEXT,
created_at TEXT NOT NULL,
FOREIGN KEY (book_id) REFERENCES books(id)
);CREATE TABLE book_access_grants (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
email TEXT NOT NULL,
password_hash TEXT,
mode TEXT NOT NULL,
allowed INTEGER NOT NULL DEFAULT 1,
comments_allowed INTEGER NOT NULL DEFAULT 0,
offline_allowed INTEGER NOT NULL DEFAULT 0,
expires_at TEXT,
invited_by_user_id TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (book_id) REFERENCES books(id),
FOREIGN KEY (invited_by_user_id) REFERENCES users(id)
);CREATE TABLE reader_sessions (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
email TEXT NOT NULL,
session_token_hash TEXT NOT NULL,
expires_at TEXT NOT NULL,
created_at TEXT NOT NULL,
revoked_at TEXT,
FOREIGN KEY (book_id) REFERENCES books(id)
);CREATE TABLE reading_progress (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
user_email TEXT NOT NULL,
locator_json TEXT NOT NULL,
progress_percent REAL,
updated_at TEXT NOT NULL,
UNIQUE(book_id, user_email)
);CREATE TABLE bookmarks (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
user_email TEXT NOT NULL,
locator_json TEXT NOT NULL,
label TEXT,
created_at TEXT NOT NULL
);CREATE TABLE highlights (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
user_email TEXT NOT NULL,
chapter_ref TEXT,
cfi_range TEXT,
selected_text TEXT,
note TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);CREATE TABLE comments (
id TEXT PRIMARY KEY,
book_id TEXT NOT NULL,
user_email TEXT NOT NULL,
chapter_ref TEXT,
cfi_range TEXT,
selected_text TEXT,
body TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'open',
visibility TEXT NOT NULL DEFAULT 'shared',
parent_comment_id TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
resolved_at TEXT,
FOREIGN KEY (parent_comment_id) REFERENCES comments(id)
);CREATE TABLE audit_log (
id TEXT PRIMARY KEY,
actor_email TEXT,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
action TEXT NOT NULL,
payload_json TEXT,
created_at TEXT NOT NULL
);For annotations and progress, prefer:
- EPUB CFI or equivalent robust locator
- selected text excerpt
- chapter reference
Do not rely only on raw DOM offsets.
Keep routes narrow and explicit.
Input:
{
"bookSlug": "my-book",
"email": "reader@example.com",
"password": "optional"
}Output:
{
"ok": true,
"sessionToken": "token",
"book": {
"id": "book-id",
"title": "My Book"
},
"capabilities": {
"canRead": true,
"canComment": true,
"canDownloadOffline": true
}
}Returns a short-lived signed R2 URL.
do-epub-studio/
├─ AGENTS.md
├─ README.md
├─ LICENSE
├─ package.json
├─ pnpm-workspace.yaml
├─ turbo.json
├─ tsconfig.base.json
├─ eslint.config.js
├─ vitest.workspace.ts
├─ playwright.config.ts
├─ .editorconfig
├─ .prettierrc.json
├─ .gitignore
├─ .github/
│ └─ workflows/
│ ├─ ci.yml
│ ├─ preview.yml
│ └─ release.yml
├─ plans/
│ ├─ 000-product-overview.md
│ ├─ 001-goap-roadmap.md
│ ├─ 002-adr-monorepo-stack.md
│ ├─ 003-adr-storage-model.md
│ ├─ 004-adr-auth-and-access.md
│ ├─ 005-adr-offline-sync.md
│ ├─ 006-adr-annotation-model.md
│ └─ 007-implementation-phases.md
├─ docs/
│ ├─ architecture.md
│ ├─ api.md
│ ├─ security.md
│ ├─ offline.md
│ ├─ accessibility.md
│ ├─ setup-local.md
│ ├─ setup-cloudflare.md
│ └─ setup-turso.md
├─ .agents/
│ └─ skills/
│ ├─ cloudflare-worker-api/
│ │ └─ SKILL.md
│ ├─ turso-schema-migrations/
│ │ └─ SKILL.md
│ ├─ epub-rendering-and-cfi/
│ │ └─ SKILL.md
│ ├─ pwa-offline-sync/
│ │ └─ SKILL.md
│ ├─ secure-invite-and-access/
│ │ └─ SKILL.md
│ ├─ reader-ui-ux/
│ │ └─ SKILL.md
│ └─ testdata-builders/
│ └─ SKILL.md
├─ apps/
│ ├─ web/
│ │ ├─ .env.local.example
│ │ ├─ public/
│ │ ├─ src/
│ │ │ ├─ app/
│ │ │ ├─ components/
│ │ │ ├─ features/
│ │ │ ├─ lib/
│ │ │ ├─ routes/
│ │ │ ├─ stores/
│ │ │ ├─ styles/
│ │ │ └─ workers/
│ │ ├─ tests/
│ │ ├─ index.html
│ │ └─ vite.config.ts
│ └─ worker/
│ ├─ wrangler.jsonc
│ ├─ .dev.vars.example
│ ├─ src/
│ │ ├─ routes/
│ │ ├─ services/
│ │ ├─ db/
│ │ ├─ auth/
│ │ ├─ storage/
│ │ └─ lib/
│ └─ tests/
├─ packages/
│ ├─ schema/
│ │ ├─ src/
│ │ └─ migrations/
│ ├─ shared/
│ │ └─ src/
│ ├─ ui/
│ │ └─ src/
│ ├─ reader-core/
│ │ └─ src/
│ └─ testkit/
│ └─ src/
└─ scripts/
├─ verify.mjs
├─ bootstrap.mjs
├─ db-migrate-local.mjs
├─ db-migrate-prod.mjs
└─ db-check.mjs
Do not use a single generic root .env as the main config model.
Use this split:
- Worker runtime config:
wrangler.jsonc - Worker deployed secrets:
wrangler secret put - Worker local dev secrets/config:
.dev.vars - Frontend public config:
.env.local - database provisioning: Turso CLI
- matches Cloudflare-native deployment
- keeps secrets out of frontend and repo
- separates browser-safe and server-only config
- keeps local development simple
- leaves room for environment-specific deployment
Because Wrangler supports both TOML and JSON/JSONC, and Cloudflare recommends JSONC for new projects, use:
apps/worker/wrangler.jsonc
APP_BASE_URLis fine invarsTURSO_DATABASE_URLis typically acceptable invars- secrets should not live in this file
- use R2 bindings rather than raw storage credentials
Use Cloudflare secrets for:
TURSO_AUTH_TOKENSESSION_SIGNING_SECRETINVITE_TOKEN_SECRET
Example commands:
wrangler secret put TURSO_AUTH_TOKEN
wrangler secret put SESSION_SIGNING_SECRET
wrangler secret put INVITE_TOKEN_SECRETThese are Worker-only values.
Do not expose them to the browser.
TURSO_DATABASE_URL=
TURSO_AUTH_TOKEN=
SESSION_SIGNING_SECRET=
INVITE_TOKEN_SECRET=
APP_BASE_URL=http://127.0.0.1:5173TURSO_DATABASE_URL=libsql://do-epub-studio-your-org.turso.io
TURSO_AUTH_TOKEN=local-dev-token
SESSION_SIGNING_SECRET=local-dev-session-secret
INVITE_TOKEN_SECRET=local-dev-invite-secret
APP_BASE_URL=http://127.0.0.1:5173VITE_API_BASE_URL=http://127.0.0.1:8787
VITE_APP_NAME=do EPUB StudioVITE_API_BASE_URL=http://127.0.0.1:8787
VITE_APP_NAME=do EPUB StudioTurso CLI is for provisioning and operations.
It does not replace Worker runtime configuration.
- create database
- inspect database
- create auth token
- operational management
turso db create do-epub-studioTake the resulting values and wire them into:
wrangler.jsoncfor non-secret configwrangler secret putfor secrets.dev.varsfor local development
Use Wrangler bindings for R2.
Do not put raw object storage credentials into Worker env unless there is no other option.
- cleaner Cloudflare-native model
- fewer exposed secrets
- simpler Worker code
- safer deployment model
# local config
**/.env.local
**/.dev.vars
# node
node_modules
coverage
.playwrightCommit only:
.env.local.example.dev.vars.example
Do not commit real secret files.
Use this at repo root.
# AGENTS.md
## Purpose
This repository builds `do EPUB Studio`, a production-grade EPUB reading and editorial workspace with gated access, offline reading, comments, highlights, and secure distribution.
## Mandatory working style
- Read before write.
- Plan first, then execute.
- Use GOAP thinking for every non-trivial task.
- Keep ADRs and phase plans in `plans/`.
- Verify every important architectural decision before implementation.
- Use analysis swarm mindset when reviewing key changes:
- methodical validator
- rapid challenger
- skeptical reviewer
- Do not update source-of-truth documentation until implementation is verified.
## Constraints
- Max 500 LOC per source file.
- No hardcoded secrets.
- No hardcoded environment-specific URLs.
- No silent failures.
- No `any` unless justified and isolated.
- No skipping tests for core permission, sync, or auth flows.
- No direct public file URLs for private books.
- No unsafe EPUB HTML rendering.
## Architecture rules
- Store EPUB files in object storage, not as primary Turso blobs.
- Turso stores app state, permissions, progress, comments, highlights, and audit logs.
- Browser stores offline state first; sync is explicit and resilient.
- Signed URLs must be short-lived.
- Access validation must happen in the app backend.
- Annotation anchors must use robust locators, not raw DOM offsets alone.
## Configuration rules
- Use `wrangler.jsonc` for new Worker projects.
- Do not use a single generic `.env` as the main project config model.
- For `apps/worker`, use `wrangler.jsonc`, `wrangler secret put`, and `.dev.vars` for local development.
- For `apps/web`, use `.env.local` only for safe browser-visible values.
- Never expose Turso auth tokens or signing secrets to the frontend.
- Prefer Cloudflare bindings for R2 over raw object storage credentials.
- Use Turso CLI for provisioning and admin tasks, not as a replacement for Worker runtime configuration.
- Commit only example config files, never live secret files.
## Coding rules
- TypeScript everywhere by default.
- Zod for validation at boundaries.
- Zustand for client state.
- Vitest for unit and integration tests.
- Playwright for end-to-end tests.
- Tailwind for styling.
- Prefer pure functions for domain logic.
- Keep service interfaces small and explicit.
- Use dependency injection where it simplifies testing.
- Create test data builders for grants, books, comments, and sessions.
## Security rules
- Hash passwords using a strong KDF.
- Sanitize all rendered EPUB content.
- Validate file type and size on upload.
- Log permission grants, revocations, and access-sensitive changes.
- Use audit logs for admin actions.
- Avoid user enumeration in auth responses.
- Revoke sessions on permission revocation.
## Delivery rules
A task is complete only when:
- plan updated if needed
- implementation done
- lint passes
- typecheck passes
- tests pass
- build passes
- docs updated if behavior changedCreate skills under .agents/skills/ following the on-demand loading pattern (per AGENTS.md).
Use the skill(name="skill-name") tool to load full SKILL.md content when needed.
At startup, only skill names/descriptions are loaded (~50 tokens each). Full SKILL.md content (~500-2000 tokens) loads only when the agent determines the skill is relevant.
triz-analysis,triz-solver— TRIZ contradiction resolutioncloudflare-worker-api— Worker route structureturso-schema-migrations— Schema designpwa-offline-sync— Offline sync strategysecure-invite-and-access— Auth flowsepub-rendering-and-cfi— EPUB.js + CFI anchoringreader-ui-ux— Reader/admin UI patternstestdata-builders— Test fixturescode-quality,code-review-assistant,security-code-auditor— Quality checkstask-decomposition,parallel-execution— Coordinationlearn,memory-context— Knowledge captureanti-ai-slop,agent-browser,dogfood— UX + testingskill-creator,skill-evaluator— Skill developmentshell-script-quality— Shell best practices
Run ./scripts/validate-skills.sh to verify skill integrity.
Build a secure offline-capable EPUB reading and editorial review platform.
- no scaffold
- no schema
- no access flow
- no reader
- no admin UI
- deployable PWA
- secure grants and sessions
- private/public book modes
- offline reading
- comments/highlights
- tests and docs
- create monorepo
- add AGENTS.md
- add plans and ADRs
- configure pnpm/turbo
- configure lint/typecheck/test/build
- add CI
- define enums and DTOs
- create migrations
- add test fixtures/builders
- implement repository interfaces
- access request endpoint
- password validation
- session issuance
- signed R2 URLs
- audit logging
- reader shell
- EPUB.js integration
- TOC
- progress save/restore
- theme and typography controls
- service worker
- cache strategy
- IndexedDB persistence
- sync queue
- highlights
- anchors
- comments
- replies
- resolve state
- books list
- upload flow
- grant editor
- revoke access
- audit screen
- accessibility
- security
- performance
- regression coverage
- release readiness
Create these first:
000-product-overview.md001-goap-roadmap.md002-adr-monorepo-stack.md003-adr-storage-model.md004-adr-auth-and-access.md005-adr-offline-sync.md006-adr-annotation-model.md007-implementation-phases.md
Decide:
- pnpm + turbo
- TypeScript
- Vite web app
- Worker backend
- shared packages
Decide:
- R2 for EPUB files
- Turso for metadata/state
- IndexedDB + Cache Storage locally
Decide:
- email + optional password grants
- short-lived sessions
- short-lived signed URLs
- audit trail
Decide:
- local-first writes
- queued sync
- idempotent mutations
- conflict strategies by entity type
Decide:
- CFI anchors
- selected text snapshot
- chapter reference
- fallback re-anchoring strategy
- top bar
- full-width reading area
- TOC as slide-over drawer
- comments as bottom sheet or tab
- optional split view
- TOC on left
- reader center
- comments side panel on demand
- TOC left
- reader center
- comments/highlights right
- collapsible sidebars
- font size
- font family
- line height
- page width
- light/dark/sepia/system themes
- resume position
- chapter navigation
- search
- bookmark current position
- keyboard navigation
- visible focus states
- semantic landmarks
- reduced motion support
- touch target minimum size
- screen reader labels
- never reveal whether a specific email exists
- return generic access-denied responses
- rate limit access attempts
- hash passwords with a strong KDF
- expire sessions
- revoke sessions on permission revocation
- private books use signed R2 URLs only
- signed URLs are short-lived
- do not expose raw storage paths in UI
- validate MIME type and extension
- optionally store checksum
- sanitize EPUB HTML before rendering
- strip unsafe scripts
- block remote script execution
- control iframe usage strictly
Log:
- grant created
- grant updated
- grant revoked
- access granted or denied
- comment moderation actions
- visibility changes
Use for:
- app shell
- static assets
- cached EPUB assets
- cover images
Use for:
- progress
- bookmarks
- highlights
- pending comments
- sync queue
- reader preferences
- write locally first
- enqueue sync job
- optimistic UI update
- idempotent mutation IDs
- last-write-wins for progress/preferences
- append-only semantics for comments/audit
- explicit merge rules for editable entities
A private book should not promise full offline availability until it has been opened online once and cached successfully.
Cover:
- permission evaluation
- password validation
- session creation
- locator serialization
- progress merging
- annotation reducers
Cover:
- Worker routes with test DB
- signed URL issuance
- grant revocation
- sync queue replay
Cover:
- admin creates book
- admin grants access
- reader authenticates
- reader opens book
- reader resumes position
- reviewer adds comment
- offline reading works
- reconnect sync works
- invalid access does not leak user existence
- revoked users lose fresh file access
- offline queue does not duplicate comments
- malformed EPUB content does not execute scripts
Contains:
- SQL migrations
- DB-adjacent types
- schema constants
Contains:
- shared DTOs
- validation helpers
- enums
- error classes
Contains:
- EPUB abstractions
- locator mapping
- selection anchors
- preference logic
Contains:
- reusable UI components
- layout primitives
- forms
- modals
- panels
Contains:
- routes
- reader UI
- admin UI
- local persistence
- sync orchestration
Contains:
- API routes
- session/auth logic
- Turso access
- R2 signing
- audit logging
Example root package.json script section:
{
"scripts": {
"dev": "turbo run dev --parallel",
"build": "turbo run build",
"lint": "turbo run lint",
"typecheck": "turbo run typecheck",
"test": "turbo run test",
"test:e2e": "playwright test",
"test:e2e:smoke": "playwright test --grep @smoke",
"verify:fast": "pnpm lint && pnpm typecheck && pnpm --filter @do-epub-studio/web test:unit -- src/features/reader/components/annotations src/features/admin",
"verify": "pnpm lint && pnpm typecheck && pnpm test && pnpm build",
"db:migrate:local": "node scripts/db-migrate-local.mjs",
"db:migrate:prod": "node scripts/db-migrate-prod.mjs",
"db:check": "node scripts/db-check.mjs"
}
}GitHub Actions should run:
- install
- lint
- typecheck
- unit/integration tests
- build
- optionally Playwright on preview or gated branch
No feature is done unless:
- lint passes
- typecheck passes
- tests pass
- build passes
This is the best first implementation slice.
-
monorepo scaffold
-
root AGENTS.md
-
plans + ADRs
-
initial schema:
booksbook_filesbook_access_grantsreader_sessionsreading_progress
-
admin create-book screen
-
admin grant-access form
-
EPUB upload to R2
-
access request route
-
session issuance
-
signed file URL route
-
reader shell with EPUB load
-
save/restore progress
- admin can create one private book
- admin can grant one email access
- reader can authenticate
- reader can open EPUB
- reader progress persists
- revoked grant blocks fresh access
- lint passes
- typecheck passes
- tests pass
- build passes
Use a disciplined orchestrated approach.
Responsibilities:
- read AGENTS.md
- read
plans/ - choose next GOAP action
- assign subtasks
- verify completion gates
- validates ADRs
- checks module boundaries
- prevents coupling drift
- Worker routes
- Turso repositories
- auth/session logic
- R2 signed URLs
- reader UI
- admin UI
- Zustand stores
- responsive UX
- EPUB.js integration
- CFI anchors
- TOC and locator logic
- service worker
- IndexedDB
- cache strategy
- sync queue
- Vitest
- Playwright
- test builders
- regression coverage
- auth leak checks
- sanitization checks
- token expiry checks
- audit logging checks
- no code before reading plans
- no source file over 500 LOC
- no merge without verify gate
- no docs update before successful implementation verification
ReadReviewPublic
Private accessPassword requiredComments enabledOffline reading allowedAccess expires
Best UI wording:
Editorial reviewReview commentsProofing access
German locale later:
LektoratKommentareOffline lesenZugriff
Mitigation:
- CFI + selected text + chapter reference fallback
Mitigation:
- entity-specific merge rules
- append-only comments
- idempotent sync mutations
Mitigation:
- generic auth errors
- short-lived sessions
- short-lived signed URLs
- audit logs
Mitigation:
- start with email + optional password
- avoid full account system in MVP
Mitigation:
- all file access goes through Worker gate
- never expose raw storage paths as the source of truth
A change is done only if:
- plan impact checked
- implementation complete
- no source file exceeds 500 LOC
- lint passes
- typecheck passes
- tests pass
- build passes
- generated artifacts (e.g.,
playwright-report/,test-results/,verification_output.txt) are NOT committed - security implications reviewed
- docs updated if behavior changed
Start do-epub-studio as:
- private GitHub repo
- pnpm + turbo monorepo
apps/web,apps/worker,packages/*- Cloudflare Workers + R2 + Turso
wrangler.jsoncfor Worker config- Wrangler secrets for sensitive Worker values
.dev.varsfor local Worker dev.env.localonly for browser-safe frontend values- Turso CLI for DB provisioning and token generation
- EPUB.js for MVP
- IndexedDB + Cache Storage for offline
- AGENTS.md + plans/ for AI-agent execution
One private EPUB, one approved reader grant, one successful authenticated reading session, and one offline-capable resume flow.
If you want the next step, turn this guide into repo files (README.md, AGENTS.md, wrangler.jsonc, example config files, plans, ADRs, CI, schema/API skeleton). This guide is now the canonical reference.
Use this checklist when handling cross-cutting requests (optimization + new features + docs + test strategy):
- Load prior context first
- Read
agents-docs/LEARNINGS.mdbefore implementation.
- Read
- Update plan artifacts before code changes
- Add/adjust entries in
plans/007-implementation-phases.mdand relevant backlog plan.
- Add/adjust entries in
- Prefer deterministic test defaults
- Vitest should run in non-watch mode for CI (
vitest --run). - Playwright should keep trace/video/screenshot artifacts on failure.
- Vitest should run in non-watch mode for CI (
- Separate PR checks from nightly depth
- PR: lint + typecheck + unit tests + smoke E2E.
- Nightly: full cross-browser E2E + benchmarks + budget/perf checks.
- Track missing tasks explicitly
- Do not leave “known gaps” only in PR text; store them in
plans/with owner/acceptance criteria.
- Do not leave “known gaps” only in PR text; store them in
- Close verification loop
- Run
./scripts/quality_gate.shand keep the output green before commit.
- Run
- Capture non-obvious learnings
- Append durable discoveries (not session noise) to
agents-docs/LEARNINGS.md.
- Append durable discoveries (not session noise) to
{ "name": "do-epub-studio-worker", "main": "src/index.ts", "compatibility_date": "2026-04-07", "vars": { "APP_BASE_URL": "https://do-epub-studio.example.com", "TURSO_DATABASE_URL": "libsql://do-epub-studio-your-org.turso.io", }, "r2_buckets": [ { "binding": "BOOKS_BUCKET", "bucket_name": "do-epub-studio-books", }, ], }