Local Development¶
The deep material lives in AGENTS.md
This page only covers getting the project running. Architecture, coding conventions, the release
pipeline and all the accumulated gotchas are in
AGENTS.md at the repository
root — read it before changing code. (It is written in Chinese.)
Requirements¶
- Python 3.10 or 3.11 (3.8 – 3.13 all work)
- Node.js 20 or higher (a Playwright requirement, for E2E)
Start the backend (port 5005)¶
Use the repository's venv, not your system Python. The system environment's fastapi +
starlette combination prevents the app from starting, with
TypeError: Router.__init__() got an unexpected keyword argument 'on_startup'.
Create the virtualenv and install dependencies first:
(On Linux / macOS use venv/bin/python instead of venv/Scripts/python.exe.)
Then start it:
Start the frontend (port 8080)¶
Open http://localhost:8080. The dev server proxies /api to 127.0.0.1:5005, so no CORS setup is
needed locally.
VS Code users can press Ctrl+Shift+B — there are tasks that bring up both sides in parallel.
Running the tests¶
Backend unit tests —
End-to-end tests (Playwright) — e2e/ drives the real frontend and backend through complete
flows (actually rendering images, actually downloading attachments); a few branches that are hard to
trigger for real (such as the queue-full 503) are simulated with route interception.
- Dev servers that are not running are started automatically (backend 5005, frontend 8080) and shut down afterwards.
- Ones that are already running are reused rather than restarted.
- The run sets
CPU_USAGE_LIMIT=100so that a dev machine saturated by webpack does not trip the backend's overload guard. - Failure screenshots, videos and traces go to
e2e/test-results/; open the HTML report withnpm run report. - If no Python interpreter is found, point at one with
E2E_PYTHON.
Every pull request runs this via .github/workflows/e2e.yml.
Desktop end-to-end — this drives the real packaged build, so build it first:
What the code looks like¶
| Path | Contents |
|---|---|
frontend/src/views/HomeView.vue |
The main page: parameters, preview, generation flow |
frontend/src/views/TextInput.vue |
Text box and document upload |
frontend/src/components/ |
Letter layout, generation status, splash animation, PWA prompt |
frontend/src/i18n.js |
Chinese and English strings |
backend/app.py |
Every route plus the rendering logic (~1300 lines) |
backend/task_store.py |
SQLite task queue (WAL, 30-minute expiry) |
backend/identify.py |
Detects margins and line spacing from a background image |
backend/pdf.py |
PDF generation |
A request comes in, the task is submitted and written to SQLite, a task_id is returned immediately,
a background coroutine queues the render, the frontend gets progress over a WebSocket (falling back to
polling), and finally fetches the result.
Commit conventions¶
- Commit messages must follow Conventional Commits — semantic-release derives the version number from them, and getting it wrong bumps the wrong version.
- User-visible strings need both Chinese and English, added to
frontend/src/i18n.js. - Elements that E2E needs to click get a
data-testid; tests usegetByTestIdonly and never rely on copy or CSS classes. - Do not hand-edit
CHANGELOG.mdor version numbers — the release pipeline owns them.