1616# ============================================================================
1717
1818# Python environment
19- VENV_DIR := backend/ .venv
19+ VENV_DIR := .venv
2020PYTHON := python3.12
2121POETRY := poetry
2222
@@ -64,10 +64,10 @@ $(VENV_DIR)/bin/activate:
6464 echo " $( RED) ❌ Poetry not found. Installing Poetry...$( NC) " ; \
6565 curl -sSL https://install.python-poetry.org | $(PYTHON ) -; \
6666 fi
67- @cd backend && $(POETRY ) config virtualenvs.in-project true
68- @cd backend && $(POETRY ) install --with dev,test
69- @echo " $( GREEN) ✅ Virtual environment created at backend/ .venv$( NC) "
70- @echo " $( CYAN) 💡 Activate with: source backend/ .venv/bin/activate$( NC) "
67+ @$(POETRY ) config virtualenvs.in-project true
68+ @$(POETRY ) install --with dev,test
69+ @echo " $( GREEN) ✅ Virtual environment created at .venv$( NC) "
70+ @echo " $( CYAN) 💡 Activate with: source .venv/bin/activate$( NC) "
7171
7272clean-venv :
7373 @echo " $( CYAN) 🧹 Cleaning virtual environment...$( NC) "
@@ -115,22 +115,22 @@ local-dev-infra:
115115 @echo " MinIO: localhost:9001"
116116 @echo " MLFlow: localhost:5001"
117117
118- local-dev-backend :
118+ local-dev-backend : venv
119119 @echo " $( CYAN) 🐍 Starting backend with hot-reload (uvicorn)...$( NC) "
120120 @echo " $( YELLOW) ⚠️ Make sure infrastructure is running: make local-dev-infra$( NC) "
121- @cd backend && $(POETRY ) run uvicorn main:app --reload --host 0.0.0.0 --port 8000
121+ @PYTHONPATH= backend $(POETRY ) run uvicorn main:app --reload --host 0.0.0.0 --port 8000 --app-dir backend
122122
123123local-dev-frontend :
124124 @echo " $( CYAN) ⚛️ Starting frontend with HMR (Vite)...$( NC) "
125125 @cd frontend && npm run dev
126126
127- local-dev-all :
127+ local-dev-all : venv
128128 @echo " $( CYAN) 🚀 Starting full local development stack...$( NC) "
129129 @PROJECT_ROOT=$$(pwd ) ; \
130130 mkdir -p $$ PROJECT_ROOT/.dev-pids $$ PROJECT_ROOT/logs; \
131131 $(MAKE ) local-dev-infra; \
132132 echo " $( CYAN) 🐍 Starting backend in background...$( NC) " ; \
133- cd backend && $(POETRY ) run uvicorn main:app --reload --host 0.0.0.0 --port 8000 > $$ PROJECT_ROOT/logs/backend.log 2>&1 & echo $$ ! > $$ PROJECT_ROOT/.dev-pids/backend.pid; \
133+ PYTHONPATH= backend $(POETRY ) run uvicorn main:app --reload --host 0.0.0.0 --port 8000 --app-dir backend > $$ PROJECT_ROOT/logs/backend.log 2>&1 & echo $$ ! > $$ PROJECT_ROOT/.dev-pids/backend.pid; \
134134 sleep 2; \
135135 if [ -f $$ PROJECT_ROOT/.dev-pids/backend.pid ]; then \
136136 if kill -0 $$ (cat $$ PROJECT_ROOT/.dev-pids/backend.pid) 2> /dev/null; then \
@@ -221,31 +221,38 @@ build-backend:
221221 @echo " $( CYAN) 🔨 Building backend image...$( NC) "
222222 @if [ " $( BUILDX_AVAILABLE) " = " yes" ]; then \
223223 echo " Using Docker BuildKit with buildx..." ; \
224- cd backend && $(CONTAINER_CLI ) buildx build --load \
224+ $(CONTAINER_CLI ) buildx build --load \
225225 -t $(GHCR_REPO ) /backend:$(PROJECT_VERSION ) \
226226 -t $(GHCR_REPO ) /backend:latest \
227- -f Dockerfile.backend . ; \
227+ -f backend/Dockerfile.backend \
228+ --build-arg BUILDKIT_INLINE_CACHE=1 \
229+ . ; \
228230 else \
229231 echo " Using standard Docker build..." ; \
230- cd backend && $(CONTAINER_CLI ) build \
232+ $(CONTAINER_CLI ) build \
231233 -t $(GHCR_REPO ) /backend:$(PROJECT_VERSION ) \
232234 -t $(GHCR_REPO ) /backend:latest \
233- -f Dockerfile.backend . ; \
235+ -f backend/Dockerfile.backend \
236+ . ; \
234237 fi
235238 @echo " $( GREEN) ✅ Backend image built$( NC) "
236239
237240build-frontend :
238241 @echo " $( CYAN) 🔨 Building frontend image...$( NC) "
239242 @if [ " $( BUILDX_AVAILABLE) " = " yes" ]; then \
240243 echo " Using Docker BuildKit with buildx..." ; \
241- cd frontend && $(CONTAINER_CLI ) buildx build --load \
244+ $(CONTAINER_CLI ) buildx build --load \
242245 -t $(GHCR_REPO ) /frontend:$(PROJECT_VERSION ) \
243- -t $(GHCR_REPO ) /frontend:latest . ; \
246+ -t $(GHCR_REPO ) /frontend:latest \
247+ -f frontend/Dockerfile \
248+ . ; \
244249 else \
245250 echo " Using standard Docker build..." ; \
246- cd frontend && $(CONTAINER_CLI ) build \
251+ $(CONTAINER_CLI ) build \
247252 -t $(GHCR_REPO ) /frontend:$(PROJECT_VERSION ) \
248- -t $(GHCR_REPO ) /frontend:latest . ; \
253+ -t $(GHCR_REPO ) /frontend:latest \
254+ -f frontend/Dockerfile \
255+ . ; \
249256 fi
250257 @echo " $( GREEN) ✅ Frontend image built$( NC) "
251258
@@ -264,18 +271,18 @@ build-all: build-backend build-frontend
264271
265272test-atomic : venv
266273 @echo " $( CYAN) ⚡ Running atomic tests (no DB, no coverage)...$( NC) "
267- @cd backend && PYTHONPATH=.. poetry run pytest -c pytest-atomic.ini ../ tests/unit/schemas/ -v -m atomic
274+ @PYTHONPATH=backend $( POETRY ) run pytest -c backend/ pytest-atomic.ini tests/unit/schemas/ -v -m atomic
268275 @echo " $( GREEN) ✅ Atomic tests passed$( NC) "
269276
270277test-unit-fast : venv
271278 @echo " $( CYAN) 🏃 Running unit tests (mocked dependencies)...$( NC) "
272- @cd backend && PYTHONPATH=.. poetry run pytest ../tests/unit/ -v ../ tests/unit/ -v
279+ @PYTHONPATH=backend $( POETRY ) run pytest tests/unit/ -v
273280 @echo " $( GREEN) ✅ Unit tests passed$( NC) "
274281
275282test-integration : venv local-dev-infra
276283 @echo " $( CYAN) 🔗 Running integration tests (with real services)...$( NC) "
277284 @echo " $( YELLOW) 💡 Using shared dev infrastructure (fast, reuses containers)$( NC) "
278- @cd backend && PYTHONPATH=.. poetry run pytest ../ tests/integration/ -v -m integration
285+ @PYTHONPATH=backend $( POETRY ) run pytest tests/integration/ -v -m integration
279286 @echo " $( GREEN) ✅ Integration tests passed$( NC) "
280287
281288test-integration-ci : venv
@@ -350,58 +357,58 @@ test-all-ci: test-atomic test-unit-fast test-integration-ci test-e2e-ci-parallel
350357
351358lint : venv
352359 @echo " $( CYAN) 🔍 Running linters...$( NC) "
353- @cd backend && $(POETRY ) run ruff check . --config pyproject.toml
354- @cd backend && $(POETRY ) run mypy . --config-file pyproject.toml --ignore-missing-imports
360+ @$(POETRY ) run ruff check backend --config pyproject.toml
361+ @$(POETRY ) run mypy backend --config-file pyproject.toml --ignore-missing-imports
355362 @echo " $( GREEN) ✅ Linting passed$( NC) "
356363
357364format : venv
358365 @echo " $( CYAN) 🎨 Formatting code...$( NC) "
359- @cd backend && $(POETRY ) run ruff format . --config pyproject.toml
360- @cd backend && $(POETRY ) run ruff check --fix . --config pyproject.toml
366+ @$(POETRY ) run ruff format backend --config pyproject.toml
367+ @$(POETRY ) run ruff check --fix backend --config pyproject.toml
361368 @echo " $( GREEN) ✅ Code formatted$( NC) "
362369
363370quick-check : venv
364371 @echo " $( CYAN) ⚡ Running quick quality checks...$( NC) "
365- @cd backend && $(POETRY ) run ruff format --check . --config pyproject.toml
366- @cd backend && $(POETRY ) run ruff check . --config pyproject.toml
372+ @$(POETRY ) run ruff format --check backend --config pyproject.toml
373+ @$(POETRY ) run ruff check backend --config pyproject.toml
367374 @echo " $( GREEN) ✅ Quick checks passed$( NC) "
368375
369376security-check : venv
370377 @echo " $( CYAN) 🔒 Running security checks...$( NC) "
371- @cd backend && $(POETRY ) run bandit -r rag_solution/ -ll || echo " $( YELLOW) ⚠️ Security issues found$( NC) "
372- @cd backend && $(POETRY ) run safety check || echo " $( YELLOW) ⚠️ Vulnerabilities found$( NC) "
378+ @$(POETRY ) run bandit -r backend/ rag_solution/ -ll || echo " $( YELLOW) ⚠️ Security issues found$( NC) "
379+ @$(POETRY ) run safety check || echo " $( YELLOW) ⚠️ Vulnerabilities found$( NC) "
373380 @echo " $( GREEN) ✅ Security scan complete$( NC) "
374381
375382pre-commit-run : venv
376383 @echo " $( CYAN) 🎯 Running pre-commit checks...$( NC) "
377384 @echo " $( CYAN) Step 1/4: Formatting code...$( NC) "
378- @cd backend && $(POETRY ) run ruff format . --config pyproject.toml
385+ @$(POETRY ) run ruff format backend --config pyproject.toml
379386 @echo " $( GREEN) ✅ Code formatted$( NC) "
380387 @echo " "
381388 @echo " $( CYAN) Step 2/4: Running ruff linter...$( NC) "
382- @cd backend && $(POETRY ) run ruff check --fix . --config pyproject.toml
389+ @$(POETRY ) run ruff check --fix backend --config pyproject.toml
383390 @echo " $( GREEN) ✅ Ruff checks passed$( NC) "
384391 @echo " "
385392 @echo " $( CYAN) Step 3/4: Running mypy type checker...$( NC) "
386- @cd backend && $(POETRY ) run mypy . --config-file pyproject.toml --ignore-missing-imports
393+ @$(POETRY ) run mypy backend --config-file pyproject.toml --ignore-missing-imports
387394 @echo " $( GREEN) ✅ Type checks passed$( NC) "
388395 @echo " "
389396 @echo " $( CYAN) Step 4/4: Running pylint...$( NC) "
390- @cd backend && $(POETRY ) run pylint rag_solution/ --rcfile=pyproject.toml || echo " $( YELLOW) ⚠️ Pylint warnings found$( NC) "
397+ @$(POETRY ) run pylint backend/ rag_solution/ --rcfile=pyproject.toml || echo " $( YELLOW) ⚠️ Pylint warnings found$( NC) "
391398 @echo " "
392399 @echo " $( GREEN) ✅ Pre-commit checks complete!$( NC) "
393400 @echo " $( CYAN) 💡 Tip: Always run this before committing$( NC) "
394401
395402coverage : venv
396403 @echo " $( CYAN) 📊 Running tests with coverage...$( NC) "
397- @cd backend && PYTHONPATH=.. poetry run pytest ../ tests/unit/ \
398- --cov=rag_solution \
404+ @PYTHONPATH=backend $( POETRY ) run pytest tests/unit/ \
405+ --cov=backend/ rag_solution \
399406 --cov-report=term-missing \
400407 --cov-report=html:htmlcov \
401408 --cov-fail-under=60 \
402409 -v
403410 @echo " $( GREEN) ✅ Coverage report generated$( NC) "
404- @echo " $( CYAN) 💡 View report: open backend/ htmlcov/index.html$( NC) "
411+ @echo " $( CYAN) 💡 View report: open htmlcov/index.html$( NC) "
405412
406413# ============================================================================
407414# PRODUCTION DEPLOYMENT
@@ -442,7 +449,7 @@ prod-status:
442449
443450clean :
444451 @echo " $( CYAN) 🧹 Cleaning up...$( NC) "
445- @rm -rf .pytest_cache .mypy_cache .ruff_cache backend/ htmlcov backend/ .coverage
452+ @rm -rf .pytest_cache .mypy_cache .ruff_cache htmlcov .coverage
446453 @find . -type d -name __pycache__ -exec rm -rf {} + 2> /dev/null || true
447454 @echo " $( GREEN) ✅ Cleanup complete$( NC) "
448455
0 commit comments