Skip to content

Commit acf51b6

Browse files
manavgupclaude
andcommitted
refactor: Move Poetry configuration to project root for cleaner monorepo structure
## Summary Move pyproject.toml and poetry.lock from backend/ to project root to centralize Python dependency management and fix virtual environment accessibility issues. ## Changes ### Poetry Configuration (Moved) - backend/pyproject.toml → pyproject.toml - backend/poetry.lock → poetry.lock ### Makefile (100+ lines across 20+ targets) - Changed VENV_DIR from backend/.venv to .venv - Updated all Poetry commands to run from project root with PYTHONPATH=backend - Added venv dependency to local-dev-backend and local-dev-all targets - Updated build targets to use project root as Docker build context - Updated all test targets (atomic, unit, integration, e2e) - Updated code quality targets (lint, format, security-check, coverage) - Fixed clean target to reference root-level paths ### CI/CD Workflows (5 files) - poetry-lock-check.yml: Updated paths and removed cd backend commands - 01-lint.yml: Removed working-directory, updated all tool paths - 04-pytest.yml: Updated cache keys and test commands - 05-ci.yml: Updated dependency installation commands - makefile-testing.yml: Updated test execution paths ### Docker Configuration - backend/Dockerfile.backend: Updated COPY commands for new build context - docker-compose.dev.yml: Changed context from ./backend to . + fixed indentation ## Benefits - Single source of truth for Python dependencies at project root - Simplified virtual environment management (.venv/ at root) - Consistent build context across all tools (Makefile, docker-compose, CI/CD) - Better monorepo structure for future frontend/backend separation - Fixes dependency accessibility issues (e.g., docling import errors) ## Breaking Changes Developers need to: 1. Remove old venv: rm -rf backend/.venv 2. Create new venv: make venv 3. Update IDE Python interpreter from backend/.venv to .venv 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 98572db commit acf51b6

File tree

10 files changed

+75
-77
lines changed

10 files changed

+75
-77
lines changed

.github/workflows/01-lint.yml

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Lint & Static Analysis
22

3-
# This workflow uses tool versions and configurations from backend/pyproject.toml
3+
# This workflow uses tool versions and configurations from pyproject.toml (project root)
44
# All linting tools (Ruff, MyPy, Pylint, Pydocstyle) reference pyproject.toml as single source of truth
55
# Tool versions: Ruff ^0.14.0, MyPy ^1.15.0, Pylint ^3.3.8, Pydocstyle ^6.3.0
66

@@ -119,48 +119,44 @@ jobs:
119119
blocking: true
120120
cmd: |
121121
pip install toml
122-
python -c "import toml; toml.load(open('backend/pyproject.toml'))"
122+
python -c "import toml; toml.load(open('pyproject.toml'))"
123123
124124
# Python backend linting (blocking) - Check ALL backend Python files
125125
- id: ruff
126126
name: "Ruff (Lint + Format)"
127-
working-directory: backend
128127
blocking: true
129128
cmd: |
130129
pip install poetry
131130
poetry install --only dev
132131
echo "Running Ruff linting..."
133-
poetry run ruff check . --config pyproject.toml
132+
poetry run ruff check backend --config pyproject.toml
134133
echo "Running Ruff formatting check..."
135-
poetry run ruff format --check . --config pyproject.toml
134+
poetry run ruff format --check backend --config pyproject.toml
136135
137136
# Python type/quality checking (non-blocking / informational)
138137
- id: mypy
139138
name: "MyPy Type Check (Informational)"
140-
working-directory: backend
141139
blocking: false
142140
cmd: |
143141
pip install poetry
144142
poetry install --only dev
145-
poetry run mypy . --config-file pyproject.toml --ignore-missing-imports --show-error-codes || true
143+
poetry run mypy backend --config-file pyproject.toml --ignore-missing-imports --show-error-codes || true
146144
147145
- id: pylint
148146
name: "Pylint Quality (Informational)"
149-
working-directory: backend
150147
blocking: false
151148
cmd: |
152149
pip install poetry
153150
poetry install --only dev
154-
poetry run pylint rag_solution/ vectordbs/ core/ auth/ --rcfile=pyproject.toml || true
151+
poetry run pylint backend/rag_solution/ backend/vectordbs/ backend/core/ backend/auth/ --rcfile=pyproject.toml || true
155152
156153
- id: pydocstyle
157154
name: "Docstring Style (Informational)"
158-
working-directory: backend
159155
blocking: false
160156
cmd: |
161157
pip install poetry
162158
poetry install --only dev
163-
poetry run pydocstyle rag_solution/ vectordbs/ core/ auth/ --config=pyproject.toml --count || true
159+
poetry run pydocstyle backend/rag_solution/ backend/vectordbs/ backend/core/ backend/auth/ --config=pyproject.toml --count || true
164160
165161
name: ${{ matrix.name }}
166162

.github/workflows/04-pytest.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,20 @@ jobs:
7777
uses: actions/cache@v4
7878
with:
7979
path: ~/.cache/pypoetry
80-
key: ${{ runner.os }}-poetry-${{ hashFiles('backend/poetry.lock') }}
80+
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
8181
restore-keys: |
8282
${{ runner.os }}-poetry-
8383
8484
# 5️⃣ Install Python dependencies
8585
- name: 📥 Install dependencies
86-
run: cd backend && poetry install --with dev,test
86+
run: poetry install --with dev,test
8787

