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í modularchive/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:
- 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_parametersasolve_full_export) a třídách s více než 8 veřejnými metodami (IModelTemplateRepository,WorkerManager). - DRY: Vyskytují se duplicity v obsluze procesů FreeCADu mezi lokální službou
LocalCADServicea worker solveremcad/worker/solver.py, a rovněž v databázových repozitářích a HTTP klientech. - 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_workersaSolver._daemon_process) a široké zachytávání výjimekexcept 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.pyvs.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.PopensFREECAD_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í
- Dotčené soubory:
api/repositories/sql_model_repository.py,api/repositories/sql_order_repository.py,api/repositories/sql_part_repository.py - Popis duplicity:
- Opakovaná vzorová logika pro otevírání a uzavírání SQLAlchemy relací, explicitní vyvolávání
self.db.rollback()při chybách a ošetřování chyb relace. - Duplikovaná logika pro ping databáze (
ping_db) napříč repozitáři.
3.3 Duplikace parametrických operací s tabulkou Vars ve FreeCADu
- Dotčené soubory:
cad/scripts/runner.pyvs.cad/scripts/cad_daemon.py - Popis duplicity:
Otevírání
.FCStddokumentů, hledání objektu tabulkyVars, 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.pyacad/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_workersje 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íKeyErrornebo nekonzistentní stav dispečinku.cad/worker/solver.py(L19–L50): Třídní proměnná_daemon_processje 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) acad/worker/solver.py(L140, L198): Při selhání nebo nedostupnosti in-memory daemona systém automaticky spouští nový procesfreecadcmd. 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 vCoveroq.Cad.Api.api/schemas/model.py: Pydantic schémata byla nahrazena C# Record DTOs vCoveroq.Cad.Application.
B. Pomocné a testovací skripty bez explicitního úklidu
scratch/create_bed_assembly.pyascripts/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Á)
- Do konfiguračního souboru
cad/worker/config.pyaapi/config.pypřidať konstantuDEFAULT_TIMEOUT = 30.0(sekund). - Doplnit parametr
timeout=DEFAULT_TIMEOUTdo všech HTTP volání (requests.get,requests.post,httpx,aiohttp) v: cad/scripts/parameters.pycad/worker/client.pycad/worker/uploader.pycad/worker/solver.py- Doplnit explicitní
timeoutdo všech volánísubprocess.run(...)asubprocess.Popen.communicate(timeout=...).
Krok 2: Zabezpečení přístupu ke sdílenému stavu (Priorita: VYSOKÁ)
- V
api/services/worker_manager.pyzavéstself._lock = asyncio.Lock()pro synchronizaci operací nad_active_workers. - V
cad/worker/solver.pyzavéstthreading.Lock()kolem manipulace s procesem_daemon_process. - V
api/services/local_cad_service.pydoplnitasyncio.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Í)
- Nahradit generické
except Exception:konkrétními výjimkami (např.requests.RequestException,subprocess.CalledProcessError,FreeCADError,FileNotFoundError). - Odstranit tiché potlačování chyb (
pass) vcad/scripts/runner.pya nahradit jej strukturovaným logováním přescad_loggera propagací chyb do výstupního statusu JSON.
Krok 4: Eliminace duplicit kódu (DRY) (Priorita: STŘEDNÍ)
- Vytvořit společný modul
cad/common/process.pyse sdílenou logikou pro spouštění, monitoring a ukončování FreeCAD daemon a CLI procesů (sjednotitLocalCADServiceacad/worker/solver.py). - Vytvořit sdílenou pomocnou třídu pro HTTP komunikaci workeru v
cad/worker/http_client.py. - Vytvořit generický repozitář nebo pomocné metody v
api/repositories/base.pypro redukci duplicitního SQLAlchemy kódu.
Krok 5: Refaktorace SOLID / SRP (Priorita: NÍZKÁ)
- Rozdělit metodu
bulk_upsert_templates_and_parametersvSQLModelTemplateRepositoryna pomocné podmetody (_upsert_templates,_sync_parameters,_cleanup_stale_records). - Rozdělit metodu
solve_full_exportvcad/worker/solver.pyna fáze: příprava prostředí, vyvolání solveru, parsing výsledku. - Rozdělit rozhraní
IModelTemplateRepositorynaIModelTemplateRepositoryaIParameterRepository(Interface Segregation Principle). - 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.