openconstructionerp 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openconstructionerp-0.2.1/.env.example +25 -0
- openconstructionerp-0.2.1/.gitignore +115 -0
- openconstructionerp-0.2.1/CLAUDE.md +60 -0
- openconstructionerp-0.2.1/PKG-INFO +138 -0
- openconstructionerp-0.2.1/README.md +45 -0
- openconstructionerp-0.2.1/alembic/env.py +71 -0
- openconstructionerp-0.2.1/alembic/script.py.mako +26 -0
- openconstructionerp-0.2.1/alembic/versions/129188e46db8_init_create_all_tables.py +32 -0
- openconstructionerp-0.2.1/alembic.ini +35 -0
- openconstructionerp-0.2.1/app/__init__.py +0 -0
- openconstructionerp-0.2.1/app/__main__.py +56 -0
- openconstructionerp-0.2.1/app/cli.py +236 -0
- openconstructionerp-0.2.1/app/cli_static.py +92 -0
- openconstructionerp-0.2.1/app/config.py +94 -0
- openconstructionerp-0.2.1/app/core/__init__.py +0 -0
- openconstructionerp-0.2.1/app/core/cache.py +180 -0
- openconstructionerp-0.2.1/app/core/demo_projects.py +2551 -0
- openconstructionerp-0.2.1/app/core/events.py +174 -0
- openconstructionerp-0.2.1/app/core/hooks.py +167 -0
- openconstructionerp-0.2.1/app/core/i18n.py +3221 -0
- openconstructionerp-0.2.1/app/core/i18n_router.py +24 -0
- openconstructionerp-0.2.1/app/core/marketplace.py +1015 -0
- openconstructionerp-0.2.1/app/core/module_loader.py +234 -0
- openconstructionerp-0.2.1/app/core/permissions.py +159 -0
- openconstructionerp-0.2.1/app/core/plugin_manager.py +229 -0
- openconstructionerp-0.2.1/app/core/rate_limiter.py +40 -0
- openconstructionerp-0.2.1/app/core/sqlite_migrator.py +86 -0
- openconstructionerp-0.2.1/app/core/validation/__init__.py +0 -0
- openconstructionerp-0.2.1/app/core/validation/engine.py +391 -0
- openconstructionerp-0.2.1/app/core/validation/rules/__init__.py +1853 -0
- openconstructionerp-0.2.1/app/core/vector.py +345 -0
- openconstructionerp-0.2.1/app/database.py +126 -0
- openconstructionerp-0.2.1/app/dependencies.py +193 -0
- openconstructionerp-0.2.1/app/main.py +713 -0
- openconstructionerp-0.2.1/app/middleware/__init__.py +0 -0
- openconstructionerp-0.2.1/app/middleware/fingerprint.py +34 -0
- openconstructionerp-0.2.1/app/modules/__init__.py +0 -0
- openconstructionerp-0.2.1/app/modules/ai/__init__.py +13 -0
- openconstructionerp-0.2.1/app/modules/ai/ai_client.py +506 -0
- openconstructionerp-0.2.1/app/modules/ai/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/ai/models.py +95 -0
- openconstructionerp-0.2.1/app/modules/ai/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/ai/prompts.py +198 -0
- openconstructionerp-0.2.1/app/modules/ai/repository.py +78 -0
- openconstructionerp-0.2.1/app/modules/ai/router.py +858 -0
- openconstructionerp-0.2.1/app/modules/ai/schemas.py +155 -0
- openconstructionerp-0.2.1/app/modules/ai/service.py +1033 -0
- openconstructionerp-0.2.1/app/modules/assemblies/__init__.py +13 -0
- openconstructionerp-0.2.1/app/modules/assemblies/manifest.py +18 -0
- openconstructionerp-0.2.1/app/modules/assemblies/models.py +114 -0
- openconstructionerp-0.2.1/app/modules/assemblies/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/assemblies/repository.py +196 -0
- openconstructionerp-0.2.1/app/modules/assemblies/router.py +473 -0
- openconstructionerp-0.2.1/app/modules/assemblies/schemas.py +173 -0
- openconstructionerp-0.2.1/app/modules/assemblies/service.py +677 -0
- openconstructionerp-0.2.1/app/modules/backup/__init__.py +0 -0
- openconstructionerp-0.2.1/app/modules/backup/manifest.py +12 -0
- openconstructionerp-0.2.1/app/modules/backup/router.py +470 -0
- openconstructionerp-0.2.1/app/modules/boq/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/boq/ai_prompts.py +178 -0
- openconstructionerp-0.2.1/app/modules/boq/cad_import.py +745 -0
- openconstructionerp-0.2.1/app/modules/boq/epd_materials.py +266 -0
- openconstructionerp-0.2.1/app/modules/boq/events.py +156 -0
- openconstructionerp-0.2.1/app/modules/boq/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/boq/models.py +272 -0
- openconstructionerp-0.2.1/app/modules/boq/pdf_export.py +1035 -0
- openconstructionerp-0.2.1/app/modules/boq/permissions.py +18 -0
- openconstructionerp-0.2.1/app/modules/boq/repository.py +342 -0
- openconstructionerp-0.2.1/app/modules/boq/router.py +3788 -0
- openconstructionerp-0.2.1/app/modules/boq/schemas.py +897 -0
- openconstructionerp-0.2.1/app/modules/boq/service.py +3368 -0
- openconstructionerp-0.2.1/app/modules/boq/templates.py +1274 -0
- openconstructionerp-0.2.1/app/modules/cad/__init__.py +0 -0
- openconstructionerp-0.2.1/app/modules/cad/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/catalog/__init__.py +13 -0
- openconstructionerp-0.2.1/app/modules/catalog/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/catalog/models.py +60 -0
- openconstructionerp-0.2.1/app/modules/catalog/permissions.py +17 -0
- openconstructionerp-0.2.1/app/modules/catalog/repository.py +199 -0
- openconstructionerp-0.2.1/app/modules/catalog/router.py +392 -0
- openconstructionerp-0.2.1/app/modules/catalog/schemas.py +111 -0
- openconstructionerp-0.2.1/app/modules/catalog/service.py +462 -0
- openconstructionerp-0.2.1/app/modules/changeorders/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/changeorders/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/changeorders/models.py +93 -0
- openconstructionerp-0.2.1/app/modules/changeorders/permissions.py +17 -0
- openconstructionerp-0.2.1/app/modules/changeorders/repository.py +145 -0
- openconstructionerp-0.2.1/app/modules/changeorders/router.py +320 -0
- openconstructionerp-0.2.1/app/modules/changeorders/schemas.py +157 -0
- openconstructionerp-0.2.1/app/modules/changeorders/service.py +317 -0
- openconstructionerp-0.2.1/app/modules/costmodel/__init__.py +13 -0
- openconstructionerp-0.2.1/app/modules/costmodel/manifest.py +18 -0
- openconstructionerp-0.2.1/app/modules/costmodel/models.py +156 -0
- openconstructionerp-0.2.1/app/modules/costmodel/permissions.py +15 -0
- openconstructionerp-0.2.1/app/modules/costmodel/repository.py +322 -0
- openconstructionerp-0.2.1/app/modules/costmodel/router.py +449 -0
- openconstructionerp-0.2.1/app/modules/costmodel/schemas.py +333 -0
- openconstructionerp-0.2.1/app/modules/costmodel/service.py +1061 -0
- openconstructionerp-0.2.1/app/modules/costs/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/costs/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/costs/models.py +56 -0
- openconstructionerp-0.2.1/app/modules/costs/permissions.py +18 -0
- openconstructionerp-0.2.1/app/modules/costs/repository.py +169 -0
- openconstructionerp-0.2.1/app/modules/costs/router.py +1948 -0
- openconstructionerp-0.2.1/app/modules/costs/schemas.py +110 -0
- openconstructionerp-0.2.1/app/modules/costs/service.py +235 -0
- openconstructionerp-0.2.1/app/modules/documents/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/documents/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/documents/models.py +51 -0
- openconstructionerp-0.2.1/app/modules/documents/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/documents/repository.py +103 -0
- openconstructionerp-0.2.1/app/modules/documents/router.py +201 -0
- openconstructionerp-0.2.1/app/modules/documents/schemas.py +59 -0
- openconstructionerp-0.2.1/app/modules/documents/service.py +213 -0
- openconstructionerp-0.2.1/app/modules/projects/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/projects/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/projects/models.py +52 -0
- openconstructionerp-0.2.1/app/modules/projects/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/projects/repository.py +81 -0
- openconstructionerp-0.2.1/app/modules/projects/router.py +235 -0
- openconstructionerp-0.2.1/app/modules/projects/schemas.py +79 -0
- openconstructionerp-0.2.1/app/modules/projects/service.py +160 -0
- openconstructionerp-0.2.1/app/modules/reporting/__init__.py +0 -0
- openconstructionerp-0.2.1/app/modules/reporting/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/risk/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/risk/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/risk/models.py +54 -0
- openconstructionerp-0.2.1/app/modules/risk/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/risk/repository.py +84 -0
- openconstructionerp-0.2.1/app/modules/risk/router.py +183 -0
- openconstructionerp-0.2.1/app/modules/risk/schemas.py +132 -0
- openconstructionerp-0.2.1/app/modules/risk/service.py +234 -0
- openconstructionerp-0.2.1/app/modules/schedule/__init__.py +12 -0
- openconstructionerp-0.2.1/app/modules/schedule/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/schedule/models.py +170 -0
- openconstructionerp-0.2.1/app/modules/schedule/permissions.py +17 -0
- openconstructionerp-0.2.1/app/modules/schedule/repository.py +206 -0
- openconstructionerp-0.2.1/app/modules/schedule/router.py +487 -0
- openconstructionerp-0.2.1/app/modules/schedule/schemas.py +354 -0
- openconstructionerp-0.2.1/app/modules/schedule/service.py +1677 -0
- openconstructionerp-0.2.1/app/modules/takeoff/__init__.py +8 -0
- openconstructionerp-0.2.1/app/modules/takeoff/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/takeoff/models.py +56 -0
- openconstructionerp-0.2.1/app/modules/takeoff/permissions.py +16 -0
- openconstructionerp-0.2.1/app/modules/takeoff/repository.py +51 -0
- openconstructionerp-0.2.1/app/modules/takeoff/router.py +990 -0
- openconstructionerp-0.2.1/app/modules/takeoff/schemas.py +86 -0
- openconstructionerp-0.2.1/app/modules/takeoff/service.py +211 -0
- openconstructionerp-0.2.1/app/modules/tendering/__init__.py +1 -0
- openconstructionerp-0.2.1/app/modules/tendering/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/tendering/models.py +92 -0
- openconstructionerp-0.2.1/app/modules/tendering/permissions.py +19 -0
- openconstructionerp-0.2.1/app/modules/tendering/repository.py +120 -0
- openconstructionerp-0.2.1/app/modules/tendering/router.py +430 -0
- openconstructionerp-0.2.1/app/modules/tendering/schemas.py +160 -0
- openconstructionerp-0.2.1/app/modules/tendering/service.py +317 -0
- openconstructionerp-0.2.1/app/modules/users/__init__.py +11 -0
- openconstructionerp-0.2.1/app/modules/users/manifest.py +15 -0
- openconstructionerp-0.2.1/app/modules/users/models.py +82 -0
- openconstructionerp-0.2.1/app/modules/users/permissions.py +18 -0
- openconstructionerp-0.2.1/app/modules/users/repository.py +123 -0
- openconstructionerp-0.2.1/app/modules/users/router.py +266 -0
- openconstructionerp-0.2.1/app/modules/users/schemas.py +158 -0
- openconstructionerp-0.2.1/app/modules/users/service.py +476 -0
- openconstructionerp-0.2.1/app/modules/validation/__init__.py +0 -0
- openconstructionerp-0.2.1/app/schemas.py +268 -0
- openconstructionerp-0.2.1/app/scripts/__init__.py +0 -0
- openconstructionerp-0.2.1/app/scripts/create_tables.py +26 -0
- openconstructionerp-0.2.1/app/scripts/export_catalog_csv.py +245 -0
- openconstructionerp-0.2.1/app/scripts/export_full_catalog.py +288 -0
- openconstructionerp-0.2.1/app/scripts/seed_catalog.py +227 -0
- openconstructionerp-0.2.1/app/scripts/seed_demo.py +252 -0
- openconstructionerp-0.2.1/app/scripts/seed_demo_4d5d.py +273 -0
- openconstructionerp-0.2.1/app/scripts/seed_demo_estimates.py +859 -0
- openconstructionerp-0.2.1/app/scripts/seed_international.py +231 -0
- openconstructionerp-0.2.1/app/scripts/seed_schedule_demo.py +674 -0
- openconstructionerp-0.2.1/app/scripts/seed_sections.py +77 -0
- openconstructionerp-0.2.1/build_all_catalogs.py +247 -0
- openconstructionerp-0.2.1/build_catalog.py +94 -0
- openconstructionerp-0.2.1/locales/ar.json +163 -0
- openconstructionerp-0.2.1/locales/cs.json +141 -0
- openconstructionerp-0.2.1/locales/da.json +141 -0
- openconstructionerp-0.2.1/locales/de.json +182 -0
- openconstructionerp-0.2.1/locales/en.json +182 -0
- openconstructionerp-0.2.1/locales/es.json +141 -0
- openconstructionerp-0.2.1/locales/fi.json +141 -0
- openconstructionerp-0.2.1/locales/fr.json +141 -0
- openconstructionerp-0.2.1/locales/hi.json +141 -0
- openconstructionerp-0.2.1/locales/it.json +141 -0
- openconstructionerp-0.2.1/locales/ja.json +141 -0
- openconstructionerp-0.2.1/locales/ko.json +141 -0
- openconstructionerp-0.2.1/locales/nl.json +141 -0
- openconstructionerp-0.2.1/locales/no.json +141 -0
- openconstructionerp-0.2.1/locales/pl.json +141 -0
- openconstructionerp-0.2.1/locales/pt.json +141 -0
- openconstructionerp-0.2.1/locales/ru.json +182 -0
- openconstructionerp-0.2.1/locales/sv.json +141 -0
- openconstructionerp-0.2.1/locales/tr.json +141 -0
- openconstructionerp-0.2.1/locales/zh.json +141 -0
- openconstructionerp-0.2.1/openestimate-server.spec +54 -0
- openconstructionerp-0.2.1/pyproject.toml +192 -0
- openconstructionerp-0.2.1/qa_ai_test.py +303 -0
- openconstructionerp-0.2.1/qa_api_test.py +1785 -0
- openconstructionerp-0.2.1/requirements.txt +238 -0
- openconstructionerp-0.2.1/tests/__init__.py +0 -0
- openconstructionerp-0.2.1/tests/conftest.py +110 -0
- openconstructionerp-0.2.1/tests/integration/__init__.py +0 -0
- openconstructionerp-0.2.1/tests/integration/test_api_smoke.py +286 -0
- openconstructionerp-0.2.1/tests/integration/test_full_platform.py +1496 -0
- openconstructionerp-0.2.1/tests/unit/__init__.py +0 -0
- openconstructionerp-0.2.1/tests/unit/test_ai_client.py +171 -0
- openconstructionerp-0.2.1/tests/unit/test_ai_prompts.py +108 -0
- openconstructionerp-0.2.1/tests/unit/test_boq_schemas.py +300 -0
- openconstructionerp-0.2.1/tests/unit/test_boq_templates.py +123 -0
- openconstructionerp-0.2.1/tests/unit/test_config.py +166 -0
- openconstructionerp-0.2.1/tests/unit/test_cost_schemas.py +163 -0
- openconstructionerp-0.2.1/tests/unit/test_database.py +151 -0
- openconstructionerp-0.2.1/tests/unit/test_events_hooks.py +198 -0
- openconstructionerp-0.2.1/tests/unit/test_i18n.py +203 -0
- openconstructionerp-0.2.1/tests/unit/test_permissions.py +376 -0
- openconstructionerp-0.2.1/tests/unit/test_project_schemas.py +137 -0
- openconstructionerp-0.2.1/tests/unit/test_schemas_core.py +247 -0
- openconstructionerp-0.2.1/tests/unit/test_users.py +580 -0
- openconstructionerp-0.2.1/tests/unit/test_validation_engine.py +237 -0
- openconstructionerp-0.2.1/tmp_api.json +1 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Database (default: SQLite, no config needed)
|
|
2
|
+
# DATABASE_URL=sqlite+aiosqlite:///./openestimate.db
|
|
3
|
+
# For PostgreSQL:
|
|
4
|
+
# DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/openestimate
|
|
5
|
+
|
|
6
|
+
# Auth
|
|
7
|
+
JWT_SECRET=change-me-in-production
|
|
8
|
+
|
|
9
|
+
# Redis (optional)
|
|
10
|
+
# REDIS_URL=redis://localhost:6379/0
|
|
11
|
+
|
|
12
|
+
# S3/MinIO (optional)
|
|
13
|
+
# S3_ENDPOINT=http://localhost:9000
|
|
14
|
+
# S3_ACCESS_KEY=minioadmin
|
|
15
|
+
# S3_SECRET_KEY=minioadmin
|
|
16
|
+
|
|
17
|
+
# AI (optional — add your provider key)
|
|
18
|
+
# OPENAI_API_KEY=sk-...
|
|
19
|
+
# ANTHROPIC_API_KEY=sk-ant-...
|
|
20
|
+
|
|
21
|
+
# Vector search backend (default: lancedb)
|
|
22
|
+
# VECTOR_BACKEND=lancedb
|
|
23
|
+
|
|
24
|
+
# Demo accounts (set to false in production)
|
|
25
|
+
# SEED_DEMO=true
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.eggs/
|
|
8
|
+
*.egg
|
|
9
|
+
.venv/
|
|
10
|
+
venv/
|
|
11
|
+
|
|
12
|
+
# Node
|
|
13
|
+
node_modules/
|
|
14
|
+
frontend/dist/
|
|
15
|
+
|
|
16
|
+
# IDE
|
|
17
|
+
.vscode/
|
|
18
|
+
.idea/
|
|
19
|
+
*.swp
|
|
20
|
+
*.swo
|
|
21
|
+
|
|
22
|
+
# OS
|
|
23
|
+
.DS_Store
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# Environment
|
|
27
|
+
.env
|
|
28
|
+
.env.local
|
|
29
|
+
.env.production
|
|
30
|
+
|
|
31
|
+
# Database
|
|
32
|
+
*.db
|
|
33
|
+
*.db-shm
|
|
34
|
+
*.db-wal
|
|
35
|
+
*.sqlite3
|
|
36
|
+
openestimate.db*
|
|
37
|
+
|
|
38
|
+
# Docker volumes
|
|
39
|
+
pg_data/
|
|
40
|
+
minio_data/
|
|
41
|
+
qdrant_data/
|
|
42
|
+
|
|
43
|
+
# Testing
|
|
44
|
+
htmlcov/
|
|
45
|
+
.coverage
|
|
46
|
+
coverage.xml
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
frontend/test-results/
|
|
49
|
+
frontend/e2e-results/
|
|
50
|
+
*.trace.zip
|
|
51
|
+
|
|
52
|
+
# Build
|
|
53
|
+
*.tar.gz
|
|
54
|
+
*.whl
|
|
55
|
+
frontend/stats.html
|
|
56
|
+
|
|
57
|
+
# Logs
|
|
58
|
+
*.log
|
|
59
|
+
logs/
|
|
60
|
+
|
|
61
|
+
# Generated
|
|
62
|
+
backend/locales/
|
|
63
|
+
i18n-audit/
|
|
64
|
+
translation_keys.txt
|
|
65
|
+
|
|
66
|
+
# Claude Code / MCP
|
|
67
|
+
.claude/
|
|
68
|
+
.mcp.json
|
|
69
|
+
.playwright-mcp/
|
|
70
|
+
|
|
71
|
+
# QA / Dev artifacts
|
|
72
|
+
screenshots/
|
|
73
|
+
!docs/screenshots/
|
|
74
|
+
qa-tests/
|
|
75
|
+
ux-review/
|
|
76
|
+
QA_*.md
|
|
77
|
+
UX_*.md
|
|
78
|
+
TESTING_PLAN.md
|
|
79
|
+
TAKEOFF_TESTING_PLAN.md
|
|
80
|
+
IMPROVEMENTS_TODO.md
|
|
81
|
+
AUDIT_*.md
|
|
82
|
+
REVIEW_PROGRESS.md
|
|
83
|
+
test-screenshots/
|
|
84
|
+
|
|
85
|
+
# Dev screenshots & images
|
|
86
|
+
*.png
|
|
87
|
+
*.jpeg
|
|
88
|
+
*.jpg
|
|
89
|
+
!frontend/public/favicon.png
|
|
90
|
+
!frontend/public/logo.png
|
|
91
|
+
!docs/screenshots/*.png
|
|
92
|
+
!frontend/public/og-image.png
|
|
93
|
+
!frontend/public/*.jpg
|
|
94
|
+
!frontend/public/*.jpeg
|
|
95
|
+
|
|
96
|
+
# QA test scripts (contain demo credentials)
|
|
97
|
+
backend/qa_*.py
|
|
98
|
+
backend/tmp_*.json
|
|
99
|
+
|
|
100
|
+
# LanceDB local data
|
|
101
|
+
lancedb_data/
|
|
102
|
+
*.lance
|
|
103
|
+
|
|
104
|
+
# Cached data
|
|
105
|
+
*.parquet
|
|
106
|
+
.openestimator/
|
|
107
|
+
|
|
108
|
+
# Desktop build
|
|
109
|
+
desktop/dist/
|
|
110
|
+
desktop/build/
|
|
111
|
+
desktop/src-tauri/target/
|
|
112
|
+
desktop/src-tauri/binaries/
|
|
113
|
+
|
|
114
|
+
# Backup files
|
|
115
|
+
*.backup.*
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# CLAUDE.md — Backend (FastAPI)
|
|
2
|
+
|
|
3
|
+
Parent: [../CLAUDE.md](../CLAUDE.md)
|
|
4
|
+
|
|
5
|
+
## Контекст
|
|
6
|
+
|
|
7
|
+
FastAPI backend для OpenEstimate. Async-first, module-based architecture.
|
|
8
|
+
Все бизнес-модули в `app/modules/`. Core framework в `app/core/`.
|
|
9
|
+
|
|
10
|
+
## Команды
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
uvicorn app.main:create_app --factory --reload --port 8000
|
|
14
|
+
pytest
|
|
15
|
+
pytest --cov=app --cov-report=term
|
|
16
|
+
ruff check app/ tests/
|
|
17
|
+
ruff format app/ tests/
|
|
18
|
+
alembic upgrade head
|
|
19
|
+
alembic revision --autogenerate -m "description"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Архитектурные правила
|
|
23
|
+
|
|
24
|
+
### Layered Architecture
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
Router (HTTP) → Service (Business Logic) → Repository (Data Access) → Database
|
|
28
|
+
↕ ↕
|
|
29
|
+
Events/Hooks SQLAlchemy Models
|
|
30
|
+
↕
|
|
31
|
+
Validation
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- **Router**: только HTTP логика. НЕ бизнес-логика.
|
|
35
|
+
- **Service**: вся бизнес-логика. Stateless. Events, hooks, validation.
|
|
36
|
+
- **Repository**: data access. SQLAlchemy queries only.
|
|
37
|
+
- **Models**: SQLAlchemy ORM. Наследуют `app.database.Base`.
|
|
38
|
+
- **Schemas**: Pydantic v2 request/response.
|
|
39
|
+
|
|
40
|
+
### Database Conventions
|
|
41
|
+
|
|
42
|
+
- Table names: `oe_{module}_{entity}`
|
|
43
|
+
- All tables: `id` (UUID PK), `created_at`, `updated_at`, `created_by`
|
|
44
|
+
- JSONB для metadata
|
|
45
|
+
- Temporal: `valid_from`, `valid_to` для versioned records
|
|
46
|
+
|
|
47
|
+
### Validation — обязательна при любом импорте данных
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
report = await validation_engine.validate(data=parsed, rule_sets=["gaeb", "boq_quality"])
|
|
51
|
+
if report.has_errors:
|
|
52
|
+
return ImportResult(status="validation_failed", report=report)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Performance Targets
|
|
56
|
+
|
|
57
|
+
- CRUD: < 200ms (p95)
|
|
58
|
+
- BOQ load 1000 positions: < 500ms
|
|
59
|
+
- Validation 1000 positions: < 2s
|
|
60
|
+
- CWICR search: < 100ms
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openconstructionerp
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: The #1 open-source platform for construction cost estimation — BOQ, 4D/5D, AI, CAD/BIM takeoff
|
|
5
|
+
Project-URL: Homepage, https://datadrivenconstruction.io/erp
|
|
6
|
+
Project-URL: Documentation, https://openconstructionerp.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/datadrivenconstruction/OpenConstructionERP
|
|
8
|
+
Project-URL: Issues, https://github.com/datadrivenconstruction/OpenConstructionERP/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/datadrivenconstruction/OpenConstructionERP/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Artem Boiko <info@datadrivenconstruction.io>
|
|
11
|
+
Maintainer-email: Data Driven Construction <info@datadrivenconstruction.io>
|
|
12
|
+
License-Expression: AGPL-3.0-or-later
|
|
13
|
+
Keywords: bill-of-quantities,bim,boq,cad,construction,cost-estimation,cwicr,din276,erp,fastapi,gaeb,ifc,masterformat,nrm,open-source,quantity-surveying,react,revit
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
26
|
+
Requires-Dist: alembic>=1.14.0
|
|
27
|
+
Requires-Dist: bcrypt>=4.0.0
|
|
28
|
+
Requires-Dist: email-validator>=2.1.0
|
|
29
|
+
Requires-Dist: fastapi>=0.115.0
|
|
30
|
+
Requires-Dist: httpx>=0.28.0
|
|
31
|
+
Requires-Dist: openpyxl>=3.1.0
|
|
32
|
+
Requires-Dist: orjson>=3.10.0
|
|
33
|
+
Requires-Dist: pdfplumber>=0.11.0
|
|
34
|
+
Requires-Dist: pydantic-settings>=2.6.0
|
|
35
|
+
Requires-Dist: pydantic>=2.10.0
|
|
36
|
+
Requires-Dist: python-dateutil>=2.9.0
|
|
37
|
+
Requires-Dist: python-jose[cryptography]>=3.3.0
|
|
38
|
+
Requires-Dist: python-multipart>=0.0.12
|
|
39
|
+
Requires-Dist: reportlab>=4.0.0
|
|
40
|
+
Requires-Dist: sqlalchemy[asyncio]>=2.0.36
|
|
41
|
+
Requires-Dist: structlog>=24.4.0
|
|
42
|
+
Requires-Dist: tenacity>=9.0.0
|
|
43
|
+
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
44
|
+
Provides-Extra: ai
|
|
45
|
+
Requires-Dist: anthropic>=0.40.0; extra == 'ai'
|
|
46
|
+
Requires-Dist: openai>=1.55.0; extra == 'ai'
|
|
47
|
+
Requires-Dist: qdrant-client>=1.12.0; extra == 'ai'
|
|
48
|
+
Requires-Dist: sentence-transformers>=3.3.0; extra == 'ai'
|
|
49
|
+
Provides-Extra: all
|
|
50
|
+
Requires-Dist: anthropic>=0.40.0; extra == 'all'
|
|
51
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'all'
|
|
52
|
+
Requires-Dist: boto3>=1.35.0; extra == 'all'
|
|
53
|
+
Requires-Dist: celery[redis]>=5.4.0; extra == 'all'
|
|
54
|
+
Requires-Dist: fastembed>=0.4.0; extra == 'all'
|
|
55
|
+
Requires-Dist: lancedb>=0.17.0; extra == 'all'
|
|
56
|
+
Requires-Dist: openai>=1.55.0; extra == 'all'
|
|
57
|
+
Requires-Dist: opencv-python-headless>=4.10.0; extra == 'all'
|
|
58
|
+
Requires-Dist: paddleocr>=2.9.0; extra == 'all'
|
|
59
|
+
Requires-Dist: pillow>=11.0.0; extra == 'all'
|
|
60
|
+
Requires-Dist: psycopg2-binary>=2.9.10; extra == 'all'
|
|
61
|
+
Requires-Dist: pyarrow>=18.0.0; extra == 'all'
|
|
62
|
+
Requires-Dist: pymupdf>=1.25.0; extra == 'all'
|
|
63
|
+
Requires-Dist: qdrant-client>=1.12.0; extra == 'all'
|
|
64
|
+
Requires-Dist: sentence-transformers>=3.3.0; extra == 'all'
|
|
65
|
+
Requires-Dist: ultralytics>=8.3.0; extra == 'all'
|
|
66
|
+
Provides-Extra: cv
|
|
67
|
+
Requires-Dist: opencv-python-headless>=4.10.0; extra == 'cv'
|
|
68
|
+
Requires-Dist: paddleocr>=2.9.0; extra == 'cv'
|
|
69
|
+
Requires-Dist: pillow>=11.0.0; extra == 'cv'
|
|
70
|
+
Requires-Dist: pymupdf>=1.25.0; extra == 'cv'
|
|
71
|
+
Requires-Dist: ultralytics>=8.3.0; extra == 'cv'
|
|
72
|
+
Provides-Extra: dev
|
|
73
|
+
Requires-Dist: factory-boy>=3.3.0; extra == 'dev'
|
|
74
|
+
Requires-Dist: httpx>=0.28.0; extra == 'dev'
|
|
75
|
+
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
|
76
|
+
Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
|
|
77
|
+
Requires-Dist: pyinstaller>=6.0.0; extra == 'dev'
|
|
78
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
79
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
|
|
80
|
+
Requires-Dist: pytest-xdist>=3.5.0; extra == 'dev'
|
|
81
|
+
Requires-Dist: pytest>=8.3.0; extra == 'dev'
|
|
82
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
83
|
+
Provides-Extra: server
|
|
84
|
+
Requires-Dist: asyncpg>=0.30.0; extra == 'server'
|
|
85
|
+
Requires-Dist: boto3>=1.35.0; extra == 'server'
|
|
86
|
+
Requires-Dist: celery[redis]>=5.4.0; extra == 'server'
|
|
87
|
+
Requires-Dist: psycopg2-binary>=2.9.10; extra == 'server'
|
|
88
|
+
Provides-Extra: vector
|
|
89
|
+
Requires-Dist: fastembed>=0.4.0; extra == 'vector'
|
|
90
|
+
Requires-Dist: lancedb>=0.17.0; extra == 'vector'
|
|
91
|
+
Requires-Dist: pyarrow>=18.0.0; extra == 'vector'
|
|
92
|
+
Description-Content-Type: text/markdown
|
|
93
|
+
|
|
94
|
+
# OpenConstructionERP
|
|
95
|
+
|
|
96
|
+
**The #1 open-source platform for construction cost estimation**
|
|
97
|
+
|
|
98
|
+
Professional BOQ, 4D scheduling, 5D cost model, AI-powered estimation, CAD/BIM takeoff — all in one platform.
|
|
99
|
+
|
|
100
|
+
## Quick Start
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install openconstructionerp
|
|
104
|
+
openconstructionerp serve --open
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Opens at http://localhost:8080 with SQLite — zero configuration needed.
|
|
108
|
+
|
|
109
|
+
## Features
|
|
110
|
+
|
|
111
|
+
- **BOQ Editor** — Hierarchical Bill of Quantities with AG Grid, markups, validation, export (PDF/Excel/CSV/GAEB)
|
|
112
|
+
- **55,000+ Cost Items** — CWICR database across 11 regions with resource breakdown
|
|
113
|
+
- **7,000+ Resource Catalog** — Materials, labor, equipment with prices
|
|
114
|
+
- **AI Estimation** — Generate BOQ from text, photo, PDF, Excel, or CAD/BIM (7 LLM providers)
|
|
115
|
+
- **4D Schedule** — Gantt chart with CPM, dependencies, auto-generate from BOQ
|
|
116
|
+
- **5D Cost Model** — Earned Value Management, S-curve, budget tracking
|
|
117
|
+
- **20 Regional Standards** — DIN 276, NRM, MasterFormat, GAEB, and 16 more
|
|
118
|
+
- **21 Languages** — Full i18n with RTL support
|
|
119
|
+
- **42 Validation Rules** — Automatic compliance checking
|
|
120
|
+
|
|
121
|
+
## CLI Commands
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
openconstructionerp serve [--host HOST] [--port PORT] [--open]
|
|
125
|
+
openconstructionerp init [--data-dir DIR]
|
|
126
|
+
openconstructionerp seed [--demo]
|
|
127
|
+
openconstructionerp version
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Links
|
|
131
|
+
|
|
132
|
+
- [Documentation](https://openconstructionerp.com/docs)
|
|
133
|
+
- [GitHub](https://github.com/datadrivenconstruction/OpenConstructionERP)
|
|
134
|
+
- [Telegram Community](https://t.me/datadrivenconstruction)
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
AGPL-3.0 — [Data Driven Construction](https://datadrivenconstruction.io)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# OpenConstructionERP
|
|
2
|
+
|
|
3
|
+
**The #1 open-source platform for construction cost estimation**
|
|
4
|
+
|
|
5
|
+
Professional BOQ, 4D scheduling, 5D cost model, AI-powered estimation, CAD/BIM takeoff — all in one platform.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install openconstructionerp
|
|
11
|
+
openconstructionerp serve --open
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Opens at http://localhost:8080 with SQLite — zero configuration needed.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **BOQ Editor** — Hierarchical Bill of Quantities with AG Grid, markups, validation, export (PDF/Excel/CSV/GAEB)
|
|
19
|
+
- **55,000+ Cost Items** — CWICR database across 11 regions with resource breakdown
|
|
20
|
+
- **7,000+ Resource Catalog** — Materials, labor, equipment with prices
|
|
21
|
+
- **AI Estimation** — Generate BOQ from text, photo, PDF, Excel, or CAD/BIM (7 LLM providers)
|
|
22
|
+
- **4D Schedule** — Gantt chart with CPM, dependencies, auto-generate from BOQ
|
|
23
|
+
- **5D Cost Model** — Earned Value Management, S-curve, budget tracking
|
|
24
|
+
- **20 Regional Standards** — DIN 276, NRM, MasterFormat, GAEB, and 16 more
|
|
25
|
+
- **21 Languages** — Full i18n with RTL support
|
|
26
|
+
- **42 Validation Rules** — Automatic compliance checking
|
|
27
|
+
|
|
28
|
+
## CLI Commands
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
openconstructionerp serve [--host HOST] [--port PORT] [--open]
|
|
32
|
+
openconstructionerp init [--data-dir DIR]
|
|
33
|
+
openconstructionerp seed [--demo]
|
|
34
|
+
openconstructionerp version
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Links
|
|
38
|
+
|
|
39
|
+
- [Documentation](https://openconstructionerp.com/docs)
|
|
40
|
+
- [GitHub](https://github.com/datadrivenconstruction/OpenConstructionERP)
|
|
41
|
+
- [Telegram Community](https://t.me/datadrivenconstruction)
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
AGPL-3.0 — [Data Driven Construction](https://datadrivenconstruction.io)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Alembic migration environment.
|
|
2
|
+
|
|
3
|
+
Auto-discovers all module models via Base.metadata.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from logging.config import fileConfig
|
|
7
|
+
|
|
8
|
+
from alembic import context
|
|
9
|
+
from sqlalchemy import pool
|
|
10
|
+
from sqlalchemy.engine import Connection
|
|
11
|
+
from sqlalchemy import create_engine
|
|
12
|
+
|
|
13
|
+
from app.config import get_settings
|
|
14
|
+
from app.database import Base
|
|
15
|
+
|
|
16
|
+
# Import all module models so they're registered with Base.metadata.
|
|
17
|
+
# This is done automatically by the module loader at runtime,
|
|
18
|
+
# but we need it here for autogenerate to work.
|
|
19
|
+
from app.modules.users import models as _users # noqa: F401
|
|
20
|
+
from app.modules.projects import models as _projects # noqa: F401
|
|
21
|
+
from app.modules.boq import models as _boq # noqa: F401
|
|
22
|
+
from app.modules.costs import models as _costs # noqa: F401
|
|
23
|
+
from app.modules.assemblies import models as _asm # noqa: F401
|
|
24
|
+
from app.modules.schedule import models as _sched # noqa: F401
|
|
25
|
+
from app.modules.costmodel import models as _cm # noqa: F401
|
|
26
|
+
from app.modules.ai import models as _ai # noqa: F401
|
|
27
|
+
from app.modules.tendering import models as _tender # noqa: F401
|
|
28
|
+
from app.modules.catalog import models as _catalog # noqa: F401
|
|
29
|
+
from app.modules.takeoff import models as _takeoff # noqa: F401
|
|
30
|
+
|
|
31
|
+
config = context.config
|
|
32
|
+
settings = get_settings()
|
|
33
|
+
|
|
34
|
+
# Render UUID columns properly for autogenerate
|
|
35
|
+
def render_item(type_, obj, autogen_context):
|
|
36
|
+
"""Custom render for UUID type."""
|
|
37
|
+
if type_ == "type" and hasattr(obj, "__class__") and obj.__class__.__name__ == "GUID":
|
|
38
|
+
return "sa.String(36)"
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
if config.config_file_name is not None:
|
|
42
|
+
fileConfig(config.config_file_name)
|
|
43
|
+
|
|
44
|
+
target_metadata = Base.metadata
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run_migrations_offline() -> None:
|
|
48
|
+
url = settings.database_sync_url
|
|
49
|
+
context.configure(
|
|
50
|
+
url=url,
|
|
51
|
+
target_metadata=target_metadata,
|
|
52
|
+
literal_binds=True,
|
|
53
|
+
dialect_opts={"paramstyle": "named"},
|
|
54
|
+
)
|
|
55
|
+
with context.begin_transaction():
|
|
56
|
+
context.run_migrations()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def run_migrations_online() -> None:
|
|
60
|
+
connectable = create_engine(settings.database_sync_url, poolclass=pool.NullPool)
|
|
61
|
+
|
|
62
|
+
with connectable.connect() as connection:
|
|
63
|
+
context.configure(connection=connection, target_metadata=target_metadata)
|
|
64
|
+
with context.begin_transaction():
|
|
65
|
+
context.run_migrations()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if context.is_offline_mode():
|
|
69
|
+
run_migrations_offline()
|
|
70
|
+
else:
|
|
71
|
+
run_migrations_online()
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""${message}
|
|
2
|
+
|
|
3
|
+
Revision ID: ${up_revision}
|
|
4
|
+
Revises: ${down_revision | comma,n}
|
|
5
|
+
Create Date: ${create_date}
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
${imports if imports else ""}
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = ${repr(up_revision)}
|
|
16
|
+
down_revision: Union[str, None] = ${repr(down_revision)}
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
${upgrades if upgrades else "pass"}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade() -> None:
|
|
26
|
+
${downgrades if downgrades else "pass"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""init: create all tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 129188e46db8
|
|
4
|
+
Revises:
|
|
5
|
+
Create Date: 2026-03-26 14:32:37.263344
|
|
6
|
+
|
|
7
|
+
Note: Tables are auto-created by SQLAlchemy Base.metadata.create_all() at startup.
|
|
8
|
+
This migration exists as a baseline marker for Alembic version tracking.
|
|
9
|
+
On fresh databases, all tables already exist before this migration runs.
|
|
10
|
+
"""
|
|
11
|
+
from typing import Sequence, Union
|
|
12
|
+
|
|
13
|
+
from alembic import op
|
|
14
|
+
import sqlalchemy as sa
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# revision identifiers, used by Alembic.
|
|
18
|
+
revision: str = '129188e46db8'
|
|
19
|
+
down_revision: Union[str, None] = None
|
|
20
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
21
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def upgrade() -> None:
|
|
25
|
+
# Tables are created by SQLAlchemy at app startup.
|
|
26
|
+
# This migration serves as the Alembic baseline.
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def downgrade() -> None:
|
|
31
|
+
# No-op: tables are managed by SQLAlchemy metadata.
|
|
32
|
+
pass
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[alembic]
|
|
2
|
+
script_location = alembic
|
|
3
|
+
sqlalchemy.url = sqlite:///./openestimate.db
|
|
4
|
+
|
|
5
|
+
[loggers]
|
|
6
|
+
keys = root,sqlalchemy,alembic
|
|
7
|
+
|
|
8
|
+
[handlers]
|
|
9
|
+
keys = console
|
|
10
|
+
|
|
11
|
+
[formatters]
|
|
12
|
+
keys = generic
|
|
13
|
+
|
|
14
|
+
[logger_root]
|
|
15
|
+
level = WARN
|
|
16
|
+
handlers = console
|
|
17
|
+
|
|
18
|
+
[logger_sqlalchemy]
|
|
19
|
+
level = WARN
|
|
20
|
+
handlers =
|
|
21
|
+
qualname = sqlalchemy.engine
|
|
22
|
+
|
|
23
|
+
[logger_alembic]
|
|
24
|
+
level = INFO
|
|
25
|
+
handlers =
|
|
26
|
+
qualname = alembic
|
|
27
|
+
|
|
28
|
+
[handler_console]
|
|
29
|
+
class = StreamHandler
|
|
30
|
+
args = (sys.stderr,)
|
|
31
|
+
level = NOTSET
|
|
32
|
+
formatter = generic
|
|
33
|
+
|
|
34
|
+
[formatter_generic]
|
|
35
|
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
|
File without changes
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Entry point for PyInstaller / standalone execution.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m app # Dev mode
|
|
5
|
+
openestimate-server.exe # Production (PyInstaller bundle)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import multiprocessing
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
"""Start the OpenConstructionERP backend server."""
|
|
15
|
+
import uvicorn
|
|
16
|
+
|
|
17
|
+
# Parse CLI args: --host X --port Y
|
|
18
|
+
host = "127.0.0.1"
|
|
19
|
+
port = 8741
|
|
20
|
+
args = sys.argv[1:]
|
|
21
|
+
for i, arg in enumerate(args):
|
|
22
|
+
if arg == "--host" and i + 1 < len(args):
|
|
23
|
+
host = args[i + 1]
|
|
24
|
+
elif arg == "--port" and i + 1 < len(args):
|
|
25
|
+
try:
|
|
26
|
+
port = int(args[i + 1])
|
|
27
|
+
except ValueError:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
# Also check env vars as fallback
|
|
31
|
+
host = os.environ.get("HOST", host)
|
|
32
|
+
port = int(os.environ.get("PORT", str(port)))
|
|
33
|
+
|
|
34
|
+
# Desktop app mode: serve frontend, production settings
|
|
35
|
+
if getattr(sys, "frozen", False):
|
|
36
|
+
os.environ.setdefault("SERVE_FRONTEND", "1")
|
|
37
|
+
os.environ.setdefault("APP_ENV", "production")
|
|
38
|
+
os.environ.setdefault("APP_DEBUG", "false")
|
|
39
|
+
|
|
40
|
+
print(f"Starting OpenConstructionERP on http://{host}:{port}")
|
|
41
|
+
|
|
42
|
+
# Use direct app import for PyInstaller compatibility
|
|
43
|
+
from app.main import create_app
|
|
44
|
+
app = create_app()
|
|
45
|
+
|
|
46
|
+
uvicorn.run(
|
|
47
|
+
app,
|
|
48
|
+
host=host,
|
|
49
|
+
port=port,
|
|
50
|
+
log_level="info",
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if __name__ == "__main__":
|
|
55
|
+
multiprocessing.freeze_support()
|
|
56
|
+
main()
|