Skip to content

Audit Kódu 3D-Platforma (HISTORICKÝ ODKAZ: PŘED MIGRACÍ NA .NET 10)

Poznámka k migracím: Tento dokument reprezentuje historický audit původního Python backendu z září 2026. Celá backendová a worker architektura byla následně v plném rozsahu refaktorována a migrována na C# .NET 10 Clean Architecture (Coveroq.Cad.Api, Coveroq.Cad.Application, Coveroq.Cad.Infrastructure, Coveroq.Cad.Worker). Původní nefunkční modul archive/python-backend/ byl kompletně odstraněn.

Datum konání auditování: Září 2026 Cíl auditování: Komplexní statická analýza a hodnocení kvality kódu repozitáře 3D-platforma se zaměřením na dodržování principů SOLID/SRP, DRY (duplikace kódu), Bezpečnost a Stabilitu systému.


1. Shrnutí stavu (Executive Summary)

Repozitář 3D-platforma představuje architekturu parametrického 3D konfigurátoru využívajícího C# .NET 10 na backendu, FreeCAD 1.1 jako geometrický solver a Three.js na frontendové části. Kód vykazuje vysoký stupeň modulárního uspořádání, separace vrstev (Clean Architecture) a má rozsáhlou sadu automatických testů.

I přes celkově vysokou kvalitu architektury byly během hloubkového auditu identifikovány oblasti vyžadující pozornost:

  1. SOLID & SRP: Byla nalezena porušení pravidla jedné odpovědnosti (Single Responsibility Principle) v několika klíčových metodách přesahujících limit 60 řádků (např. bulk_upsert_templates_and_parameters a solve_full_export) a třídách s více než 8 veřejnými metodami (IModelTemplateRepository, WorkerManager).
  2. DRY: Vyskytují se duplicity v obsluze procesů FreeCADu mezi lokální službou LocalCADService a worker solverem cad/worker/solver.py, a rovněž v databázových repozitářích a HTTP klientech.
  3. Bezpečnost a Spolehlivost: Byly detekovány kritické chybějící timeouty u síťových a I/O operací (HTTP volání bez timeout), nechráněný přístup ke sdílenému stavu v asynchronním/vláknovém prostředí (WorkerManager._active_workers a Solver._daemon_process) a široké zachytávání výjimek except Exception: bez korektního re-raise nebo propagace chyb.

2. Zjištěná porušení SOLID / SRP

Pravidlo jedné odpovědnosti (SRP) stanovuje, že třída nebo metoda by měla mít pouze jeden důvod ke změně. V rámci auditu byly aplikovány metriky: metody delší než 60 řádků a třídy s více než 8 veřejnými metodami.

2.1 Metody delší než 60 řádků

Soubor Metoda / Funkce Řádky kódu Rozsah řádků Popis porušení SRP
api/repositories/sql_model_repository.py bulk_upsert_templates_and_parameters() 63 L85–L147 Kombinuje spráci DB transakce, mapování entit, hromadný upsert šablon, synchronizaci parametrů a mazání zastaralých záznamů v jedné metodě.
cad/worker/solver.py solve_full_export() 61 L121–L181 Zajišťuje komunikaci s daemonem, záložní spouštění subprocessu FreeCADu, nastavení enviromentálních proměnných, správu dočasných adresářů a parsing výsledků.
scratch/create_bed_assembly.py create_bed_assembly() 101 L8–L108 Pomocný skript spojující vytvoření dokumentu, generování 3D geometrie, plnění tabulky parametrů a export do jednoho bloku.
scripts/db/benchmark_db_cleanup.py main() 62 L76–L137 Skript spojuje logiku měření výkonu, volání REST API v cyklu, sběr statistik a čištění databáze.
scripts/dev/verify_and_push.py audit_solid_rules() 64 L42–L105 Provádí AST průchod, počítání řádků, vyhodnocování pravidel a formátovaný výstup do konzole.
tests/test_architecture.py test_no_raw_enum_values() 70 L166–L235 Testovací metoda kontroluje více architektonických pravidel naráz.
tests/test_architecture.py test_mandatory_test_coverage_for_public_methods() 80 L382–L461 Komplexní AST inspekce testovacího pokrytí spojená s parsováním souborů.
tests/test_architecture.py test_automatic_documentation_generation() 88 L463–L550 Generování a validace dokumentace v jediném testu.
tests/test_repositories.py test_bulk_upsert_templates_and_parameters() 68 L94–L161 Testování přípravy dat, samotného upsertu i následného ověření stavu databáze.
tests/test_suite.py run_all_tests() 200 L7–L206 Sestavování testovací sady, spouštění runners, formátování výsledků a správa výstupů.

