ashmatics-datamodels 0.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. ashmatics_datamodels/__init__.py +38 -0
  2. ashmatics_datamodels/common/__init__.py +80 -0
  3. ashmatics_datamodels/common/base.py +76 -0
  4. ashmatics_datamodels/common/enums.py +119 -0
  5. ashmatics_datamodels/common/frameworks.py +168 -0
  6. ashmatics_datamodels/common/regulators.py +152 -0
  7. ashmatics_datamodels/common/validators.py +237 -0
  8. ashmatics_datamodels/documents/__init__.py +272 -0
  9. ashmatics_datamodels/documents/base.py +438 -0
  10. ashmatics_datamodels/documents/evidence.py +236 -0
  11. ashmatics_datamodels/documents/governance.py +696 -0
  12. ashmatics_datamodels/documents/governance_enums.py +151 -0
  13. ashmatics_datamodels/documents/manufacturers.py +299 -0
  14. ashmatics_datamodels/documents/models.py +431 -0
  15. ashmatics_datamodels/documents/products.py +347 -0
  16. ashmatics_datamodels/documents/regulatory.py +981 -0
  17. ashmatics_datamodels/documents/use_cases.py +335 -0
  18. ashmatics_datamodels/fda/__init__.py +165 -0
  19. ashmatics_datamodels/fda/adverse_events.py +309 -0
  20. ashmatics_datamodels/fda/classifications.py +389 -0
  21. ashmatics_datamodels/fda/clearances.py +481 -0
  22. ashmatics_datamodels/fda/enums.py +186 -0
  23. ashmatics_datamodels/fda/manufacturers.py +180 -0
  24. ashmatics_datamodels/fda/products.py +228 -0
  25. ashmatics_datamodels/fda/recalls.py +213 -0
  26. ashmatics_datamodels/use_cases/__init__.py +57 -0
  27. ashmatics_datamodels/use_cases/categories.py +116 -0
  28. ashmatics_datamodels/use_cases/enums.py +137 -0
  29. ashmatics_datamodels/use_cases/use_cases.py +188 -0
  30. ashmatics_datamodels/utils/__init__.py +19 -0
  31. ashmatics_datamodels-0.3.2.dist-info/METADATA +134 -0
  32. ashmatics_datamodels-0.3.2.dist-info/RECORD +34 -0
  33. ashmatics_datamodels-0.3.2.dist-info/WHEEL +4 -0
  34. ashmatics_datamodels-0.3.2.dist-info/licenses/LICENSE +190 -0
