Issue #41: Model updates for Phase 2 features
Bounty model:
- Add deleted_at: int | None - timestamp when deleted (soft-delete)
- Add created_by_username: str | None - username for display purposes
RoomData model:
- Add timezone: str | None - room's timezone (e.g., "Asia/Jakarta")
- Add admin_user_ids: list[int] - list of admin user IDs
Storage adapter updated to handle new fields in load/save operations.
Tests added for new fields.
Add tests/__init__.py to make tests/ a proper Python package,
enabling cross-imports between test modules (e.g., test_services
importing from test_ports).
All 145 tests pass:
- tests/: 90 tests
- apps/telegram-bot/tests/: 55 tests
- Tests mock dependencies and verify command existence, flag processing, and output format
- Tests use --group-id=-1001 format (equals sign) to avoid argparse treating -1001 as a flag
- All 17 tests passing
- Add tests/test_json_file.py with unit tests for JsonFileRoomStorage and JsonFileTrackingStorage
- Reorganize data directories per han's feedback:
- Rooms: ~/.jigaido/data/room/<room_id>.json (was ~/.jigaido/data/<room_id>.json)
- Tracking: ~/.jigaido/data/tracking/<room_id>_<user_id>.json (was ~/.jigaido/tracking/...)
- Note: duplicate tracking is handled at TrackingService layer (returns False if already tracking), adapter allows duplicates by design
Add JsonFileRoomStorage and JsonFileTrackingStorage implementations
that implement the RoomStorage and TrackingStorage ports.
- Stores room data at ~/.jigaido/data/<room_id>.json
- Stores tracking data at ~/.jigaido/tracking/<room_id>_<user_id>.json
- Implements all port methods: load, save, add_bounty, update_bounty,
delete_bounty, get_bounty for rooms; load, save, track_bounty,
untrack_bounty for tracking
Fixes#9
Tests with SimpleRoomStorage and SimpleTrackingStorage (without ensure_*)
show that add_bounty() and track_bounty() work fine without explicit
ensure methods - they create rooms/tracking internally.
This simplifies the Protocol to only essential methods.
- Removed PersonalStorage (redundant - RoomStorage handles both via room_id)
- Added ensure_room() and ensure_tracking() methods for explicit creation
- Added @runtime_checkable to Protocols for isinstance checks
- Added tests/test_ports.py with 11 unit tests for storage protocols
- Bounty.created_by_user_id is now non-optional (always required)
- Removed is_group from RoomData (negative room_id is self-documenting)
- Added room_id to TrackedBounty to track which room bounty was tracked from
- Added clarifying docstrings explaining TrackingData vs TrackedBounty
- Updated tests to match new model structure
- Remove GroupBounty/PersonalBounty subclasses, use Bounty with optional created_by_user_id
- Combine UserData/GroupData into RoomData with room_id and is_group fields
- Add group_id field to TrackingData (supports negative Telegram group IDs)
- Add test_bounty_comparison_not_equal for verifying different bounties are not equal
- Update core/__init__.py exports