Initial commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
"""Domain entity: BreakPeriod.
|
||||
|
||||
A user-defined window the family wants to be home together (e.g. summer, winter
|
||||
holidays). Drives the parent-swap tip. Lengths and dates are entirely family-specific;
|
||||
seeded with editable defaults.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class BreakPeriod:
|
||||
"""A user-defined window for the family to be home together."""
|
||||
|
||||
id: UUID
|
||||
workspace_id: UUID
|
||||
name: str # 'Summer', 'Winter holidays', ...
|
||||
start_date: date
|
||||
end_date: date
|
||||
target_weeks: int # desired weeks home together for this break
|
||||
created_at: datetime | None = None
|
||||
updated_at: datetime | None = None
|
||||
@@ -0,0 +1,15 @@
|
||||
"""Domain entity: Child (per-child entitlement anchor)."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class Child:
|
||||
id: UUID
|
||||
workspace_id: UUID
|
||||
name: str
|
||||
birth_date: date # use expected_birth_date (due date) if unborn
|
||||
preschool_start_date: date | None = None # drives the preschool-day reserve tip
|
||||
created_at: datetime | None = None
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Domain entity: ParentalLeaveFetch.
|
||||
|
||||
Represents a snapshot of a parent's Försäkringskassan data — either scraped via
|
||||
the headless-browser flow or entered manually. The `source` field records the
|
||||
provenance so the UI can display freshness information ("Manually entered on …").
|
||||
|
||||
tier_data is stored as a JSON string in the DB and should be decoded on load.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class TierData:
|
||||
"""Breakdown of days by compensation tier."""
|
||||
|
||||
sjukpenning_total: int
|
||||
sjukpenning_used: int
|
||||
sjukpenning_left: int
|
||||
lagsta_niva_total: int
|
||||
lagsta_niva_used: int
|
||||
lagsta_niva_left: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParentalLeaveFetch:
|
||||
id: UUID
|
||||
personal_data_uuid: UUID
|
||||
workspace_id: UUID
|
||||
child_id: UUID
|
||||
source: str # 'scraped' | 'manual'
|
||||
fetched_at: datetime
|
||||
total_days: int
|
||||
days_used: int
|
||||
days_left: int
|
||||
reserved_days_total: int
|
||||
reserved_days_left: int
|
||||
transferable_days_left: int
|
||||
dubbeldagar_left: int
|
||||
tier_data: TierData
|
||||
created_at: datetime | None = field(default=None)
|
||||
updated_at: datetime | None = field(default=None)
|
||||
@@ -0,0 +1,25 @@
|
||||
"""Domain entity: PersonalData (parent profile).
|
||||
|
||||
A PersonalData represents a parent in the planning workspace. It intentionally
|
||||
exists without a User login so that solo planning for a partner who hasn't
|
||||
registered is possible (see ARCHITECTURE.md §3.0).
|
||||
|
||||
personnummer storage is discouraged (see §11). If kept, personnummer_enc must
|
||||
be keyed HMAC / authenticated encryption — never a plain SHA-256.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class PersonalData:
|
||||
uuid: UUID
|
||||
workspace_id: UUID
|
||||
name: str
|
||||
salary_type: str = "monthly" # 'monthly' | 'hourly'
|
||||
employment_status: str = "employed" # 'employed' | 'jobseeking' | 'none'
|
||||
personnummer_enc: str | None = None # encrypted/HMAC; prefer None
|
||||
created_at: datetime | None = field(default=None)
|
||||
deleted_at: datetime | None = field(default=None)
|
||||
@@ -0,0 +1,18 @@
|
||||
"""Domain entity: PlannedLeaveDay (a single calendar day of planned leave)."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlannedLeaveDay:
|
||||
id: UUID
|
||||
workspace_id: UUID
|
||||
child_id: UUID
|
||||
parent_personal_data_uuid: UUID
|
||||
date: date
|
||||
day_type: str # 'sjukpenning' | 'lagsta' | 'vacation'
|
||||
is_dubbeldag: bool = False # True → counts against the 60-day dubbeldagar quota
|
||||
created_at: datetime | None = None
|
||||
updated_at: datetime | None = None
|
||||
@@ -0,0 +1,15 @@
|
||||
"""Domain entity: User (login account, linked 1:1 to PersonalData)."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
id: UUID
|
||||
personal_data_uuid: UUID # FK to PersonalData; workspace derived from it
|
||||
email: str
|
||||
hashed_password: str # argon2 hash; never plain SHA
|
||||
created_at: datetime
|
||||
is_active: bool = True
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Domain entity: VacationDays.
|
||||
|
||||
This is the REFERENCE entity — copy this shape for the other entities
|
||||
(parental_leave, planned_leave, child, break_period, ...). A domain entity is a
|
||||
plain dataclass with no framework or persistence concerns.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class VacationDays:
|
||||
"""Manual vacation (semester) entry per parent per year.
|
||||
|
||||
Swedish semester is typically 25 statutory days/year; days above 20 may be
|
||||
saved up to 5 years. `saved_days_in` carries those over so the tips engine
|
||||
can warn before they expire.
|
||||
"""
|
||||
|
||||
id: UUID
|
||||
personal_data_uuid: UUID
|
||||
workspace_id: UUID
|
||||
year: int
|
||||
total_days: int # entitlement for this year
|
||||
saved_days_in: int = 0 # carried over from prior years
|
||||
created_at: datetime | None = None
|
||||
updated_at: datetime | None = None
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Domain entity: Workspace (shared planning space for 1–2 parents)."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class Workspace:
|
||||
id: UUID
|
||||
name: str
|
||||
planning_goal: str = "balanced" # 'max_time' | 'max_money' | 'balanced'
|
||||
created_at: datetime | None = None
|
||||
@@ -0,0 +1,22 @@
|
||||
"""Domain entity: WorkspaceInvitation (single-use partner invite).
|
||||
|
||||
token_hash stores SHA-256(raw_token). The raw token is returned to the caller
|
||||
once and never persisted. Redemption compares SHA-256(presented_token) against
|
||||
this hash.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class WorkspaceInvitation:
|
||||
id: UUID
|
||||
workspace_id: UUID
|
||||
token_hash: str # SHA-256 of the one-time token; raw token never stored
|
||||
invited_by_user_id: UUID
|
||||
status: str # 'pending' | 'accepted' | 'revoked' | 'expired'
|
||||
expires_at: datetime
|
||||
created_at: datetime
|
||||
accepted_at: datetime | None = None
|
||||
Reference in New Issue
Block a user