Files
worktimeBot/README.md
db123 af23f80fbb fix: address audit findings — nil pointers, timezone bug, dead code, tests, README
- Fix nil pointer dereference in clock.go (guard GetOrCreateSettings and
  GetOrCreateRPGStats errors before accessing fields)
- Fix timezone bug in handleSetBreakMsg (was using system time.Now()
  instead of user's configured timezone)
- Remove dead code: sendExportMonthPicker (unused wrapper)
- Simplify xpForWorkSeconds (xpPerSecond=1, inline to just return sec)
- Extract computeStreakFromDates as pure testable function from
  recalcAggregates; add 6 tests covering empty, current, gaps,
  no-today, long streak, longest-not-current edge cases
- Update README with full feature documentation: RPG, League, Salary,
  Burnout, Work Types, Inline History Editing, all missing commands
2026-06-25 02:25:13 +03:30

188 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WorkTime Bot
A Telegram time-tracking bot with **RPG progression system**, **WorkTime League**, **salary estimation**, **burnout assessment**, and **multi-calendar support** (Gregorian, Jalali/Persian, Hijri). Clock in/out, track work types, mark day off, get daily reports, browse and edit history by month, and export monthly `.xlsx` reports.
## Quick Start
```bash
cp .env.example .env
# edit .env — set BOT_TOKEN and BOT_ALLOWED_USERS
docker compose up -d
```
## Environment Variables
| Variable | Default | Purpose |
| ------------------- | ------------ | ----------------------------------------------------- |
| `BOT_TOKEN` | — | Telegram Bot API token **(required)** |
| `BOT_ALLOWED_USERS` | (all) | Comma-separated Telegram user IDs (empty = allow all) |
| `HTTP_PROXY` | — | Outbound HTTP proxy for Telegram API |
| `HTTPS_PROXY` | — | Outbound HTTPS proxy for Telegram API |
| `DB_PATH` | `db.sqlite3` | Path to SQLite database file |
| `BOT_WEBHOOK_URL` | — | Set for webhook mode (omit for long-polling) |
| `BOT_LISTEN` | `:8080` | Listen address for webhook mode |
| `BOT_TLS_CERT` | — | TLS certificate path (webhook HTTPS) |
| `BOT_TLS_KEY` | — | TLS key path (webhook HTTPS) |
## Calendar Support
Users can choose between three calendars via Settings:
- **Gregorian** — standard international calendar
- **Jalali** (Persian/Solar Hijri) — official calendar of Iran and Afghanistan
- **Hijri** (Islamic lunar) — used in many Muslim-majority countries
The history view, export month picker, and date displays all adapt to the user's chosen calendar. The `/export` and `/edit` commands accept dates in the user's calendar. Internally, all dates are stored as Gregorian.
## Features
### RPG Progression System
Every second of tracked work earns XP. Level up as you accumulate XP with a quadratic curve. Maintain consecutive workdays to build a streak for bonus XP.
| Feature | Details |
| ------------ | --------------------------------------------------------------------------------------------------------- |
| XP rate | 1 XP per second worked |
| Level curve | `totalXP(n) = n * (n + 1) * 50` (Level 10 = 5,500 XP, Level 27 = 37,800 XP) |
| Streak bonus | `streak × 50` XP per session, capped at 1,000 XP |
| Achievements | 12 achievements for milestones (early bird, night owl, streaks, hours, levels, overtime, weekend warrior) |
Use `/rpg` to view your stats and achievements. Enable/disable via Settings or `/rpgtoggle`.
### WorkTime League
Compete with other users on the leaderboard. Sortable by XP, Level, Streak, or Hours. Opt in via Settings or `/leaguetoggle`. Users without a display name appear as "Anonymous".
### Salary Estimation
Estimate monthly earnings based on tracked work time. Configure your hourly rate with `/setrate <amount>` and currency symbol with `/setcurrency <symbol> <code>`. View the estimate with `/salary`.
### Burnout Assessment
Get a 0-100 burnout score based on consecutive workdays, long hours, late-night sessions, break ratio, and work volume trends. Use `/burnout`.
### Inline History Editing
Browse past days with the History button, then tap any event to edit its time, type, work type, or note. Add missing events or delete incorrect ones. Changes are reflected immediately in XP, streaks, and totals.
### Work Types
Categorize your work sessions (e.g., Remote, Onsite, Meeting). The current work type is assigned to new clock-ins. Change via the inline menu or `/worktype`.
## Usage
**Persistent reply keyboard** at the bottom of the chat: `Clock In` / `Clock Out`
**Inline menu** on `/start`:
| Button | Action |
| -------------------- | --------------------------------- |
| Clock In / Clock Out | Record work event |
| Report | Today's work & break summary |
| Export | Pick a month → download `.xlsx` |
| History | Browse past days in calendar view |
| Work Type | Switch work type (Remote/Onsite) |
| Day Off | Mark today as day off |
| RPG / Achievements | View RPG stats and achievements |
| League | View leaderboard |
| Salary | View monthly salary estimate |
| Burnout | View burnout assessment |
| Settings | Timezone, calendar, accent, more |
### Commands
| Command | Action |
| --------------------------- | ----------------------------------------------------------- |
| `/start` | Show inline menu |
| `/clockin` | Record clock-in |
| `/clockout` | Record clock-out |
| `/worktype` | Change current work type |
| `/report` | Today's work & break summary |
| `/dayoff` | Toggle today as day off |
| `/export [YYYY-MM]` | Export monthly report (optional `YYYY-MM` in your calendar) |
| `/summary [YYYY-MM]` | Show monthly summary (optional `YYYY-MM`) |
| `/edit YYYY-MM-DD` | View/edit events for a specific date |
| `/note [DATE] HH:MM <text>` | Set note for an event at a specific time |
| `/settimezone <IANA>` | Set timezone (e.g. `Asia/Tehran`) |
| `/setbreak <minutes>` | Set minimum break threshold (0-480, default 5) |
| `/setaccent` | Select export accent color |
| `/setreporttime HH:MM` | Set daily auto-report time |
| `/reporttoggle` | Enable/disable daily auto-report |
| `/rpg` | View RPG stats |
| `/rpgtoggle` | Enable/disable RPG system |
| `/league` | View WorkTime League leaderboard |
| `/leaguetoggle` | Opt in/out of the league |
| `/salary` | View monthly salary estimate |
| `/setrate <amount>` | Set hourly rate for salary estimation |
| `/setcurrency <sym> <code>` | Set currency (e.g. `$ USD`, `T Toman`, `€ EUR`) |
| `/burnout` | View burnout assessment |
| `/setusername <name>` | Set display name for the league |
## Daily Report
A daily summary is sent automatically at the user's configured report time (default `23:00`). The scheduler checks every 30 seconds.
## How Break Time Works
The gap between a clock-out and the next clock-in is counted as break. Gaps shorter than the **min break threshold** (default 5 minutes) are absorbed into work time. Use `/setbreak <minutes>` to adjust per day (0-480).
```
09:00 Clock In → work starts
12:00 Clock Out → work: 3h, break starts
13:00 Clock In → break: 1h, work resumes
17:00 Clock Out → work: 4h
total: 7h work, 1h break
```
## Export
The `/export` command opens a month picker. Select any month in your calendar and download an `.xlsx` file with columns: Date, Clock In, Clock Out, Type, Work, Break.
Four color themes are available in settings: **Ocean**, **Beach**, **Rose**, **Catppuccin**.
## Project Structure
```
├── cmd/bot/
│ ├── main.go Entrypoint, polling/webhook, scheduler
│ └── webhook.go Webhook mode with TLS support
├── internal/
│ ├── bot/
│ │ ├── handlers.go Message/callback routing, views, menu builders
│ │ ├── clock.go Clock in/out, day off, report
│ │ ├── totals.go Break/work computation state machine
│ │ ├── calendar.go History view and inline event editing
│ │ ├── export.go Excel (.xlsx) report generation
│ │ ├── dateutil.go Gregorian/Jalali/Hijri conversions & calendars
│ │ ├── rpg.go XP, levels, streaks, achievements
│ │ ├── league.go WorkTime League leaderboard
│ │ ├── salary.go Salary estimation, rate/currency commands
│ │ ├── burnout.go Burnout assessment model
│ │ ├── settings.go Settings menu with inline pickers
│ │ ├── summary.go Monthly summary
│ │ ├── report.go Daily report builder
│ │ └── sanitize.go Input sanitization helpers
│ └── db/
│ ├── store.go SQLite store (data access layer)
│ └── migrations/ Goose-managed SQL migrations
│ ├── 001_init.sql Initial schema
│ └── 002_features.sql RPG, achievements, user_settings
├── .gitea/workflows/
│ └── ci.yml Gitea Actions CI
├── Dockerfile
├── docker-compose.yml
├── Makefile
├── .env.example
└── README.md
```
## Build & Run
```bash
# Local (requires Go 1.26+ and CGo-free SQLite)
make run
# Docker
docker compose up -d --build
```