@@ -0,0 +1,38 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ AshMatics Core DataModels
17
+
18
+ Canonical Pydantic data models for AshMatics healthcare applications.
19
+ Provides FDA vocabulary, regulatory schemas, clinical AI use case taxonomy,
20
+ and MongoDB document schemas with standardized three-tier structure.
21
+
22
+ Usage:
23
+ from ashmatics_datamodels.fda import FDA_ManufacturerBase, FDA_510kClearance
24
+ from ashmatics_datamodels.common import AshMaticsBaseModel
25
+ from ashmatics_datamodels.use_cases import UseCaseCategoryBase
26
+ from ashmatics_datamodels.documents import EvidenceDocument, RegulatoryDocument
27
+ """
28
+
29
+ __version__ = "0.3.2"
30
+ __author__ = "Asher Informatics PBC"
31
+
32
+ from ashmatics_datamodels.common import AshMaticsBaseModel, TimestampedModel
33
+
34
+ __all__ = [
35
+ "__version__",
36
+ "AshMaticsBaseModel",
37
+ "TimestampedModel",
38
+ ]
@@ -0,0 +1,80 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Common base models and utilities shared across all jurisdictions.
17
+ """
18
+
19
+ from ashmatics_datamodels.common.base import (
20
+ AshMaticsBaseModel,
21
+ AuditedModel,
22
+ TimestampedModel,
23
+ )
24
+ from ashmatics_datamodels.common.enums import (
25
+ AuthorizationStatus,
26
+ ParsingStatus,
27
+ Region,
28
+ RegulatoryStatus,
29
+ RiskCategory,
30
+ )
31
+ from ashmatics_datamodels.common.frameworks import (
32
+ RegulatoryFrameworkBase,
33
+ RegulatoryFrameworkCreate,
34
+ RegulatoryFrameworkResponse,
35
+ RegulatoryFrameworkStats,
36
+ RegulatoryFrameworkSummary,
37
+ RegulatoryFrameworkUpdate,
38
+ )
39
+ from ashmatics_datamodels.common.regulators import (
40
+ RegulatorBase,
41
+ RegulatorCreate,
42
+ RegulatorResponse,
43
+ RegulatorStats,
44
+ RegulatorSummary,
45
+ RegulatorUpdate,
46
+ )
47
+ from ashmatics_datamodels.common.validators import (
48
+ validate_country_code,
49
+ validate_iso_date,
50
+ )
51
+
52
+ __all__ = [
53
+ # Base models
54
+ "AshMaticsBaseModel",
55
+ "TimestampedModel",
56
+ "AuditedModel",
57
+ # Enums
58
+ "AuthorizationStatus",
59
+ "RegulatoryStatus",
60
+ "RiskCategory",
61
+ "ParsingStatus",
62
+ "Region",
63
+ # Validators
64
+ "validate_country_code",
65
+ "validate_iso_date",
66
+ # Regulators
67
+ "RegulatorBase",
68
+ "RegulatorCreate",
69
+ "RegulatorUpdate",
70
+ "RegulatorResponse",
71
+ "RegulatorSummary",
72
+ "RegulatorStats",
73
+ # Regulatory Frameworks
74
+ "RegulatoryFrameworkBase",
75
+ "RegulatoryFrameworkCreate",
76
+ "RegulatoryFrameworkUpdate",
77
+ "RegulatoryFrameworkResponse",
78
+ "RegulatoryFrameworkSummary",
79
+ "RegulatoryFrameworkStats",
80
+ ]
@@ -0,0 +1,76 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Base model classes for all AshMatics schemas.
17
+
18
+ These models are database-agnostic and provide common configuration
19
+ and functionality across all domain-specific schemas.
20
+ """
21
+
22
+ from datetime import datetime
23
+ from typing import Optional
24
+
25
+ from pydantic import BaseModel, ConfigDict, Field
26
+
27
+
28
+ class AshMaticsBaseModel(BaseModel):
29
+ """
30
+ Base model for all AshMatics schemas.
31
+
32
+ Configuration:
33
+ - from_attributes: Enable ORM mode for SQLAlchemy integration in apps
34
+ - validate_assignment: Validate on field assignment
35
+ - use_enum_values: Use enum values, not names, in serialization
36
+ - extra: Forbid extra fields by default for strict validation
37
+ - str_strip_whitespace: Strip whitespace from string fields
38
+ """
39
+
40
+ model_config = ConfigDict(
41
+ from_attributes=True,
42
+ validate_assignment=True,
43
+ use_enum_values=True,
44
+ extra="forbid",
45
+ str_strip_whitespace=True,
46
+ )
47
+
48
+
49
+ class TimestampedModel(AshMaticsBaseModel):
50
+ """
51
+ Model with creation and update timestamps.
52
+
53
+ Use for entities that need temporal tracking but not full audit trails.
54
+ """
55
+
56
+ created_at: Optional[datetime] = Field(
57
+ None, description="Timestamp when record was created"
58
+ )
59
+ updated_at: Optional[datetime] = Field(
60
+ None, description="Timestamp when record was last updated"
61
+ )
62
+
63
+
64
+ class AuditedModel(TimestampedModel):
65
+ """
66
+ Model with full audit trail support.
67
+
68
+ Use for entities requiring user attribution for changes.
69
+ """
70
+
71
+ created_by: Optional[str] = Field(
72
+ None, description="User ID or system identifier who created the record"
73
+ )
74
+ updated_by: Optional[str] = Field(
75
+ None, description="User ID or system identifier who last updated the record"
76
+ )
@@ -0,0 +1,119 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Common enumerations shared across jurisdictions.
17
+
18
+ These enums represent concepts that are jurisdiction-agnostic or
19
+ shared across multiple regulatory frameworks.
20
+ """
21
+
22
+ from enum import Enum
23
+
24
+
25
+ class AuthorizationStatus(str, Enum):
26
+ """
27
+ Lifecycle status of regulatory authorizations.
28
+
29
+ Workflow: UNDER_REVIEW → ACTIVE → {EXPIRED | WITHDRAWN | SUSPENDED}
30
+
31
+ Used for tracking state of 510(k) clearances, PMA approvals,
32
+ CE Marks, and other regulatory authorizations.
33
+
34
+ Reference: ASHMATICS Workflow Ontology
35
+ """
36
+
37
+ ACTIVE = "active" # Authorization currently valid and in effect
38
+ EXPIRED = "expired" # Authorization past expiry date, no longer valid
39
+ WITHDRAWN = "withdrawn" # Authorization voluntarily withdrawn by holder
40
+ SUSPENDED = "suspended" # Authorization temporarily suspended by authority
41
+ UNDER_REVIEW = "under_review" # Application under regulatory review
42
+
43
+
44
+ class RegulatoryStatus(str, Enum):
45
+ """
46
+ Overall regulatory standing of a product across jurisdictions.
47
+
48
+ Workflow: PENDING → {APPROVED | REJECTED}
49
+ Post-Market: APPROVED → {WITHDRAWN | SUSPENDED}
50
+
51
+ Represents product-level regulatory status, distinct from
52
+ individual authorization status.
53
+
54
+ Reference: ASHMATICS Workflow Ontology
55
+ """
56
+
57
+ APPROVED = "approved" # Product has received regulatory approval
58
+ PENDING = "pending" # Product submission under regulatory review
59
+ REJECTED = "rejected" # Product submission rejected by authority
60
+ WITHDRAWN = "withdrawn" # Product voluntarily withdrawn from market
61
+ SUSPENDED = "suspended" # Product marketing suspended by authority
62
+
63
+
64
+ class RiskCategory(str, Enum):
65
+ """
66
+ General risk categorization for medical devices.
67
+
68
+ Maps to FDA Device Class: Low (I), Moderate (II), High (III)
69
+
70
+ Used for risk-based filtering and analysis across regulatory
71
+ jurisdictions. Aligns with FDA device classification system.
72
+
73
+ Reference: ASHMATICS Risk Ontology
74
+ """
75
+
76
+ LOW = "low" # Minimal potential for harm (Class I devices)
77
+ MODERATE = "moderate" # Moderate potential requiring special controls (Class II)
78
+ HIGH = "high" # Significant potential for harm (Class III)
79
+
80
+
81
+ class ParsingStatus(str, Enum):
82
+ """
83
+ Document parsing workflow status.
84
+
85
+ Workflow: PENDING → IN_PROGRESS → {COMPLETED | FAILED}
86
+ Alternative: PENDING → SKIPPED
87
+
88
+ Used for tracking AI-powered document processing, chunking,
89
+ and knowledge graph extraction workflows.
90
+
91
+ Reference: ASHMATICS Internal Workflow Ontology
92
+ """
93
+
94
+ PENDING = "pending" # Document queued for parsing
95
+ IN_PROGRESS = "in_progress" # Document currently being processed
96
+ COMPLETED = "completed" # Document successfully parsed
97
+ FAILED = "failed" # Document parsing encountered errors
98
+ SKIPPED = "skipped" # Document intentionally not parsed
99
+
100
+
101
+ class Region(str, Enum):
102
+ """
103
+ Geographic regions for manufacturer categorization.
104
+
105
+ Maps to ISO 3166-1 country codes where applicable, with custom
106
+ regional groupings (EU, APAC, LATAM).
107
+ """
108
+
109
+ USA = "USA"
110
+ EU = "EU"
111
+ DE = "DE"
112
+ UK = "UK"
113
+ CHINA = "CHINA"
114
+ APAC = "APAC"
115
+ LATAM = "LATAM"
116
+ AUS = "AUS"
117
+ JP = "JP"
118
+ KR = "KR"
119
+ OTHER = "OTHER"
@@ -0,0 +1,168 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Regulatory Framework schemas for multi-jurisdiction support.
17
+
18
+ Regulatory frameworks represent specific approval pathways within
19
+ each jurisdiction (510(k), PMA, CE Mark, ARTG, etc.).
20
+
21
+ Migrated from: KB src/app/schemas/regulatory_framework_schema.py
22
+ JIRA: ASHKBAPP-28 (Phase 2.1)
23
+ """
24
+
25
+ from datetime import datetime
26
+ from typing import Optional
27
+
28
+ from pydantic import Field
29
+
30
+ from ashmatics_datamodels.common.base import AshMaticsBaseModel, TimestampedModel
31
+ from ashmatics_datamodels.common.regulators import RegulatorSummary
32
+
33
+
34
+ class RegulatoryFrameworkBase(AshMaticsBaseModel):
35
+ """
36
+ Base schema for regulatory frameworks.
37
+
38
+ A regulatory framework represents a specific pathway for device
39
+ authorization (e.g., FDA 510(k), FDA PMA, EU CE Mark, TGA ARTG).
40
+ """
41
+
42
+ framework_code: str = Field(
43
+ ...,
44
+ max_length=50,
45
+ description="Unique framework code (e.g., '510K', 'PMA', 'CE_MARK', 'ARTG')",
46
+ )
47
+ framework_name: str = Field(
48
+ ...,
49
+ max_length=255,
50
+ description="Full framework name (e.g., 'Premarket Notification 510(k)')",
51
+ )
52
+ authorization_type: str = Field(
53
+ ...,
54
+ max_length=50,
55
+ description="Type: clearance, approval, registration, notification, self_certification",
56
+ )
57
+ requires_premarket_review: bool = Field(
58
+ ...,
59
+ description="Whether premarket review by regulator is required",
60
+ )
61
+ requires_clinical_data: bool = Field(
62
+ False,
63
+ description="Whether clinical data submission is required",
64
+ )
65
+ description: Optional[str] = Field(
66
+ None,
67
+ description="Detailed framework description",
68
+ )
69
+ typical_review_time_days: Optional[int] = Field(
70
+ None,
71
+ ge=0,
72
+ description="Typical review time in days",
73
+ )
74
+ renewal_required: bool = Field(
75
+ False,
76
+ description="Whether periodic renewal is required",
77
+ )
78
+ renewal_frequency_years: Optional[int] = Field(
79
+ None,
80
+ ge=1,
81
+ description="Renewal frequency in years (if applicable)",
82
+ )
83
+ is_active: bool = Field(
84
+ True,
85
+ description="Whether framework is currently active",
86
+ )
87
+
88
+
89
+ class RegulatoryFrameworkCreate(RegulatoryFrameworkBase):
90
+ """Schema for creating a new regulatory framework."""
91
+
92
+ regulator_id: int = Field(
93
+ ...,
94
+ gt=0,
95
+ description="Foreign key to regulators",
96
+ )
97
+
98
+
99
+ class RegulatoryFrameworkUpdate(AshMaticsBaseModel):
100
+ """Schema for updating an existing regulatory framework."""
101
+
102
+ model_config = {"extra": "ignore"}
103
+
104
+ framework_name: Optional[str] = Field(None, max_length=255)
105
+ authorization_type: Optional[str] = Field(None, max_length=50)
106
+ requires_premarket_review: Optional[bool] = None
107
+ requires_clinical_data: Optional[bool] = None
108
+ description: Optional[str] = None
109
+ typical_review_time_days: Optional[int] = None
110
+ renewal_required: Optional[bool] = None
111
+ renewal_frequency_years: Optional[int] = None
112
+ is_active: Optional[bool] = None
113
+
114
+
115
+ class RegulatoryFrameworkResponse(RegulatoryFrameworkBase, TimestampedModel):
116
+ """
117
+ Schema for regulatory framework responses.
118
+
119
+ Includes nested regulator information and computed fields.
120
+ """
121
+
122
+ id: Optional[int] = Field(None, description="Framework ID")
123
+ regulator_id: int = Field(..., description="Foreign key to regulators")
124
+
125
+ # Nested regulator information
126
+ regulator: Optional[RegulatorSummary] = Field(
127
+ None, description="Regulator details"
128
+ )
129
+
130
+ # Computed fields
131
+ authorization_count: int = Field(
132
+ 0, description="Number of authorizations under this framework"
133
+ )
134
+
135
+
136
+ class RegulatoryFrameworkSummary(AshMaticsBaseModel):
137
+ """Minimal framework information for nested responses."""
138
+
139
+ id: int
140
+ framework_code: str
141
+ framework_name: str
142
+ authorization_type: str
143
+ regulator_code: Optional[str] = None
144
+
145
+
146
+ class RegulatoryFrameworkStats(AshMaticsBaseModel):
147
+ """Schema for regulatory framework statistics."""
148
+
149
+ total_frameworks: int = Field(..., description="Total number of frameworks")
150
+ active_frameworks: int = Field(..., description="Number of active frameworks")
151
+ by_authorization_type: dict[str, int] = Field(
152
+ default_factory=dict, description="Count by authorization type"
153
+ )
154
+ by_regulator: dict[str, int] = Field(
155
+ default_factory=dict, description="Count by regulator"
156
+ )
157
+ requiring_premarket_review: int = Field(
158
+ 0, description="Frameworks requiring premarket review"
159
+ )
160
+ requiring_clinical_data: int = Field(
161
+ 0, description="Frameworks requiring clinical data"
162
+ )
163
+ requiring_renewal: int = Field(
164
+ 0, description="Frameworks requiring periodic renewal"
165
+ )
166
+ avg_review_time_days: Optional[float] = Field(
167
+ None, description="Average review time in days"
168
+ )
@@ -0,0 +1,152 @@
1
+ # Copyright 2025 Asher Informatics PBC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Regulator schemas for multi-jurisdiction support.
17
+
18
+ Regulators are the governing bodies that oversee medical device approval
19
+ in their respective jurisdictions (FDA, EMA, TGA, MHRA, etc.).
20
+
21
+ Migrated from: KB src/app/schemas/regulator_schema.py
22
+ JIRA: ASHKBAPP-28 (Phase 2.1)
23
+ """
24
+
25
+ from datetime import datetime
26
+ from typing import Optional
27
+
28
+ from pydantic import Field, HttpUrl, field_validator
29
+
30
+ from ashmatics_datamodels.common.base import AshMaticsBaseModel, TimestampedModel
31
+ from ashmatics_datamodels.common.validators import validate_country_code
32
+
33
+
34
+ class RegulatorBase(AshMaticsBaseModel):
35
+ """
36
+ Base schema for regulatory authorities.
37
+
38
+ Represents governing bodies like FDA (US), EMA (EU), TGA (Australia),
39
+ MHRA (UK), Health Canada, PMDA (Japan), etc.
40
+ """
41
+
42
+ code: str = Field(
43
+ ...,
44
+ max_length=20,
45
+ description="Regulator code (e.g., FDA, EMA, TGA, MHRA, PMDA)",
46
+ )
47
+ name: str = Field(
48
+ ...,
49
+ max_length=255,
50
+ description="Short official name (e.g., 'Food and Drug Administration')",
51
+ )
52
+ full_name: Optional[str] = Field(
53
+ None,
54
+ max_length=500,
55
+ description="Complete official name",
56
+ )
57
+ country_code: Optional[str] = Field(
58
+ None,
59
+ max_length=2,
60
+ description="ISO 3166-1 alpha-2 country code (e.g., 'US', 'DE')",
61
+ )
62
+ region: Optional[str] = Field(
63
+ None,
64
+ max_length=50,
65
+ description="Geographic region (e.g., 'North America', 'EU', 'Asia-Pacific')",
66
+ )
67
+ website: Optional[str] = Field(
68
+ None,
69
+ max_length=500,
70
+ description="Official website URL",
71
+ )
72
+ api_endpoint: Optional[str] = Field(
73
+ None,
74
+ max_length=500,
75
+ description="API endpoint for data integration (e.g., OpenFDA)",
76
+ )
77
+ is_active: bool = Field(
78
+ True,
79
+ description="Whether regulator is currently active",
80
+ )
81
+
82
+ @field_validator("country_code")
83
+ @classmethod
84
+ def validate_country(cls, v: Optional[str]) -> Optional[str]:
85
+ return validate_country_code(v)
86
+
87
+
88
+ class RegulatorCreate(RegulatorBase):
89
+ """Schema for creating a new regulator."""
90
+
91
+ pass
92
+
93
+
94
+ class RegulatorUpdate(AshMaticsBaseModel):
95
+ """Schema for updating an existing regulator (all fields optional)."""
96
+
97
+ model_config = {"extra": "ignore"} # Allow partial updates
98
+
99
+ code: Optional[str] = Field(None, max_length=20)
100
+ name: Optional[str] = Field(None, max_length=255)
101
+ full_name: Optional[str] = Field(None, max_length=500)
102
+ country_code: Optional[str] = Field(None, max_length=2)
103
+ region: Optional[str] = Field(None, max_length=50)
104
+ website: Optional[str] = None
105
+ api_endpoint: Optional[str] = None
106
+ is_active: Optional[bool] = None
107
+
108
+
109
+ class RegulatorResponse(RegulatorBase, TimestampedModel):
110
+ """
111
+ Schema for regulator responses.
112
+
113
+ Includes computed fields for framework and classification counts.
114
+ """
115
+
116
+ id: Optional[int] = Field(None, description="Regulator ID")
117
+
118
+ # Computed fields (populated by endpoint logic)
119
+ framework_count: int = Field(
120
+ 0, description="Number of regulatory frameworks under this regulator"
121
+ )
122
+ classification_system_count: int = Field(
123
+ 0, description="Number of classification systems managed"
124
+ )
125
+
126
+
127
+ class RegulatorSummary(AshMaticsBaseModel):
128
+ """Minimal regulator information for nested responses."""
129
+
130
+ id: int
131
+ code: str
132
+ name: str
133
+ region: Optional[str] = None
134
+
135
+
136
+ class RegulatorStats(AshMaticsBaseModel):
137
+ """Schema for regulator statistics."""
138
+
139
+ total_regulators: int = Field(..., description="Total number of regulators")
140
+ active_regulators: int = Field(..., description="Number of active regulators")
141
+ by_region: dict[str, int] = Field(
142
+ default_factory=dict, description="Count by region"
143
+ )
144
+ by_country: dict[str, int] = Field(
145
+ default_factory=dict, description="Count by country code"
146
+ )
147
+ with_frameworks: int = Field(
148
+ 0, description="Regulators with at least one framework"
149
+ )
150
+ with_classification_systems: int = Field(
151
+ 0, description="Regulators with at least one classification system"
152
+ )