2.2 Třídy s více než 8 veřejnými metodami

Soubor Třída / Rozhraní Počet veřejných metod Metody Popis porušení
api/repositories/base.py IModelTemplateRepository 9 list_model_templates, ping_db, get_model_template, get_parameter_definitions, upsert_model_template, upsert_parameter_definitions, bulk_upsert_templates_and_parameters, delete_stale_templates, delete_model_template Rozhraní sdružuje CRUD šablon, CRUD parametrů, hromadné operace i zdraví databáze (ping_db).
api/repositories/sql_model_repository.py SQLModelTemplateRepository 9 viz výše Konkrétní implementace rozhraní IModelTemplateRepository.
api/repositories/worker_manager.py WorkerManager 9 register_template_sync_handler, get_instance, is_connected, register_worker, unregister_worker, dispatch_job, dispatch_git_update, dispatch_validation_job, handle_worker_message Spojuje správu životního cyklu WebSocket workerů, dispečink úloh (job, git update, validation) a zpracování příchozích zpráv.
tests/test_architecture.py TestArchitecture 12 12 testovacích metod Třída obsahuje testy různorodých architektonických aspektů.
tests/test_repositories.py TestDatabaseRepositories 12 12 testovacích metod Testuje modely šablon, objednávek, dílů i sestav v jedné třídě.
tests/test_services.py TestOrderOrchestrator 18 18 testovacích metod Sdružuje testy konfigurace, exportů, souborů i validace šablon.
tests/test_services.py TestStorageService 10 10 testovacích metod Testuje lokální i vzdálené (Google Drive) úložiště.
tests/test_services.py TestLocalCADServiceErrorHandling 11 11 testovacích metod Testuje validaci, daemon solver i subprocess výjimky.
tests/test_worker_manager.py TestWorkerManagerConcurrency 16 16 testovacích metod Testuje registraci workerů, concurrency i dispečink.

3. Zjištěná porušení DRY (Duplikace Kódu)

Princip Don't Repeat Yourself (DRY) vyžaduje, aby každá znalost nebo logika měla v systému jednoznačnou a nezpochybnitelnou reprezentaci.

3.1 Duplikace obsluhy FreeCAD procesů

  • Dotčené soubory: api/services/local_cad_service.py vs. cad/worker/solver.py
  • Popis duplicity: Oba soubory nezávisle na sobě implementují téměř identickou logiku pro:
  • Spouštění a zastavování na pozadí běžícího daemona (subprocess.Popen s FREECAD_PYTHON, přesměrování stdout/stderr do souborového logu, posílání SIGTERM/kill).
  • Spouštění záložního CLI procesu pro plný export (solve_full_export), včetně sestavování argumentů příkazové řádky (-c, cesta k runneru), nastavení enviromentálních proměnných (FREECAD_LIB_PATH, PYTHONPATH) a parsování výstupního JSONu.

3.2 Duplikace databázových vzorů a mapování

3.3 Duplikace parametrických operací s tabulkou Vars ve FreeCADu

  • Dotčené soubory: cad/scripts/runner.py vs. cad/scripts/cad_daemon.py
  • Popis duplicity: Otevírání .FCStd dokumentů, hledání objektu tabulky Vars, iterace přes klíče a zapisování nových hodnot do buněk se nachází na obou místech s minimálními odchylkami.