8888
# 6️⃣ Run unit/atomic tests with coverage
8989
- name: 🧪 Run unit tests with coverage
9090
run: |
91-
# Run from backend directory using poetry, but test from project root
92-
cd backend && poetry run pytest ../tests/ -m "unit or atomic" \
93-
--cov=rag_solution \
91+
# Run from project root using poetry
92+
PYTHONPATH=backend poetry run pytest tests/ -m "unit or atomic" \
93+
--cov=backend/rag_solution \
9494
--cov-report=term-missing \
9595
--cov-report=html \
9696
--tb=short \

.github/workflows/05-ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
timeout_minutes: 10
5050
max_attempts: 3
5151
retry_wait_seconds: 30
52-
command: cd backend && poetry install --with dev,test
52+
command: poetry install --with dev,test
5353

5454
- name: Run test isolation checker
5555
run: |
@@ -108,7 +108,6 @@ jobs:
108108
max_attempts: 3
109109
retry_wait_seconds: 30
110110
command: |
111-
cd backend
112111
pip install poetry
113112
poetry config virtualenvs.in-project true
114113
# Regenerate lock file to ensure sync

.github/workflows/makefile-testing.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ jobs:
3232

3333
- name: Install dependencies
3434
run: |
35-
cd backend
3635
poetry install --with test
3736
3837
- name: Set up Docker Buildx
@@ -41,7 +40,7 @@ jobs:
4140
- name: Test Makefile targets directly
4241
run: |
4342
echo "Running direct Makefile tests..."
44-
cd backend && poetry run pytest ../tests/test_makefile_targets_direct.py -v
43+
PYTHONPATH=backend poetry run pytest tests/test_makefile_targets_direct.py -v
4544
4645
- name: Test make help
4746
run: |

.github/workflows/poetry-lock-check.yml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ name: Poetry Lock Validation
66
on:
77
pull_request:
88
paths:
9-
- 'backend/pyproject.toml'
10-
- 'backend/poetry.lock'
9+
- 'pyproject.toml'
10+
- 'poetry.lock'
1111
push:
1212
branches: [main, develop]
1313
paths:
14-
- 'backend/pyproject.toml'
15-
- 'backend/poetry.lock'
14+
- 'pyproject.toml'
15+
- 'poetry.lock'
1616

1717
permissions:
1818
contents: read
@@ -37,7 +37,6 @@ jobs:
3737

3838
- name: Validate poetry.lock is in sync
3939
run: |
40-
cd backend
4140
echo "🔍 Checking if poetry.lock is in sync with pyproject.toml..."
4241
4342
if poetry check --lock; then
@@ -50,18 +49,16 @@ jobs:
5049
echo "but poetry.lock was not regenerated."
5150
echo ""
5251
echo "To fix this:"
53-
echo " 1. cd backend"
54-
echo " 2. poetry lock"
55-
echo " 3. git add poetry.lock"
56-
echo " 4. git commit -m 'chore: update poetry.lock'"
57-
echo " 5. git push"
52+
echo " 1. poetry lock"
53+
echo " 2. git add poetry.lock"
54+
echo " 3. git commit -m 'chore: update poetry.lock'"
55+
echo " 4. git push"
5856
echo ""
5957
exit 1
6058
fi
6159
6260
- name: Check for dependency conflicts
6361
run: |
64-
cd backend
6562
echo "🔍 Checking for dependency conflicts..."
6663
poetry check
6764
echo "✅ No dependency conflicts detected"

Makefile

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ endif
1616
# ============================================================================
1717

1818
# Python environment
19-
VENV_DIR := backend/.venv
19+
VENV_DIR := .venv
2020
PYTHON := python3.12
2121
POETRY := 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

7272
clean-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

123123
local-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

237240
build-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

265272
test-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

270277
test-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

275282
test-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

281288
test-integration-ci: venv
@@ -350,58 +357,58 @@ test-all-ci: test-atomic test-unit-fast test-integration-ci test-e2e-ci-parallel
350357

351358
lint: 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

357364
format: 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

363370
quick-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

369376
security-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

375382
pre-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

395402
coverage: 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

443450
clean:
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

backend/Dockerfile.backend

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ WORKDIR /app
7070
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
7171
COPY --from=builder /usr/local/bin /usr/local/bin
7272

73-
# Copy only essential application files
74-
COPY main.py healthcheck.py ./
75-
COPY rag_solution/ ./rag_solution/
76-
COPY auth/ ./auth/
77-
COPY core/ ./core/
78-
COPY cli/ ./cli/
79-
COPY vectordbs/ ./vectordbs/
73+
# Copy only essential application files from backend directory
74+
COPY backend/main.py backend/healthcheck.py ./
75+
COPY backend/rag_solution/ ./rag_solution/
76+
COPY backend/auth/ ./auth/
77+
COPY backend/core/ ./core/
78+
COPY backend/cli/ ./cli/
79+
COPY backend/vectordbs/ ./vectordbs/
8080
COPY pyproject.toml ./
8181

8282
# Create a non-root user and group

0 commit comments

Comments
 (0)