domain/entities.rs
1//! Core pet-resort entities and operational records.
2//!
3//! These structs and enums are the normalized domain facts used by workflow, policy, storage, and
4//! source adapters. They should be read as external contracts: every field is either a source-backed
5//! fact, a reviewable derived state, or a safety/labor signal used to reduce manual resort work
6//! without bypassing manager, medical, behavior, payment, or customer-message gates.
7
8use chrono::{DateTime, NaiveDate, Utc};
9use nutype::nutype;
10#[allow(unused_imports)]
11use serde::{Deserialize, Serialize};
12use uuid::Uuid;
13
14use bon::Builder;
15
16use crate::{
17 agent, care, customer, document, incident, location, message, payment, pet, policy, portal,
18 temperament, vaccine,
19};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
22/// Stable identifier for a resort location across source imports, policies, reports, and workflows.
23pub struct LocationId(pub Uuid);
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
26/// Stable identifier for the customer/account responsible for pets, reservations, messages, and payments.
27pub struct CustomerId(pub Uuid);
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30/// Stable identifier for a pet whose care, temperament, vaccine, and reservation facts drive safety decisions.
31pub struct PetId(pub Uuid);
32
33/// Reservation-facing source vocabulary embedded in core entity records.
34pub mod reservation {
35 use serde::{Deserialize, Serialize};
36 use uuid::Uuid;
37
38 use super::PortalProvider;
39
40 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
41 /// Provider or source identifier retained as the stable join key.
42 pub struct Id(pub Uuid);
43
44 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45 /// Normalized lifecycle states used to reconcile source-system data with domain workflows.
46 pub enum Status {
47 /// Inquiry state or source category preserved for normalized resort records.
48 Inquiry,
49 /// Reservation has been requested but not yet confirmed.
50 Requested,
51 /// Missing info state or source category preserved for normalized resort records.
52 MissingInfo,
53 /// Vaccine pending state or source category preserved for normalized resort records.
54 VaccinePending,
55 /// Special review state or source category preserved for normalized resort records.
56 SpecialReview,
57 /// Waitlisted state or source category preserved for normalized resort records.
58 Waitlisted,
59 /// Offered state or source category preserved for normalized resort records.
60 Offered,
61 /// Reservation has been accepted by the resort.
62 Confirmed,
63 /// Pet has arrived and is in care.
64 CheckedIn,
65 /// Active state or source category preserved for normalized resort records.
66 Active,
67 /// Pet has left care and the stay is complete.
68 CheckedOut,
69 /// Reservation is no longer active.
70 Cancelled,
71 /// Rejected state or source category preserved for normalized resort records.
72 Rejected,
73 }
74
75 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76 /// Origin channel for a reservation or operational fact before it becomes trusted domain evidence.
77 pub enum Source {
78 /// Portal state or source category preserved for normalized resort records.
79 Portal(PortalProvider),
80 /// Website form state or source category preserved for normalized resort records.
81 WebsiteForm,
82 /// Phone transcript state or source category preserved for normalized resort records.
83 PhoneTranscript,
84 /// Sms state or source category preserved for normalized resort records.
85 Sms,
86 /// Email state or source category preserved for normalized resort records.
87 Email,
88 /// Staff created state or source category preserved for normalized resort records.
89 StaffCreated,
90 }
91}
92
93#[nutype(
94 sanitize(trim),
95 validate(not_empty, len_char_max = 120),
96 derive(
97 Debug,
98 Clone,
99 PartialEq,
100 Eq,
101 PartialOrd,
102 Ord,
103 Hash,
104 Serialize,
105 Deserialize
106 )
107)]
108pub struct StaffId(String);
109
110/// Manager identifier used when approvals, overrides, or escalations require accountable leadership.
111#[nutype(
112 sanitize(trim),
113 validate(not_empty, len_char_max = 120),
114 derive(
115 Debug,
116 Clone,
117 PartialEq,
118 Eq,
119 PartialOrd,
120 Ord,
121 Hash,
122 Serialize,
123 Deserialize
124 )
125)]
126pub struct ManagerId(String);
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
129/// Resort location record that scopes local capabilities, timezone, brand, and policy references.
130pub struct Location {
131 /// Source-backed id carried by this normalized pet-resort entity.
132 pub id: LocationId,
133 /// Source-backed brand carried by this normalized pet-resort entity.
134 pub brand: Brand,
135 /// Contact or display name used by staff.
136 pub name: location::Name,
137 /// Source-backed timezone carried by this normalized pet-resort entity.
138 pub timezone: location::Timezone,
139 /// Source-backed capabilities carried by this normalized pet-resort entity.
140 pub capabilities: Vec<ServiceKind>,
141 /// Source-backed policies carried by this normalized pet-resort entity.
142 pub policies: LocationPolicyRefs,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146/// Brand family used to group multi-site operating records without losing local resort identity.
147pub enum Brand {
148 /// Nva pet resorts state or source category preserved for normalized resort records.
149 NvaPetResorts,
150 /// Pet suites state or source category preserved for normalized resort records.
151 PetSuites,
152 /// Contact or display name used by staff.
153 NeighborhoodPetResort {
154 /// Name carried by this variant.
155 name: location::Name,
156 },
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
160/// References to the local policy set that controls automation, vaccine, and play-safety decisions.
161pub struct LocationPolicyRefs {
162 /// Source-backed vaccine policy ID carried by this normalized pet-resort entity.
163 pub vaccine_policy_id: policy::Id,
164 /// Source-backed deposit policy ID carried by this normalized pet-resort entity.
165 pub deposit_policy_id: policy::Id,
166 /// Source-backed playgroup policy ID carried by this normalized pet-resort entity.
167 pub playgroup_policy_id: policy::Id,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
171/// Customer/account profile used for reservation ownership, consent-sensitive messaging, and follow-up work.
172pub struct Customer {
173 /// Source-backed id carried by this normalized pet-resort entity.
174 pub id: CustomerId,
175 /// Source-backed full name carried by this normalized pet-resort entity.
176 pub full_name: customer::Name,
177 /// Source-backed email carried by this normalized pet-resort entity.
178 pub email: Option<customer::Email>,
179 /// Source-backed mobile phone carried by this normalized pet-resort entity.
180 pub mobile_phone: Option<customer::Phone>,
181 /// Source-backed preferred contact carried by this normalized pet-resort entity.
182 pub preferred_contact: ContactChannel,
183 /// Source-backed portal account carried by this normalized pet-resort entity.
184 pub portal_account: Option<PortalAccountRef>,
185}
186
187#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
188/// Link to the customer portal account that supplied or owns source records.
189pub struct PortalAccountRef {
190 /// Source-backed provider carried by this normalized pet-resort entity.
191 pub provider: PortalProvider,
192 /// Source-backed external customer ID carried by this normalized pet-resort entity.
193 pub external_customer_id: portal::CustomerId,
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
197/// Portal provider that owns the account or operational record.
198pub enum PortalProvider {
199 /// Gingr reservation and pet-care operating system.
200 Gingr,
201 /// Non-dog, non-cat pet handled by exception policy.
202 Other(String),
203}
204
205#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
206/// Customer contact channel preference or observed route used by draft/message workflows.
207pub enum ContactChannel {
208 /// Email state or source category preserved for normalized resort records.
209 Email,
210 /// Sms state or source category preserved for normalized resort records.
211 Sms,
212 /// Phone state or source category preserved for normalized resort records.
213 Phone,
214 /// Portal state or source category preserved for normalized resort records.
215 Portal,
216}
217
218#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
219/// Pet profile carrying identity, species, age, sex, sterilization, temperament, and care facts for safe service decisions.
220pub struct Pet {
221 /// Source-backed id carried by this normalized pet-resort entity.
222 pub id: PetId,
223 /// Source-backed customer ID carried by this normalized pet-resort entity.
224 pub customer_id: CustomerId,
225 /// Contact or display name used by staff.
226 pub name: pet::Name,
227 /// Source-backed species carried by this normalized pet-resort entity.
228 pub species: Species,
229 /// Source-backed birth date carried by this normalized pet-resort entity.
230 pub birth_date: Option<NaiveDate>,
231 /// Source-backed sex carried by this normalized pet-resort entity.
232 pub sex: Option<Sex>,
233 /// Source-backed spay neuter status carried by this normalized pet-resort entity.
234 pub spay_neuter_status: SpayNeuterStatus,
235 #[builder(default)]
236 /// Source-backed temperament carried by this normalized pet-resort entity.
237 pub temperament: TemperamentProfile,
238 #[builder(default)]
239 /// Source-backed care profile carried by this normalized pet-resort entity.
240 pub care_profile: CareProfile,
241}
242
243#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
244/// Pet species category used by boarding/daycare/play policies and labor planning.
245pub enum Species {
246 /// Dog guest, using dog-specific policy and capacity rules.
247 Dog,
248 /// Cat guest, using cat-specific policy and accommodation rules.
249 Cat,
250 /// Non-dog, non-cat pet handled by exception policy.
251 Other(String),
252}
253
254#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
255/// Recorded pet sex when the source system supplies it.
256pub enum Sex {
257 /// Female pet sex recorded for profile and policy context.
258 Female,
259 /// Male pet sex recorded for profile and policy context.
260 Male,
261 /// Provider role or status could not be mapped confidently.
262 Unknown,
263}
264
265#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
266/// Spay/neuter status used by group-play eligibility, safety review, and policy gating.
267pub enum SpayNeuterStatus {
268 /// Pet has been spayed for policy and playgroup eligibility checks.
269 Spayed,
270 /// Pet has been neutered for policy and playgroup eligibility checks.
271 Neutered,
272 /// Pet is intact and may trigger extra policy review.
273 Intact,
274 /// Provider role or status could not be mapped confidently.
275 Unknown,
276}
277
278#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder, Default)]
279/// Temperament evidence used to decide group-play, individual care, and behavior-review routing.
280pub struct TemperamentProfile {
281 #[builder(default)]
282 /// Source-backed group play observation carried by this normalized pet-resort entity.
283 pub group_play_observation: temperament::GroupPlayObservation,
284 #[builder(default)]
285 /// Source-backed people orientation carried by this normalized pet-resort entity.
286 pub people_orientation: temperament::PeopleOrientation,
287 #[builder(default)]
288 /// Source-backed rating carried by this normalized pet-resort entity.
289 pub rating: temperament::Rating,
290 #[builder(default)]
291 /// Source-backed behavior observations carried by this normalized pet-resort entity.
292 pub behavior_observations: Vec<temperament::BehaviorObservation>,
293 #[builder(default)]
294 /// Source-backed staff notes carried by this normalized pet-resort entity.
295 pub staff_notes: Vec<temperament::StaffNote>,
296}
297
298impl TemperamentProfile {
299 /// Reports whether temperament facts require staff evaluation before group play or similar services.
300 pub fn needs_staff_play_evaluation(&self) -> bool {
301 self.group_play_observation.needs_staff_evaluation()
302 }
303}
304
305#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
306/// Feeding, medication, handling, and special-care summary used for staff handoffs and briefings.
307pub struct CareProfile {
308 /// Source-backed feeding instructions carried by this normalized pet-resort entity.
309 pub feeding_instructions: Option<care::FeedingInstruction>,
310 /// Source-backed medications carried by this normalized pet-resort entity.
311 pub medications: Vec<MedicationInstruction>,
312 /// Source-backed allergies carried by this normalized pet-resort entity.
313 pub allergies: Vec<care::AllergyName>,
314 /// Source-backed medical conditions carried by this normalized pet-resort entity.
315 pub medical_conditions: Vec<care::MedicalConditionName>,
316 /// Source-backed emergency contact carried by this normalized pet-resort entity.
317 pub emergency_contact: Option<care::ContactRef>,
318 /// Source-backed veterinarian contact carried by this normalized pet-resort entity.
319 pub veterinarian_contact: Option<care::ContactRef>,
320}
321
322#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
323/// Medication instruction that must remain explicit for care safety and shift handoff evidence.
324pub struct MedicationInstruction {
325 /// Contact or display name used by staff.
326 pub name: care::MedicationName,
327 /// Source-backed dose carried by this normalized pet-resort entity.
328 pub dose: care::MedicationDose,
329 /// Source-backed schedule carried by this normalized pet-resort entity.
330 pub schedule: care::MedicationSchedule,
331 /// Source-backed review requirement carried by this normalized pet-resort entity.
332 pub review_requirement: care::MedicationReviewRequirement,
333}
334
335#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
336/// Reservation record tying customer, pet, service, status, deposit, add-ons, and safety stops together.
337pub struct Reservation {
338 /// Source-backed id carried by this normalized pet-resort entity.
339 pub id: reservation::Id,
340 /// Source-backed location ID carried by this normalized pet-resort entity.
341 pub location_id: LocationId,
342 /// Source-backed customer ID carried by this normalized pet-resort entity.
343 pub customer_id: CustomerId,
344 /// Source-backed pet IDs carried by this normalized pet-resort entity.
345 pub pet_ids: Vec<PetId>,
346 /// Requested service that drives scheduling and labor estimates.
347 pub service: ServiceKind,
348 /// Source-backed status carried by this normalized pet-resort entity.
349 pub status: reservation::Status,
350 /// Source-backed starts at carried by this normalized pet-resort entity.
351 pub starts_at: DateTime<Utc>,
352 /// Source-backed ends at carried by this normalized pet-resort entity.
353 pub ends_at: DateTime<Utc>,
354 /// Source-backed deposit carried by this normalized pet-resort entity.
355 pub deposit: Option<Deposit>,
356 /// Source-backed source carried by this normalized pet-resort entity.
357 pub source: reservation::Source,
358 #[builder(default)]
359 /// Source-backed requested add ons carried by this normalized pet-resort entity.
360 pub requested_add_ons: Vec<AddOn>,
361 #[builder(default)]
362 /// Source-backed hard stops carried by this normalized pet-resort entity.
363 pub hard_stops: Vec<HardStop>,
364}
365
366#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
367/// Resort service line used for labor planning, capacity, policy, upsell, and workflow routing.
368pub enum ServiceKind {
369 /// Overnight stay service line.
370 Boarding,
371 /// Single-day play visit without overnight lodging.
372 DayPlay,
373 /// Daytime boarding care with lodging-style supervision.
374 DayBoarding,
375 /// Grooming service line or care-note category.
376 Grooming,
377 /// Training service line or care-note category.
378 Training,
379 /// Day-spa service package.
380 DaySpa,
381}
382
383/// Shared deposit type used across the entities boundary.
384pub type Deposit = payment::Deposit;
385/// Shared payment status type used across the entities boundary.
386pub type PaymentStatus = payment::DepositStatus;
387
388#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
389/// Optional reservation add-ons that affect labor, revenue, care planning, or customer follow-up.
390pub enum AddOn {
391 /// Group-play add-on or accommodation feature.
392 GroupPlay,
393 /// Individual play add-on for pets not suited to group play.
394 IndividualPlay,
395 /// Premium suite with webcam visibility.
396 WebcamSuite,
397 /// Bath offered before departure from boarding.
398 ExitBath,
399 /// Progress report shared with the customer during care.
400 PawgressReport,
401 /// Medication service that requires care instructions.
402 MedicationAdministration,
403 /// Non-dog, non-cat pet handled by exception policy.
404 Other(crate::reservation::AddOnLabel),
405}
406
407#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
408/// Non-ignorable condition that blocks or routes a reservation before staff or customer action proceeds.
409pub enum HardStop {
410 /// Missing required vaccine state or source category preserved for normalized resort records.
411 MissingRequiredVaccine(policy::VaccineName),
412 /// Ineligible for group play state or source category preserved for normalized resort records.
413 IneligibleForGroupPlay(policy::play::IneligibilityReason),
414 /// Pet is in heat and requires policy handling.
415 InHeat,
416 /// Age below minimum weeks state or source category preserved for normalized resort records.
417 AgeBelowMinimumWeeks(crate::reservation::AgeThreshold),
418 /// Medical or medication information requires review before service.
419 MedicalOrMedicationReviewRequired,
420 /// Behavior history requires review before service.
421 BehaviorReviewRequired,
422 /// Deposit must be collected before the booking is secure.
423 DepositRequired,
424}
425
426#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
427/// Stable identifier for a document artifact used as vaccine, waiver, medical, or incident evidence.
428pub struct DocumentId(pub Uuid);
429
430#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
431/// Stable identifier for a vaccine compliance record tied to a pet and proof document.
432pub struct VaccineRecordId(pub Uuid);
433
434/// Care-note vocabulary for staff-visible, customer-visible, and internal handoff notes.
435pub mod care_note {
436 use nutype::nutype;
437 #[allow(unused_imports)]
438 use serde::{Deserialize, Serialize};
439 use uuid::Uuid;
440
441 use super::{IncidentId, PetId, reservation};
442
443 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
444 /// Provider or source identifier retained as the stable join key.
445 pub struct Id(pub Uuid);
446
447 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
448 /// Subject that a care, document, incident, audit, or message record is about.
449 pub enum Subject {
450 /// Pet record participating in the workflow.
451 Pet(PetId),
452 /// Reservation record participating in the workflow.
453 Reservation(reservation::Id),
454 /// Incident record participating in the workflow.
455 Incident(IncidentId),
456 }
457
458 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
459 /// Care-note category used to route safety, feeding, medication, behavior, and staff handoff information.
460 pub enum Kind {
461 /// Feeding state or source category preserved for normalized resort records.
462 Feeding,
463 /// Medication state or source category preserved for normalized resort records.
464 Medication,
465 /// Medical state or source category preserved for normalized resort records.
466 Medical,
467 /// Behavior state or source category preserved for normalized resort records.
468 Behavior,
469 /// Grooming service line or care-note category.
470 Grooming,
471 /// Training service line or care-note category.
472 Training,
473 /// General state or source category preserved for normalized resort records.
474 General,
475 }
476
477 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
478 /// Visibility boundary that determines whether a care note may be shown to customers or only staff.
479 pub enum Visibility {
480 /// Internal only state or source category preserved for normalized resort records.
481 InternalOnly,
482 /// Customer visible state or source category preserved for normalized resort records.
483 CustomerVisible,
484 /// Customer visible after review state or source category preserved for normalized resort records.
485 CustomerVisibleAfterReview,
486 }
487
488 #[nutype(
489 sanitize(trim),
490 validate(not_empty, len_char_max = 2000),
491 derive(
492 Debug,
493 Clone,
494 PartialEq,
495 Eq,
496 PartialOrd,
497 Ord,
498 Hash,
499 Serialize,
500 Deserialize
501 )
502 )]
503 pub struct Body(String);
504}
505
506#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
507/// Stable identifier for a pet, customer, or operational incident requiring evidence and follow-up.
508pub struct IncidentId(pub Uuid);
509
510#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
511/// Stable identifier for a customer or internal message workflow.
512pub struct MessageId(pub Uuid);
513
514/// Approval record vocabulary for review-gated automation outcomes.
515pub mod approval {
516 use bon::Builder;
517 use chrono::{DateTime, Utc};
518 use serde::{Deserialize, Serialize};
519 use uuid::Uuid;
520
521 use super::{
522 ActorRef, DocumentId, IncidentId, MessageId, VaccineRecordId, policy, reservation,
523 };
524
525 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
526 /// Provider or source identifier retained as the stable join key.
527 pub struct Id(pub Uuid);
528
529 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
530 /// Approval record showing who decided, what target was reviewed, and what lifecycle state resulted.
531 pub struct Record {
532 /// Source-backed id carried by this normalized pet-resort entity.
533 pub id: Id,
534 /// Source-backed target carried by this normalized pet-resort entity.
535 pub target: Target,
536 /// Source-backed gate carried by this normalized pet-resort entity.
537 pub gate: policy::ReviewGate,
538 /// Source-backed lifecycle carried by this normalized pet-resort entity.
539 pub lifecycle: Lifecycle,
540 /// Source-backed requested by carried by this normalized pet-resort entity.
541 pub requested_by: ActorRef,
542 /// Source-backed requested at carried by this normalized pet-resort entity.
543 pub requested_at: DateTime<Utc>,
544 #[builder(default)]
545 /// Source-backed audit refs carried by this normalized pet-resort entity.
546 pub audit_refs: Vec<crate::audit::EventId>,
547 }
548
549 impl Record {
550 /// Returns the normalized operational status represented by this record.
551 pub fn status(&self) -> Status {
552 self.lifecycle.status()
553 }
554
555 /// Reports whether this approval gate currently applies to the target workflow.
556 pub fn is_applicable(&self) -> bool {
557 matches!(self.lifecycle, Lifecycle::Approved { .. })
558 }
559
560 /// Reports whether the review lifecycle has reached an approval, rejection, or non-applicable endpoint.
561 pub fn is_terminal_decision(&self) -> bool {
562 self.lifecycle.is_terminal_decision()
563 }
564
565 /// Returns the accountable actor and timestamp when the review reached a terminal decision.
566 pub fn decision_actor_and_time(&self) -> Option<(&ActorRef, DateTime<Utc>)> {
567 self.lifecycle.decision_actor_and_time()
568 }
569 }
570
571 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
572 /// Operational artifact that an approval gate is allowed to approve, reject, or mark non-applicable.
573 pub enum Target {
574 /// Reservation record participating in the workflow.
575 Reservation(reservation::Id),
576 /// Customer or pet document participating in review.
577 Document(DocumentId),
578 /// Vaccination document or status record under review.
579 VaccineRecord(VaccineRecordId),
580 /// Incident record participating in the workflow.
581 Incident(IncidentId),
582 /// Customer communication record participating in approval.
583 Message(MessageId),
584 }
585
586 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
587 /// Approval lifecycle state for draft, requested, approved, rejected, or non-applicable review gates.
588 pub enum Lifecycle {
589 /// Approval requested state or source category preserved for normalized resort records.
590 ApprovalRequested,
591 /// Approved state or source category preserved for normalized resort records.
592 Approved {
593 /// Source-backed decided by carried by this normalized pet-resort entity.
594 decided_by: ActorRef,
595 /// Source-backed decided at carried by this normalized pet-resort entity.
596 decided_at: DateTime<Utc>,
597 },
598 /// Rejected state or source category preserved for normalized resort records.
599 Rejected {
600 /// Source-backed decided by carried by this normalized pet-resort entity.
601 decided_by: ActorRef,
602 /// Source-backed decided at carried by this normalized pet-resort entity.
603 decided_at: DateTime<Utc>,
604 },
605 /// Reservation is no longer active.
606 Cancelled,
607 /// Superseded state or source category preserved for normalized resort records.
608 Superseded,
609 }
610
611 impl Lifecycle {
612 /// Returns the normalized operational status represented by this record.
613 pub fn status(&self) -> Status {
614 match self {
615 Self::ApprovalRequested => Status::ApprovalRequested,
616 Self::Approved { .. } => Status::Approved,
617 Self::Rejected { .. } => Status::Rejected,
618 Self::Cancelled => Status::Cancelled,
619 Self::Superseded => Status::Superseded,
620 }
621 }
622
623 /// Reports whether the review lifecycle has reached an approval, rejection, or non-applicable endpoint.
624 pub fn is_terminal_decision(&self) -> bool {
625 matches!(self, Self::Approved { .. } | Self::Rejected { .. })
626 }
627
628 /// Returns the accountable actor and timestamp when the review reached a terminal decision.
629 pub fn decision_actor_and_time(&self) -> Option<(&ActorRef, DateTime<Utc>)> {
630 match self {
631 Self::Approved {
632 decided_by,
633 decided_at,
634 }
635 | Self::Rejected {
636 decided_by,
637 decided_at,
638 } => Some((decided_by, *decided_at)),
639 Self::ApprovalRequested | Self::Cancelled | Self::Superseded => None,
640 }
641 }
642 }
643
644 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
645 /// Normalized lifecycle states used to reconcile source-system data with domain workflows.
646 pub enum Status {
647 /// Approval requested state or source category preserved for normalized resort records.
648 ApprovalRequested,
649 /// Approved state or source category preserved for normalized resort records.
650 Approved,
651 /// Rejected state or source category preserved for normalized resort records.
652 Rejected,
653 /// Reservation is no longer active.
654 Cancelled,
655 /// Superseded state or source category preserved for normalized resort records.
656 Superseded,
657 }
658}
659
660#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
661/// Document record tying storage, classification, source, scan, redaction, and review status together.
662pub struct Document {
663 /// Source-backed id carried by this normalized pet-resort entity.
664 pub id: DocumentId,
665 /// Source-backed location ID carried by this normalized pet-resort entity.
666 pub location_id: LocationId,
667 /// Source-backed subject carried by this normalized pet-resort entity.
668 pub subject: DocumentSubject,
669 /// Source-backed classification carried by this normalized pet-resort entity.
670 pub classification: document::Classification,
671 /// Source-backed source carried by this normalized pet-resort entity.
672 pub source: document::Source,
673 /// Source-backed uploaded by actor carried by this normalized pet-resort entity.
674 pub uploaded_by_actor: ActorRef,
675 /// Source-backed uploaded at carried by this normalized pet-resort entity.
676 pub uploaded_at: DateTime<Utc>,
677 /// Source-backed original file carried by this normalized pet-resort entity.
678 pub original_file: document::OriginalFile,
679 /// Source-backed storage ref carried by this normalized pet-resort entity.
680 pub storage_ref: document::StorageRef,
681 /// Source-backed virus scan status carried by this normalized pet-resort entity.
682 pub virus_scan_status: document::VirusScanStatus,
683 /// Source-backed pii redaction status carried by this normalized pet-resort entity.
684 pub pii_redaction_status: document::PiiRedactionStatus,
685 /// Source-backed verification status carried by this normalized pet-resort entity.
686 pub verification_status: document::Status,
687 #[builder(default)]
688 /// Source-backed audit refs carried by this normalized pet-resort entity.
689 pub audit_refs: Vec<crate::audit::EventId>,
690}
691
692impl Document {
693 /// Reports whether the document must be reviewed before agents or staff treat it as usable evidence.
694 pub fn requires_human_review_before_use(&self) -> bool {
695 matches!(
696 self.verification_status,
697 document::Status::Received
698 | document::Status::Extracting
699 | document::Status::ExtractionFailed
700 | document::Status::AwaitingReview
701 | document::Status::QuarantinedRejected
702 ) || !matches!(self.virus_scan_status, document::VirusScanStatus::Passed)
703 }
704}
705
706#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
707/// Entity or workflow subject a document is evidence for.
708pub enum DocumentSubject {
709 /// Customer record participating in the workflow.
710 Customer(CustomerId),
711 /// Pet record participating in the workflow.
712 Pet(PetId),
713 /// Reservation record participating in the workflow.
714 Reservation(reservation::Id),
715 /// Incident record participating in the workflow.
716 Incident(IncidentId),
717}
718
719#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
720/// Vaccine compliance record linking pet, vaccine name, expiration, proof document, and review status.
721pub struct VaccineRecord {
722 /// Source-backed id carried by this normalized pet-resort entity.
723 pub id: VaccineRecordId,
724 /// Pet receiving the grooming or care service.
725 pub pet_id: PetId,
726 /// Source-backed vaccine name carried by this normalized pet-resort entity.
727 pub vaccine_name: policy::VaccineName,
728 /// Source-backed source document ID carried by this normalized pet-resort entity.
729 pub source_document_id: DocumentId,
730 /// Source-backed status carried by this normalized pet-resort entity.
731 pub status: vaccine::Status,
732 /// Source-backed effective on carried by this normalized pet-resort entity.
733 pub effective_on: NaiveDate,
734 /// Source-backed expires on carried by this normalized pet-resort entity.
735 pub expires_on: Option<NaiveDate>,
736 /// Source-backed review gate carried by this normalized pet-resort entity.
737 pub review_gate: policy::ReviewGate,
738 #[builder(default)]
739 /// Source-backed audit refs carried by this normalized pet-resort entity.
740 pub audit_refs: Vec<crate::audit::EventId>,
741}
742
743impl VaccineRecord {
744 /// Reports whether vaccine proof is still unverified, rejected, or otherwise unsafe for compliance automation.
745 pub fn requires_human_review_before_compliance(&self) -> bool {
746 matches!(
747 self.status,
748 vaccine::Status::SuggestedExtracted
749 | vaccine::Status::PendingReview
750 | vaccine::Status::Rejected
751 | vaccine::Status::ExceptionRequested
752 )
753 }
754}
755
756#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
757/// Care note with author, visibility, subject, body, source, and review-sensitive timestamps.
758pub struct CareNote {
759 /// Source-backed id carried by this normalized pet-resort entity.
760 pub id: care_note::Id,
761 /// Source-backed subject carried by this normalized pet-resort entity.
762 pub subject: care_note::Subject,
763 /// Source-backed kind carried by this normalized pet-resort entity.
764 pub kind: care_note::Kind,
765 /// Source-backed visibility carried by this normalized pet-resort entity.
766 pub visibility: care_note::Visibility,
767 /// Source-backed body carried by this normalized pet-resort entity.
768 pub body: care_note::Body,
769 /// Source-backed author carried by this normalized pet-resort entity.
770 pub author: ActorRef,
771 /// Source-backed recorded at carried by this normalized pet-resort entity.
772 pub recorded_at: DateTime<Utc>,
773 #[builder(default)]
774 /// Source-backed audit refs carried by this normalized pet-resort entity.
775 pub audit_refs: Vec<crate::audit::EventId>,
776}
777
778impl CareNote {
779 /// Reports whether this care note may be surfaced to customers without an additional approval gate.
780 pub fn is_customer_visible_without_review(&self) -> bool {
781 matches!(self.visibility, care_note::Visibility::CustomerVisible)
782 && !matches!(
783 self.kind,
784 care_note::Kind::Medication | care_note::Kind::Medical | care_note::Kind::Behavior
785 )
786 }
787}
788
789#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
790/// Incident record used for manager attention, safety follow-up, customer messaging, and audit evidence.
791pub struct Incident {
792 /// Source-backed id carried by this normalized pet-resort entity.
793 pub id: IncidentId,
794 /// Source-backed location ID carried by this normalized pet-resort entity.
795 pub location_id: LocationId,
796 /// Source-backed primary subject carried by this normalized pet-resort entity.
797 pub primary_subject: IncidentSubject,
798 /// Source-backed category carried by this normalized pet-resort entity.
799 pub category: incident::Category,
800 /// Source-backed severity carried by this normalized pet-resort entity.
801 pub severity: incident::Severity,
802 /// Source-backed status carried by this normalized pet-resort entity.
803 pub status: incident::Status,
804 /// Source-backed reported by carried by this normalized pet-resort entity.
805 pub reported_by: ActorRef,
806 /// Source-backed reported at carried by this normalized pet-resort entity.
807 pub reported_at: DateTime<Utc>,
808 /// Source-backed summary carried by this normalized pet-resort entity.
809 pub summary: incident::Summary,
810 #[builder(default)]
811 /// Source-backed required review gates carried by this normalized pet-resort entity.
812 pub required_review_gates: Vec<policy::ReviewGate>,
813 #[builder(default)]
814 /// Source-backed audit refs carried by this normalized pet-resort entity.
815 pub audit_refs: Vec<crate::audit::EventId>,
816}
817
818impl Incident {
819 /// Reports whether the incident is still active enough to require manager attention.
820 pub fn requires_manager_attention(&self) -> bool {
821 matches!(
822 self.status,
823 incident::Status::NeedsManagerReview | incident::Status::LegalHold
824 ) || matches!(
825 self.severity,
826 incident::Severity::High | incident::Severity::Critical
827 ) || self
828 .required_review_gates
829 .contains(&policy::ReviewGate::ManagerApproval)
830 }
831}
832
833#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
834/// Entity or workflow subject affected by an incident.
835pub enum IncidentSubject {
836 /// Pet record participating in the workflow.
837 Pet(PetId),
838 /// Reservation record participating in the workflow.
839 Reservation(reservation::Id),
840 /// Customer record participating in the workflow.
841 Customer(CustomerId),
842 /// Resort location record participating in the workflow.
843 Location(LocationId),
844}
845
846#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Builder)]
847/// Customer/internal message record that tracks subject, channel, draft/reference body, approval, and delivery state.
848pub struct Message {
849 /// Source-backed id carried by this normalized pet-resort entity.
850 pub id: MessageId,
851 /// Source-backed subject carried by this normalized pet-resort entity.
852 pub subject: MessageSubject,
853 /// Source-backed direction carried by this normalized pet-resort entity.
854 pub direction: message::Direction,
855 /// Source-backed channel carried by this normalized pet-resort entity.
856 pub channel: message::Channel,
857 /// Source-backed status carried by this normalized pet-resort entity.
858 pub status: message::Status,
859 /// Source-backed body ref carried by this normalized pet-resort entity.
860 pub body_ref: message::BodyRef,
861 /// Source-backed approval gate carried by this normalized pet-resort entity.
862 pub approval_gate: Option<policy::ReviewGate>,
863 #[builder(default)]
864 /// Source-backed audit refs carried by this normalized pet-resort entity.
865 pub audit_refs: Vec<crate::audit::EventId>,
866}
867
868impl Message {
869 /// Reports whether the message is still a draft or awaiting approval before any outbound send.
870 pub fn requires_approval_before_send(&self) -> bool {
871 self.approval_gate.is_some()
872 || matches!(self.status, message::Status::ApprovalRequested)
873 || matches!(self.direction, message::Direction::OutboundDraft)
874 }
875}
876
877#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
878/// Entity or workflow subject that a message refers to.
879pub enum MessageSubject {
880 /// Customer record participating in the workflow.
881 Customer(CustomerId),
882 /// Pet record participating in the workflow.
883 Pet(PetId),
884 /// Reservation record participating in the workflow.
885 Reservation(reservation::Id),
886 /// Incident record participating in the workflow.
887 Incident(IncidentId),
888 /// Approval decision record participating in audit history.
889 Approval(approval::Id),
890}
891
892/// Audit vocabulary for source-backed event trails across automated and staff actions.
893pub mod audit {
894 use chrono::{DateTime, Utc};
895 use nutype::nutype;
896 #[allow(unused_imports)]
897 use serde::{Deserialize, Serialize};
898 use std::collections::BTreeMap;
899
900 use super::{
901 CustomerId, DocumentId, IncidentId, LocationId, MessageId, PetId, VaccineRecordId,
902 approval, care_note, reservation,
903 };
904
905 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
906 /// Audit event capturing actor, subject, action, timestamp, and metadata evidence.
907 pub struct Event {
908 /// Source-backed at carried by this normalized pet-resort entity.
909 pub at: DateTime<Utc>,
910 /// Source-backed actor carried by this normalized pet-resort entity.
911 pub actor: super::ActorRef,
912 /// Source-backed subject carried by this normalized pet-resort entity.
913 pub subject: Subject,
914 /// Source-backed action carried by this normalized pet-resort entity.
915 pub action: Action,
916 /// Source-backed metadata carried by this normalized pet-resort entity.
917 pub metadata: BTreeMap<MetadataKey, MetadataValue>,
918 }
919
920 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
921 /// Subject that a care, document, incident, audit, or message record is about.
922 pub enum Subject {
923 /// Customer record participating in the workflow.
924 Customer(CustomerId),
925 /// Pet record participating in the workflow.
926 Pet(PetId),
927 /// Reservation record participating in the workflow.
928 Reservation(reservation::Id),
929 /// Resort location record participating in the workflow.
930 Location(LocationId),
931 /// Customer or pet document participating in review.
932 Document(DocumentId),
933 /// Vaccination document or status record under review.
934 VaccineRecord(VaccineRecordId),
935 /// Care note state or source category preserved for normalized resort records.
936 CareNote(care_note::Id),
937 /// Incident record participating in the workflow.
938 Incident(IncidentId),
939 /// Customer communication record participating in approval.
940 Message(MessageId),
941 /// Approval decision record participating in audit history.
942 Approval(approval::Id),
943 /// Workflow event state or source category preserved for normalized resort records.
944 WorkflowEvent(crate::workflow::EventId),
945 /// External system object referenced from domain history.
946 External {
947 /// Source-backed provider carried by this normalized pet-resort entity.
948 provider: crate::workflow::external::Provider,
949 /// Source-backed id carried by this normalized pet-resort entity.
950 id: crate::workflow::external::Id,
951 },
952 }
953
954 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
955 /// Auditable action category produced by staff, source ingestion, policy, approval, or automation.
956 pub enum Action {
957 /// Customer profile updated state or source category preserved for normalized resort records.
958 CustomerProfileUpdated,
959 /// Pet profile updated state or source category preserved for normalized resort records.
960 PetProfileUpdated,
961 /// Reservation status suggested state or source category preserved for normalized resort records.
962 ReservationStatusSuggested,
963 /// Reservation status changed state or source category preserved for normalized resort records.
964 ReservationStatusChanged,
965 /// Policy decision recorded state or source category preserved for normalized resort records.
966 PolicyDecisionRecorded,
967 /// Document received state or source category preserved for normalized resort records.
968 DocumentReceived,
969 /// Vaccine record review requested state or source category preserved for normalized resort records.
970 VaccineRecordReviewRequested,
971 /// Incident status changed state or source category preserved for normalized resort records.
972 IncidentStatusChanged,
973 /// Message approval requested state or source category preserved for normalized resort records.
974 MessageApprovalRequested,
975 /// Approval decision recorded state or source category preserved for normalized resort records.
976 ApprovalDecisionRecorded,
977 /// Workflow event recorded state or source category preserved for normalized resort records.
978 WorkflowEventRecorded,
979 /// Extension point for provider-specific values not modeled directly.
980 Extension(ActionLabel),
981 }
982
983 /// Human-readable audit action label for imported or locally defined operational events.
984 #[nutype(
985 sanitize(trim),
986 validate(not_empty, len_char_max = 160),
987 derive(
988 Debug,
989 Clone,
990 PartialEq,
991 Eq,
992 PartialOrd,
993 Ord,
994 Hash,
995 Serialize,
996 Deserialize
997 )
998 )]
999 pub struct ActionLabel(String);
1000
1001 /// Audit metadata key used to preserve source evidence without flattening it into prose.
1002 #[nutype(
1003 sanitize(trim),
1004 validate(not_empty, len_char_max = 80),
1005 derive(
1006 Debug,
1007 Clone,
1008 PartialEq,
1009 Eq,
1010 PartialOrd,
1011 Ord,
1012 Hash,
1013 Serialize,
1014 Deserialize
1015 )
1016 )]
1017 pub struct MetadataKey(String);
1018
1019 /// Audit metadata value attached to an event for review, reporting, or source repair.
1020 #[nutype(
1021 sanitize(trim),
1022 validate(not_empty, len_char_max = 500),
1023 derive(
1024 Debug,
1025 Clone,
1026 PartialEq,
1027 Eq,
1028 PartialOrd,
1029 Ord,
1030 Hash,
1031 Serialize,
1032 Deserialize
1033 )
1034 )]
1035 pub struct MetadataValue(String);
1036}
1037
1038#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1039/// Actor that performed or is accountable for an audited action.
1040pub enum ActorRef {
1041 /// Customer record participating in the workflow.
1042 Customer(CustomerId),
1043 /// Source-backed staff ID carried by this normalized pet-resort entity.
1044 Staff {
1045 /// Staff id carried by this variant.
1046 staff_id: StaffId,
1047 },
1048 /// Source-backed manager ID carried by this normalized pet-resort entity.
1049 Manager {
1050 /// Manager id carried by this variant.
1051 manager_id: ManagerId,
1052 },
1053 /// System state or source category preserved for normalized resort records.
1054 System,
1055 /// Source-backed workflow carried by this normalized pet-resort entity.
1056 Agent {
1057 /// Workflow carried by this variant.
1058 workflow: agent::Name,
1059 },
1060}