Work Hours Bot is a Telegram bot that helps users track their daily work hours, manage work records, and generate weekly and monthly summaries.
It was built as a backend-focused project with an emphasis on clean architecture, maintainability, and scalable application design.
- π€ Telegram bot built with TypeScript, Node.js, and Telegraf
- ποΈ Layered backend architecture
- ποΈ PostgreSQL database with Prisma ORM
- π Weekly and monthly work summaries
- βοΈ Configurable work schedules and timezone support
- π³ Docker support for local development
- π Deployable on Render
- Daily work tracking β clock in with
/start, check progress with/status, and close the day with/end - Record lookup β use
/record dd-mmto instantly view the details of any specific date (read-only) - Edit past dates β use
/edit dd-mmto fix hours or mark absences on any workday - Absence types β sick, vacation, holiday, holiday eve, unpaid absence, and election (via the edit flow)
- Summaries β weekly and monthly balance views against your configured required hours
- Settings β one-time
/setup, then/settingsand/settings_editfor daily hours, workdays, and timezone
| Command | Description |
|---|---|
/setup |
First-time setup: daily required hours, workdays, and timezone |
/settings |
Show your current work settings |
/settings_edit |
Change daily hours, workdays, or timezone |
/start |
Start today's workday |
/status |
Show today's active workday status |
/end |
End today's active workday |
/record dd-mm |
View the record for a specific date (e.g. /record 12-06) |
/edit dd-mm |
Edit or fix a specific date (e.g. /edit 12-06) |
/week |
Show current week summary |
/month |
Show current month summary |
/help |
List all available commands |
The application follows a layered architecture that separates presentation, business logic, and data access.
Telegram REST API
β β
βΌ βΌ
Telegraf Bot REST Controllers
β β
βΌ β
Conversation Flows β
β β
βΌ β
Telegram Handlers β
β β
ββββββββββββ¬βββββββββββββββββ
βΌ
Business Services
β
Repositories
β
Prisma ORM
β
PostgreSQL
Both the Telegram bot and the REST API share the same business service layer to keep the application modular and avoid duplicated logic.
| Category | Technology |
|---|---|
| Language | TypeScript |
| Runtime | Node.js |
| Framework | Express |
| Bot Framework | Telegraf |
| Database | PostgreSQL |
| ORM | Prisma |
| Validation | Zod |
| Package Manager | npm Workspaces |
| Deployment | Render |
| Local Development | Docker |
WorkHours-Bot/
βββ backend/ # Express API + Telegram bot
β βββ prisma/ # Schema and migrations
β βββ src/
β βββ bot/ # Handlers, conversation flows, session store
β βββ constants/ # Time formats, timezones, edit actions, etc.
β βββ controllers/ # REST API controllers
β βββ lang/ # botLabels.json (English bot messages)
β βββ middlewares/ # Express middleware (validation, error handling)
β βββ repositories/ # Data access layer (Prisma)
β βββ routes/ # Express route definitions
β βββ services/ # Business logic layer
β βββ utils/ # Shared helpers (dates, errors, API responses)
β βββ validators/ # Request validation (Zod)
βββ shared/ # Shared types and utilities
β βββ src/
β βββ types/
β βββ utils/
βββ docker-compose.yml # Local PostgreSQL
βββ package.json # npm workspaces root
The project was designed with maintainability and extensibility in mind.
Key design decisions include:
- Layered architecture to separate presentation, business logic, and data access.
- Prisma ORM for type-safe database operations.
- PostgreSQL for reliable relational data storage.
- Zod for runtime validation of incoming requests.
- Shared workspace for reusable types and utilities.
- Configuration-driven bot messages using a centralized JSON labels file.
Follow these steps from a fresh clone to a running local bot.
- Node.js 20+
- Docker + Docker Compose
- A Telegram bot token from @BotFather
git clone https://github.com/dorhaboosha/Work-Hours-Bot.git
cd Work-Hours-Bot
npm installThis installs dependencies for both workspaces (backend and shared).
docker compose up -dPostgreSQL runs on port 5435 on the host (mapped from container port 5432). Credentials and database name match docker-compose.yml.
cp backend/.env.example backend/.envOn Windows (PowerShell): Copy-Item backend\.env.example backend\.env
Edit backend/.env and set at minimum:
| Variable | Local value |
|---|---|
DATABASE_URL |
postgresql://workhours:workhours_password@localhost:5435/workhours_bot |
TELEGRAM_BOT_TOKEN |
Your token from BotFather |
NODE_ENV |
development |
PORT defaults to 3000 if omitted. See backend/.env.example for production notes.
cd backend
npx prisma migrate dev
cd ..This applies all migrations and generates the Prisma client. Accept the default migration name if prompted on first run.
From the repository root (not backend/):
npm run devYou should see Server running on port 3000 [development]. In Telegram, send /setup to configure your account, then /start to begin tracking.
Production runs as a single Node process: Express (including GET /health) and the Telegram bot (long-polling) together. The deployment checklist in openspec/changes/remove-multi-language-support/tasks.md (section 9) captures the full Render setup; the summary below matches what is configured in production.
- PostgreSQL β provision a database in the same region as the web service. Use the Internal Database URL for the web service env var.
- Web Service β connect the GitHub repo and use the commands below.
| Setting | Value |
|---|---|
| Build Command | npm install --include=dev && npm run migrate:deploy -w backend && npm run build -w backend |
| Start Command | npm start -w backend |
--include=dev is required because Render sets NODE_ENV=production during build, which otherwise skips TypeScript and other devDependencies needed to compile. Migrations run in the build step because Pre-Deploy commands are not available on the free tier.
The backend build script runs prisma generate && tsc && tsc-alias; start runs node dist/backend/src/server.js.
Set these on the Render Web Service (see also backend/.env.example for local development):
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string. Use Render's Internal URL when the database and web service are in the same region. |
TELEGRAM_BOT_TOKEN |
Yes | Bot token from @BotFather. Mark as Secret in Render. |
NODE_ENV |
Yes | Set to production. |
PORT |
No | Injected automatically by Render. Do not set manually in production. |
Locally, copy backend/.env.example to backend/.env and fill in DATABASE_URL and TELEGRAM_BOT_TOKEN. PORT defaults to 3000 for local dev.
All commands run from the repository root unless noted. The backend lives in the backend workspace.
| Command | Description |
|---|---|
npm run dev |
Start the bot in development mode (hot reload via ts-node-dev) |
npm run build -w backend |
Generate Prisma client, compile TypeScript, and rewrite path aliases |
npm start -w backend |
Run the compiled production server (dist/backend/src/server.js) |
npm test -w backend |
Run backend unit tests (Node.js test runner) |
Additional backend scripts (run from backend/ or with -w backend):
| Command | Description |
|---|---|
npm run migrate:deploy -w backend |
Apply pending Prisma migrations (production / Render) |
Issues and pull requests are welcome. For local development, follow Getting Started. Run npm test -w backend before submitting changes.
This project is licensed under the MIT License.