3.4 Duplikace HTTP komunikace u Worker Agenta

  • Dotčené soubory: cad/worker/client.py a cad/worker/uploader.py
  • Popis duplicity: Příprava HTTP záhlaví, odesílání POST požadavků s binárními daty nebo JSON payloadem na gateway server a zachytávání síťových výjimek je implementováno duplicitně bez sdíleného HTTP klienta.

4. Bezpečnostní a Stabilitní Rizika

Zjištěná rizika byla rozdělena do 3 kategorií podle závažnosti: Vysoké, Střední a Nízké.

4.1 Vysoké riziko (High Severity)

A. Chybějící timeouty u I/O a síťových volání (Blocking / Hang Hazard)

Sítě a podprocesy bez explicitního timeoutu mohou způsobit zablokování celého workeru nebo API serveru (zavěšené vteřiny až hodiny) při výpadku sítě nebo zamrznutí CAD jádra. - cad/scripts/parameters.py (L21, L30, L31, L32, L33, L34, L37, L96): HTTP get() volání bez nastavení timeout. - cad/worker/client.py (L29, L52, L106, L109, L126–L130, L137, L157–L160, L194): Volání HTTP API gateway z workeru bez timeoutu. - cad/worker/uploader.py (L35) a cad/worker/solver.py (L114): Odesílání vygenerovaných artefaktů přes HTTP bez timeoutu. - cad/worker_agent.py (L20, L33): Spouštění podprocesů (subprocess.run) a HTTP kontrol bez timeoutu.

B. Nekontrolovaný přístup ke stavu a Race Conditions (Concurrency Hazard)

  • api/services/worker_manager.py (L9–L175): Slovník _active_workers je modifikován a čten napříč asynchronními WebSocket spojeními (register_worker, unregister_worker, dispatch_job) bez použití asyncio.Lock. Při současném připojení/odpojení workerů hrozí KeyError nebo nekonzistentní stav dispečinku.
  • cad/worker/solver.py (L19–L50): Třídní proměnná _daemon_process je upravována v vícevláknovém/asynchronním prostředí bez použití threading.Lock.

4.2 Střední riziko (Medium Severity)

A. Nechráněné bloky except Exception: (Silent Swallowing & Masking)

Použití obecné výjimky bez opětného vyvolání (raise) nebo nastavení chybového stavu skrývá reálné příčiny havárií (např. chyby paměti, chyby zápisu na disk, nekorektní FreeCAD objekty). - cad/scripts/runner.py (L139, L180, L190, L211, L220, L227, L262, L282, L291, L325, L377): Výjimky jsou zachytávány obecně; na několika místech obsahují pouze pass nebo prostý výpis do logu, aniž by selhání propagovaly zpět do nadřazeného runneru. - cad/worker/client.py (L69, L133, L145, L170, L197): Zachytávání except Exception: v hlavním cyklu WebSocketu může zamaskovat kritické systemové chyby. - cad/worker/solver.py (L61, L117, L223, L231): Neuzavřené výjimky při komunikaci s daemonem. - cad/worker/syncer.py (L41) a cad/worker/uploader.py (L36): Tiché potlačení výjimek.

B. Neomezené spouštění náhradních subprocessů (Resource Exhaustion)

  • api/services/local_cad_service.py (L189, L250) a cad/worker/solver.py (L140, L198): Při selhání nebo nedostupnosti in-memory daemona systém automaticky spouští nový proces freecadcmd. Bez omezení paralelních požadavků (např. pomocí asyncio.Semaphore) může náhlý nápor požadavků způsobit vyčerpání CPU a paměti RAM na serveru.

4.3 Nízké riziko (Low Severity)

