refactor(backend/api): extract BannerConsent + BannerAdmin services (Step 4)

Phase 1 Step 4, file 2 of 18. Same cookbook as audit_routes (4a91814 +
883ef70) applied to banner_routes.py.

compliance/api/banner_routes.py (653 LOC) is decomposed into:

  compliance/api/banner_routes.py                (255) — thin handlers
  compliance/services/banner_consent_service.py  (298) — public SDK surface
  compliance/services/banner_admin_service.py    (238) — site/category/vendor CRUD
  compliance/services/_banner_serializers.py     ( 81) — ORM-to-dict helpers
                                                         shared between the
                                                         two services
  compliance/schemas/banner.py                   ( 85) — Pydantic request models

Split rationale: the SDK-facing endpoints (consent CRUD, config
retrieval, export, stats) and the admin CRUD endpoints (sites +
categories + vendors) have distinct audiences and different auth stories,
and combined they would push the service file over the 500 hard cap.
Two focused services is cleaner than one ~540-line god class.

The shared ORM-to-dict helpers live in a private sibling module
(_banner_serializers) rather than a static method on either service, so
both services can import without a cycle.

Handlers follow the established pattern:
  - Depends(get_consent_service) or Depends(get_admin_service)
  - `with translate_domain_errors():` wrapping the service call
  - Explicit return type annotations
  - ~3-5 lines per handler

Services raise NotFoundError / ConflictError / ValidationError from
compliance.domain; no HTTPException in the service layer.

mypy.ini flips compliance.api.banner_routes from ignore_errors=True to
False, joining audit_routes in the strict scope. The services carry the
same scoped `# mypy: disable-error-code="arg-type,assignment"` header
used by the audit services for the ORM Column[T] issue.

Pydantic schemas moved to compliance.schemas.banner (mirroring the Step 3
schemas split). They were previously defined inline in banner_routes.py
and not referenced by anything outside it, so no backwards-compat shim
is needed.

Verified:
  - 224/224 pytest (173 baseline + 26 audit integration + 25 banner
    integration) pass
  - tests/contracts/test_openapi_baseline.py green (360/484 unchanged)
  - mypy compliance/ -> Success: no issues found in 123 source files
  - All new files under the 300 soft target (largest: 298)
  - banner_routes.py drops from 653 -> 255 LOC (below hard cap)

Hard-cap violations remaining: 16 (was 17).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-04-07 18:52:31 +02:00
parent 883ef702ac
commit 10073f3ef0
7 changed files with 975 additions and 587 deletions

View File

@@ -2008,6 +2008,7 @@
"type": "object"
},
"CategoryConfigCreate": {
"description": "Request body for adding a cookie category to a site.",
"properties": {
"category_key": {
"title": "Category Key",
@@ -16041,6 +16042,7 @@
"type": "object"
},
"SiteConfigCreate": {
"description": "Request body for creating a banner site configuration.",
"properties": {
"banner_description": {
"anyOf": [
@@ -16159,6 +16161,7 @@
"type": "object"
},
"SiteConfigUpdate": {
"description": "Partial update for a banner site configuration.",
"properties": {
"banner_description": {
"anyOf": [
@@ -19274,6 +19277,7 @@
"type": "object"
},
"VendorConfigCreate": {
"description": "Request body for adding a vendor under a site's category.",
"properties": {
"category_key": {
"title": "Category Key",
@@ -19495,73 +19499,6 @@
"title": "VersionResponse",
"type": "object"
},
"compliance__api__banner_routes__ConsentCreate": {
"properties": {
"categories": {
"default": [],
"items": {
"type": "string"
},
"title": "Categories",
"type": "array"
},
"consent_string": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Consent String"
},
"device_fingerprint": {
"title": "Device Fingerprint",
"type": "string"
},
"ip_address": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Ip Address"
},
"site_id": {
"title": "Site Id",
"type": "string"
},
"user_agent": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "User Agent"
},
"vendors": {
"default": [],
"items": {
"type": "string"
},
"title": "Vendors",
"type": "array"
}
},
"required": [
"site_id",
"device_fingerprint"
],
"title": "ConsentCreate",
"type": "object"
},
"compliance__api__einwilligungen_routes__ConsentCreate": {
"properties": {
"consent_version": {
@@ -20353,6 +20290,74 @@
],
"title": "TemplateCreate",
"type": "object"
},
"compliance__schemas__banner__ConsentCreate": {
"description": "Request body for recording a device consent.",
"properties": {
"categories": {
"default": [],
"items": {
"type": "string"
},
"title": "Categories",
"type": "array"
},
"consent_string": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Consent String"
},
"device_fingerprint": {
"title": "Device Fingerprint",
"type": "string"
},
"ip_address": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Ip Address"
},
"site_id": {
"title": "Site Id",
"type": "string"
},
"user_agent": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "User Agent"
},
"vendors": {
"default": [],
"items": {
"type": "string"
},
"title": "Vendors",
"type": "array"
}
},
"required": [
"site_id",
"device_fingerprint"
],
"title": "ConsentCreate",
"type": "object"
}
}
},
@@ -21019,7 +21024,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Delete Audit Session Api Compliance Audit Sessions Session Id Delete",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21103,7 +21112,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Archive Audit Session Api Compliance Audit Sessions Session Id Archive Put",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21145,7 +21158,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Complete Audit Session Api Compliance Audit Sessions Session Id Complete Put",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21250,7 +21267,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Start Audit Session Api Compliance Audit Sessions Session Id Start Put",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21336,7 +21357,14 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Response List Site Configs Api Compliance Banner Admin Sites Get",
"type": "array"
}
}
},
"description": "Successful Response"
@@ -21393,7 +21421,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Create Site Config Api Compliance Banner Admin Sites Post",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21512,7 +21544,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Update Site Config Api Compliance Banner Admin Sites Site Id Put",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21570,7 +21606,14 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Response List Categories Api Compliance Banner Admin Sites Site Id Categories Get",
"type": "array"
}
}
},
"description": "Successful Response"
@@ -21636,7 +21679,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Create Category Api Compliance Banner Admin Sites Site Id Categories Post",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21694,7 +21741,14 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"items": {
"additionalProperties": true,
"type": "object"
},
"title": "Response List Vendors Api Compliance Banner Admin Sites Site Id Vendors Get",
"type": "array"
}
}
},
"description": "Successful Response"
@@ -21760,7 +21814,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Create Vendor Api Compliance Banner Admin Sites Site Id Vendors Post",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21818,7 +21876,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Get Site Stats Api Compliance Banner Admin Stats Site Id Get",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21913,7 +21975,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Get Site Config Api Compliance Banner Config Site Id Get",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -21980,7 +22046,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Get Consent Api Compliance Banner Consent Get",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -22027,7 +22097,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/compliance__api__banner_routes__ConsentCreate"
"$ref": "#/components/schemas/compliance__schemas__banner__ConsentCreate"
}
}
},
@@ -22037,7 +22107,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Record Consent Api Compliance Banner Consent Post",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -22104,7 +22178,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Export Consent Api Compliance Banner Consent Export Get",
"type": "object"
}
}
},
"description": "Successful Response"
@@ -22162,7 +22240,11 @@
"200": {
"content": {
"application/json": {
"schema": {}
"schema": {
"additionalProperties": true,
"title": "Response Withdraw Consent Api Compliance Banner Consent Consent Id Delete",
"type": "object"
}
}
},
"description": "Successful Response"