From 49a9493ca0438b1f0d009e97ba281b46178fe0b6 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Fri, 18 Sep 2026 12:58:31 +0200 Subject: [PATCH] =?UTF-8?q?fix(migrations):=20F19=20(Astra=20P1)=20?= =?UTF-8?q?=E2=80=94=20deterministische=20vollstaendige=20Model-Discovery?= =?UTF-8?q?=20fuer=20Alembic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vorher: alembic/env.py importierte nur from app.models import * — das laedt im frischen Prozess nur die 48 CORE-Modelle. Contact und ~80 weitere Tabellen liegen physikalisch in Plugins (lazy __getattr__ feuert bei Wildcard-Import nie). Metadatensortierung scheiterte an contact_merge_history -> contacts (NoReferencedTableError, Astra-Repro); alembic check haette gegen ein unvollstaendiges Schema verglichen. Fix: deterministische Plugin-Model-Discovery in env.py — gleiches Muster wie tests/conftest.py: Registry discover_builtins, dann pro Plugin das models-Modul importieren (ImportError = kein models-Modul, bewusst uebersprungen). Side-effect-frei (nur Modell-Registrierung, kein DB-Zugriff). Beweis: frischer Prozess laedt jetzt 129 Tabellen, Sortierung OK (Vorher: 48 + NoReferencedTableError). Bekannt und separat offen: der contacts/contactpersons-FK-Zyklus (SAWarning, dokumentiert) und der entity_attachments.dms_file_id-FK auf die DMS-Tabelle (R3). Verifikation: Syntax OK, ruff clean. --- alembic/env.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/alembic/env.py b/alembic/env.py index bec8c62..7f0fbd1 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -3,6 +3,15 @@ from __future__ import annotations import asyncio + +# F19 (Astra P1): deterministic full-model discovery for Alembic. +# `from app.models import *` only loads CORE models (48 tables in a fresh +# process). Contact and ~80 other tables physically live in plugins +# (e.g. app.plugins.builtins.contacts.models) — the lazy package +# __getattr__ never fires for wildcard imports. Without the plugin models +# the metadata sort fails (contact_merge_history → contacts FK) and +# `alembic check` compares against an incomplete schema. +import importlib from logging.config import fileConfig from sqlalchemy import pool @@ -13,6 +22,15 @@ from alembic import context from app.config import get_settings from app.core.db import Base from app.models import * # noqa: F401,F403 +from app.plugins.registry import get_registry + +_registry = get_registry() +_registry.discover_builtins() +for _plugin_name in _registry.list_discovered(): + try: + importlib.import_module(f"app.plugins.builtins.{_plugin_name}.models") + except ImportError: + pass # plugin has no models module config = context.config if config.config_file_name is not None: