# JIGAIDO — Specification > Named after Nanami Kento's Cursed Technique restriction. Suppresses power during normal hours, exerts it during overtime. A bounty tracker that keeps you honest when the clock runs long. --- ## Overview JIGAIDO is a Telegram bot that lets groups and individuals track bounties — tasks, obligations, and deadlines — with optional due dates and personal tracking. - **Group mode**: Each Telegram group has its own bounty list. Anyone can add bounties. Only creator can edit/delete. - **DM mode**: Personal bounty list. Anyone can manage their own bounties. - **Tracking**: Users can track any bounty (group or personal) to their tracking list. - **Due dates**: Free-form text (`"april 15"`, `"in 3 days"`, `"tomorrow"`) parsed at add time, stored as Unix timestamp. If unparseable, stored as `NULL`. - **Links**: Optional. If provided, stored with the bounty. - **Informed by**: Every bounty stores the Telegram username of who posted/added it. --- ## Architecture ### Stack - **Bot**: `python-telegram-bot` (pure Python, no C extensions) - **Storage**: Per-user JSON files (zero-setup, no DB server) - **Date parsing**: `dateparser` - **Runtime**: Python 3.10+ - **Deployment**: Any $5 VPS with Python 3.10+ ### Directory Structure ``` jigaido/ ├── apps/ │ └── telegram-bot/ # Telegram bot app │ ├── bot.py # Entrypoint │ ├── commands.py # Command handlers │ ├── storage.py # JSON file storage │ ├── data/ │ │ └── users/ # Per-user JSON files │ │ └── {telegram_user_id}.json │ ├── requirements.txt │ └── .env.example ├── SPEC.md # This document ├── README.md └── CONTRIBUTING.md ``` ### Storage Design **File structure (`data/users/{telegram_user_id}.json`):** ```json { "user_id": 123, "username": "alice", "personal_bounties": [ { "id": 1, "text": "Fix login bug", "link": "https://github.com/example/repo/issues/1", "due_date_ts": 1735689600, "group_id": null, "informed_by_username": "alice", "created_at": 1735603200 } ], "tracked_bounties": [ {"bounty_id": 5, "group_id": -1001, "created_at": 1735600000}, {"bounty_id": 3, "group_id": null, "created_at": 1735590000} ] } ``` **Key design decisions:** 1. **Single file per user** — Personal bounties live in the creator's file. Group bounties also live in creator's file with `group_id` set. 2. **Bounty IDs are sequential integers per file** — Not global. Each user's file has its own ID counter. 3. **Atomic writes** — Uses `tempfile` + `rename` for safe writes. 4. **No reminders in v1** — Dropped for simplicity. --- ## Commands ### In Group | Command | Who | Description | |---|---|---| | `/bounty` | anyone | List all bounties in this group | | `/my` | anyone | List bounties tracked by you | | `/add [link] [due date]` | anyone | Add a new bounty to the group | | `/update [text] [link] [due_date]` | creator only | Update an existing bounty | | `/delete ` | creator only | Delete a bounty | | `/track ` | anyone | Add a group bounty to your tracking | | `/untrack ` | anyone | Remove a bounty from your tracking | ### In DM (1:1 with bot) | Command | Description | |---|---| | `/bounty` | List all your personal bounties | | `/my` | List bounties you're tracking | | `/add [link] [due date]` | Add a personal bounty | | `/update [text] [link] [due_date]` | Update a personal bounty | | `/delete ` | Delete a personal bounty | | `/track ` | Add a personal bounty to your tracking | ### Add/Update Syntax ``` /add Some task description https://example.com in 3 days /add Just a text reminder /add https://link-only.example.com tomorrow ``` - `link` is optional - `due_date` is optional, free-form --- ## Informed By When a user triggers `/add`, the bot captures `message.from_user.username` and stores it in `informed_by_username`. This is displayed on bounty listings so the group/DM knows who posted or requested the bounty. --- ## Due Date Parsing Uses `dateparser` library. Examples: - `"april 15"`, `"April 15, 2026"` - `"in 3 days"` - `"tomorrow"` - `"2026-04-15"` - `"next friday"` If parsing fails → `due_date_ts = NULL`. No error is shown to user. Stored as Unix timestamp. User-facing display can be localized/converted to any timezone at render time. --- ## Error Handling - Unknown command → help text with available commands - `/update`/`/delete` by non-creator → "⛔ Group creator only." - `/track` already tracked → "Already tracking" (idempotent) - `/untrack` not tracked → "Not tracking" (idempotent) - Bounty not found → "Bounty not found" --- ## When to Revert to SQLite - Multiple concurrent users with write conflicts - Complex queries across users - Reminder system with proper dedup - Scale > 1,000 users - Need ACID guarantees on concurrent writes