feat(core): implement domain dataclasses for issue #5 #19

Merged
shoko merged 4 commits from feat/issue-5-core-models into main 2026-04-03 00:37:30 +02:00
Owner

Summary

Implement core/models.py with all domain dataclasses for the JIGAIDO bounty tracker.

Files

  • core/__init__.py - Core module init
  • core/models.py - Domain dataclasses
  • tests/test_models.py - 15 passing tests

Dataclasses

  • Bounty (base class)
  • GroupBounty (extends Bounty)
  • PersonalBounty (extends Bounty)
  • TrackedBounty
  • GroupData
  • TrackingData
  • UserData

Acceptance Criteria

  • All dataclasses defined with proper types
  • Optional fields properly typed with Optional[T]
  • Can be instantiated and compared
  • Unit tests in tests/test_models.py pass

Fixes #5

## Summary Implement core/models.py with all domain dataclasses for the JIGAIDO bounty tracker. ## Files - `core/__init__.py` - Core module init - `core/models.py` - Domain dataclasses - `tests/test_models.py` - 15 passing tests ## Dataclasses - `Bounty` (base class) - `GroupBounty` (extends Bounty) - `PersonalBounty` (extends Bounty) - `TrackedBounty` - `GroupData` - `TrackingData` - `UserData` ## Acceptance Criteria - [x] All dataclasses defined with proper types - [x] Optional fields properly typed with Optional[T] - [x] Can be instantiated and compared - [x] Unit tests in tests/test_models.py pass Fixes #5
shoko added 1 commit 2026-04-02 22:45:25 +02:00
- Create core/__init__.py
- Create core/models.py with all domain dataclasses:
  - Bounty (base class)
  - GroupBounty (extends Bounty)
  - PersonalBounty (extends Bounty)
  - TrackedBounty
  - GroupData
  - TrackingData
  - UserData
- Create tests/test_models.py with 15 passing tests

Fixes #5
han reviewed 2026-04-02 23:04:48 +02:00
@@ -0,0 +19,4 @@
class GroupBounty(Bounty):
"""Bounty created in a group context."""
created_by_user_id: int
Collaborator

can we simplify the Bounty by not having both GroupBounty and PersonalBounty? can we utilize Bounty by adding optional created_by_user_id so in this case we can use Bounty for Group and Personal Bounty. what do you think?

can we simplify the Bounty by not having both GroupBounty and PersonalBounty? can we utilize Bounty by adding optional created_by_user_id so in this case we can use Bounty for Group and Personal Bounty. what do you think?
han marked this conversation as resolved
han reviewed 2026-04-02 23:07:28 +02:00
core/models.py Outdated
@@ -0,0 +43,4 @@
group_id: int
bounties: list[GroupBounty]
next_id: int
Collaborator

what is this next_id refers to?

what is this next_id refers to?
han marked this conversation as resolved
han reviewed 2026-04-02 23:08:59 +02:00
core/models.py Outdated
@@ -0,0 +47,4 @@
@dataclass
class TrackingData:
Collaborator

in the tracking data, why there is no grouip id? in a way how do we know this tracking is for user in which group?

in the tracking data, why there is no grouip id? in a way how do we know this tracking is for user in which group?
han marked this conversation as resolved
han reviewed 2026-04-02 23:11:02 +02:00
core/models.py Outdated
@@ -0,0 +55,4 @@
@dataclass
class UserData:
Collaborator

is it possible to combine both UserData and GroupData? since their attributes are similar as well. we can name it maybe like RoomData? it sounds too specific to telegram, but that is the bigger picture. so we used the room_id. and makes sure it can be minus as well because telegram's id for group has minus in it. if we can't do that maybe we can add attribute like is this group or personal. is that makes sense?

is it possible to combine both UserData and GroupData? since their attributes are similar as well. we can name it maybe like RoomData? it sounds too specific to telegram, but that is the bigger picture. so we used the room_id. and makes sure it can be minus as well because telegram's id for group has minus in it. if we can't do that maybe we can add attribute like is this group or personal. is that makes sense?
han marked this conversation as resolved
han reviewed 2026-04-02 23:12:43 +02:00
@@ -0,0 +42,4 @@
assert b.link is None
assert b.due_date_ts is None
def test_bounty_comparison(self):
Collaborator

