generated from coulomb/repo-seed
Add a local /services router (source of truth for the catalog itself):
- GET /services/catalog with hosting_type / development_type / maturity_level /
status filters (eager-loads all four extensions)
- GET /services/{slug}
- POST /services/catalog upsert-by-slug, applying the dimension extensions;
first_party.repo_slug resolves to a managed_repos FK.
Extensions are read/written via session.get (not the relationship attribute) to
avoid async lazy-load. /tpsc/* is left intact for dependency snapshots. 7 tests.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
117 lines
3.7 KiB
Python
117 lines
3.7 KiB
Python
"""Schemas for the two-dimension service catalog (STATE-WP-0062)."""
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
# ── Extension read models ────────────────────────────────────────────────────
|
|
|
|
class ServiceThirdPartyRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
pricing_model: str
|
|
upstream_packages: list | None = None
|
|
upstream_contacts: list | None = None
|
|
source_url: str | None = None
|
|
support_url: str | None = None
|
|
license: str | None = None
|
|
|
|
|
|
class ServiceFirstPartyRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
repo_id: uuid.UUID | None = None
|
|
owning_domain: str | None = None
|
|
|
|
|
|
class ServiceCloudRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
gdpr_maturity: str
|
|
gdpr_notes: str | None = None
|
|
dpa_available: bool
|
|
tos_url: str | None = None
|
|
privacy_policy_url: str | None = None
|
|
data_processing_regions: list | None = None
|
|
data_retention_notes: str | None = None
|
|
|
|
|
|
class ServiceSelfHostedRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
helix_instance: str | None = None
|
|
host_node: str | None = None
|
|
deployment_ref: str | None = None
|
|
runbook_ref: str | None = None
|
|
upstream_oss_project: str | None = None
|
|
|
|
|
|
class ServiceCatalogRead(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
id: uuid.UUID
|
|
slug: str
|
|
name: str
|
|
owner_or_provider: str | None = None
|
|
category: str | None = None
|
|
description: str | None = None
|
|
website_url: str | None = None
|
|
status: str
|
|
hosting_type: str
|
|
development_type: str
|
|
maturity_level: int | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
third_party: ServiceThirdPartyRead | None = None
|
|
first_party: ServiceFirstPartyRead | None = None
|
|
cloud: ServiceCloudRead | None = None
|
|
self_hosted: ServiceSelfHostedRead | None = None
|
|
|
|
|
|
# ── Write (upsert) models ────────────────────────────────────────────────────
|
|
|
|
class ServiceThirdPartyIn(BaseModel):
|
|
pricing_model: str = "unknown"
|
|
upstream_packages: list | None = None
|
|
upstream_contacts: list | None = None
|
|
source_url: str | None = None
|
|
support_url: str | None = None
|
|
license: str | None = None
|
|
|
|
|
|
class ServiceFirstPartyIn(BaseModel):
|
|
repo_id: uuid.UUID | None = None
|
|
repo_slug: str | None = None
|
|
owning_domain: str | None = None
|
|
|
|
|
|
class ServiceCloudIn(BaseModel):
|
|
gdpr_maturity: str = "unknown"
|
|
gdpr_notes: str | None = None
|
|
dpa_available: bool = False
|
|
tos_url: str | None = None
|
|
privacy_policy_url: str | None = None
|
|
data_processing_regions: list | None = None
|
|
data_retention_notes: str | None = None
|
|
|
|
|
|
class ServiceSelfHostedIn(BaseModel):
|
|
helix_instance: str | None = None
|
|
host_node: str | None = None
|
|
deployment_ref: str | None = None
|
|
runbook_ref: str | None = None
|
|
upstream_oss_project: str | None = None
|
|
|
|
|
|
class ServiceUpsert(BaseModel):
|
|
slug: str
|
|
name: str
|
|
owner_or_provider: str | None = None
|
|
category: str | None = None
|
|
description: str | None = None
|
|
website_url: str | None = None
|
|
status: str = "active"
|
|
hosting_type: str # self_hosted | cloud_hosted
|
|
development_type: str # first_party | third_party
|
|
maturity_level: int | None = None
|
|
third_party: ServiceThirdPartyIn | None = None
|
|
first_party: ServiceFirstPartyIn | None = None
|
|
cloud: ServiceCloudIn | None = None
|
|
self_hosted: ServiceSelfHostedIn | None = None
|