Phase 6: replace app template with the vet sample domain + jobs slice, pipelines and worker
- templates/app now carries the vet server (parents/pets/treatments/vets/appointments) - added domain/jobs slice with /jobs OpenAPI paths and Job schema (x- extensions) - added pipelines/shared scaffold (loader, ports, registry) and the appointment_reminder family; worker.py dispatches jobs by kind - wired init.py, config.py worker knobs, .env.example, docker-compose worker - unit tests for jobs routes, the pipeline family and worker dispatch (12 passing)
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Appointments domain slice."""
|
||||
68
standards/src/templates/app/domain/appointments/models.py
Normal file
68
standards/src/templates/app/domain/appointments/models.py
Normal file
@@ -0,0 +1,68 @@
|
||||
"""# Summary
|
||||
|
||||
Appointments domain — scheduled visits linking a pet, a vet and a treatment.
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
from domain.parents.models import Metadata
|
||||
|
||||
|
||||
class ProcedureNote(BaseModel):
|
||||
"""A single procedure note; ``noteType`` selects the shape.
|
||||
|
||||
Attributes:
|
||||
noteType (str): Discriminator (basic, heart_rate, dental, vaccine,
|
||||
preop, surgery).
|
||||
summary (str | None): Short summary. Defaults to None.
|
||||
details (str | None): Longer details. Defaults to None.
|
||||
"""
|
||||
|
||||
noteType: str
|
||||
summary: str | None = None
|
||||
details: str | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
|
||||
|
||||
class Procedure(BaseModel):
|
||||
"""A procedure performed during an appointment.
|
||||
|
||||
Attributes:
|
||||
name (str): Procedure name.
|
||||
description (str | None): Procedure description. Defaults to None.
|
||||
cost (float | None): Cost of the procedure. Defaults to None.
|
||||
notes (ProcedureNote | None): Typed procedure note. Defaults to None.
|
||||
"""
|
||||
|
||||
name: str
|
||||
description: str | None = None
|
||||
cost: float | None = None
|
||||
notes: ProcedureNote | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
|
||||
|
||||
class Appointment(BaseModel):
|
||||
"""A scheduled appointment.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
date (str): ISO date-time of the appointment.
|
||||
notes (str | None): Additional notes. Defaults to None.
|
||||
procedures (list[Procedure]): Procedures performed. Defaults to empty.
|
||||
pet (dict | int | None): Embedded pet object or pet id.
|
||||
vet (dict | int | None): Embedded vet object or vet id.
|
||||
treatment (dict | int | None): Embedded treatment or treatment id.
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
date: str
|
||||
notes: str | None = None
|
||||
procedures: list[Procedure] = []
|
||||
pet: dict | int | None = None
|
||||
vet: dict | int | None = None
|
||||
treatment: dict | int | None = None
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Appointments domain ports."""
|
||||
25
standards/src/templates/app/domain/appointments/ports/db.py
Normal file
25
standards/src/templates/app/domain/appointments/ports/db.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""# Summary
|
||||
|
||||
Appointments persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.appointments.models import Appointment
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class AppointmentDocument(Appointment, BaseDocument):
|
||||
"""Persisted appointment document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_appointment_repo():
|
||||
"""Create the appointment repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``appointments`` collection/store.
|
||||
"""
|
||||
return create_repo("appointments", AppointmentDocument)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the appointment aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.appointments.models import Appointment
|
||||
from domain.appointments.ports.db import AppointmentDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class AppointmentCrudsService(CrudsServiceAdaptor[Appointment, AppointmentDocument]):
|
||||
"""Appointment CRUD service resolving :class:`AppointmentDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_appointment_service`. The ``model``
|
||||
and ``schema`` class attributes bind the domain model and its document.
|
||||
"""
|
||||
|
||||
model = Appointment
|
||||
schema = AppointmentDocument
|
||||
|
||||
|
||||
def get_appointment_service(repo) -> AppointmentCrudsService:
|
||||
"""Build an appointment CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Integer-id appointment repository from
|
||||
:func:`create_appointment_repo`.
|
||||
|
||||
Returns:
|
||||
AppointmentCrudsService: Ready-to-use appointment CRUD service.
|
||||
"""
|
||||
return build(AppointmentCrudsService, instances={"repo": repo})
|
||||
@@ -1,21 +0,0 @@
|
||||
"""# Summary
|
||||
|
||||
Item domain model — the neutral resource used throughout the template.
|
||||
"""
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
"""A single countable resource.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Item name.
|
||||
quantity (int): Item quantity. Defaults to 1.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
quantity: int = Field(default=1)
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -1,18 +0,0 @@
|
||||
"""# Summary
|
||||
|
||||
Optional converters for the item slice — pure functions mapping between domain
|
||||
types. Add a converter here when a service must reshape data; keep it pure.
|
||||
"""
|
||||
from domain.item.models import Item
|
||||
|
||||
|
||||
def to_item(data: dict) -> Item:
|
||||
"""Build an :class:`Item` from a raw mapping.
|
||||
|
||||
Args:
|
||||
data (dict): Field mapping matching the item model.
|
||||
|
||||
Returns:
|
||||
Item: The constructed item model.
|
||||
"""
|
||||
return Item(**data)
|
||||
@@ -1,25 +0,0 @@
|
||||
"""# Summary
|
||||
|
||||
Items persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.item.models import Item
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class ItemDocument(Item, BaseDocument):
|
||||
"""Persisted item document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_item_repo():
|
||||
"""Create the item repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``items`` collection/store.
|
||||
"""
|
||||
return create_repo("items", ItemDocument)
|
||||
@@ -1,33 +0,0 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the item aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.item.models import Item
|
||||
from domain.item.ports.db import ItemDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class ItemCrudsService(CrudsServiceAdaptor[Item, ItemDocument]):
|
||||
"""Item CRUD service resolving :class:`ItemDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_item_service`. The ``model`` and
|
||||
``schema`` class attributes bind the domain model and its document type.
|
||||
"""
|
||||
|
||||
model = Item
|
||||
schema = ItemDocument
|
||||
|
||||
|
||||
def get_item_service(repo) -> ItemCrudsService:
|
||||
"""Build an item CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Mongo-backed item repository from :func:`create_item_repo`.
|
||||
|
||||
Returns:
|
||||
ItemCrudsService: Ready-to-use item CRUD service.
|
||||
"""
|
||||
return build(ItemCrudsService, instances={"repo": repo})
|
||||
@@ -1,29 +0,0 @@
|
||||
"""# Summary
|
||||
|
||||
Job domain model — a pipeline work item consumed by the background worker.
|
||||
"""
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Job(BaseModel):
|
||||
"""A unit of background work.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Job name.
|
||||
status (str): Lifecycle status. Defaults to "pending".
|
||||
retry_count (int): Times the job failed. Defaults to 0.
|
||||
error_message (str | None): Last failure message. Defaults to None.
|
||||
payload (dict | None): Arbitrary job payload. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
status: Literal["pending", "processing", "done", "failed"] = "pending"
|
||||
retry_count: int = Field(default=0)
|
||||
error_message: str | None = None
|
||||
payload: dict | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
37
standards/src/templates/app/domain/jobs/models.py
Normal file
37
standards/src/templates/app/domain/jobs/models.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""# Summary
|
||||
|
||||
Jobs domain — the worker's queue. Each job is a unit of pipeline work the
|
||||
background worker claims and executes.
|
||||
"""
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from domain.parents.models import Metadata
|
||||
|
||||
|
||||
class Job(BaseModel):
|
||||
"""A unit of background work.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Human label for the job.
|
||||
kind (str): Dispatch key — selects the pipeline (e.g.
|
||||
``appointment_reminder``).
|
||||
status (str): Lifecycle status. Defaults to ``pending``.
|
||||
payload (dict | None): Job-specific input. Defaults to None.
|
||||
retry_count (int): Failed attempts so far. Defaults to 0.
|
||||
error_message (str | None): Last failure detail. Defaults to None.
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
kind: str
|
||||
status: Literal["pending", "processing", "done", "failed"] = "pending"
|
||||
payload: dict | None = None
|
||||
retry_count: int = 0
|
||||
error_message: str | None = None
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -5,7 +5,8 @@ Jobs persistence ports — integer-id document and repository factory.
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.job.models import Job
|
||||
from config import settings
|
||||
from domain.jobs.models import Job
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
@@ -22,4 +23,5 @@ def create_job_repo():
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``jobs`` collection/store.
|
||||
"""
|
||||
_ = settings # backend chosen centrally by create_repo
|
||||
return create_repo("jobs", JobDocument)
|
||||
@@ -4,8 +4,8 @@ CRUD service wiring for the job aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.job.models import Job
|
||||
from domain.job.ports.db import JobDocument
|
||||
from domain.jobs.models import Job
|
||||
from domain.jobs.ports.db import JobDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ def get_job_service(repo) -> JobCrudsService:
|
||||
"""Build a job CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Mongo-backed job repository from :func:`create_job_repo`.
|
||||
repo (Any): Integer-id job repository from :func:`create_job_repo`.
|
||||
|
||||
Returns:
|
||||
JobCrudsService: Ready-to-use job CRUD service.
|
||||
"""
|
||||
return build(JobCrudsService, instances={"repo": repo})
|
||||
return build(JobCrudsService, instances={"repo": repo})
|
||||
3
standards/src/templates/app/domain/parents/__init__.py
Normal file
3
standards/src/templates/app/domain/parents/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Parents domain slice."""
|
||||
39
standards/src/templates/app/domain/parents/models.py
Normal file
39
standards/src/templates/app/domain/parents/models.py
Normal file
@@ -0,0 +1,39 @@
|
||||
"""# Summary
|
||||
|
||||
Parents domain — pet owners referenced by :class:`domain.pets.models.Pet`.
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Metadata(BaseModel):
|
||||
"""Optional presentation metadata carried alongside a resource.
|
||||
|
||||
Attributes:
|
||||
createdOn (str | None): ISO creation timestamp. Defaults to None.
|
||||
updatedOn (str | None): ISO update timestamp. Defaults to None.
|
||||
"""
|
||||
|
||||
createdOn: str | None = None
|
||||
updatedOn: str | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
|
||||
|
||||
class Parent(BaseModel):
|
||||
"""A pet owner.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Parent's full name.
|
||||
email (str): Email address.
|
||||
phone (str | None): Contact phone number. Defaults to None.
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
email: str
|
||||
phone: str | None = None
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Parents domain ports."""
|
||||
27
standards/src/templates/app/domain/parents/ports/db.py
Normal file
27
standards/src/templates/app/domain/parents/ports/db.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""# Summary
|
||||
|
||||
Parents persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from config import settings
|
||||
from domain.parents.models import Parent
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class ParentDocument(Parent, BaseDocument):
|
||||
"""Persisted parent document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_parent_repo():
|
||||
"""Create the parent repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``parents`` collection/store.
|
||||
"""
|
||||
_ = settings # backend chosen centrally by create_repo
|
||||
return create_repo("parents", ParentDocument)
|
||||
33
standards/src/templates/app/domain/parents/ports/service.py
Normal file
33
standards/src/templates/app/domain/parents/ports/service.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the parent aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.parents.models import Parent
|
||||
from domain.parents.ports.db import ParentDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class ParentCrudsService(CrudsServiceAdaptor[Parent, ParentDocument]):
|
||||
"""Parent CRUD service resolving :class:`ParentDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_parent_service`. The ``model`` and
|
||||
``schema`` class attributes bind the domain model and its document type.
|
||||
"""
|
||||
|
||||
model = Parent
|
||||
schema = ParentDocument
|
||||
|
||||
|
||||
def get_parent_service(repo) -> ParentCrudsService:
|
||||
"""Build a parent CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Integer-id parent repository from :func:`create_parent_repo`.
|
||||
|
||||
Returns:
|
||||
ParentCrudsService: Ready-to-use parent CRUD service.
|
||||
"""
|
||||
return build(ParentCrudsService, instances={"repo": repo})
|
||||
3
standards/src/templates/app/domain/pets/__init__.py
Normal file
3
standards/src/templates/app/domain/pets/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Pets domain slice."""
|
||||
37
standards/src/templates/app/domain/pets/models.py
Normal file
37
standards/src/templates/app/domain/pets/models.py
Normal file
@@ -0,0 +1,37 @@
|
||||
"""# Summary
|
||||
|
||||
Pets domain — animals owned by parents and treated in appointments.
|
||||
"""
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from domain.parents.models import Metadata
|
||||
|
||||
|
||||
class Pet(BaseModel):
|
||||
"""A pet patient.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Name of the pet.
|
||||
species (str): Type of animal (dog, cat, bird).
|
||||
age (int | None): Age in years. Defaults to None.
|
||||
weight (float | None): Weight in kilograms. Defaults to None.
|
||||
birthDate (str | None): ISO date of birth. Defaults to None.
|
||||
photo (str | None): Stored photo path after upload. Defaults to None.
|
||||
parents (list[dict]): Embedded parent objects (or bare ids on input).
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
species: Literal["dog", "cat", "bird"]
|
||||
age: int | None = None
|
||||
weight: float | None = None
|
||||
birthDate: str | None = None
|
||||
photo: str | None = None
|
||||
parents: list[dict] = []
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Pets domain ports."""
|
||||
25
standards/src/templates/app/domain/pets/ports/db.py
Normal file
25
standards/src/templates/app/domain/pets/ports/db.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""# Summary
|
||||
|
||||
Pets persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.pets.models import Pet
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class PetDocument(Pet, BaseDocument):
|
||||
"""Persisted pet document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_pet_repo():
|
||||
"""Create the pet repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``pets`` collection/store.
|
||||
"""
|
||||
return create_repo("pets", PetDocument)
|
||||
33
standards/src/templates/app/domain/pets/ports/service.py
Normal file
33
standards/src/templates/app/domain/pets/ports/service.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the pet aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.pets.models import Pet
|
||||
from domain.pets.ports.db import PetDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class PetCrudsService(CrudsServiceAdaptor[Pet, PetDocument]):
|
||||
"""Pet CRUD service resolving :class:`PetDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_pet_service`. The ``model`` and
|
||||
``schema`` class attributes bind the domain model and its document type.
|
||||
"""
|
||||
|
||||
model = Pet
|
||||
schema = PetDocument
|
||||
|
||||
|
||||
def get_pet_service(repo) -> PetCrudsService:
|
||||
"""Build a pet CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Integer-id pet repository from :func:`create_pet_repo`.
|
||||
|
||||
Returns:
|
||||
PetCrudsService: Ready-to-use pet CRUD service.
|
||||
"""
|
||||
return build(PetCrudsService, instances={"repo": repo})
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Treatments domain slice."""
|
||||
25
standards/src/templates/app/domain/treatments/models.py
Normal file
25
standards/src/templates/app/domain/treatments/models.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""# Summary
|
||||
|
||||
Treatments domain — the catalogue of treatments offered by the clinic.
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
from domain.parents.models import Metadata
|
||||
|
||||
|
||||
class Treatment(BaseModel):
|
||||
"""A catalogue treatment.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
label (str): Name of the treatment.
|
||||
description (str | None): Detailed description. Defaults to None.
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
label: str
|
||||
description: str | None = None
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Treatments domain ports."""
|
||||
25
standards/src/templates/app/domain/treatments/ports/db.py
Normal file
25
standards/src/templates/app/domain/treatments/ports/db.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""# Summary
|
||||
|
||||
Treatments persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.treatments.models import Treatment
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class TreatmentDocument(Treatment, BaseDocument):
|
||||
"""Persisted treatment document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_treatment_repo():
|
||||
"""Create the treatment repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``treatments`` collection/store.
|
||||
"""
|
||||
return create_repo("treatments", TreatmentDocument)
|
||||
@@ -0,0 +1,34 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the treatment aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.treatments.models import Treatment
|
||||
from domain.treatments.ports.db import TreatmentDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class TreatmentCrudsService(CrudsServiceAdaptor[Treatment, TreatmentDocument]):
|
||||
"""Treatment CRUD service resolving :class:`TreatmentDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_treatment_service`. The ``model``
|
||||
and ``schema`` class attributes bind the domain model and its document.
|
||||
"""
|
||||
|
||||
model = Treatment
|
||||
schema = TreatmentDocument
|
||||
|
||||
|
||||
def get_treatment_service(repo) -> TreatmentCrudsService:
|
||||
"""Build a treatment CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Integer-id treatment repository from
|
||||
:func:`create_treatment_repo`.
|
||||
|
||||
Returns:
|
||||
TreatmentCrudsService: Ready-to-use treatment CRUD service.
|
||||
"""
|
||||
return build(TreatmentCrudsService, instances={"repo": repo})
|
||||
3
standards/src/templates/app/domain/vets/__init__.py
Normal file
3
standards/src/templates/app/domain/vets/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Vets domain slice."""
|
||||
29
standards/src/templates/app/domain/vets/models.py
Normal file
29
standards/src/templates/app/domain/vets/models.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""# Summary
|
||||
|
||||
Vets domain — veterinarians referenced by appointments.
|
||||
"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
from domain.parents.models import Metadata
|
||||
|
||||
|
||||
class Vet(BaseModel):
|
||||
"""A veterinarian.
|
||||
|
||||
Attributes:
|
||||
id (int | None): Server-assigned identifier. Defaults to None.
|
||||
name (str): Veterinarian's full name.
|
||||
specialty (str | None): Area of specialization. Defaults to None.
|
||||
email (str | None): Email address. Defaults to None.
|
||||
phone (str | None): Contact phone number. Defaults to None.
|
||||
metadata (Metadata | None): Presentation metadata. Defaults to None.
|
||||
"""
|
||||
|
||||
id: int | None = None
|
||||
name: str
|
||||
specialty: str | None = None
|
||||
email: str | None = None
|
||||
phone: str | None = None
|
||||
metadata: Metadata | None = None
|
||||
|
||||
model_config = {"extra": "ignore"}
|
||||
@@ -0,0 +1,3 @@
|
||||
"""# Summary
|
||||
|
||||
Vets domain ports."""
|
||||
25
standards/src/templates/app/domain/vets/ports/db.py
Normal file
25
standards/src/templates/app/domain/vets/ports/db.py
Normal file
@@ -0,0 +1,25 @@
|
||||
"""# Summary
|
||||
|
||||
Vets persistence ports — integer-id document and repository factory.
|
||||
"""
|
||||
from mongo_ops import BaseDocument
|
||||
from pydantic import Field
|
||||
|
||||
from domain.vets.models import Vet
|
||||
from infra.db.repos import create_repo
|
||||
|
||||
|
||||
class VetDocument(Vet, BaseDocument):
|
||||
"""Persisted vet document. The integer ``id`` shadows the ObjectId."""
|
||||
|
||||
id: int | None = Field(default=None, validation_alias="_id")
|
||||
|
||||
|
||||
def create_vet_repo():
|
||||
"""Create the vet repository selected by ``settings.repo_backend``.
|
||||
|
||||
Returns:
|
||||
IntIdMemoryRepository | IntIdMongoRepository: Repository wired to the
|
||||
``vets`` collection/store.
|
||||
"""
|
||||
return create_repo("vets", VetDocument)
|
||||
33
standards/src/templates/app/domain/vets/ports/service.py
Normal file
33
standards/src/templates/app/domain/vets/ports/service.py
Normal file
@@ -0,0 +1,33 @@
|
||||
"""# Summary
|
||||
|
||||
CRUD service wiring for the vet aggregate via the hexa container.
|
||||
"""
|
||||
from hexa import build
|
||||
|
||||
from domain.vets.models import Vet
|
||||
from domain.vets.ports.db import VetDocument
|
||||
from infra.adapters.service import CrudsServiceAdaptor
|
||||
|
||||
|
||||
class VetCrudsService(CrudsServiceAdaptor[Vet, VetDocument]):
|
||||
"""Vet CRUD service resolving :class:`VetDocument` from a repo.
|
||||
|
||||
Notes:
|
||||
Instances are created by :func:`get_vet_service`. The ``model`` and
|
||||
``schema`` class attributes bind the domain model and its document type.
|
||||
"""
|
||||
|
||||
model = Vet
|
||||
schema = VetDocument
|
||||
|
||||
|
||||
def get_vet_service(repo) -> VetCrudsService:
|
||||
"""Build a vet CRUD service wired to ``repo``.
|
||||
|
||||
Args:
|
||||
repo (Any): Integer-id vet repository from :func:`create_vet_repo`.
|
||||
|
||||
Returns:
|
||||
VetCrudsService: Ready-to-use vet CRUD service.
|
||||
"""
|
||||
return build(VetCrudsService, instances={"repo": repo})
|
||||
Reference in New Issue
Block a user