A. Zastarávání starých konfiguračních vzorů (Před migrací na .NET 10)

  • api/main.py: Staré FastAPI konfigurační vzory byly nahrazeny ASP.NET Core Minimal API v Coveroq.Cad.Api.
  • api/schemas/model.py: Pydantic schémata byla nahrazena C# Record DTOs v Coveroq.Cad.Application.

B. Pomocné a testovací skripty bez explicitního úklidu

  • scratch/create_bed_assembly.py a scripts/db/benchmark_db_cleanup.py: Případné nedovřené souborové deskriptory při předčasném ukončení skriptu.

5. Doporučený Plán Nápravy v Krocích

Pro odstranění identifikovaných nedostatků doporučujeme následující postupné kroky:

[ Krok 1: Bezpečnost a Timeouty ] ──► [ Krok 2: Synchro a Stav ] ──► [ Krok 3: Výjimky ]
                                                                             │
[ Krok 5: Architektura & SOLID ] ◄── [ Krok 4: Refaktorace DRY ] ◄───────────┘

Krok 1: Doplnění timeoutů u I/O a síťových volání (Priorita: VYSOKÁ)

  1. Do konfiguračního souboru cad/worker/config.py a api/config.py přidať konstantu DEFAULT_TIMEOUT = 30.0 (sekund).
  2. Doplnit parametr timeout=DEFAULT_TIMEOUT do všech HTTP volání (requests.get, requests.post, httpx, aiohttp) v:
  3. cad/scripts/parameters.py
  4. cad/worker/client.py
  5. cad/worker/uploader.py
  6. cad/worker/solver.py
  7. Doplnit explicitní timeout do všech volání subprocess.run(...) a subprocess.Popen.communicate(timeout=...).

Krok 2: Zabezpečení přístupu ke sdílenému stavu (Priorita: VYSOKÁ)

  1. V api/services/worker_manager.py zavést self._lock = asyncio.Lock() pro synchronizaci operací nad _active_workers.
  2. V cad/worker/solver.py zavést threading.Lock() kolem manipulace s procesem _daemon_process.
  3. V api/services/local_cad_service.py doplnit asyncio.Semaphore(max_concurrent_solves) pro omezení počtu současně běžících FreeCAD subprocessů.

Krok 3: Refaktorace zachytávání výjimek (Priorita: STŘEDNÍ)

  1. Nahradit generické except Exception: konkrétními výjimkami (např. requests.RequestException, subprocess.CalledProcessError, FreeCADError, FileNotFoundError).
  2. Odstranit tiché potlačování chyb (pass) v cad/scripts/runner.py a nahradit jej strukturovaným logováním přes cad_logger a propagací chyb do výstupního statusu JSON.

Krok 4: Eliminace duplicit kódu (DRY) (Priorita: STŘEDNÍ)

  1. Vytvořit společný modul cad/common/process.py se sdílenou logikou pro spouštění, monitoring a ukončování FreeCAD daemon a CLI procesů (sjednotit LocalCADService a cad/worker/solver.py).
  2. Vytvořit sdílenou pomocnou třídu pro HTTP komunikaci workeru v cad/worker/http_client.py.
  3. Vytvořit generický repozitář nebo pomocné metody v api/repositories/base.py pro redukci duplicitního SQLAlchemy kódu.

Krok 5: Refaktorace SOLID / SRP (Priorita: NÍZKÁ)

  1. Rozdělit metodu bulk_upsert_templates_and_parameters v SQLModelTemplateRepository na pomocné podmetody (_upsert_templates, _sync_parameters, _cleanup_stale_records).
  2. Rozdělit metodu solve_full_export v cad/worker/solver.py na fáze: příprava prostředí, vyvolání solveru, parsing výsledku.
  3. Rozdělit rozhraní IModelTemplateRepository na IModelTemplateRepository a IParameterRepository (Interface Segregation Principle).
  4. Migrovat backend na C# .NET 10 Minimal APIs a MediatR CQRS (Dokončeno).

Zprávu vygeneroval automatizovaný auditor kvality kódu Jules pro projekt 3D-platforma.