can we add a test to compare two different bounty with different data as well?

can we add a test to compare two different bounty with different data as well?
han marked this conversation as resolved
Author
Owner

Test results for feat/issue-5-core-models:

============================= test session starts ==============================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0
plugins: anyio-4.13.0, asyncio-0.25.2
collecting ... collected 15 items

tests/test_models.py::TestBounty::test_create_bounty PASSED              [  6%]
tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 13%]
tests/test_models.py::TestBounty::test_bounty_comparison PASSED          [ 20%]
tests/test_models.py::TestGroupBounty::test_create_group_bounty PASSED   [ 26%]
tests/test_models.py::TestGroupBounty::test_group_bounty_inherits_from_bounty PASSED [ 33%]
tests/test_models.py::TestPersonalBounty::test_create_personal_bounty PASSED [ 40%]
tests/test_models.py::TestPersonalBounty::test_personal_bounty_inherits_from_bounty PASSED [ 46%]
tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 53%]
tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 60%]
tests/test_models.py::TestGroupData::test_create_group_data PASSED       [ 66%]
tests/test_models.py::TestGroupData::test_group_data_with_bounties PASSED [ 73%]
tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 80%]
tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [ 86%]
tests/test_models.py::TestUserData::test_create_user_data PASSED         [ 93%]
tests/test_models.py::TestUserData::test_user_data_with_bounties PASSED  [100%]

========================= 15 passed, 1 warning in 0.02s =========================
Test results for feat/issue-5-core-models: ``` ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 plugins: anyio-4.13.0, asyncio-0.25.2 collecting ... collected 15 items tests/test_models.py::TestBounty::test_create_bounty PASSED [ 6%] tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 13%] tests/test_models.py::TestBounty::test_bounty_comparison PASSED [ 20%] tests/test_models.py::TestGroupBounty::test_create_group_bounty PASSED [ 26%] tests/test_models.py::TestGroupBounty::test_group_bounty_inherits_from_bounty PASSED [ 33%] tests/test_models.py::TestPersonalBounty::test_create_personal_bounty PASSED [ 40%] tests/test_models.py::TestPersonalBounty::test_personal_bounty_inherits_from_bounty PASSED [ 46%] tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 53%] tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 60%] tests/test_models.py::TestGroupData::test_create_group_data PASSED [ 66%] tests/test_models.py::TestGroupData::test_group_data_with_bounties PASSED [ 73%] tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 80%] tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [ 86%] tests/test_models.py::TestUserData::test_create_user_data PASSED [ 93%] tests/test_models.py::TestUserData::test_user_data_with_bounties PASSED [100%] ========================= 15 passed, 1 warning in 0.02s ========================= ```
shoko added 1 commit 2026-04-02 23:47:34 +02:00
- 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
Author
Owner

Addressed all review feedback:

  1. Removed GroupBounty/PersonalBounty subclasses - now using Bounty with optional created_by_user_id field. If set, it is a group bounty; if None, it is a personal bounty.

  2. Combined UserData/GroupData into RoomData - single dataclass with room_id (supports negative Telegram group IDs) and is_group: bool to distinguish.

  3. Added group_id to TrackingData - supports negative values for Telegram group IDs.

  4. Added test_bounty_comparison_not_equal - verifies bounties with different data are not equal.

Test results:

============================= test session starts ==============================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0
plugins: anyio-4.13.0, asyncio-0.25.2
collecting ... collected 12 items

tests/test_models.py::TestBounty::test_create_bounty PASSED              [  8%]
tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 16%]
tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED    [ 25%]
tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 33%]
tests/test_models.py::TestBounty::test_bounty_with_created_by_user_id PASSED [ 41%]
tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 50%]
tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 58%]
tests/test_models.py::TestRoomData::test_create_group_room_data PASSED   [ 66%]
tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED      [ 75%]
tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED  [ 83%]
tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 91%]
tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%]

