On a factory or warehouse floor, someone decides every day which worker stands at which station on which line. Usually with a whiteboard and paper.
haizu turns that into a floor map you can drag people onto, and a screen the floor can read.
- Upload a floor plan, place spots on it, and build a placement area spec
- Pick a date and a shift, then drag employees onto spots
- Show the confirmed placement in a display-only viewer for large screens
→ User guide — how to use each screen, step by step.
You need Node.js 24.18+ (see .nvmrc), pnpm 10+, and Docker.
git clone https://github.com/uswebk/haizu.git
cd haizu
pnpm install
docker compose up -d # PostgreSQL + Mailpit (dev mail)
cp apps/api/.env.example apps/api/.env # set BETTER_AUTH_SECRET to 32+ random chars
cp apps/web/.env.example apps/web/.env
cd apps/api && pnpm db:migrate && pnpm db:seed && cd ../..
pnpm dev # web: 3000, api: 3001Open http://localhost:3000 and create a company from the sign-up screen.
Note
Email delivery and file storage are pluggable adapters. By default nothing is sent: verification codes, invitation links, and password resets are printed to the API server console (prefixed [email:console]), and uploaded images are stored on local disk (apps/api/uploads).
docker compose up -d also starts Mailpit, a dev mail server. Set EMAIL_DRIVER=smtp in apps/api/.env and outgoing mail is captured by Mailpit — view it at http://localhost:8025 (nothing leaves your machine).
| Concern | Env var | Default | Swap for production |
|---|---|---|---|
EMAIL_DRIVER |
console |
Set smtp and point SMTP_* at a real SMTP provider (SendGrid / SES), or implement EmailSender and add a case in src/email/ |
|
| File storage | STORAGE_DRIVER |
local (local disk) |
Implement FileStorage (e.g. S3 / GCS) and add a case in src/storage/ |
The app runs fully on the defaults. Contributions for production adapters are welcome (see CONTRIBUTING.md).
The web app (apps/web) reads two deploy-time defaults from its environment (Vite bakes VITE_-prefixed vars in at build time):
| Concern | Env var | Default | Notes |
|---|---|---|---|
| Language | VITE_DEFAULT_LOCALE |
en |
en or ja. The deploy-wide default. Users can switch language from the in-app switcher (sidebar user menu / account settings); their choice is remembered in a cookie and overrides this default. |
| Timezone | VITE_DEFAULT_TIMEZONE |
(runtime TZ) | An IANA name such as Asia/Tokyo. Used to decide "today" and shift times. If unset, it falls back to the runtime timezone (the server's TZ on SSR, the browser's timezone on the client). |
Set them in apps/web/.env (copied from apps/web/.env.example). There is no per-user timezone setting: the app assumes a single site/timezone per deployment. Running one instance across multiple timezones would need a site-level timezone setting (not implemented).
| docs/guide/ | User guide: what each screen does and how to operate it (English + Japanese) |
| docs/architecture.md | Design decisions you will break if you don't know them |
| docs/domain/ | Domain knowledge, one file per concept (English + Japanese) |
| CONTRIBUTING.md | Development commands, conventions, and how to open a PR |
MIT
