Skip to main content
The project is built with Next.js 15 (App Router), React 19, and Tailwind CSS, and written in TypeScript. Before you start developing, complete the local setup in Quickstart.

Common commands

Before you commit changes, run the tests, linting, type checking, and the production build in that order.

Tests

npm test runs tests/api.test.ts and tests/i18n.test.ts. api.test.ts imports the other test files, so a single command runs every test. When debugging, you can also run a single file with tsx:

Project structure

Add interface messages

Messages are defined in app/i18n/messages.ts. The Simplified Chinese source text is the key, and the other three languages are the values:
app/i18n/messages.ts
Use it in a component with t("历史记录"). When you add a message, provide all three translations, zh-TW, en, and ko. i18n.test.ts checks for completeness.

Continuous integration

.github/workflows/docker.yml runs on pushes to any branch, pushes of v* tags, pull requests, and manual triggers:
1

Verify

Runs npm ci, npm test, npm run lint, and npm run build in order, using Node.js 22.
2

Build the image

After verification passes, builds the Docker image. Regular branches and pull requests build only linux/amd64, to check that the image builds successfully.
3

Publish the image

On pushes to the default branch, the howendev/dev branch, or any tag, builds both linux/amd64 and linux/arm64. If Docker Hub secrets are configured, it pushes the multi-architecture image.

Image tags

Docker Hub secrets

In your GitHub repository, open Settings → Secrets and variables → Actions and add: If these two secrets aren’t configured, the workflow only builds the image without pushing it and prints a warning.
Don’t bake runtime secrets into the Docker image. Inject DEEPSEEK_API_KEY, GEMINI_API_KEY, CODE, and the Umami settings when you run the container, through .env.production or -e flags.

Docker image

The Dockerfile uses a multi-stage build based on node:22-alpine with Next.js standalone output:
  • The runtime stage runs as the non-root user nextjs.
  • It listens on 0.0.0.0:3002 by default.
  • The image includes the license files LICENSE, NOTICE, LICENSING.md, and LICENSES/.

Contributing

Issues and pull requests are welcome. License new contributions under terms compatible with AGPL-3.0-only, and keep the notices of any third-party code you bring in. For details, see License.