Projektwissen: Git-Vorgaben, Ticketzugriff, Tests und Einstieg
Erster Stand des Repositories AG_QGIS/Projektwissen (bisher Arbeitstitel "Workspace", ADR 0006). Der lokale Ordner heisst weiter AG_QGIS, weil darin auch die Plugin-Klone liegen. Git verbindlich (ADR 0007), aus dem bisherigen Wiki-Konzept entwickelt: - docs/leitfaden/05_git_arbeitsweise.md mit Kanal-Kette, Branch-Namen und Gitea-Branch-Schutz. - Der Einstiegspunkt eines Fixes richtet sich nach dem Kanal, in dem der Fehler sitzt; ein Fix an testing oder stable ist erst mit der Rueckfuehrung nach unten abgeschlossen. Das fehlte bisher. - Der stabile Kanal heisst stable, nicht main: der Release-Workflow in Repository:hidden/workflows fuehrt git checkout "$CHANNEL" aus, der Branchname muss also dem Kanalnamen entsprechen. Er existiert in keinem Plugin-Repo und ist vom Maintainer anzulegen. - Der Mensch drueckt ab: .claude/settings.json sperrt push, merge, tag. - scripts/hallo.py und /hallo holen den Stand aller Klone, per Fast-Forward wo gefahrlos; nie mergen, stashen oder verwerfen. Ticketzugriff: - scripts/gitea.py liest Issues, Kommentare und PRs ueber die oeffentliche API, ohne Token, nur GET. Schreibendes nur als Entwurf in entwuerfe/. - Skill sn-ticket. Tests (ADR 0009): - docs/leitfaden/06_tests.md: Testebenen, Testpflicht, und wie eine Fachperson beurteilt, ob Tests fachlich sinnvoll sind. - scripts/testkatalog.py erzeugt docs/tests/testkatalog.md per ast-Parsing, ohne Import und ohne QGIS. Befund: nur 100 von 332 Tests haben einen Docstring, sn_basis keinen einzigen von 87. - Vorlage und erste Testkonzept-Seite mit Mermaid. Dabei gefunden und gegen origin geprueft: _ermittle_gebietstyp_aus_fbschl hat keinen Test, obwohl PR #44/#45 genau diese Funktion tolerant gemacht hat. - docs/konzept/07_qgis_tests_plan.md: Stufenplan fuer Tests gegen echtes QGIS. Dabei aufgefallen: QGIS 3.40 ist seit Januar 2026 End of Life, qgis_min steht aber noch darauf. Werkzeuge (ADR 0008): - 04_werkzeuge_einrichten.md nur noch Claude Code als CLI und in VS Code. - .vscode/ entfernt, brauchbare Einstellungen als persoenliche Vorlage. Ausserdem: README als Einstieg neu aufgebaut, Mermaid-Diagramm in schnittstellen.md repariert (unmaskierte Klammern, rendert seither nicht). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
# Modulkarte
|
||||
|
||||
Lebende Referenz: **welche Datei tut was und wie groß ist sie**. Zweck: Agenten und Entwickler lesen gezielt statt ganze
|
||||
Dateien zu laden. Zeilenzahlen Stand 02.09.2026 (`unstable`). Bei Änderungen an Modulzuschnitt bitte mitpflegen.
|
||||
|
||||
Legende: ⚠ = über 600 Zeilen, nie komplett laden, per `grep -n "def "` navigieren.
|
||||
|
||||
## sn_basis (Repository `Plugin_SN_Basis`) – Plattform
|
||||
|
||||
### Einstieg und UI-Rahmen
|
||||
|
||||
| Datei | Zeilen | Zweck |
|
||||
|---|---:|---|
|
||||
| `__init__.py` | 20 | `classFactory` → `BasisPlugin` |
|
||||
| `main.py` | 64 | `BasisPlugin`: baut `Navigation`, startet Verfahrensgebiet-Listener, ruft `initGui()` aller `sn_*`-Plugins nach, räumt beim Unload auf |
|
||||
| `ui/navigation.py` | 127 | Menü und Toolbar „LNO Sachsen“; `add_action(text, callback, tooltip, priority)`, `finalize_menu_and_toolbar()`, `set_active_plugin()`. Enthält noch Debug-`print` und eine `TEST ACTION` |
|
||||
| `ui/dockmanager.py` | 86 | `DockManager.show(dock)`: entfernt alle anderen `sn_dock_*`-Docks, zeigt das neue rechts an |
|
||||
| `ui/base_dockwidget.py` | 126 | `BaseDockWidget`: Titel „LNO Sachsen \| <Untertitel>“, Tabs aus Klassenattribut `tabs`, ruft `cleanup()` der Tabs beim Schließen, setzt Toolbar-Action zurück |
|
||||
| `ui/tabs/settings_tab.py` | 158 | Tab „Projekteigenschaften“: Benutzer- und Projektfelder → Projektvariablen (`SettingsLogic`) |
|
||||
| `ui/tabs/print_tab.py` ⚠ | 709 | Tab „Druck“: Druckbereich, Maßstab, Format, Themen, Legende, Atlas; nutzt `print_logic` |
|
||||
|
||||
### functions/ – Wrapper-Schicht (Qt/QGIS/OS mit Mock-Fallback)
|
||||
|
||||
| Datei | Zeilen | Zweck |
|
||||
|---|---:|---|
|
||||
| `functions/__init__.py` | 50 | Re-Export vieler Wrapper (`from sn_basis.functions import QgsProject, info, ...`) |
|
||||
| `functions/qt_wrapper.py` ⚠ | 796 | Qt-Symbole: PyQt6 primär, PyQt5-Fallback, sonst Mock. `QT_VERSION` (0/5/6), Enum-Aliase (`DockAreaRight`, …), `exec_dialog()` |
|
||||
| `functions/qgiscore_wrapper.py` ⚠ | 1 122 | `qgis.core`-Symbole und Konstanten; ab Zeile ~255 Mock-Klassen; Helfer `network_head`, `get_layer_extent`, `create_buffer_layer`, `layer_exists_in_gpkg`, `polygon_zu_linie` |
|
||||
| `functions/qgisui_wrapper.py` | 258 | `iface`-Zugriffe: Hauptfenster, Docks, Menüs, Toolbars, Layoutdesigner; Mock-`iface` |
|
||||
| `functions/dialog_wrapper.py` | 393 | Dialoge: `ask_yes_no`, `show_info_dialog`, `ask_text`, Überschreiben/Anhängen/Abbrechen, `ProgressDialog`/`create_progress_dialog` |
|
||||
| `functions/message_wrapper.py` | 85 | MessageBar: `info`, `warning`, `error`, `success`, `push_message` |
|
||||
| `functions/variable_wrapper.py` | 120 | `get_variable(key, scope)`, `set_variable(...)` mit Präfix `sn_`; Mock-Speicher |
|
||||
| `functions/settings_logic.py` | 50 | `SettingsLogic.VARIABLEN`: Liste der gespeicherten Projektvariablen, `load()/save()` |
|
||||
| `functions/verfahrensgebiet_manager.py` | 217 | Zentrale Verfolgung des Verfahrensgebiet-Layers über Projektsignale; `get/set_verfahrensgebiet_layer_id`, `setup_/teardown_verfahrensgebiet_listener` |
|
||||
| `functions/ly_*_wrapper.py` | 32–98 | Layer-Helfer: Existenz, Geometrie/Featurezahl, Metadaten (Typ, CRS, Felder, Quelle), Stil (`apply_style`), Sichtbarkeit |
|
||||
| `functions/os_wrapper.py` | 102 | Pfade, Home, Groß-/Kleinschreibung des Dateisystems |
|
||||
| `functions/sys_wrapper.py` | 106 | `get_plugin_root`, `join_path`, `file_exists`, `read_text`, `add_to_sys_path`, `getattr_safe` |
|
||||
| `functions/landkreise.py` | 48 | Sächsische Landkreise aus `data/landkreise.json` (`LANDKREISE`, `ALLE_LANDKREISE`) |
|
||||
| `functions/laenderkennung.py` | 52 | ALKIS-Länderkennung je Aufrufer-Präfix |
|
||||
|
||||
### modules/ – Prüfen, Laden, Schreiben, Drucken
|
||||
|
||||
| Datei | Zeilen | Zweck |
|
||||
|---|---:|---|
|
||||
| `modules/pruef_ergebnis.py` | 196 | `pruef_ergebnis(ok, meldung, aktion, kontext)` und `PruefAktion`-Literal (Fehler-/Entscheidungscodes) |
|
||||
| `modules/Pruefmanager.py` | 295 | Entscheidungsinstanz: `verarbeite(ergebnis)` fragt Nutzer oder entscheidet still (`ui_modus != "qgis"`); `report_error`, `frage_ja_nein`, `frage_text` |
|
||||
| `modules/Dateipruefer.py` | 267 | Prüft Dateipfade/GeoPackages (existiert, erzeugen, überschreiben, anhängen) |
|
||||
| `modules/layerpruefer.py` | 183 | Prüft QGIS-Layer (vorhanden, Geometrietyp, CRS, Felder, editierbar) |
|
||||
| `modules/linkpruefer.py` | 136 | Prüft URLs/lokale Links (Erreichbarkeit) |
|
||||
| `modules/stilpruefer.py` | 82 | Prüft QML-Stildateien |
|
||||
| `modules/Datenbankpruefer.py` | 40 | Prüft SQLite/GeoPackage-Datenbanken |
|
||||
| `modules/DataGrabber.py` | 363 | Klassifiziert Quelle (Excel, GeoPackage, Dienst) und liefert normalisierte Zeilen; Excel-Pfad nutzt **Lazy-Import** `sn_plan41.modules.listenauswerter` |
|
||||
| `modules/excel_importer.py` | 92 | Excel lesen (`openpyxl`, harte Abhängigkeit) |
|
||||
| `modules/Datenabruf.py` ⚠ | 636 | `Datenabruf.datenabruf(...)`: WFS, ArcGIS REST, OGR laden; Raumfilter Verfahrensgebiet/Puffer/ohne |
|
||||
| `modules/LayerLoader.py` | 422 | `create_layer(provider, link, thema)`, `apply_style`, `filter_by_extent`, `filter_by_layer`, `add_to_project` |
|
||||
| `modules/Datenschreiber.py` | 448 | `schreibe_Daten(...)` in GeoPackage, `lade_Layer(...)` ins Projekt, `schreibe_log(...)` HTML-Protokoll |
|
||||
| `modules/print_logic.py` ⚠ | 1 321 | `PrintLogic`, `AtlasConfig`, `RectangleCaptureTool`: Druckbereich, Maßstab, Atlas, Layoutaufruf |
|
||||
| `modules/print_layout.py` ⚠ | 1 078 | `PrintLayout`: Layoutaufbau für § 38 / § 41 (Karte, Legende, Gitter, Schriftfeld) |
|
||||
| `modules/print_layout_baufreigabe.py` | 403 | Layout „Anlage zur Baufreigabe“ (feste DIN A3/A4 quer) |
|
||||
|
||||
### Sonstiges
|
||||
|
||||
| Pfad | Zweck |
|
||||
|---|---|
|
||||
| `tests/` | 13 Testdateien, `unittest`, Mock-Modus; `run_tests.py` (farbiger Runner), `test_qgis.bat` (Coverage in OSGeo4W) |
|
||||
| `styles/` | QML-Stile (Verfahrensgebiet, LSG, Denkmalschutz, Flurstücksbeschriftung) |
|
||||
| `data/landkreise.json` | Landkreise mit Kennzahl |
|
||||
| `assets/plan-qgis340ExitCrashFix.prompt.md` | KI-Planungsnotiz zum Exit-Crash (historisch) |
|
||||
| `.gitea/workflows/release.yaml`, `.gitea/templates/metadata.template` | Release-Auslöser, Vorlage für `metadata.txt` |
|
||||
|
||||
## sn_verfahrensgebiet (Repository `Plugin_SN_Verfahrensgebiet`) – Fachplugin
|
||||
|
||||
| Datei | Zeilen | Zweck |
|
||||
|---|---:|---|
|
||||
| `main.py` | 80 | `Verfahrensgebiet`: registriert Action (Priorität 10), erzeugt `DockWidget` mit `Pruefmanager` und `DataGrabber` |
|
||||
| `ui/dockwidget.py` | 60 | Tabs `WorkingTab`, `PrintTab`, `SettingsTab`; injiziert Services per `set_services()` |
|
||||
| `ui/tabs/working_tab.py` ⚠ | 873 | Tab „Bearbeitung“: Buttons und Handler für ALKIS/Shape laden, Gemarkungen, Flurstücke, Grenzpunkte, Beteiligung, Statistik; hält viel Ablauflogik |
|
||||
| `functions/verfahrensgebiet_alkis.py` | 359 | WFS-Suche `BauRaumOderBodenordnungsrecht` per Verfahrensnummer/Landkreis, `LoadStatus` |
|
||||
| `functions/verfahrensgebiet_alkis_komplett.py` ⚠ | 661 | Vollständiger Ladeablauf aus ALKIS: BROR → Gemarkungen → Flurstücke → Flächenvergleich → Detailprüfung |
|
||||
| `functions/verfahrensgebiet_shape_komplett.py` ⚠ | 978 | Ladeablauf aus Shape/ZIP (Mehrfachauswahl, `FBSchl`-Klassifikation, Abgleich mit BROR) – siehe `docs/aus_shape_laden_technisch.md` im Repo |
|
||||
| `functions/verfahrensgebiet_dialoge.py` | 300 | Dialoge: BROR-Kombinationen, Landkreis-Objekte, Landkreisauswahl |
|
||||
| `functions/verfahrensgebiet_edit_service.py` | 359 | Verfahrensgebiet aus Flurstücksauswahl bilden, ergänzen, entfernen, ersetzen |
|
||||
| `functions/gemarkung_alkis.py` | 229 | Gemarkungen aus vereinfachtem ALKIS-WFS |
|
||||
| `functions/flurstueck_alkis.py` | 259 | Flurstücke je Gemarkung aus ALKIS-SF-WFS (BBOX, Batches) |
|
||||
| `functions/grenzpunkt_alkis.py` ⚠ | 1 674 | Grenzpunkte/`PunktortTA` gemarkungsweise, GML-Parsing, URL-sichere Batches |
|
||||
| `functions/knickpunkt_pruefung.py` ⚠ | 810 | Knickpunktbasierte BROR-Prüfung, Ergebnislayer mit Kategorien |
|
||||
| `functions/umringspruefung.py` | 312 | Umringsprüfung (Variante 1) |
|
||||
| `functions/umringstatistik_grenzpunkte.py` | 374 | Statistik Grenzpunkte am Umring |
|
||||
| `functions/beteiligung_pruefung.py` | 453 | Abgleich BI-Server-CSV mit ALKIS-Flurstücken |
|
||||
| `tests/` | 12 Dateien | Mock-Modus, aktuell 157/201 grün (Baseline) |
|
||||
| `docs/` | 3 Dateien | Ablaufdiagramme (Mermaid) für ALKIS- und Shape-Laden |
|
||||
| `styles/` | 6 QML | BROR, Gemarkungen, Beteiligung, Verfahrensgebiet |
|
||||
|
||||
## sn_plan41 (Repository `Plugin_SN_Plan41`) – Fachplugin
|
||||
|
||||
| Datei | Zeilen | Zweck |
|
||||
|---|---:|---|
|
||||
| `main.py` | 71 | `Plan41`: Action mit Priorität 20, Dock mit `Pruefmanager`/`DataGrabber` |
|
||||
| `ui/dockwidget.py` | 65 | Tabs `TabA` (Daten), `TabB` (Beispiel), `PrintTab`, `SettingsTab` |
|
||||
| `ui/tab_a_ui.py` ⚠ | 633 | UI von Tab A: Verfahrens-GeoPackage, Linkliste, Raumfilter, VLN-API-Bereich |
|
||||
| `ui/tab_a_logic.py` ⚠ | 1 239 | Fachlogik Tab A: Prüf-Pipeline (Datei, Linkliste, Stil, Layer), Abruf über `DataGrabber`/`Datenabruf`, Schreiben, Protokoll; `_SilentPruefmanagerProxy` |
|
||||
| `ui/tabs/tab_b.py` | 27 | Beispiel-Tab ohne Funktion |
|
||||
| `modules/listenauswerter.py` | 142 | Validiert Linklistenzeilen (Schema `ident, gruppe, kartenebene, inhalt, link, provider, stildatei`) – wird von `sn_basis.DataGrabber` lazy importiert |
|
||||
| `modules/vln_api_client.py` | 249 | HTTP-Client VLN-Karten-API v2 (Login, `X-API-Key`, Verfahren, Plan41-Datensatz, Upload) |
|
||||
| `modules/vln_api_logic.py` | 379 | Ablauflogik der API-Integration in Tab A |
|
||||
| `modules/vln_layer_manager.py` | 178 | GeoJSON ↔ Memory-Layer nach Geometriefamilie (Punkt/Linie/Fläche), EPSG:25833 |
|
||||
| `assets/` | 33 Dateien | `Linkliste.xlsx` (44 Dienste) und QML-Stile |
|
||||
| `doc/Datenbank_ERD.md` | 57 | Ziel-Datenmodell (Maßnahmen, Konten, Ausbauarten, Akteure) – Entwurf, nicht implementiert |
|
||||
| `tests/` | 5 Dateien | 43/44 grün (Baseline) |
|
||||
|
||||
## sn_widmung (Repository `Plugin_SN_Widmung`) – Gerüst
|
||||
|
||||
`main.py` (Priorität 30), `ui/dockwidget.py`, `ui/tabs/tab_a.py`, `tab_b.py`: Registrierung funktioniert, Tabs enthalten nur Platzhalter. Keine Tests.
|
||||
Dient als **minimales Muster** für ein neues Fachplugin (Skill `sn-neues-fachplugin`).
|
||||
|
||||
## Platzhalter und Infrastruktur
|
||||
|
||||
| Repository | Inhalt |
|
||||
|---|---|
|
||||
| `Plugin_SN_FLT`, `Plugin_SN_Topografie`, `Plugin_SN_Template` | nur Release-Workflow, Metadata-Vorlage (teils noch `Plugin_SN_Neu`), leere README |
|
||||
| `Plugin_Test_Action` | Minimalplugin zum Testen der Release-Pipeline |
|
||||
| `Repository` | `plugins.xml` (stable, leer), `plugins-testing.xml`, `plugins-unstable.xml`; Branches `hidden/workflows` (zentrale Release-Orchestrierung) und `hidden/templates` |
|
||||
| `Linkliste` | `linkliste.csv` → Gitea Action erzeugt XML/JSON/YAML |
|
||||
| `Defaults` | Beispiel-Verfahrensdaten (JSON) und `styles/verfahrensgebiet.qml`; nicht vom Code referenziert |
|
||||
|
||||
## Größte Dateien (Kandidaten für das spätere Refactoring)
|
||||
|
||||
| Datei | Zeilen |
|
||||
|---|---:|
|
||||
| `sn_verfahrensgebiet/functions/grenzpunkt_alkis.py` | 1 674 |
|
||||
| `sn_basis/modules/print_logic.py` | 1 321 |
|
||||
| `sn_plan41/ui/tab_a_logic.py` | 1 239 |
|
||||
| `sn_basis/functions/qgiscore_wrapper.py` | 1 122 |
|
||||
| `sn_basis/modules/print_layout.py` | 1 078 |
|
||||
| `sn_verfahrensgebiet/functions/verfahrensgebiet_shape_komplett.py` | 978 |
|
||||
| `sn_verfahrensgebiet/ui/tabs/working_tab.py` | 873 |
|
||||
| `sn_verfahrensgebiet/functions/knickpunkt_pruefung.py` | 810 |
|
||||
| `sn_basis/functions/qt_wrapper.py` | 796 |
|
||||
| `sn_basis/ui/tabs/print_tab.py` | 709 |
|
||||
@@ -0,0 +1,128 @@
|
||||
# Schnittstellen und Verträge
|
||||
|
||||
Lebende Referenz der **impliziten Verträge** zwischen den Komponenten. Wer eine dieser Stellen ändert, ändert eine
|
||||
Schnittstelle und muss alle Nutzer mit anpassen. Stand 02.09.2026.
|
||||
|
||||
## 1. Plugin-Lebenszyklus: sn_basis ↔ Fachplugin
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant QGIS
|
||||
participant B as sn_basis.BasisPlugin
|
||||
participant F as Fachplugin (z. B. Verfahrensgebiet)
|
||||
QGIS->>B: classFactory(iface) / initGui()
|
||||
B->>B: Navigation().init_ui() (Menü + Toolbar "LNO Sachsen")
|
||||
B->>B: setup_verfahrensgebiet_listener()
|
||||
loop für jedes Plugin in qgis.utils.plugins mit Namen sn_* (außer sn_basis)
|
||||
B->>F: initGui()
|
||||
F->>B: basis.ui.add_action(name, run, tooltip, priority)
|
||||
end
|
||||
B->>B: finalize_menu_and_toolbar() (sortiert nach priority)
|
||||
QGIS->>F: Nutzer klickt Action → run()
|
||||
F->>F: DockWidget(...) mit objectName "sn_dock_<name>"
|
||||
F->>B: DockManager.show(dock) (entfernt andere sn_dock_*)
|
||||
F->>B: basis.ui.set_active_plugin(action)
|
||||
QGIS->>F: unload() → removeDockWidget, basis.ui.remove_action(action)
|
||||
```
|
||||
|
||||
Vertrag für ein Fachplugin (Muster: `Plugin_SN_Widmung/main.py`):
|
||||
|
||||
- Paketname beginnt mit `sn_` (nur dann ruft `sn_basis` das `initGui()` nach).
|
||||
- `initGui()` holt `plugins.get("sn_basis")`; ohne `basis.ui` nichts tun (QGIS lädt Plugins in nicht garantierter Reihenfolge; `sn_basis` ruft später nach).
|
||||
- `add_action(text, callback, tooltip="", priority=100)` → `QAction` (checkable, in exklusiver Gruppe). Vergebene Prioritäten: Verfahrensgebiet 10, Plan41 20, Widmung 30.
|
||||
- Dock-Objektname `sn_dock_<pluginname klein>`; nur ein `sn_dock_*` ist gleichzeitig sichtbar.
|
||||
- `unload()` muss Dock entfernen und Action abmelden, sonst bleiben Reste in Menü/Toolbar.
|
||||
|
||||
## 2. DockWidget und Tabs
|
||||
|
||||
- Fachplugin-Dock erbt von `sn_basis.ui.base_dockwidget.BaseDockWidget`; Klassenattribut `tabs = [TabKlasse, ...]`.
|
||||
- Tab-Klasse: `QWidget`-Unterklasse mit Klassenattribut `tab_title`; Konstruktor `Tab(parent)`.
|
||||
Optional `set_services(pruefmanager=..., data_grabber=...)` (wird von Fachplugin-Docks aufgerufen) und `cleanup()` (wird beim Schließen des Docks aufgerufen – Signale trennen!).
|
||||
- Gemeinsame Tabs aus `sn_basis`: `ui.tabs.print_tab.PrintTab` (Druck), `ui.tabs.settings_tab.SettingsTab` (Projekteigenschaften).
|
||||
- `dock.action` = Referenz auf die Toolbar-Action; `BaseDockWidget.closeEvent` setzt sie zurück.
|
||||
|
||||
## 3. Projektvariablen (gemeinsamer Zustand im QGIS-Projekt)
|
||||
|
||||
Zugriff nur über `sn_basis.functions.variable_wrapper.get_variable(key, scope="project")` / `set_variable(...)`.
|
||||
Der Wrapper setzt das Präfix `sn_` selbst; Schlüssel **ohne** Präfix übergeben.
|
||||
|
||||
| Schlüssel (ohne `sn_`) | Gesetzt von | Gelesen von | Bedeutung |
|
||||
|---|---|---|---|
|
||||
| `amt`, `behoerde`, `landkreis_user`, `sachgebiet` | SettingsTab | Druck (Schriftfeld) | benutzerspezifische Angaben |
|
||||
| `bezeichnung`, `name`, `verfahrensnummer`, `gemeinden`, `landkreise_proj`, `landkreis_kennzahl` | SettingsTab | Verfahrensgebiet (ALKIS-Suche), Druck | Verfahrensangaben; `verfahrensnummer` = VKZ |
|
||||
| `verfahrensgebiet_layer` | `verfahrensgebiet_manager`, WorkingTab | alle Fachplugins, Druck | Layer-ID des aktuellen Verfahrensgebiets |
|
||||
| `verfahrens_db`, `tab_a_verfahrens_db` | Plan41 Tab A | Plan41 | Pfad des Verfahrens-GeoPackages |
|
||||
| `linkliste`, `tab_a_linkliste` | Plan41 Tab A | Plan41 | Pfad der Linkliste (XLSX) |
|
||||
| `tab_a_layer_id`, `Raumfilter` | Plan41 Tab A | Plan41 | Raumfilter-Einstellung |
|
||||
| `druckrechteck_xmin/xmax/ymin/ymax` | PrintTab/PrintLogic | Druck | gespeicherter Druckbereich |
|
||||
| `sn_abdeckungslayer` ⚠ | PrintTab/PrintLogic | Druck (Atlas) | Atlas-Abdeckungslayer. **Schlüssel enthält bereits `sn_` → tatsächliche Variable `sn_sn_abdeckungslayer`**; funktioniert, ist aber inkonsistent |
|
||||
| `verfahrensgebietslayer` ⚠ | `print_logic.py` | `print_logic.py` | **Zweite Schreibweise neben `verfahrensgebiet_layer`** – vermutlich Altlast, beim Refactoring zusammenführen |
|
||||
|
||||
Benutzer-/Maschinendaten außerhalb des Projekts: `QSettings` in `sn_plan41` (`mail`, `api_key` der VLN-API).
|
||||
|
||||
## 4. Prüf- und Entscheidungsmodell
|
||||
|
||||
- `pruef_ergebnis(ok: bool, meldung, aktion: PruefAktion, kontext)` ist das einheitliche Rückgabeobjekt aller Prüfer (`Dateipruefer`, `Layerpruefer`, `Linkpruefer`, `Stilpruefer`, `Datenbankpruefer`) und vieler Fachfunktionen.
|
||||
- `PruefAktion` ist ein `Literal` mit Codes wie `datei_nicht_gefunden`, `layer_leer`, `datei_existiert_ueberschreiben`, `verfahrensgebiet_ergaenzen`. Neue Codes dort ergänzen, nicht als freie Strings verwenden.
|
||||
- `Pruefmanager(ui_modus="qgis")`: `verarbeite(ergebnis)` entscheidet je Aktion (Dialog, Meldung, Standardwert). Mit `ui_modus != "qgis"` (Tests) werden Standardantworten ohne Dialog geliefert.
|
||||
- Fachplugins erhalten **eine** `Pruefmanager`- und **eine** `DataGrabber`-Instanz aus `main.py` (Konstruktor) und reichen sie an Tabs weiter.
|
||||
|
||||
## 5. Datenpipeline Plan41 (Fachdaten aus Linkliste)
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
XLSX[assets/Linkliste.xlsx] --> DG[DataGrabber.run]
|
||||
DG -->|Excel| LA[sn_plan41.Listenauswerter.validate_rows]
|
||||
LA --> DA[Datenabruf.datenabruf]
|
||||
VG[(Verfahrensgebiet / Puffer)] --> DA
|
||||
DA --> LL[LayerLoader: create_layer, filter_by_layer/extent, apply_style]
|
||||
LL --> DS[Datenschreiber.schreibe_Daten → GeoPackage]
|
||||
DS --> P[Datenschreiber.lade_Layer + schreibe_log HTML]
|
||||
```
|
||||
|
||||
- Erwartetes Spaltenschema der XLSX: `ident, gruppe, kartenebene, inhalt, link, provider, stildatei`. `provider` ∈ WFS, REST (ArcGIS), OGR.
|
||||
- Das zentrale Repository `Linkliste` (`linkliste.csv`: `id;gruppe;ebene;inhalt;url;provider;stil`) ist **nicht** angebunden → zwei Wahrheiten, siehe `fallstricke.md`.
|
||||
- Die einzige Rückwärtsabhängigkeit `sn_basis → sn_plan41` ist der Lazy-Import von `Listenauswerter` in `DataGrabber._process_excel_source` (seit PR #57 abgesichert, damit `sn_verfahrensgebiet` ohne `sn_plan41` lädt).
|
||||
|
||||
## 6. Verfahrensgebiet-Abläufe (Fachplugin)
|
||||
|
||||
- Zentrale Kennung des Verfahrens: Projektvariable `verfahrensnummer` (VKZ) und/oder `landkreis_kennzahl`.
|
||||
- ALKIS-Quellen: vereinfachtes ALKIS (`.../public_alkis/vereinf/wfs`) für Gemarkungen/BROR, ALKIS-SF (`.../public_alkis/sf/wfs`) für Flurstücke und `PunktortTA`.
|
||||
- Layer-Namenskonventionen (String-Konstanten in den Modulen): `BROR_LAYER_NAME`, `FLST_LAYER_NAME`, `JOINED_LAYER_NAME`, „Verfahrensgebiet“, „Neuordnungsgebiet (NoBIS)“, „Neuvermessungsgebiet (NoBIS)“. Andere Module finden Layer **über den Namen** – Umbenennungen sind Schnittstellenänderungen.
|
||||
- Ablaufdokumentation mit Diagrammen: `Plugin_SN_Verfahrensgebiet/docs/`.
|
||||
|
||||
## 7. VLN-Karten-API (Plan41)
|
||||
|
||||
- Basis-URL `https://api.flurneuordnung-sachsen.de/v2`; Login per E-Mail/Passwort, danach Header `X-API-Key`.
|
||||
- Laden: Verfahren (VKZ) → Plan41-GeoJSON → Memory-Layer je Geometriefamilie (`vln_layer_manager`). Upload: alle Teillayer → eine FeatureCollection, `PUT` ersetzt den Serverbestand der VKZ vollständig.
|
||||
- Arbeits-CRS EPSG:25833.
|
||||
|
||||
## 8. Mock-Modus (Tests ohne QGIS)
|
||||
|
||||
- Jeder Wrapper versucht den Import von `qgis`/`PyQt6`/`PyQt5`; schlägt das fehl, definiert er `_Mock*`-Klassen. Kennzeichen: `qgiscore_wrapper.QGIS_AVAILABLE`, `qt_wrapper.QT_VERSION == 0`.
|
||||
- Tests importieren Module über den Paketnamen (`from sn_basis...`), deshalb müssen die Repos unter ihrem Paketnamen erreichbar sein → `scripts/run_tests.py` erledigt das über ein temporäres Verzeichnis.
|
||||
- Tests, die echtes Layer- oder Netzwerkverhalten brauchen, laufen nur in QGIS (`tests/test_qgis.bat`, Windows).
|
||||
|
||||
## 9. Release-Vertrag
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
T["Tag v26.9.1-u auf Plugin-Repo"] --> W1["Plugin-Workflow release.yaml"]
|
||||
W1 -->|"workflow_dispatch + Payload"| W2["Repository, Branch hidden/workflows"]
|
||||
W2 --> C["checkout Branch = Kanal<br/>(unstable / testing / stable)"]
|
||||
C --> M["metadata.template → metadata.txt:<br/>version, experimental, repository-URL"]
|
||||
M --> Z["rsync ohne .git .gitea .gitignore __pycache__ → ZIP_FOLDER.zip"]
|
||||
Z --> R["Gitea-Release + Asset"]
|
||||
R --> X["plugins-<kanal>.xml aktualisieren"]
|
||||
```
|
||||
|
||||
- Tagformat `v<JJ.M.N>-u` (unstable), `-t` (testing), ohne Suffix (stable). Version = Jahr.Monat.Laufnummer.
|
||||
- **Gebaut wird der Kopf des Kanal-Branches, nicht der getaggte Commit.** Tag also nur auf dem aktuellen Kopf von `unstable` bzw. `testing` setzen.
|
||||
- Paketname im ZIP kommt aus der Gitea-Repo-Variable `ZIP_FOLDER` (z. B. `sn_basis`).
|
||||
- `metadata.txt` im Repo ist nur ein Abbild des letzten Builds; gepflegt wird `.gitea/templates/metadata.template`.
|
||||
- Release-Body = Block über dem ersten `---` in `changelog.txt`.
|
||||
- Neue Workspace-Dateien (`AGENTS.md`, `CLAUDE.md`, `.agents/`, `.claude/`, `docs/` der Repos) landen derzeit im ZIP → Excludes im zentralen Workflow ergänzen (offener Punkt in `STATUS.md`).
|
||||
|
||||
## 10. Linkliste-Repository
|
||||
|
||||
`linkliste.csv` (Semikolon, Spalten `id;gruppe;ebene;inhalt;url;provider;stil`) → Gitea Action → `linkliste.xml/json/yaml` auf `main`. Die Plan41-Laufzeit nutzt stattdessen die mitgelieferte `assets/Linkliste.xlsx` mit abweichenden Spaltennamen.
|
||||
Reference in New Issue
Block a user