========================= 12 passed, 1 warning in 0.02s =========================
Addressed all review feedback: 1. **Removed GroupBounty/PersonalBounty subclasses** - now using Bounty with optional `created_by_user_id` field. If set, it is a group bounty; if None, it is a personal bounty. 2. **Combined UserData/GroupData into RoomData** - single dataclass with `room_id` (supports negative Telegram group IDs) and `is_group: bool` to distinguish. 3. **Added `group_id` to TrackingData** - supports negative values for Telegram group IDs. 4. **Added `test_bounty_comparison_not_equal`** - verifies bounties with different data are not equal. Test results: ``` ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 plugins: anyio-4.13.0, asyncio-0.25.2 collecting ... collected 12 items tests/test_models.py::TestBounty::test_create_bounty PASSED [ 8%] tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 16%] tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED [ 25%] tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 33%] tests/test_models.py::TestBounty::test_bounty_with_created_by_user_id PASSED [ 41%] tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 50%] tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 58%] tests/test_models.py::TestRoomData::test_create_group_room_data PASSED [ 66%] tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED [ 75%] tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED [ 83%] tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 91%] tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%] ========================= 12 passed, 1 warning in 0.02s ========================= ```
han requested changes 2026-04-03 00:20:52 +02:00
Dismissed
core/models.py Outdated
@@ -0,0 +17,4 @@
link: Optional[str]
due_date_ts: Optional[int]
created_at: int
created_by_user_id: Optional[int] = None
Collaborator

created_by_user_id by default will refer to the user who created it, so I think its not none and not optional. but created_by_user_id doesnt reflect if its a group or not. Bounty doesn't need to know if its a group or not. because we have list of bounties in the RoomData and that is enough

created_by_user_id by default will refer to the user who created it, so I think its not none and not optional. but created_by_user_id doesnt reflect if its a group or not. Bounty doesn't need to know if its a group or not. because we have list of bounties in the RoomData and that is enough
han marked this conversation as resolved
core/models.py Outdated
@@ -0,0 +21,4 @@
@dataclass
class TrackedBounty:
Collaborator

we should also add room_id in this trackedbounty to know where the user is tracking the bounty from. to show their list track bounties depends on the room

we should also add room_id in this trackedbounty to know where the user is tracking the bounty from. to show their list track bounties depends on the room
han marked this conversation as resolved
@@ -0,0 +37,4 @@
next_id is used to generate unique bounty IDs within this room.
"""
room_id: int
Collaborator

since room_id can be negative in RoomData, I don't think we need is_group anymore. if its negative, its group, that should be clear enough

since room_id can be negative in RoomData, I don't think we need is_group anymore. if its negative, its group, that should be clear enough
han marked this conversation as resolved
core/models.py Outdated
@@ -0,0 +44,4 @@
@dataclass
class TrackingData:
Collaborator

I dont understand the difference of TrackingData and TrackedBounty. when to use which?

I dont understand the difference of TrackingData and TrackedBounty. when to use which?
han marked this conversation as resolved
shoko added 1 commit 2026-04-03 00:24:18 +02:00
- 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
Author
Owner

Addressed remaining feedback:

  1. Bounty.created_by_user_id is now non-optional - always required, indicates who created the bounty (not group vs personal)

  2. RoomData no longer has is_group - negative room_id is self-documenting for Telegram groups

  3. TrackedBounty now has room_id - to know which room the bounty was tracked from

  4. Clarified TrackingData vs TrackedBounty - added docstrings explaining TrackingData is the container (user's full tracking state in a group), TrackedBounty is a single tracked bounty entry

  5. test_bounty_comparison_not_equal already added

Test results:

============================= test session starts ==============================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0
collecting ... collected 11 items

tests/test_models.py::TestBounty::test_create_bounty PASSED              [  9%]
tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 18%]
tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED    [ 27%]
tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 36%]
tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 45%]
tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 54%]
tests/test_models.py::TestRoomData::test_create_group_room_data PASSED   [ 63%]
tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED      [ 72%]
tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED   [ 81%]
tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 90%]
tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%]

========================= 11 passed, 1 warning in 0.02s =========================
Addressed remaining feedback: 1. **Bounty.created_by_user_id is now non-optional** - always required, indicates who created the bounty (not group vs personal) 2. **RoomData no longer has is_group** - negative room_id is self-documenting for Telegram groups 3. **TrackedBounty now has room_id** - to know which room the bounty was tracked from 4. **Clarified TrackingData vs TrackedBounty** - added docstrings explaining TrackingData is the container (user's full tracking state in a group), TrackedBounty is a single tracked bounty entry 5. **test_bounty_comparison_not_equal** already added Test results: ``` ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 collecting ... collected 11 items tests/test_models.py::TestBounty::test_create_bounty PASSED [ 9%] tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 18%] tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED [ 27%] tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 36%] tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 45%] tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 54%] tests/test_models.py::TestRoomData::test_create_group_room_data PASSED [ 63%] tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED [ 72%] tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED [ 81%] tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 90%] tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%] ========================= 11 passed, 1 warning in 0.02s ========================= ```
han requested changes 2026-04-03 00:31:24 +02:00
Dismissed
core/models.py Outdated
@@ -0,0 +32,4 @@
bounty_id: int
created_at: int
room_id: int
Collaborator

we can remove room_id from here since TrackedBounty is just a relation, while we store the actual data in the TrackingData

we can remove room_id from here since TrackedBounty is just a relation, while we store the actual data in the TrackingData
han marked this conversation as resolved
core/models.py Outdated
@@ -0,0 +60,4 @@
TrackingData is the container, TrackedBounty is the item.
"""
group_id: int
Collaborator

I think we should rename it into room_id to make it works and makes sense for both group and DM

I think we should rename it into room_id to make it works and makes sense for both group and DM
han marked this conversation as resolved
han added a new dependency 2026-04-03 00:33:02 +02:00
han removed a dependency 2026-04-03 00:33:06 +02:00
shoko added 1 commit 2026-04-03 00:34:26 +02:00
- TrackingData.group_id renamed to room_id (works for both group and DM)
- Removed room_id from TrackedBounty (it's just a lightweight pointer)
Author
Owner

Addressed latest feedback:

  1. TrackingData.group_id renamed to room_id - now works for both group (negative) and DM (positive) contexts

  2. Removed room_id from TrackedBounty - it is now just a lightweight relation/pointer; the room context lives in TrackingData

Test results:

============================= test session starts ==============================
platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0
collecting ... collected 11 items

tests/test_models.py::TestBounty::test_create_bounty PASSED              [  9%]
tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 18%]
tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED    [ 27%]
tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 36%]
tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 45%]
tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 54%]
tests/test_models.py::TestRoomData::test_create_group_room_data PASSED   [ 63%]
tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED      [ 72%]
tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED   [ 81%]
tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 90%]
tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%]

========================= 11 passed, 1 warning in 0.02s =========================
Addressed latest feedback: 1. **TrackingData.group_id renamed to room_id** - now works for both group (negative) and DM (positive) contexts 2. **Removed room_id from TrackedBounty** - it is now just a lightweight relation/pointer; the room context lives in TrackingData Test results: ``` ============================= test session starts ============================== platform linux -- Python 3.14.3, pytest-8.3.5, pluggy-1.6.0 collecting ... collected 11 items tests/test_models.py::TestBounty::test_create_bounty PASSED [ 9%] tests/test_models.py::TestBounty::test_bounty_optional_fields_can_be_none PASSED [ 18%] tests/test_models.py::TestBounty::test_bounty_comparison_equal PASSED [ 27%] tests/test_models.py::TestBounty::test_bounty_comparison_not_equal PASSED [ 36%] tests/test_models.py::TestTrackedBounty::test_create_tracked_bounty PASSED [ 45%] tests/test_models.py::TestTrackedBounty::test_tracked_bounty_comparison PASSED [ 54%] tests/test_models.py::TestRoomData::test_create_group_room_data PASSED [ 63%] tests/test_models.py::TestRoomData::test_create_dm_room_data PASSED [ 72%] tests/test_models.py::TestRoomData::test_room_data_with_bounties PASSED [ 81%] tests/test_models.py::TestTrackingData::test_create_tracking_data PASSED [ 90%] tests/test_models.py::TestTrackingData::test_tracking_data_with_tracked PASSED [100%] ========================= 11 passed, 1 warning in 0.02s ========================= ```
han approved these changes 2026-04-03 00:35:55 +02:00
han left a comment
Collaborator

lgtm

lgtm
shoko merged commit ddd44cb593 into main 2026-04-03 00:37:30 +02:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: shoko/jigaido#19