# SecInterp - Detailed Project Architecture > **Comprehensive Technical Documentation for the SecInterp QGIS Plugin** > Version 3.11.0 | Last Updated: 2026-10-24 --- ## ๐Ÿ“‘ Table of Contents 1. [Overview](#overview) 2. [Directory Structure](#directory-structure) 3. [System Architecture](#system-architecture) 4. [GUI Layer - User Interface](#gui-layer---user-interface) 5. [Core Layer - Business Logic](#core-layer---business-logic) 6. [Exporters Layer - Data Export](#exporters-layer---data-export) 7. [Design Principles](#design-principles) 8. [Extensibility](#extensibility) 9. [Project Metrics](#project-metrics) 10. [Quality Assurance & Security Scanning](#quality-assurance--security-scanning) --- ## ๐ŸŽฏ Overview **SecInterp** (Section Interpreter) is a QGIS plugin designed for extracting and visualizing geological data in cross-sections. The plugin allows geologists to generate topographic profiles, project geological outcrops, and analyze structural data in a unified 2D view. ### Key Features - โœ… **Interactive Preview System** with real-time rendering and adaptive LOD (Level of Detail) based on zoom. - โœ… **Parallel Processing** for complex geological intersections. - โœ… **DEM & Profile Insights**: DEM band statistics and profile-vs-DEM min/max/mean, plus gradient/single-color profile styling. - โœ… **CRS Safety**: mixed-CRS warnings and a blocking check for mislabelled layer CRS. - โœ… **Adaptive Vertical Exaggeration** (auto, clamped `0.5ร—โ€“20ร—`) with manual override. - โœ… **Optional Smoothed Topography** profile (distance-window moving average) with matching smoothed geology. - โœ… **Measurement Tools** with automatic snapping. - โœ… **Drillhole Support** with 3Dโ†’2D trajectory projection. - โœ… **Multi-format Export** (SHP, GPKG, DXF, CSV, PDF, SVG, PNG). --- ## ๐Ÿ“‚ Directory Structure The project organization follows a highly modular architecture based on the **Separation of Concerns** (SoC) principle, decoupling the interface, business logic, and export formats. Each layer has a distinct responsibility and communicates through well-defined interfaces. - `sec_interp/` โ€” plugin root โ†’ [`layer_plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_plugin.md) ยท [`plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/plugin.md) - `__init__.py` โ€” Plugin entry point (registers with QGIS) โ†’ [`root`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/root.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_plugin.md) - `sec_interp_plugin.py` โ€” Root class `SecInterp` (facade) โ†’ [`sec_interp_plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/sec_interp_plugin.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/sec_interp_plugin.md) - `plugin/` โ€” Plugin mixins composed by `SecInterp` โ†’ [`plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/plugin.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_plugin.md) - `plugin/lifecycle.py` โ€” `PluginLifecycleMixin` (`add_action`, `initGui`, `run`, `unload`) โ†’ [`plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/plugin.md) - `plugin/input_validator.py` โ€” `InputValidationMixin` (`_get_and_validate_inputs`) โ†’ [`plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/plugin.md) - `plugin/render_pipeline.py` โ€” `RenderPipelineMixin` (`draw_preview`) โ†’ [`plugin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/plugin.md) - `metadata.txt` โ€” QGIS plugin metadata - `Makefile` โ€” Automation (deploy, tests, docs) - `logger_config.py` โ†’ [`logger_config`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/logger_config.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/logger_config.md) - `core/` โš™๏ธ โ€” Business Logic (QGIS-agnostic, thread-safe) โ†’ [`layer_core`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core.md) - `controller.py` โ€” Orchestrator `ProfileController` โ†’ [`controller`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/controller.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/controller.md) - `config.py` โ†’ [`config`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/config.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/config.md) - `data_cache.py` โ†’ [`data_cache`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/data_cache.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/data_cache.md) - `exceptions.py` โ†’ [`exceptions`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/exceptions.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/exceptions.md) - `performance_metrics.py` โ†’ [`performance_metrics`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/performance_metrics.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/performance_metrics.md) - `algorithms.py` โ€” Reserved placeholder for pure business-logic algorithms โ†’ [`layer_core`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core.md) - `domain/` โ€” DTOs `ProfileData`, `GeologySegment`; modules `dtos.py`, `entities.py`, `enums.py`, `spatial_meta.py`, `task_inputs.py` โ†’ [`domain`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/domain.md) ยท [`layer_core_domain`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_domain.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/domain.md) - `interfaces/` โ€” ABCs for DI (`IGeologyService`, `IDrillholeService`, `IPreviewService`, โ€ฆ) โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) - `models/settings_model.py` โ€” Typed settings โ†’ [`layer_core_models`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_models.md) - `validation/` โ€” Modular pipeline โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) ยท [`layer_core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_validation.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_validation.md) - `validation/pipeline.py`, `layer_validator.py`, `field_validator.py`, `path_validator.py`, `project_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) - `validation/crs_plausibility.py` โ€” Best-effort mislabelled-CRS detection from extent plausibility โ†’ [`crs_plausibility`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/crs_plausibility.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_validation.md) - `validation/layer_metadata.py` โ€” QGIS-agnostic layer metadata for validation โ†’ [`layer_metadata`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_metadata.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_validation.md) - `utils/` โ€” Helpers (pure Python) โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) - `utils/safe_loader.py` โ†’ [`safe_loader`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/safe_loader.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/safe_loader.md) - `utils/i18n.py` โ†’ [`core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_utils.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) - `utils/geometry_utils/` (`measurement.py`, `optimization.py`, `processing.py`) โ†’ [`layer_core_utils_geometry_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils_geometry_utils.md) - `services/` โ€” Concrete implementations โ†’ [`layer_core_services`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services.md) - `services/geology_service.py` โ†’ [`geology_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/geology_service.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/geology_service.md) - `services/structure_service.py` โ†’ [`structure_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/structure_service.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/structure_service.md) - `services/drillhole_service.py` โ†’ [`drillhole_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_service.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_service.md) - `services/export_service.py` โ€” 13-line compatibility shim โ†’ [`core_services`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services.md) - `services/export/` โ€” Export package (orchestrator + handlers) โ†’ [`core_services_export`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services_export.md) ยท [`layer_core_services_export`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_export.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_export.md) - `services/export/orchestrator.py`, `path_resolver.py`, `compat.py`; map settings factory lives in `exporters/map_settings.py` - `services/export/handlers/` (topography, geology, structures, drillholes, drillholes_3d, interpretations, axes) โ†’ [`layer_core_services_export_handlers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_export_handlers.md) - `services/preview_service.py` โ†’ [`preview_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_service.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_service.md) - `services/vertical_exaggeration_service.py` โ†’ [`vertical_exaggeration_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vertical_exaggeration_service.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vertical_exaggeration_service.md) - `services/access_control_service.py` โ†’ [`core_services`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services.md) - `services/drillhole/` โ€” Drillhole pipeline โ†’ [`layer_core_services_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_drillhole.md) - `services/drillhole/collar_processor.py` โ†’ [`collar_processor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/collar_processor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/collar_processor.md) - `services/drillhole/survey_processor.py` โ†’ [`core_services_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services_drillhole.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_drillhole.md) - `services/drillhole/interval_processor.py` โ†’ [`interval_processor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interval_processor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interval_processor.md) - `services/drillhole/projection_engine.py` โ†’ [`core_services_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services_drillhole.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_services_drillhole.md) - `services/drillhole/trajectory_engine.py` โ†’ [`trajectory_engine`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/trajectory_engine.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/trajectory_engine.md) - `gui/` ๐Ÿ–ฅ๏ธ โ€” UI Layer (QGIS-dependent) โ†’ [`layer_gui`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `gui/main_dialog.py` โ€” `SecInterpDialog` orchestrator โ†’ [`main_dialog`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/main_dialog.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/main_dialog.md) - `gui/dialog_dependencies.py` โ€” Narrow dependency containers injected into managers (composition root) โ†’ [`layer_gui`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `gui/dialog_message_mixin.py`, `dialog_lifecycle_mixin.py`, `dialog_facade_mixin.py` โ€” Message / lifecycle / facade mixins โ†’ [`main_dialog`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/main_dialog.md) - `gui/interpretation_inheritance_mixin.py`, `interpretation_persistence_mixin.py` โ€” Attribute inheritance (nearest geology/drillhole) + project persistence โ†’ [`dialog_interpretation_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_interpretation_manager.md) - `gui/main_dialog_config.py`, `main_dialog_utils.py` โ€” Dialog configuration, defaults and UI helpers โ†’ [`main_dialog`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/main_dialog.md) - `gui/utils.py` โ€” General-purpose UI helpers and user messaging โ†’ [`layer_gui`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `gui/adapters/` โ€” Extract phase (QGIS โ†’ DTOs) โ†’ [`gui_adapters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_adapters.md) ยท [`layer_gui_adapters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_adapters.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_adapters.md) - `adapters/drillhole_extractor.py` โ†’ [`drillhole_extractor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_extractor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_extractor.md) - `adapters/geology_extractor.py` โ†’ [`geology_extractor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/geology_extractor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/geology_extractor.md) - `adapters/structure_extractor.py` โ†’ [`structure_extractor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/structure_extractor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/structure_extractor.md) - `adapters/validation_extractor.py` โ†’ [`validation_extractor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/validation_extractor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/validation_extractor.md) - `adapters/profile_extractor.py` โ†’ [`profile_extractor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/profile_extractor.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_adapters.md) - `adapters/feature_fetcher.py`, `layer_resolver.py`, `geometry.py` โ†’ [`gui_adapters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_adapters.md) - Managers (orchestration) - `dialog_signal_manager.py` โ†’ [`dialog_signal_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_signal_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `dialog_input_manager.py` โ†’ [`dialog_input_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_input_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `dialog_preview_manager.py` โ†’ [`dialog_preview_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_preview_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_preview_manager.md) - `dialog_export_manager.py` โ†’ [`dialog_export_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_export_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_export_manager.md) - `dialog_interpretation_manager.py` โ†’ [`dialog_interpretation_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_interpretation_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `dialog_state_manager.py` โ†’ [`dialog_state_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_state_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `dialog_settings_persistence.py` โ†’ [`dialog_state_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_state_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `dialog_tool_manager.py` โ†’ [`dialog_tool_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_tool_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `layer_notification_manager.py` โ†’ [`layer_notification_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_notification_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_notification_manager.md) - `ui_status_manager.py` โ†’ [`ui_status_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/ui_status_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/ui_status_manager.md) - `dialogs/` โ€” Modal dialogs โ†’ [`layer_gui_dialogs`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_dialogs.md) - `dialogs/interpretation_properties_dialog.py` โ†’ [`layer_gui_dialogs`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_dialogs.md) - Rendering Engine - `preview_renderer.py` โ†’ [`preview_renderer`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_renderer.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_renderer.md) - `preview_layer_factory.py` โ†’ [`preview_layer_factory`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_layer_factory.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_layer_factory.md) - `preview_axes_manager.py` โ†’ [`preview_axes_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_axes_manager.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_axes_manager.md) - `preview_param_hasher.py` โ€” Render-parameter hashing for LOD cache invalidation โ†’ [`preview_param_hasher`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_param_hasher.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `preview_render_mixin.py`, `preview_callbacks_mixin.py` โ€” Rendering and async-task callback mixins โ†’ [`preview_render_mixin`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_render_mixin.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `preview_task_orchestrator.py` โ€” Queues, prioritizes and monitors background preview tasks โ†’ [`preview_task_orchestrator`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_task_orchestrator.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `preview_legend_renderer.py` โ€” Draws the legend (topography, structures, units) on a `QPainter` โ†’ [`preview_legend_renderer`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_legend_renderer.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui.md) - `preview_reporter.py` โ†’ [`preview_state`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) - `preview_state.py` โ†’ [`preview_state`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) - `preview_side_panel.py` โ€” collapsible legend side panel (per-unit hide/color/alias, interpretations list) - `renderers/` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) ยท [`layer_gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_renderers.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_renderers.md) - `renderers/base_renderer.py`, `topo/geology/drillhole/structure/interpretation_renderer.py`, `color_manager.py` - `tasks/` (`geology_task.py`, `drillhole_task.py`) โ†’ [`gui_tasks`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_tasks.md) ยท [`layer_gui_tasks`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_tasks.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_tasks.md) - `tools/` โ€” Interactive map tools โ†’ [`layer_gui_tools`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_tools.md) - `tools/measure_tool.py` โ†’ [`measure_tool`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/measure_tool.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/measure_tool.md) - `tools/interpretation_tool.py` โ†’ [`interpretation_tool`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_tool.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_tool.md) - `tools/snapper.py` - `ui/` โ€” Programmatic window + sidebar โ†’ [`layer_gui_ui`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui.md) - `ui/main_window.py`, `ui/sidebar.py` โ†’ [`gui_ui_pages`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_ui_pages.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages.md) - `ui/pages/` โ€” Tab-based pages โ†’ [`layer_gui_ui_pages`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages.md) - `ui/pages/base_page.py`, `dem_page.py`, `section_page.py`, `geology_page.py`, `structure_page.py`, `preview_page.py` โ†’ [`gui_ui_pages`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_ui_pages.md) - `ui/pages/section_feature_selector.py` โ€” 2-vertex section selector (`fid โ€” label`, label field) โ†’ [`gui_ui_pages`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_ui_pages.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/section_feature_selector.md) - `ui/pages/interpretation_page.py` โ€” compatibility shim for `InterpretationTab` ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_tab.md) - `ui/pages/drillhole_page.py` โ†’ [`drillhole_page`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_page.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_page.md) - `ui/pages/drillhole/` (collar / survey / interval tabs) โ†’ [`gui_ui_pages_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_ui_pages_drillhole.md) ยท [`layer_gui_ui_pages_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages_drillhole.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages_drillhole.md) - `ui/pages/settings_page.py` โ†’ [`settings_page`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/settings_page.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/settings_page.md) - `ui/pages/settings/` (default / advanced / symbology / interpretation tabs + persistence) โ†’ [`gui_ui_pages_settings`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_ui_pages_settings.md) ยท [`layer_gui_ui_pages_settings`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages_settings.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_gui_ui_pages_settings.md) - `exporters/` ๐Ÿ“ค โ€” Factory `BaseExporter` โ†’ [`layer_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_exporters.md) - `base_exporter.py` โ†’ [`base_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/base_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/base_exporter.md) - `vector_exporter.py` โ†’ [`vector_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vector_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vector_exporter.md) - `dxf_exporter.py` โ†’ [`dxf_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dxf_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dxf_exporter.md) - `profile_exporters.py` / `csv_exporter.py` โ†’ [`profile_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/profile_exporters.md) ยท [`csv_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/csv_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/csv_exporter.md) - `interpretation_3d_exporter.py` โ†’ [`interpretation_3d_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_3d_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_3d_exporter.md) - `interpretation_exporters.py` โ†’ [`interpretation_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_exporters.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_exporters.md) - `drillhole_3d_exporter.py` โ†’ [`drillhole_3d_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_3d_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_3d_exporter.md) - `drillhole_exporters.py` โ†’ [`drillhole_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_exporters.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_exporters.md) - `pdf_exporter.py` โ†’ [`pdf_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/pdf_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/pdf_exporter.md) - `svg_exporter.py` โ†’ [`svg_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/svg_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/svg_exporter.md) - `image_exporter.py` โ†’ [`image_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/image_exporter.md) ยท [doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/image_exporter.md) - `docs/` ๐Ÿ“š โ€” `ARCHITECTURE_EN.md` (this file) ยท `ARCHITECTURE.mmd` ยท `code_walkthrough_v2/` vault - `tests/` ๐Ÿงช โ€” `base_test.py`, `core/`, `gui/`, `exporters/`, `integration/`, `agentic/`, `mcp/`, `mocks/`, `benchmarks/` (Mock-First, `unittest`) - `scripts/` ๐Ÿ”ง โ€” `security_scan.py` ยท `build_docs.sh` ยท `i18n/` ยท `sync_vault_mirrors.sh` - `resources/` ๐ŸŽจ โ€” `icons/`, `styles/`, `resources.qrc` โ†’ `resources.py` > [!tip] En Obsidian este รกrbol es navegable: cada `[`slug`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/slug.md)` abre la nota de la bรณveda y alimenta el Graph View. En GitHub/Sphinx usa el link `[doc](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/slug.md)` relativo. Los espejos en `docs/code_walkthrough*/ARCHITECTURE_EN.md` se re-sincronizan con `bash scripts/sync_vault_mirrors.sh`. --- ## ๐Ÿ—๏ธ System Architecture ### Complete Architecture Diagram ```mermaid graph TD classDef module fill:#f9f,stroke:#333,stroke-width:2px; classDef manager fill:#e1f5fe,stroke:#0277bd,stroke-width:2px; classDef service fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px; classDef interface fill:#fff3e0,stroke:#ef6c00,stroke-width:2px,stroke-dasharray: 5 5; classDef exporter fill:#fce4ec,stroke:#c2185b,stroke-width:2px; classDef task fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px; classDef renderer fill:#e0f2f1,stroke:#00695c,stroke-width:2px; %% ========== ENTRY POINT ========== QGIS[QGIS Application] PLUGIN[sec_interp_plugin.py
SecInterp Class
Plugin Root] %% ========== GUI LAYER ========== subgraph GUI["๐Ÿ–ฅ๏ธ GUI Layer - User Interface"] direction TB MAIN[main_dialog.py
SecInterpDialog] subgraph MANAGERS["Managers (Orchestration)"] direction TB SIGNALS_MGR[dialog_signal_manager.py
DialogSignalManager]:::manager INPUT_MGR[dialog_input_manager.py
DialogInputManager]:::manager PREVIEW_MGR[dialog_preview_manager.py
PreviewManager]:::manager EXPORT_MGR[dialog_export_manager.py
ExportManager]:::manager INTERP_MGR[dialog_interpretation_manager.py
InterpretationManager]:::manager STATE_MGR[dialog_state_manager.py
DialogStateManager]:::manager SETTINGS_MGR[dialog_settings_persistence.py
SettingsPersistence]:::manager TOOL_MGR[dialog_tool_manager.py
ToolManager]:::manager LAYER_NOTIF[layer_notification_manager.py
LayerNotificationManager]:::manager UI_STATUS[ui_status_manager.py
UIStatusManager]:::manager end subgraph RENDERING["Rendering Engine"] direction TB LAYER_FACTORY[preview_layer_factory.py
PreviewLayerFactory] AXES_MGR[preview_axes_manager.py
PreviewAxesManager] RENDERER[preview_renderer.py
PreviewRenderer] REPORTER[preview_reporter.py
PreviewReporter] PARAM_HASH[preview_param_hasher.py
PreviewParamHasher] PREVIEW_STATE[preview_state.py
PreviewState] end subgraph RENDERERS["Specialized Renderers"] direction TB BASE_RENDERER[renderers/base_renderer.py
BaseRenderer]:::renderer TOPO_RENDERER[renderers/topo_renderer.py
TopoRenderer]:::renderer GEOLOGY_RENDERER[renderers/geology_renderer.py
GeologyRenderer]:::renderer DRILLHOLE_RENDERER[renderers/drillhole_renderer.py
DrillholeRenderer]:::renderer STRUCT_RENDERER[renderers/structure_renderer.py
StructureRenderer]:::renderer INTERP_RENDERER[renderers/interpretation_renderer.py
InterpretationRenderer]:::renderer COLOR_MGR[renderers/color_manager.py
ColorManager]:::renderer end subgraph WORKERS["Async Tasks (QgsTask)"] direction TB TASK_ORCH[preview_task_orchestrator.py
PreviewTaskOrchestrator]:::task GEOLOGY_TASK[tasks/geology_task.py
GeologyTask]:::task DRILL_TASK[tasks/drillhole_task.py
DrillholeTask]:::task end subgraph TOOLS["Map Tools"] direction TB MAP_TOOLS[tools/
QgsMapTool Implementations] end subgraph UI_PAGES["UI Components"] direction TB PAGES[ui/pages/
Tab-based Pages] ADAPTERS[adapters/
UI Adapters] SIDE_PANEL[preview_side_panel.py
Preview Side Panel] SYMBOLOGY[symbology_tab.py
Live Symbology] end MAIN --> MANAGERS MAIN --> RENDERING MAIN --> RENDERERS MAIN --> WORKERS MAIN --> TOOLS MAIN --> UI_PAGES MAIN --> SIDE_PANEL MAIN --> SYMBOLOGY MANAGERS --> RENDERING MANAGERS --> WORKERS MANAGERS --> UI_PAGES WORKERS --> TASK_ORCH RENDERING --> RENDERERS end %% ========== CORE LAYER ========== subgraph CORE["โš™๏ธ Core Layer - Business Logic"] direction TB CONTROLLER[controller.py
ProfileController] subgraph INTERFACES["Abstractions (DI) - interfaces/"] direction TB I_GEOL[interfaces/geology_interface.py
IGeologyService]:::interface I_DRILL[interfaces/drillhole_interface.py
IDrillholeService]:::interface I_STRUCT[interfaces/structure_interface.py
IStructureService]:::interface I_PREVIEW[interfaces/preview_interface.py
IPreviewService]:::interface I_CACHE[interfaces/cache_interface.py
ICacheService]:::interface I_RENDER3D[interfaces/i_renderer_3d.py
IRenderer3D]:::interface end subgraph SERVICES["Concrete Services - services/"] direction TB GEOL_SVC[services/geology_service.py
GeologyService]:::service STRUCT_SVC[services/structure_service.py
StructureService]:::service DRILL_SVC[services/drillhole_service.py
DrillholeService]:::service EXPORT_SVC[services/export_service.py
ExportService]:::service PREVIEW_SVC[services/preview_service.py
PreviewService]:::service VE_SVC[services/vertical_exaggeration_service.py
VerticalExaggerationService]:::service ACCESS_SVC[services/access_control_service.py
AccessControlService]:::service subgraph DRILLHOLE_PKG["Drillhole Sub-system"] direction TB COLLAR_PROC[drillhole/collar_processor.py
CollarProcessor] SURVEY_PROC[drillhole/survey_processor.py
SurveyProcessor] INTERVAL_PROC[drillhole/interval_processor.py
IntervalProcessor] PROJ_ENGINE[drillhole/projection_engine.py
ProjectionEngine] TRAJ_ENGINE[drillhole/trajectory_engine.py
TrajectoryEngine] DRILL_SVC --> COLLAR_PROC DRILL_SVC --> SURVEY_PROC DRILL_SVC --> INTERVAL_PROC DRILL_SVC --> TRAJ_ENGINE COLLAR_PROC --> PROJ_ENGINE SURVEY_PROC --> TRAJ_ENGINE TRAJ_ENGINE --> PROJ_ENGINE end end subgraph MODELS["Domain Models - models/"] direction TB SETTINGS_MODEL[models/settings_model.py
SettingsModel] end subgraph DOMAIN["Domain Layer - domain/"] direction TB ENTITIES[Entities & DTOs
ProfileData, GeologySegment,
DrillholeData, etc.] end subgraph VALIDATION["Validation Pipeline - validation/"] direction TB BASE_VAL[base_validator.py
BaseValidator] PIPELINE[pipeline.py
ValidationPipeline] LAYER_VAL[layer_validator.py
LayerValidator] FIELD_VAL[field_validator.py
FieldValidator] PATH_VAL[path_validator.py
PathValidator] PROJECT_VAL[project_validator.py
ProjectValidator] PROJECT_VALS[project_validators.py
ProjectValidators] HELPERS[validation_helpers.py
ValidationHelpers] VALIDATORS[validators.py
Validators] end subgraph UTILS["Utilities - utils/"] direction TB DRILL_UTIL[drillhole.py
Drillhole Utils] GEOL_UTIL[geology.py
Geology Utils] GEOM_UTIL[geometry_utils/
Geometry Utilities] I18N_UTIL[i18n.py
i18n Utils] IO_UTIL[io.py
IO Utils] META_UTIL[metadata_reader.py
Metadata Reader] PARSE_UTIL[parsing.py
Parsing Utils] RENDER_UTIL[rendering.py
Rendering Utils] SAFE_LOADER[safe_loader.py
Safe Loader] SAMPLE_UTIL[sampling.py
Sampling Utils] SPATIAL_UTIL[spatial.py
Spatial Utils] end CONTROLLER --> INTERFACES INTERFACES -.-> SERVICES SERVICES --> MODELS SERVICES --> DOMAIN SERVICES --> VALIDATION SERVICES --> UTILS CONTROLLER --> VALIDATION end %% ========== EXPORTERS LAYER ========== subgraph EXPORTERS["๐Ÿ“ค Exporters Layer"] direction TB BASE_EXPORT[exporters/base_exporter.py
BaseExporter]:::exporter subgraph VECTOR["Vector Exporters"] direction TB VEC_EXPORT[exporters/vector_exporter.py
VectorExporter
GPKG/SHP/DXF]:::exporter DXF_EXPORT[exporters/dxf_exporter.py
DxfExporter]:::exporter end subgraph PROFILE["Profile Exporters"] direction TB PROF_EXPORT[exporters/profile_exporters.py
ProfileExporters]:::exporter CSV_EXPORT[exporters/csv_exporter.py
CsvExporter]:::exporter end subgraph INTERP_3D["3D Geologic Export"] direction TB INTERP_3D[exporters/interpretation_3d_exporter.py
Interpretation3DExporter]:::exporter INTERP_EXP[exporters/interpretation_exporters.py
InterpretationExporters]:::exporter end subgraph DRILL_3D["3D Drillhole Export"] direction TB DRILL_3D[exporters/drillhole_3d_exporter.py
Drillhole3DExporter]:::exporter DRILL_EXP[exporters/drillhole_exporters.py
DrillholeExporters]:::exporter end subgraph DOCUMENT["Document Exporters"] direction TB PDF_EXPORT[exporters/pdf_exporter.py
PdfExporter]:::exporter SVG_EXPORT[exporters/svg_exporter.py
SvgExporter]:::exporter IMG_EXPORT[exporters/image_exporter.py
ImageExporter]:::exporter end BASE_EXPORT --> VEC_EXPORT BASE_EXPORT --> PROF_EXPORT BASE_EXPORT --> INTERP_3D BASE_EXPORT --> DRILL_3D BASE_EXPORT --> PDF_EXPORT BASE_EXPORT --> SVG_EXPORT BASE_EXPORT --> IMG_EXPORT VEC_EXPORT --> DXF_EXPORT PROF_EXPORT --> CSV_EXPORT INTERP_3D --> INTERP_EXP DRILL_3D --> DRILL_EXP end %% ========== CONNECTIONS ========== QGIS --> PLUGIN PLUGIN --> MAIN %% GUI -> Core PREVIEW_MGR --> PREVIEW_SVC EXPORT_MGR --> EXPORT_SVC INTERP_MGR --> DRILL_SVC INTERP_MGR --> GEOL_SVC TOOL_MGR --> CONTROLLER %% Workers -> Controller TASK_ORCH --> CONTROLLER GEOLOGY_TASK --> CONTROLLER DRILL_TASK --> CONTROLLER %% Core -> Exporters EXPORT_SVC --> EXPORTERS %% Styles classDef plugin fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px,color:#fff class PLUGIN plugin ``` --- ## ๐Ÿ–ฅ๏ธ GUI Layer - User Interface ### 1. Manager-Based Orchestration (main_dialog.py) **Main Class**: `SecInterpDialog` **Responsibility**: The main dialog no longer contains business logic. It coordinates specialized **Managers** that handle specific lifecycle events and UI state. #### Key Managers (10 Specialized Managers) | Manager | File | Responsibility | |---------|------|----------------| | `DialogSignalManager` | `dialog_signal_manager.py` โ†’ [`dialog_signal_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_signal_manager.md) | Centralizes all signal/slot connections to avoid spaghetti code. | | `DialogInputManager` | `dialog_input_manager.py` โ†’ [`dialog_input_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_input_manager.md) | Manages input layer selection, schema validation, and layer compatibility. | | `PreviewManager` | `dialog_preview_manager.py` โ†’ [`dialog_preview_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_preview_manager.md) | Coordinates the preview canvas, axes, LOD calculation, and render triggering. | | `ExportManager` | `dialog_export_manager.py` โ†’ [`dialog_export_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_export_manager.md) | Maps UI selections to the `ExportService` in the Core layer. | | `InterpretationManager` | `dialog_interpretation_manager.py` โ†’ [`dialog_interpretation_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_interpretation_manager.md) | Handles 2D/3D geological interpretation state and user interactions. | | `DialogStateManager` | `dialog_state_manager.py` โ†’ [`dialog_state_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_state_manager.md) | Manages session persistence and UI defaults restoration. | | `SettingsPersistence` | `dialog_settings_persistence.py` โ†’ [`dialog_state_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_state_manager.md) | Handles QSettings-based persistence for plugin configuration. | | `ToolManager` | `dialog_tool_manager.py` โ†’ [`dialog_tool_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_tool_manager.md) | Manages `QgsMapTool` lifecycle (pan, measure, interpret tools). | | `LayerNotificationManager` | `layer_notification_manager.py` โ†’ [`layer_notification_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_notification_manager.md) | Listens to QGIS layer tree changes and updates UI accordingly. | | `UIStatusManager` | `ui_status_manager.py` โ†’ [`ui_status_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/ui_status_manager.md) | Manages status bar messages, progress indicators, and user notifications. | ### 2. Rendering Engine **Responsibility**: Handles all preview canvas rendering with adaptive LOD and specialized renderers. #### Core Rendering Components | Component | File | Responsibility | |---------|------|----------------| | `PreviewRenderer` | `preview_renderer.py` โ†’ [`preview_renderer`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_renderer.md) | Main canvas renderer orchestrating specialized renderers. | | `PreviewLayerFactory` | `preview_layer_factory.py` โ†’ [`preview_layer_factory`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_layer_factory.md) | Creates temporary memory layers for preview visualization. | | `PreviewAxesManager` | `preview_axes_manager.py` โ†’ [`preview_axes_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_axes_manager.md) | Manages coordinate axes, grids, and scale annotations. | | `PreviewReporter` | `preview_reporter.py` โ†’ [`preview_state`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) | Generates textual/tabular reports from preview data. | | `PreviewParamHasher` | `preview_param_hasher.py` โ†’ [`dialog_preview_manager`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dialog_preview_manager.md) | Hashes render parameters for LOD cache invalidation. | | `PreviewState` | `preview_state.py` โ†’ [`preview_state`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_state.md) | Encapsulates preview viewport, scale, and visibility state. | #### Specialized Renderers (Renderer Pattern) | Renderer | File | Responsibility | |----------|------|----------------| | `BaseRenderer` | `renderers/base_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Abstract base with common rendering utilities. | | `TopoRenderer` | `renderers/topo_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Renders topography profiles with elevation data. | | `GeologyRenderer` | `renderers/geology_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Renders geological units, contacts, and structures. | | `DrillholeRenderer` | `renderers/drillhole_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Renders drillhole traces, intervals, and projections. | | `StructureRenderer` | `renderers/structure_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Renders structural measurements (strike/dip, foliations). | | `InterpretationRenderer` | `renderers/interpretation_renderer.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Renders user-drawn geological interpretations. | | `ColorManager` | `renderers/color_manager.py` โ†’ [`gui_renderers`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_renderers.md) | Centralized color palette and legend management. | **LOD Optimization Methods** (in `PreviewRenderer`): | Method | Purpose | Algorithm | |--------|---------|-----------| | `_decimate_line_data()` | Line simplification | Douglas-Peucker | | `_calculate_curvature()` | Local curvature calculation | Angle between segments | | `_adaptive_sample()` | Adaptive sampling | Curvature-based density | ### 3. Async Task System (QgsTask) **Responsibility**: Offloads heavy computation to background threads keeping UI responsive. | Task | File | Responsibility | |------|------|----------------| | `PreviewTaskOrchestrator` | `preview_task_orchestrator.py` โ†’ [`gui_tasks`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_tasks.md) | Queues, prioritizes, and monitors background tasks. | | `GeologyTask` | `tasks/geology_task.py` โ†’ [`gui_tasks`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_tasks.md) | Background geological intersection calculations. | | `DrillholeTask` | `tasks/drillhole_task.py` โ†’ [`gui_tasks`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/gui_tasks.md) | Background drillhole trajectory processing. | ### 4. Map Tools & UI Components - **Map Tools** (`tools/`): `QgsMapTool` implementations for interactive editing (pan, measure, interpretation drawing). - **UI Pages** (`ui/pages/`): Page components for each plugin module; Interpretation Settings is hosted as a tab in `SettingsPage`, not a sidebar page. - **Section feature selector** (`ui/pages/section_feature_selector.py`): only single-part lines with exactly two vertices; shows `fid โ€” label`, supports `Auto` or an attribute label field, and forwards `section_feature_id` to preview/export/LOD. - **Interpretation settings tab** (`ui/pages/settings/interpretation_tab.py`): storage source (project JSON vs vector layer), custom fields and attribute inheritance; `MainWindow.page_interpretation` aliases the tab for compatibility. - **UI Adapters** (`adapters/`): Adapters bridging QGIS widgets to internal models. - **PreviewSidePanel** (`preview_side_panel.py`): Collapsible legend beside the preview, synchronized with the renderers; per-unit hide/color/alias, drillhole lithologies and the interpretations list. - **Symbology tab** (`ui/pages/settings/symbology_tab.py`, `symbology_units.py`): Live per-layer styles (topography, structures, drillholes, interpretations), the shared per-unit editor and the legend layout (position, font size, max items). ## โš™๏ธ Core Layer - Business Logic ### 1. Interface-Driven Design (interfaces/) **Pattern**: Dependency Injection (DI) via Abstract Base Classes (ABCs) **Responsibility**: All services are defined as interfaces. The `ProfileController` consumes interfaces, allowing for easy mocking during testing and replacement of logic without affecting the GUI. ```python class IGeologyService(ABC): @abstractmethod def build_segments(self, context: GeologyContext, feedback: Any | None = None) -> Any: """Build geological segments from a detached context.""" ``` #### Core Interfaces (6 Interfaces) | Interface | File | Purpose | |-----------|------|---------| | `IGeologyService` | `interfaces/geology_interface.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `build_segments()` โ€” geological segments from a detached context. | | `IDrillholeService` | `interfaces/drillhole_interface.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `process_context()` โ€” drillhole data processing, 3Dโ†’2D projection. | | `IStructureService` | `interfaces/structure_interface.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `project_structures()` โ€” structural data validation and projection. | | `IPreviewService` | `interfaces/preview_interface.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `generate_all()` โ€” preview orchestration and render data prep. | | `ICacheService` | `interfaces/cache_interface.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `get/set/invalidate/clear` โ€” caching strategy (typing `Protocol`). | | `IRenderer3D` | `interfaces/i_renderer_3d.py` โ†’ [`layer_core_interfaces`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_interfaces.md) | `render_3d()`/`clear()` โ€” 3D visualization abstraction. | ### 2. ProfileController (controller.py) **Responsibility**: Central orchestrator coordinating all services through their interfaces. #### Concrete Services (7 Services) | Service | File | Responsibility | |---------|------|----------------| | `GeologyService` | `services/geology_service.py` โ†’ [`geology_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/geology_service.md) | Core intersection algorithms (outcrops, polygons, units). | | `StructureService` | `services/structure_service.py` โ†’ [`structure_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/structure_service.md) | Structural data processing, validation, stereonets. | | `DrillholeService` | `services/drillhole_service.py` โ†’ [`drillhole_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_service.md) | 3D trajectory calculation, 2D section projection, interval management. | | `ExportService` | `services/export_service.py` โ†’ [`core_services`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services.md) | Central orchestrator for Exporters layer, format registry. | | `PreviewService` | `services/preview_service.py` โ†’ [`preview_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/preview_service.md) | Preview data preparation, LOD computation, render DTOs. | | `VerticalExaggerationService` | `services/vertical_exaggeration_service.py` โ†’ [`vertical_exaggeration_service`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vertical_exaggeration_service.md) | Adaptive vertical exaggeration from profile aspect ratio and structural density. | | `AccessControlService` | `services/access_control_service.py` โ†’ [`core_services`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services.md) | License validation, feature gating, user permissions. | #### Drillhole Sub-system (5 Components) | Component | File | Responsibility | |-----------|------|----------------| | `CollarProcessor` | `drillhole/collar_processor.py` โ†’ [`collar_processor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/collar_processor.md) | Collar data validation, coordinate transformation. | | `SurveyProcessor` | `drillhole/survey_processor.py` โ†’ [`core_services_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services_drillhole.md) | Survey data (azimuth/dip) processing, interpolation. | | `IntervalProcessor` | `drillhole/interval_processor.py` โ†’ [`interval_processor`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interval_processor.md) | Lithology/assay interval management, merging. | | `TrajectoryEngine` | `drillhole/trajectory_engine.py` โ†’ [`trajectory_engine`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/trajectory_engine.md) | 3D trajectory calculation (minimum curvature, etc.). | | `ProjectionEngine` | `drillhole/projection_engine.py` โ†’ [`core_services_drillhole`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_services_drillhole.md) | 3Dโ†’2D projection onto section plane. | #### Geology Sub-system - Geology processing is consolidated in `services/geology_service.py` (the former `services/geology/` package was removed). ### 3. Domain Layer - **Domain Models** (`models/settings_model.py`): `SettingsModel` for typed configuration. - **Entities & DTOs** (`domain/`): Immutable data transfer objects (`ProfileData`, `GeologySegment`, `DrillholeData`, etc.) for layer communication. ### 4. Validation Pipeline (validation/) Modular validation framework with 11 validators coordinated by `ValidationPipeline`: | Validator | File | Scope | |-----------|------|-------| | `BaseValidator` | `base_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Abstract base with common validation utilities. | | `ValidationPipeline` | `pipeline.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Orchestrates validators, aggregates results. | | `LayerValidator` | `layer_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | QGIS layer structure, CRS, geometry type validation. | | `FieldValidator` | `field_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Attribute field names, types, required fields. | | `PathValidator` | `path_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | File/directory paths, permissions, existence. | | `ProjectValidator` | `project_validator.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Project-level consistency (layers, settings). | | `ProjectValidators` | `project_validators.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Composite project validation rules. | | `ValidationHelpers` | `validation_helpers.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Shared validation utilities, error formatting. | | `Validators` | `validators.py` โ†’ [`core_validation`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_validation.md) | Convenience functions for common validations. | | `LayerMetadata` | `layer_metadata.py` โ†’ [`layer_metadata`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_metadata.md) | QGIS-agnostic layer metadata DTO consumed by the pipeline. | | `implausible_crs_reason()` | `crs_plausibility.py` โ†’ [`crs_plausibility`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/crs_plausibility.md) | Best-effort mislabelled-CRS detection from extent plausibility. | ### 5. Utilities (utils/) 11 specialized utility modules: | Utility | File | Purpose | |---------|------|---------| | Drillhole Utils | `drillhole.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Drillhole-specific calculations, transformations. | | Geology Utils | `geology.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Geological computations, unit conversions. | | Geometry Utils | `geometry_utils/` โ†’ [`layer_core_utils_geometry_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils_geometry_utils.md) | Advanced geometry operations (intersections, buffers). | | i18n Utils | `i18n.py` โ†’ [`core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/core_utils.md) | Translation helpers, locale management. | | QGIS I/O | `exporters/qgis_io.py` โ†’ [`layer_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_exporters.md) | Vector writer adapter (Shapefile/GPKG/DXF). | | Metadata Reader | `metadata_reader.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | QGIS layer metadata extraction. | | Parsing Utils | `parsing.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Text/CSV/XML parsing with error recovery. | | Rendering Utils | `rendering.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Render-ready data preparation. | | Safe Loader | `safe_loader.py` โ†’ [`safe_loader`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/safe_loader.md) | Safe YAML/JSON loading with schema validation. | | Sampling Utils | `sampling.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Statistical sampling, profile point generation. | | Spatial Utils | `spatial.py` โ†’ [`layer_core_utils`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/layer_core_utils.md) | Spatial queries, indexing, CRS operations. | ## ๐Ÿ“ค Exporters Layer The Exporters layer implements the **Factory Pattern** via `BaseExporter` abstract class. All exporters consume QGIS-agnostic DTOs from `core/domain`. ### Export Hierarchy ``` BaseExporter (ABC) โ”œโ”€โ”€ VectorExporter โ†’ DxfExporter โ”‚ โ”œโ”€โ”€ GPKG, SHP, DXF output โ”‚ โ””โ”€โ”€ Layer-based feature export โ”œโ”€โ”€ ProfileExporters โ†’ CsvExporter โ”‚ โ”œโ”€โ”€ Profile data (CSV, Excel) โ”‚ โ””โ”€โ”€ Sampling results export โ”œโ”€โ”€ Interpretation3DExporter โ†’ InterpretationExporters โ”‚ โ”œโ”€โ”€ 3D geological interpretations (Z-aware) โ”‚ โ””โ”€โ”€ GeoPackage 3D, CityJSON โ”œโ”€โ”€ Drillhole3DExporter โ†’ DrillholeExporters โ”‚ โ”œโ”€โ”€ 3D drillhole traces (Z-aware) โ”‚ โ””โ”€โ”€ Interval data as 3D cylinders โ”œโ”€โ”€ PdfExporter โ”‚ โ”œโ”€โ”€ Professional layouts with legends โ”‚ โ””โ”€โ”€ Multi-page section reports โ”œโ”€โ”€ SvgExporter โ”‚ โ”œโ”€โ”€ Vector graphics for publications โ”‚ โ””โ”€โ”€ Scalable section diagrams โ””โ”€โ”€ ImageExporter โ”œโ”€โ”€ PNG/JPG raster output โ””โ”€โ”€ High-DPI for presentations ``` ### Key Exporters | Exporter | File | Formats | Purpose | |----------|------|---------|---------| | `VectorExporter` | `vector_exporter.py` โ†’ [`vector_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/vector_exporter.md) | GPKG, SHP, DXF | Unified vector export for sections. | | `DxfExporter` | `dxf_exporter.py` โ†’ [`dxf_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/dxf_exporter.md) | DXF | CAD-compatible export. | | `ProfileExporters` | `profile_exporters.py` โ†’ [`profile_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/profile_exporters.md) | CSV, XLSX | Profile data tables, sampling results. | | `CsvExporter` | `csv_exporter.py` โ†’ [`csv_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/csv_exporter.md) | CSV | Raw data export. | | `Interpretation3DExporter` | `interpretation_3d_exporter.py` โ†’ [`interpretation_3d_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_3d_exporter.md) | GPKG 3D, CityJSON | 3D geological interpretations. | | `InterpretationExporters` | `interpretation_exporters.py` โ†’ [`interpretation_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/interpretation_exporters.md) | Multiple | Interpretation-specific formats. | | `Drillhole3DExporter` | `drillhole_3d_exporter.py` โ†’ [`drillhole_3d_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_3d_exporter.md) | GPKG 3D, WellKnown Text | 3D drillhole traces & intervals. | | `DrillholeExporters` | `drillhole_exporters.py` โ†’ [`drillhole_exporters`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/drillhole_exporters.md) | Multiple | Drillhole-specific formats. | | `PdfExporter` | `pdf_exporter.py` โ†’ [`pdf_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/pdf_exporter.md) | PDF | Professional section layouts. | | `SvgExporter` | `svg_exporter.py` โ†’ [`svg_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/svg_exporter.md) | SVG | Vector graphics for reports. | | `ImageExporter` | `image_exporter.py` โ†’ [`image_exporter`](https://github.com/geociencio/sec_interp/blob/main/docs/code_walkthrough_v2/image_exporter.md) | PNG, JPG | Raster images for presentations. | ### Format Decoupling All exporters implement: - `export(dto: ExportDTO, output_path: Path) -> ExportResult` - Consume only `core/domain` DTOs (no QGIS dependencies) - Return structured `ExportResult` with metadata (files created, features exported, warnings) ## ๐ŸŽจ Design Principles SecInterp v3.9.1 follows industry-standard architectural patterns to ensure high quality and testability. ### Core Architectural Patterns - **Manager Pattern (GUI)**: Decouples the main window from individual feature logic (Export, Preview, etc.). - **Dependency Injection (Core)**: Uses `core/interfaces` to decouple the `ProfileController` from concrete service implementations. - **Factory Pattern (Exporters)**: The `ExportService` dynamically selects the appropriate `BaseExporter` subclass. - **Observer Pattern (Signals)**: Extensive use of `qgis.PyQt.QtCore.pyqtSignal` for asynchronous communication between Core and GUI. - **DTO Pattern (Data Transfer Objects)**: All data passing between layers is encapsulated in immutable DTOs from `core/domain`. ### SOLID & Clean Code - **Interface Segregation**: Clients only depend on the specific service interfaces they need. - **Single Responsibility**: Each Manager and Service handles a unique, atomic part of the plugin workflow. - **Thread Safety**: Long-running operations only use `QgsTask` to avoid blocking the QGIS main thread. --- ## ๐Ÿš€ Extensibility ### Adding a New Service 1. Define the interface in `core/interfaces/` (inheriting from `abc.ABC`). 2. Implement the concrete service in `core/services/`. 3. Register the service in `controller.py` and inject it into the `ProfileController`. ### Adding a New Export Format 1. Inherit from `BaseExporter` in `exporters/`. 2. Implement the `export()` method using QGIS-agnostic logic. 3. Update the `ExportService` to include the new format in its registry. --- ## ๐Ÿ“Š Project Metrics | Metric | Value | |--------|-------| | **Python Modules** | 200 | | **Source Lines of Code (SLOC)** | ~24,400 | | **Core Layer** | ~34% | | **GUI Layer** | ~54% | | **Exporters Layer** | ~9% | | **Plugin Layer** | ~2% | --- ## ๐Ÿ”’ Quality Assurance & Security Scanning SecInterp implements a multi-layered quality assurance strategy that replicates and extends the QGIS Plugin Portal's automated scanning pipeline. ### 1. Local Security Scanning (Portal-Compatible) The project includes a custom security scanner (`scripts/security_scan.py`) that runs the **exact same tools** used by QGIS Plugin Portal: | Tool | Severity | Purpose | Configuration | |------|----------|---------|---------------| | **Bandit** | CRITICAL (Blocking) | Static analysis for Python security vulnerabilities (shell injection, pickle, eval, hardcoded secrets, weak crypto, SQL injection) | `.bandit` (excludes tests/scripts, 72 tests enabled) | | **detect-secrets** | CRITICAL (Blocking) | Scans for hardcoded credentials, API keys, private keys, high-entropy strings | `.secrets.baseline` (27 detectors, heuristic filters, excludes tests/venv) | | **Flake8** | INFO (Non-blocking) | Code quality, PEP 8 style, syntax errors, undefined names | `.flake8` (max-line-length=100, max-complexity=15, JSON output) | **Run locally:** ```bash make security-scan # Full portal-compatible scan make pylint # Additional static analysis make pep8 # Ruff-based style check (faster) ``` ### 2. QGIS Plugin Analyzer (Deep Auditing) For architectural and deep code quality audits beyond Portal scanning: ```bash # Security (Bandit + detect-secrets) uv run qgis-analyzer security . # Internationalization coverage uv run qgis-analyzer analyze i18n . # Performance (UI blocks, expensive loops, signal leaks) uv run qgis-analyzer analyze performance . # Architecture (Core/GUI separation, QGIS API usage, circular deps) uv run qgis-analyzer analyze architecture . # Full HTML report uv run qgis-analyzer analyze . --report ``` **Workflow**: `/audit-plugin` (agent `@auditor` with skills: project-context, coding-standards, i18n-standards) ### 3. Qt6 / QGIS 4 Migration Readiness Automated compatibility checking using the **same tool** QGIS Portal runs on upload: ```bash make qt6-check # Dry-run check (pyqgis4-checker via Docker) make qt6-fix # Auto-migrate enums to scoped Qt6 form (edits files) ``` ### 4. Pre-Release Validation Pipeline Complete validation before any release candidate: ```bash make pre-release # Runs: qt6-check + security-scan + docker-test ``` **`docker-test`** executes the full suite (763 tests, including 76 integration tests) in a clean QGIS Docker environment. ### 5. CI/CD Integration All tools are configured to run in CI pipelines with: - **Zero critical Bandit findings** required for merge - **Zero detect-secrets findings** (above baseline) required for merge - **Flake8 warnings** reported but non-blocking - **Full test suite** (unit + integration) must pass ### 6. Configuration Files (Committed to Repo) | File | Purpose | Portal Compatible | |------|---------|-------------------| | `.bandit` | Bandit test selection, exclude dirs | โœ… | | `.secrets.baseline` | detect-secrets baseline, filters, excludes | โœ… | | `.flake8` | Flake8 rules, complexity, output format | โœ… | | `pyproject.toml` | Ruff, pytest, mypy config | โš ๏ธ (dev only) | --- ## ๐Ÿ“ Final Notes This document provides a detailed overview of the SecInterp plugin architecture. For development information, please refer to [README_DEV.md](file:///home/jmbernales/qgispluginsdev/sec_interp/README_DEV.md). **Last Updated**: 2026-10-24 **Plugin Version**: 3.11.0 **Author**: Juan M. Bernales