chore: Remove obsolete microservices directories and update all references
- Delete data-entry-app/ (1.6GB), reports-app/ (447MB), .auto-build-data/
- Saved ~1.4GB disk space (64% reduction: 2.2GB → 845MB)
Updated references across 38 files:
- .claude/rules/ paths: backend/modules/, src/modules/
- .claude/commands/validate.md: all validation paths
- docs/ (13 files): data-entry, telegram, README, CLAUDE.md
- scripts/ (3 files): backup-secrets, restore-secrets, test-docker
- security/ (2 files): git_cleanup, SECURITY_PROCEDURES
- deployment/ & shared/: updated all stale comments
All paths now reflect ultrathin monolith architecture:
- Backend: backend/modules/{reports,data_entry,telegram}/
- Frontend: src/modules/{reports,data-entry}/
- Shared: shared/{auth,database,routes}/
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@ Comprehensive validation that tests everything in the ROA2WEB codebase. This com
|
|||||||
### Test Configuration
|
### Test Configuration
|
||||||
- **Company ID**: 110 (MARIUSM_AUTO) - has complete Oracle schema
|
- **Company ID**: 110 (MARIUSM_AUTO) - has complete Oracle schema
|
||||||
- **Credentials**: `MARIUS M` / `123`
|
- **Credentials**: `MARIUS M` / `123`
|
||||||
- **Backend Tests**: ~36 Oracle real tests in `reports-app/backend/tests/`
|
- **Backend Tests**: ~36 Oracle real tests in `backend/tests/`
|
||||||
- **Telegram Bot Tests**: Pure tests + Integration tests (mock tests removed)
|
- **Telegram Bot Tests**: Pure tests + Integration tests (mock tests removed)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -32,7 +32,7 @@ echo "===================="
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "📝 Frontend Linting..."
|
echo "📝 Frontend Linting..."
|
||||||
cd reports-app/frontend
|
cd src
|
||||||
npm run lint
|
npm run lint
|
||||||
cd ../..
|
cd ../..
|
||||||
echo "✅ Frontend linting passed"
|
echo "✅ Frontend linting passed"
|
||||||
@@ -45,7 +45,7 @@ echo "📝 Python Code Quality Checks..."
|
|||||||
|
|
||||||
# Backend
|
# Backend
|
||||||
echo " → Checking backend code..."
|
echo " → Checking backend code..."
|
||||||
cd reports-app/backend
|
cd backend
|
||||||
if [ -d "venv" ]; then
|
if [ -d "venv" ]; then
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
python -m flake8 app/ --count --select=E9,F63,F7,F82 --show-source --statistics || echo "⚠️ Backend has critical errors"
|
python -m flake8 app/ --count --select=E9,F63,F7,F82 --show-source --statistics || echo "⚠️ Backend has critical errors"
|
||||||
@@ -58,7 +58,7 @@ cd ../..
|
|||||||
|
|
||||||
# Telegram Bot
|
# Telegram Bot
|
||||||
echo " → Checking telegram bot code..."
|
echo " → Checking telegram bot code..."
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
if [ -d "venv" ]; then
|
if [ -d "venv" ]; then
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
python -m flake8 app/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics || echo "⚠️ Telegram bot has critical errors"
|
python -m flake8 app/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics || echo "⚠️ Telegram bot has critical errors"
|
||||||
@@ -93,7 +93,7 @@ echo "========================="
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "📝 Frontend Type Checking (ESLint with type checking)..."
|
echo "📝 Frontend Type Checking (ESLint with type checking)..."
|
||||||
cd reports-app/frontend
|
cd src
|
||||||
# ESLint already performs basic type checking for JavaScript
|
# ESLint already performs basic type checking for JavaScript
|
||||||
npm run lint -- --quiet
|
npm run lint -- --quiet
|
||||||
cd ../..
|
cd ../..
|
||||||
@@ -106,7 +106,7 @@ echo ""
|
|||||||
echo "📝 Python Type Hints (Optional)..."
|
echo "📝 Python Type Hints (Optional)..."
|
||||||
if command -v mypy >/dev/null 2>&1; then
|
if command -v mypy >/dev/null 2>&1; then
|
||||||
echo " → Checking backend..."
|
echo " → Checking backend..."
|
||||||
cd reports-app/backend
|
cd backend
|
||||||
if [ -d "venv" ]; then
|
if [ -d "venv" ]; then
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
mypy app/ --ignore-missing-imports --no-strict-optional || echo "⚠️ Backend type hints have issues"
|
mypy app/ --ignore-missing-imports --no-strict-optional || echo "⚠️ Backend type hints have issues"
|
||||||
@@ -115,7 +115,7 @@ if command -v mypy >/dev/null 2>&1; then
|
|||||||
cd ../..
|
cd ../..
|
||||||
|
|
||||||
echo " → Checking telegram bot..."
|
echo " → Checking telegram bot..."
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
if [ -d "venv" ]; then
|
if [ -d "venv" ]; then
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
mypy app/ --ignore-missing-imports --no-strict-optional || echo "⚠️ Telegram bot type hints have issues"
|
mypy app/ --ignore-missing-imports --no-strict-optional || echo "⚠️ Telegram bot type hints have issues"
|
||||||
@@ -139,7 +139,7 @@ echo "=========================="
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
echo "📝 Frontend Code Formatting (Prettier)..."
|
echo "📝 Frontend Code Formatting (Prettier)..."
|
||||||
cd reports-app/frontend
|
cd src
|
||||||
npm run format -- --check || echo "⚠️ Some files need formatting (run: npm run format)"
|
npm run format -- --check || echo "⚠️ Some files need formatting (run: npm run format)"
|
||||||
cd ../..
|
cd ../..
|
||||||
echo "✅ Frontend formatting checked"
|
echo "✅ Frontend formatting checked"
|
||||||
@@ -151,10 +151,10 @@ echo ""
|
|||||||
echo "📝 Python Code Formatting (Black)..."
|
echo "📝 Python Code Formatting (Black)..."
|
||||||
if command -v black >/dev/null 2>&1; then
|
if command -v black >/dev/null 2>&1; then
|
||||||
echo " → Checking backend..."
|
echo " → Checking backend..."
|
||||||
black --check reports-app/backend/app/ || echo "⚠️ Backend needs formatting (run: black reports-app/backend/app/)"
|
black --check backend/app/ || echo "⚠️ Backend needs formatting (run: black backend/app/)"
|
||||||
|
|
||||||
echo " → Checking telegram bot..."
|
echo " → Checking telegram bot..."
|
||||||
black --check reports-app/telegram-bot/app/ reports-app/telegram-bot/tests/ || echo "⚠️ Telegram bot needs formatting (run: black reports-app/telegram-bot/)"
|
black --check backend/modules/telegram/app/ backend/modules/telegram/tests/ || echo "⚠️ Telegram bot needs formatting (run: black backend/modules/telegram/)"
|
||||||
|
|
||||||
echo " → Checking shared modules..."
|
echo " → Checking shared modules..."
|
||||||
black --check shared/ || echo "⚠️ Shared modules need formatting (run: black shared/)"
|
black --check shared/ || echo "⚠️ Shared modules need formatting (run: black shared/)"
|
||||||
@@ -205,7 +205,7 @@ echo ""
|
|||||||
```bash
|
```bash
|
||||||
echo "📝 Backend Oracle Real Tests..."
|
echo "📝 Backend Oracle Real Tests..."
|
||||||
echo " → Testing backend services, API endpoints, and cache system..."
|
echo " → Testing backend services, API endpoints, and cache system..."
|
||||||
cd reports-app/backend
|
cd backend
|
||||||
|
|
||||||
if [ ! -d "venv" ]; then
|
if [ ! -d "venv" ]; then
|
||||||
echo "⚠️ Backend venv not found - creating..."
|
echo "⚠️ Backend venv not found - creating..."
|
||||||
@@ -234,7 +234,7 @@ echo ""
|
|||||||
### Telegram Bot Unit Tests (Pure - No Backend Required)
|
### Telegram Bot Unit Tests (Pure - No Backend Required)
|
||||||
```bash
|
```bash
|
||||||
echo "📝 Telegram Bot Unit Tests (Pure)..."
|
echo "📝 Telegram Bot Unit Tests (Pure)..."
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
|
|
||||||
if [ ! -d "venv" ]; then
|
if [ ! -d "venv" ]; then
|
||||||
echo "⚠️ Telegram bot venv not found - creating..."
|
echo "⚠️ Telegram bot venv not found - creating..."
|
||||||
@@ -262,7 +262,7 @@ echo ""
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo "📝 Telegram Bot Integration Tests..."
|
echo "📝 Telegram Bot Integration Tests..."
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
|
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
|
|
||||||
@@ -280,7 +280,7 @@ echo ""
|
|||||||
### Frontend Unit Tests (Playwright - E2E with API Mocking)
|
### Frontend Unit Tests (Playwright - E2E with API Mocking)
|
||||||
```bash
|
```bash
|
||||||
echo "📝 Frontend Unit/E2E Tests (Playwright with API mocking)..."
|
echo "📝 Frontend Unit/E2E Tests (Playwright with API mocking)..."
|
||||||
cd reports-app/frontend
|
cd src
|
||||||
|
|
||||||
# Ensure dependencies are installed
|
# Ensure dependencies are installed
|
||||||
if [ ! -d "node_modules" ]; then
|
if [ ! -d "node_modules" ]; then
|
||||||
@@ -720,7 +720,7 @@ echo "========================================================"
|
|||||||
|
|
||||||
echo " → Running Playwright integration tests against real backend..."
|
echo " → Running Playwright integration tests against real backend..."
|
||||||
|
|
||||||
cd reports-app/frontend
|
cd src
|
||||||
|
|
||||||
# Create integration test configuration for real backend
|
# Create integration test configuration for real backend
|
||||||
cat > playwright.integration.config.js << 'EOF'
|
cat > playwright.integration.config.js << 'EOF'
|
||||||
@@ -979,9 +979,9 @@ echo "════════════════════════
|
|||||||
- **Test Credentials**: `MARIUS M` / `123`
|
- **Test Credentials**: `MARIUS M` / `123`
|
||||||
- **API Structure**: All endpoints use query params (`?company=110`), not path params
|
- **API Structure**: All endpoints use query params (`?company=110`), not path params
|
||||||
- **Test Structure**:
|
- **Test Structure**:
|
||||||
- Backend: `reports-app/backend/tests/` (~36 Oracle real tests)
|
- Backend: `backend/tests/` (~36 Oracle real tests)
|
||||||
- Telegram Bot Pure: `reports-app/telegram-bot/tests/` (~77 pure tests)
|
- Telegram Bot Pure: `backend/modules/telegram/tests/` (~77 pure tests)
|
||||||
- Telegram Bot Integration: `reports-app/telegram-bot/tests/` (~25 real tests, marked `@pytest.mark.integration`)
|
- Telegram Bot Integration: `backend/modules/telegram/tests/` (~25 real tests, marked `@pytest.mark.integration`)
|
||||||
|
|
||||||
## Quick Run
|
## Quick Run
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
paths: {reports-app,data-entry-app}/backend/**/*.py
|
paths: backend/modules/**/*.py
|
||||||
---
|
---
|
||||||
|
|
||||||
# Backend Patterns
|
# Backend Patterns
|
||||||
@@ -19,7 +19,7 @@ app.include_router(companies_router, prefix="/api/companies")
|
|||||||
- Schema lookup: `SELECT SCHEMA FROM CONTAFIN_ORACLE.V_NOM_FIRME`
|
- Schema lookup: `SELECT SCHEMA FROM CONTAFIN_ORACLE.V_NOM_FIRME`
|
||||||
- Company access: Join V_NOM_FIRME with VDEF_UTIL_FIRME
|
- Company access: Join V_NOM_FIRME with VDEF_UTIL_FIRME
|
||||||
|
|
||||||
## Caching (reports-app)
|
## Caching (Reports Module)
|
||||||
- Use `@cached` decorator from `app/cache/decorators`
|
- Use `@cached` decorator from `app/cache/decorators`
|
||||||
- Place logic in services, not routers
|
- Place logic in services, not routers
|
||||||
- Cache schema lookups (24h TTL)
|
- Cache schema lookups (24h TTL)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
paths: {reports-app,data-entry-app}/frontend/**/*.{vue,css}
|
paths: src/modules/**/*.{vue,css}
|
||||||
---
|
---
|
||||||
|
|
||||||
# CSS Design System Rules
|
# CSS Design System Rules
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
paths: {reports-app,data-entry-app}/frontend/src/stores/**/*.js
|
paths: src/modules/**/stores/**/*.js
|
||||||
---
|
---
|
||||||
|
|
||||||
# Frontend Store Rules
|
# Frontend Store Rules
|
||||||
|
|||||||
@@ -399,6 +399,7 @@ const response = await api.get('/endpoint');
|
|||||||
### Deployment
|
### Deployment
|
||||||
- `deployment/windows/README.md` - Windows deployment quick start
|
- `deployment/windows/README.md` - Windows deployment quick start
|
||||||
- `deployment/windows/docs/WINDOWS_DEPLOYMENT.md` - Complete Windows guide
|
- `deployment/windows/docs/WINDOWS_DEPLOYMENT.md` - Complete Windows guide
|
||||||
|
- **`deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md`** - ⚠️ **PRODUCTION ARCHITECTURE** - 2-tier IIS setup with public gateway
|
||||||
- `deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md` - Bot troubleshooting
|
- `deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md` - Bot troubleshooting
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|||||||
378
DIAGNOSIS-2025-12-30.md
Normal file
378
DIAGNOSIS-2025-12-30.md
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
# ROA2WEB Production Deployment Issue - Diagnostic Report
|
||||||
|
|
||||||
|
**Date**: 2025-12-30
|
||||||
|
**Environment**: Windows Production (roa2web.romfast.ro)
|
||||||
|
**Issue**: 404 errors on API calls after deployment
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Frontend loads successfully but all API calls return **404 Not Found** errors:
|
||||||
|
- `POST /roa2web/api/auth/login` → 404
|
||||||
|
- `GET /roa2web/api/companies` → 404
|
||||||
|
|
||||||
|
Browser console shows:
|
||||||
|
```
|
||||||
|
POST https://roa2web.romfast.ro/roa2web/api/auth/login 404 (Not Found)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
**2-Tier IIS Deployment**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet → Public IIS (10.0.20.122 - roa2web.romfast.ro)
|
||||||
|
↓ HTTPS reverse proxy
|
||||||
|
Internal IIS (10.0.20.36 - application server)
|
||||||
|
↓ API proxy to localhost
|
||||||
|
Backend Service (localhost:8000 on 10.0.20.36)
|
||||||
|
↓
|
||||||
|
Oracle Database
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verified Components
|
||||||
|
|
||||||
|
✅ **Public IIS** (10.0.20.122 - roa2web.romfast.ro):
|
||||||
|
- ✅ web.config correctly proxies all requests to `https://10.0.20.36/{R:1}`
|
||||||
|
- ✅ Forwards headers: `X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Real-IP`
|
||||||
|
- ✅ Configuration verified - THIS SERVER IS CORRECT
|
||||||
|
|
||||||
|
✅ **Frontend** (10.0.20.36):
|
||||||
|
- Built with `base: '/roa2web/'` (correct for IIS sub-application)
|
||||||
|
- API calls use `baseURL: '/roa2web/api'` (correct)
|
||||||
|
- Static files load successfully
|
||||||
|
|
||||||
|
❌ **Internal IIS** (10.0.20.36) - **PROBLEMA ESTE AICI**:
|
||||||
|
- **CRITICAL**: web.config lipsește SAU nu este configurat corect
|
||||||
|
- **MUST**: Trebuie să facă proxy de la `/roa2web/api/*` către `http://localhost:8000/api/*`
|
||||||
|
- **Location**: `C:\inetpub\wwwroot\roa2web\web.config` (pe serverul 10.0.20.36)
|
||||||
|
|
||||||
|
❓ **Backend Service** (pe 10.0.20.36):
|
||||||
|
- **UNKNOWN**: Need to verify service is running
|
||||||
|
- Should be accessible at `http://localhost:8000/health` (de pe 10.0.20.36)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Root Cause Analysis
|
||||||
|
|
||||||
|
Based on Playwright testing, the issue is most likely:
|
||||||
|
|
||||||
|
### Primary Suspect: Internal Server web.config
|
||||||
|
|
||||||
|
The internal server's web.config **MUST** handle the `/roa2web/` prefix correctly.
|
||||||
|
|
||||||
|
**WRONG Configuration** (causes 404):
|
||||||
|
```xml
|
||||||
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
|
<match url="^api/(.*)" /> ❌ Missing roa2web prefix!
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
```
|
||||||
|
|
||||||
|
**CORRECT Configuration**:
|
||||||
|
```xml
|
||||||
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
|
<match url="^roa2web/api/(.*)" /> ✅ Includes roa2web prefix
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why**: Requests arrive at internal server as `/roa2web/api/auth/login` (NOT `/api/auth/login`), because the public server preserves the full path when proxying.
|
||||||
|
|
||||||
|
### Secondary Suspects
|
||||||
|
|
||||||
|
1. **Backend service not running**
|
||||||
|
- Check: `Get-Service ROA2WEB-Backend`
|
||||||
|
|
||||||
|
2. **IIS ARR not enabled**
|
||||||
|
- Check: `Get-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/proxy" -Name "enabled"`
|
||||||
|
|
||||||
|
3. **IIS sub-application misconfigured**
|
||||||
|
- Frontend should be deployed at IIS path `/roa2web`, not root
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Diagnostic Steps
|
||||||
|
|
||||||
|
### Step 1: Check Backend Service (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check service status
|
||||||
|
Get-Service ROA2WEB-Backend
|
||||||
|
|
||||||
|
# If stopped, start it
|
||||||
|
Start-Service ROA2WEB-Backend
|
||||||
|
|
||||||
|
# Test backend directly
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Output**:
|
||||||
|
```json
|
||||||
|
{"status": "healthy", "version": "..."}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Check Internal IIS web.config (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# View current web.config
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\web.config
|
||||||
|
|
||||||
|
# OR if frontend is in subdirectory:
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\frontend\web.config
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify these rules**:
|
||||||
|
- `<match url="^roa2web/api/(.*)" />` (NOT `^api/(.*)`)
|
||||||
|
- `<match url="^roa2web/uploads/(.*)" />` (NOT `^uploads/(.*)`)
|
||||||
|
- `<match url="^roa2web/.*" />` for SPA fallback
|
||||||
|
|
||||||
|
### Step 3: Check IIS ARR (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check if ARR is installed
|
||||||
|
Get-WindowsFeature -Name Web-ARR
|
||||||
|
|
||||||
|
# Check if proxy is enabled
|
||||||
|
Get-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
|
||||||
|
-Filter "system.webServer/proxy" `
|
||||||
|
-Name "enabled"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: `enabled` should be `True`
|
||||||
|
|
||||||
|
### Step 4: Test Internal IIS Proxy (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Test API endpoint through IIS
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/api/health
|
||||||
|
|
||||||
|
# Should proxy to backend and return response
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Check IIS Application Structure (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# List IIS applications
|
||||||
|
Get-WebApplication -Site "Default Web Site" | Format-Table Path, PhysicalPath
|
||||||
|
|
||||||
|
# Should show:
|
||||||
|
# /roa2web -> C:\inetpub\wwwroot\roa2web\
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fix Recommendations
|
||||||
|
|
||||||
|
### Fix #1: Update Internal Server web.config
|
||||||
|
|
||||||
|
**Server**: 10.0.20.36 (internal application server)
|
||||||
|
**Location**: `C:\inetpub\wwwroot\roa2web\web.config`
|
||||||
|
|
||||||
|
**IMPORTANT**: Acest web.config este pe serverul 10.0.20.36, NU pe 10.0.20.122!
|
||||||
|
|
||||||
|
**Required Configuration**:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<!-- Proxy API requests to unified backend -->
|
||||||
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Proxy uploads to unified backend -->
|
||||||
|
<rule name="Proxy Uploads" stopProcessing="true">
|
||||||
|
<match url="^roa2web/uploads/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- SPA fallback - serve index.html for non-file requests -->
|
||||||
|
<rule name="SPA Fallback" stopProcessing="true">
|
||||||
|
<match url="^roa2web/.*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="/roa2web/index.html" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
|
||||||
|
<staticContent>
|
||||||
|
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
||||||
|
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
||||||
|
<mimeMap fileExtension=".json" mimeType="application/json" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<httpProtocol>
|
||||||
|
<customHeaders>
|
||||||
|
<add name="Cache-Control" value="public, max-age=31536000" />
|
||||||
|
</customHeaders>
|
||||||
|
</httpProtocol>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deployment**:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# ⚠️ IMPORTANT: Rulează aceste comenzi pe serverul 10.0.20.36, NU pe 10.0.20.122!
|
||||||
|
# Conectează-te la 10.0.20.36 (internal application server)
|
||||||
|
|
||||||
|
# Backup current config
|
||||||
|
Copy-Item C:\inetpub\wwwroot\roa2web\web.config `
|
||||||
|
C:\inetpub\wwwroot\roa2web\web.config.backup.$(Get-Date -Format 'yyyyMMdd-HHmmss')
|
||||||
|
|
||||||
|
# Update web.config with corrected version
|
||||||
|
# (copy from repository: public/web.config after updating it)
|
||||||
|
|
||||||
|
# Restart IIS
|
||||||
|
iisreset
|
||||||
|
|
||||||
|
# Test
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fix #2: Ensure Backend Service is Running
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On internal server (10.0.20.36)
|
||||||
|
|
||||||
|
# Check service
|
||||||
|
Get-Service ROA2WEB-Backend
|
||||||
|
|
||||||
|
# If stopped
|
||||||
|
Start-Service ROA2WEB-Backend
|
||||||
|
|
||||||
|
# View startup logs
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50
|
||||||
|
|
||||||
|
# Check for errors
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fix #3: Enable IIS ARR (if not enabled)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On internal server (10.0.20.36)
|
||||||
|
|
||||||
|
# Enable proxy
|
||||||
|
Set-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
|
||||||
|
-Filter "system.webServer/proxy" `
|
||||||
|
-Name "enabled" `
|
||||||
|
-Value "True"
|
||||||
|
|
||||||
|
# Restart IIS
|
||||||
|
iisreset
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Steps (After Fix)
|
||||||
|
|
||||||
|
### 1. Backend Health Check (Direct)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On 10.0.20.36
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: `200 OK` with JSON response
|
||||||
|
|
||||||
|
### 2. Internal IIS Proxy Test
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On 10.0.20.36
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: `200 OK` (proxied from backend)
|
||||||
|
|
||||||
|
### 3. Public Access Test
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# From any client
|
||||||
|
Invoke-WebRequest https://roa2web.romfast.ro/roa2web/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: Frontend loads (HTML page)
|
||||||
|
|
||||||
|
### 4. Login Flow Test (Playwright)
|
||||||
|
|
||||||
|
Use Playwright to test complete login flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On development machine
|
||||||
|
cd /mnt/e/proiecte/roa2web
|
||||||
|
npx playwright test --headed --project=chromium tests/login.spec.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: Login succeeds without 404 errors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prevention
|
||||||
|
|
||||||
|
To prevent this issue in future deployments:
|
||||||
|
|
||||||
|
1. **Use Correct web.config Template**
|
||||||
|
- Repository should have separate web.config templates:
|
||||||
|
- `public/web.config` - for internal server (with `/roa2web/` prefix)
|
||||||
|
- `deployment/windows/config/web.config` - same as above
|
||||||
|
|
||||||
|
2. **Automated Deployment Script**
|
||||||
|
- PowerShell script should validate web.config before deployment
|
||||||
|
- Check for required URL patterns: `^roa2web/api/`, `^roa2web/uploads/`
|
||||||
|
|
||||||
|
3. **Deployment Checklist**
|
||||||
|
- Add to `deployment/windows/docs/DEPLOYMENT-CHECKLIST.md`:
|
||||||
|
- [ ] Verify web.config includes `/roa2web/` prefix in match rules
|
||||||
|
- [ ] Test backend: `Invoke-WebRequest http://localhost:8000/health`
|
||||||
|
- [ ] Test IIS proxy: `Invoke-WebRequest https://localhost/roa2web/api/health`
|
||||||
|
- [ ] Test public access: `Invoke-WebRequest https://roa2web.romfast.ro/roa2web/`
|
||||||
|
|
||||||
|
4. **Monitoring**
|
||||||
|
- Add health check endpoint monitoring
|
||||||
|
- Alert if backend service stops
|
||||||
|
- Monitor IIS logs for 404/502 errors
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. ✅ **Immediate**: Check internal server web.config (on 10.0.20.36)
|
||||||
|
2. ✅ **Immediate**: Verify backend service is running
|
||||||
|
3. ✅ **Immediate**: Apply Fix #1 if web.config is incorrect
|
||||||
|
4. ⏭️ **After Fix**: Run verification steps
|
||||||
|
5. ⏭️ **After Fix**: Update repository web.config template
|
||||||
|
6. ⏭️ **Future**: Add automated deployment validation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation Created
|
||||||
|
|
||||||
|
- ✅ `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md` - Complete 2-tier architecture guide
|
||||||
|
- ✅ Updated `CLAUDE.md` with deployment documentation reference
|
||||||
|
- ✅ This diagnostic report: `DIAGNOSIS-2025-12-30.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contact Information
|
||||||
|
|
||||||
|
**Issue Reported By**: User via Playwright testing
|
||||||
|
**Diagnosed By**: Claude Code
|
||||||
|
**Date**: 2025-12-30
|
||||||
|
**Severity**: HIGH (blocking production login)
|
||||||
|
**Priority**: IMMEDIATE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*For detailed architecture documentation, see: `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md`*
|
||||||
@@ -749,8 +749,8 @@ a. **Clear Build Cache**:
|
|||||||
b. **Check Dockerfile**:
|
b. **Check Dockerfile**:
|
||||||
```bash
|
```bash
|
||||||
# Validate Dockerfiles locally
|
# Validate Dockerfiles locally
|
||||||
docker build -t test-backend ./reports-app/backend
|
docker build -t test-backend ./backend
|
||||||
docker build -t test-frontend ./reports-app/frontend
|
docker build -t test-frontend ./src
|
||||||
docker build -t test-tunnel ./ssh-tunnel
|
docker build -t test-tunnel ./ssh-tunnel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -113,7 +113,7 @@ This starts SSH tunnel, unified backend (port 8001), and frontend (port 3000).
|
|||||||
**For detailed development commands, testing procedures, and troubleshooting**: See `CLAUDE.md` and component-specific READMEs:
|
**For detailed development commands, testing procedures, and troubleshooting**: See `CLAUDE.md` and component-specific READMEs:
|
||||||
- Backend: `backend/ modules and CLAUDE.md`
|
- Backend: `backend/ modules and CLAUDE.md`
|
||||||
- Frontend: `src/ and docs/MONOLITH_ARCHITECTURE.md` & `E2E testing guide in docs/`
|
- Frontend: `src/ and docs/MONOLITH_ARCHITECTURE.md` & `E2E testing guide in docs/`
|
||||||
- Telegram Bot: `reports-app/telegram-bot/README.md`
|
- Telegram Bot: `backend/modules/telegram/README.md`
|
||||||
|
|
||||||
**Key Commands**:
|
**Key Commands**:
|
||||||
```bash
|
```bash
|
||||||
@@ -269,7 +269,7 @@ All endpoints prefixed with `/api`:
|
|||||||
|
|
||||||
Copy `.env.example` to `.env` in each microservice and configure:
|
Copy `.env.example` to `.env` in each microservice and configure:
|
||||||
|
|
||||||
### Backend (`reports-app/backend/.env`)
|
### Backend (`backend/.env`)
|
||||||
```bash
|
```bash
|
||||||
# Oracle Database (through SSH tunnel)
|
# Oracle Database (through SSH tunnel)
|
||||||
ORACLE_USER=your_username
|
ORACLE_USER=your_username
|
||||||
@@ -284,7 +284,7 @@ JWT_ALGORITHM=HS256
|
|||||||
JWT_EXPIRE_MINUTES=30
|
JWT_EXPIRE_MINUTES=30
|
||||||
```
|
```
|
||||||
|
|
||||||
### Telegram Bot (`reports-app/telegram-bot/.env`)
|
### Telegram Bot (`backend/modules/telegram/.env`)
|
||||||
```bash
|
```bash
|
||||||
# Telegram Bot Token
|
# Telegram Bot Token
|
||||||
TELEGRAM_BOT_TOKEN=your_bot_token
|
TELEGRAM_BOT_TOKEN=your_bot_token
|
||||||
@@ -308,8 +308,8 @@ BACKEND_API_URL=http://localhost:8001
|
|||||||
- `backend/ modules and CLAUDE.md` - Backend specifics
|
- `backend/ modules and CLAUDE.md` - Backend specifics
|
||||||
- `src/ and docs/MONOLITH_ARCHITECTURE.md` - Frontend guide
|
- `src/ and docs/MONOLITH_ARCHITECTURE.md` - Frontend guide
|
||||||
- `E2E testing guide in docs/` - Frontend testing
|
- `E2E testing guide in docs/` - Frontend testing
|
||||||
- `reports-app/telegram-bot/README.md` - Telegram bot guide
|
- `backend/modules/telegram/README.md` - Telegram bot guide
|
||||||
- `reports-app/telegram-bot/TELEGRAM_COMMANDS.md` - Bot commands
|
- `backend/modules/telegram/TELEGRAM_COMMANDS.md` - Bot commands
|
||||||
|
|
||||||
### Frontend Styling & CSS
|
### Frontend Styling & CSS
|
||||||
- `docs/ONBOARDING_CSS.md` - CSS system onboarding guide (start here!)
|
- `docs/ONBOARDING_CSS.md` - CSS system onboarding guide (start here!)
|
||||||
|
|||||||
240
deployment/windows/config/README-WEB-CONFIG.md
Normal file
240
deployment/windows/config/README-WEB-CONFIG.md
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
# web.config Files - Which Goes Where?
|
||||||
|
|
||||||
|
## ⚠️ IMPORTANT - Read Before Deployment!
|
||||||
|
|
||||||
|
ROA2WEB uses a **2-tier IIS architecture** with **2 different web.config files** for **2 different servers**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
↓
|
||||||
|
Public Server (10.0.20.122) - roa2web.romfast.ro
|
||||||
|
↓ HTTPS reverse proxy
|
||||||
|
Internal Server (10.0.20.36) - application host
|
||||||
|
↓ API proxy to localhost
|
||||||
|
Backend Service (localhost:8000 on 10.0.20.36)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Mapping
|
||||||
|
|
||||||
|
### File: `web.config.10.0.20.122-PUBLIC`
|
||||||
|
|
||||||
|
**Server**: 10.0.20.122 (Public IIS - roa2web.romfast.ro)
|
||||||
|
**Role**: Public gateway, reverse proxy to internal server
|
||||||
|
|
||||||
|
**Purpose**:
|
||||||
|
- Proxies ALL requests to `https://10.0.20.36/{REQUEST_PATH}`
|
||||||
|
- Sets forwarding headers (`X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Real-IP`)
|
||||||
|
- Redirects root `/` to `/roa2web/`
|
||||||
|
|
||||||
|
**Key Rule**:
|
||||||
|
```xml
|
||||||
|
<match url="(.*)" />
|
||||||
|
<action type="Rewrite" url="https://10.0.20.36/{R:1}" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deployment Location**:
|
||||||
|
```
|
||||||
|
10.0.20.122:
|
||||||
|
C:\inetpub\wwwroot\[ROOT]\web.config
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### File: `web.config.10.0.20.36-INTERNAL`
|
||||||
|
|
||||||
|
**Server**: 10.0.20.36 (Internal IIS - application host)
|
||||||
|
**Role**: Serves frontend, proxies API to localhost backend
|
||||||
|
|
||||||
|
**Purpose**:
|
||||||
|
- Serves Vue.js frontend static files
|
||||||
|
- Proxies `/roa2web/api/*` to `http://localhost:8000/api/*`
|
||||||
|
- Proxies `/roa2web/uploads/*` to `http://localhost:8000/uploads/*`
|
||||||
|
- SPA fallback for client-side routing
|
||||||
|
|
||||||
|
**Key Rules**:
|
||||||
|
```xml
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
|
||||||
|
<match url="^roa2web/uploads/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
|
|
||||||
|
<match url="^roa2web/.*" />
|
||||||
|
<action type="Rewrite" url="/roa2web/index.html" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deployment Location**:
|
||||||
|
```
|
||||||
|
10.0.20.36:
|
||||||
|
C:\inetpub\wwwroot\roa2web\web.config
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: This file is also in `public/web.config` (repository root) and is automatically copied to `dist/` during Vite build.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Checklist
|
||||||
|
|
||||||
|
### ✅ Public Server (10.0.20.122)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Copy public server config
|
||||||
|
Copy-Item deployment/windows/config/web.config.10.0.20.122-PUBLIC `
|
||||||
|
C:\inetpub\wwwroot\[ROOT]\web.config
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
Get-Content C:\inetpub\wwwroot\[ROOT]\web.config | Select-String "10.0.20.36"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: Should see `url="https://10.0.20.36/{R:1}"`
|
||||||
|
|
||||||
|
### ✅ Internal Server (10.0.20.36)
|
||||||
|
|
||||||
|
**Option A: From built dist/ (recommended)**:
|
||||||
|
```powershell
|
||||||
|
# After building frontend with `npm run build`
|
||||||
|
# web.config is automatically in dist/
|
||||||
|
|
||||||
|
# Deploy entire dist/ folder
|
||||||
|
Copy-Item dist\* C:\inetpub\wwwroot\roa2web\ -Recurse -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B: Manual copy**:
|
||||||
|
```powershell
|
||||||
|
# Copy internal server config
|
||||||
|
Copy-Item deployment/windows/config/web.config.10.0.20.36-INTERNAL `
|
||||||
|
C:\inetpub\wwwroot\roa2web\web.config
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\web.config | Select-String "roa2web/api"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: Should see `url="^roa2web/api/(.*)"` and `url="http://localhost:8000/api/{R:1}"`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
### Test Public Server (10.0.20.122)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Should proxy to internal server
|
||||||
|
Invoke-WebRequest https://roa2web.romfast.ro/roa2web/ -UseBasicParsing
|
||||||
|
|
||||||
|
# Check response headers
|
||||||
|
(Invoke-WebRequest https://roa2web.romfast.ro/roa2web/).Headers
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: Request should be proxied to 10.0.20.36
|
||||||
|
|
||||||
|
### Test Internal Server (10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Test backend directly
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
|
||||||
|
# Test through IIS proxy
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/api/health
|
||||||
|
|
||||||
|
# Test frontend
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected**: All should return 200 OK
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Mistakes ❌
|
||||||
|
|
||||||
|
### ❌ WRONG: Using internal config on public server
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- On 10.0.20.122 - WRONG! -->
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem**: Public server doesn't have backend on localhost:8000
|
||||||
|
|
||||||
|
### ❌ WRONG: Using public config on internal server
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- On 10.0.20.36 - WRONG! -->
|
||||||
|
<match url="(.*)" />
|
||||||
|
<action type="Rewrite" url="https://10.0.20.36/{R:1}" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem**: Creates infinite redirect loop
|
||||||
|
|
||||||
|
### ❌ WRONG: Missing /roa2web/ prefix on internal server
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- On 10.0.20.36 - WRONG! -->
|
||||||
|
<match url="^api/(.*)" /> <!-- Missing roa2web prefix! -->
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem**: Requests come as `/roa2web/api/...` from public server, so `^api/` won't match
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Issue: 404 on API calls
|
||||||
|
|
||||||
|
**Symptom**: Frontend loads but API returns 404
|
||||||
|
|
||||||
|
**Check**: web.config on 10.0.20.36
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On 10.0.20.36
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\web.config | Select-String "roa2web/api"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**: Update to correct internal server config (see above)
|
||||||
|
|
||||||
|
### Issue: Infinite redirect loop
|
||||||
|
|
||||||
|
**Symptom**: Browser shows "Too many redirects"
|
||||||
|
|
||||||
|
**Check**: Verify you didn't put public config on internal server
|
||||||
|
|
||||||
|
### Issue: Backend not reachable
|
||||||
|
|
||||||
|
**Symptom**: 502 Bad Gateway on API calls
|
||||||
|
|
||||||
|
**Check**: Backend service on 10.0.20.36
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# On 10.0.20.36
|
||||||
|
Get-Service ROA2WEB-Backend
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference
|
||||||
|
|
||||||
|
| Server | IP | Config File | Key Pattern | Proxies To |
|
||||||
|
|--------|----|----|-------------|------------|
|
||||||
|
| **Public** | 10.0.20.122 | `web.config.10.0.20.122-PUBLIC` | `url="(.*)"` | `https://10.0.20.36/{R:1}` |
|
||||||
|
| **Internal** | 10.0.20.36 | `web.config.10.0.20.36-INTERNAL` | `url="^roa2web/api/(.*)"` | `http://localhost:8000/api/{R:1}` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
For complete architecture details, see:
|
||||||
|
- `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md`
|
||||||
|
- `DIAGNOSIS-2025-12-30.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last Updated: 2025-12-30*
|
||||||
|
*ROA2WEB Deployment Configuration Guide*
|
||||||
38
deployment/windows/config/web.config.10.0.20.122-PUBLIC
Normal file
38
deployment/windows/config/web.config.10.0.20.122-PUBLIC
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
====================================================================
|
||||||
|
ROA2WEB - Public IIS Server Configuration
|
||||||
|
====================================================================
|
||||||
|
Server: 10.0.20.122 (roa2web.romfast.ro)
|
||||||
|
Role: Public gateway / reverse proxy
|
||||||
|
|
||||||
|
This web.config ONLY goes on the PUBLIC server (10.0.20.122).
|
||||||
|
It proxies all requests to the internal application server (10.0.20.36).
|
||||||
|
|
||||||
|
⚠️ DO NOT use this config on 10.0.20.36!
|
||||||
|
====================================================================
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<!-- Redirect root to /roa2web/ -->
|
||||||
|
<rule name="Root to ROA2WEB" stopProcessing="true">
|
||||||
|
<match url="^$" />
|
||||||
|
<action type="Redirect" url="/roa2web/" redirectType="Permanent" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Reverse Proxy to internal application server -->
|
||||||
|
<rule name="ROA2WEB Reverse Proxy to HTTPS Backend" stopProcessing="true">
|
||||||
|
<match url="(.*)" />
|
||||||
|
<action type="Rewrite" url="https://10.0.20.36/{R:1}" />
|
||||||
|
<serverVariables>
|
||||||
|
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
|
||||||
|
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
|
||||||
|
<set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
|
||||||
|
</serverVariables>
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
59
deployment/windows/config/web.config.10.0.20.36-INTERNAL
Normal file
59
deployment/windows/config/web.config.10.0.20.36-INTERNAL
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
====================================================================
|
||||||
|
ROA2WEB - Internal Application Server Configuration
|
||||||
|
====================================================================
|
||||||
|
Server: 10.0.20.36 (internal application server)
|
||||||
|
Role: Application host + API proxy to localhost backend
|
||||||
|
|
||||||
|
This web.config ONLY goes on the INTERNAL server (10.0.20.36).
|
||||||
|
It serves the frontend and proxies API calls to localhost:8000.
|
||||||
|
|
||||||
|
Location: C:\inetpub\wwwroot\roa2web\web.config (on 10.0.20.36)
|
||||||
|
|
||||||
|
⚠️ DO NOT use this config on 10.0.20.122 (public server)!
|
||||||
|
====================================================================
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<!-- Proxy API requests to unified backend on localhost -->
|
||||||
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Proxy uploads to unified backend on localhost -->
|
||||||
|
<rule name="Proxy Uploads" stopProcessing="true">
|
||||||
|
<match url="^roa2web/uploads/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- SPA fallback - all other routes serve index.html -->
|
||||||
|
<rule name="SPA Fallback" stopProcessing="true">
|
||||||
|
<match url="^roa2web/.*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="/roa2web/index.html" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
|
||||||
|
<!-- Static content configuration -->
|
||||||
|
<staticContent>
|
||||||
|
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
||||||
|
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
||||||
|
<mimeMap fileExtension=".json" mimeType="application/json" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<!-- Client cache for static assets (1 year) -->
|
||||||
|
<httpProtocol>
|
||||||
|
<customHeaders>
|
||||||
|
<add name="Cache-Control" value="public, max-age=31536000" />
|
||||||
|
</customHeaders>
|
||||||
|
</httpProtocol>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
@@ -826,7 +826,7 @@ CREATE TABLE telegram_sessions (
|
|||||||
## Support
|
## Support
|
||||||
|
|
||||||
**Documentation**:
|
**Documentation**:
|
||||||
- Project README: `/mnt/e/proiecte/roa2web/roa2web/reports-app/telegram-bot/README.md`
|
- Project README: `/mnt/e/proiecte/roa2web/roa2web/backend/modules/telegram/README.md`
|
||||||
- Progress Tracker: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PROGRESS.md`
|
- Progress Tracker: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PROGRESS.md`
|
||||||
- Production Deployment Plan: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PRODUCTION_DEPLOYMENT.md`
|
- Production Deployment Plan: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PRODUCTION_DEPLOYMENT.md`
|
||||||
|
|
||||||
|
|||||||
435
deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md
Normal file
435
deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md
Normal file
@@ -0,0 +1,435 @@
|
|||||||
|
# Two-Tier IIS Deployment Architecture
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
ROA2WEB uses a **2-tier IIS architecture** for production deployment:
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
↓
|
||||||
|
Public IIS Server (roa2web.romfast.ro)
|
||||||
|
↓ HTTPS reverse proxy
|
||||||
|
Internal IIS Server (10.0.20.36)
|
||||||
|
↓ API proxy
|
||||||
|
Backend Service (localhost:8000)
|
||||||
|
↓
|
||||||
|
Oracle Database
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Components
|
||||||
|
|
||||||
|
### Tier 1: Public IIS Server (Edge/Gateway)
|
||||||
|
|
||||||
|
**Hostname**: `roa2web.romfast.ro`
|
||||||
|
**IP Address**: `10.0.20.122`
|
||||||
|
**Role**: Public-facing reverse proxy
|
||||||
|
**Location**: DMZ/Public network
|
||||||
|
|
||||||
|
**Responsibilities**:
|
||||||
|
- SSL/TLS termination (HTTPS)
|
||||||
|
- Reverse proxy to internal server
|
||||||
|
- Security headers
|
||||||
|
- Public DNS endpoint
|
||||||
|
|
||||||
|
**Configuration** (`web.config` pe serverul 10.0.20.122):
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<!-- Redirect root to /roa2web/ -->
|
||||||
|
<rule name="Root to ROA2WEB" stopProcessing="true">
|
||||||
|
<match url="^$" />
|
||||||
|
<action type="Redirect" url="/roa2web/" redirectType="Permanent" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Reverse Proxy to internal server -->
|
||||||
|
<rule name="ROA2WEB Reverse Proxy to HTTPS Backend" stopProcessing="true">
|
||||||
|
<match url="(.*)" />
|
||||||
|
<action type="Rewrite" url="https://10.0.20.36/{R:1}" />
|
||||||
|
<serverVariables>
|
||||||
|
<set name="HTTP_X_FORWARDED_PROTO" value="https" />
|
||||||
|
<set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" />
|
||||||
|
<set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" />
|
||||||
|
</serverVariables>
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features**:
|
||||||
|
- Root redirect: `https://roa2web.romfast.ro/` → `https://roa2web.romfast.ro/roa2web/`
|
||||||
|
- All requests proxied to: `https://10.0.20.36/{REQUEST_PATH}`
|
||||||
|
- Forwards client IP and protocol headers
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Tier 2: Internal IIS Server (Application Server)
|
||||||
|
|
||||||
|
**IP Address**: `10.0.20.36`
|
||||||
|
**Role**: Application host + API proxy
|
||||||
|
**Location**: Internal network
|
||||||
|
|
||||||
|
**Responsibilities**:
|
||||||
|
- Serve Vue.js frontend static files
|
||||||
|
- Proxy API requests to backend service
|
||||||
|
- Handle uploads
|
||||||
|
- IIS sub-application at `/roa2web`
|
||||||
|
|
||||||
|
**Configuration** (`web.config` pe serverul 10.0.20.36 - `C:\inetpub\wwwroot\roa2web\web.config`):
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<system.webServer>
|
||||||
|
<rewrite>
|
||||||
|
<rules>
|
||||||
|
<!-- Proxy all API requests to unified backend -->
|
||||||
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Proxy uploads to unified backend -->
|
||||||
|
<rule name="Proxy Uploads" stopProcessing="true">
|
||||||
|
<match url="^roa2web/uploads/(.*)" />
|
||||||
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- SPA fallback - all other routes serve index.html -->
|
||||||
|
<rule name="SPA Fallback" stopProcessing="true">
|
||||||
|
<match url="^roa2web/.*" />
|
||||||
|
<conditions logicalGrouping="MatchAll">
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
|
</conditions>
|
||||||
|
<action type="Rewrite" url="/roa2web/index.html" />
|
||||||
|
</rule>
|
||||||
|
</rules>
|
||||||
|
</rewrite>
|
||||||
|
|
||||||
|
<!-- Static content configuration -->
|
||||||
|
<staticContent>
|
||||||
|
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
||||||
|
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
||||||
|
<mimeMap fileExtension=".json" mimeType="application/json" />
|
||||||
|
</staticContent>
|
||||||
|
|
||||||
|
<!-- Client cache for static assets (1 year) -->
|
||||||
|
<httpProtocol>
|
||||||
|
<customHeaders>
|
||||||
|
<add name="Cache-Control" value="public, max-age=31536000" />
|
||||||
|
</customHeaders>
|
||||||
|
</httpProtocol>
|
||||||
|
</system.webServer>
|
||||||
|
</configuration>
|
||||||
|
```
|
||||||
|
|
||||||
|
**CRITICAL**: The internal server web.config must handle the `/roa2web/` prefix since requests arrive as:
|
||||||
|
- `https://10.0.20.36/roa2web/api/auth/login` (NOT `/api/auth/login`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Backend Service (FastAPI)
|
||||||
|
|
||||||
|
**Host**: `localhost` (internal server)
|
||||||
|
**Port**: `8000`
|
||||||
|
**Type**: Windows Service (NSSM)
|
||||||
|
**Name**: `ROA2WEB-Backend`
|
||||||
|
|
||||||
|
**Configuration** (`.env`):
|
||||||
|
```env
|
||||||
|
HOST=127.0.0.1
|
||||||
|
PORT=8000
|
||||||
|
ENVIRONMENT=production
|
||||||
|
```
|
||||||
|
|
||||||
|
**Base Path**: `/api` (NOT `/roa2web/api`)
|
||||||
|
|
||||||
|
The backend serves:
|
||||||
|
- `/api/auth/login`
|
||||||
|
- `/api/companies`
|
||||||
|
- `/api/calendar`
|
||||||
|
- etc.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Request Flow Example
|
||||||
|
|
||||||
|
### Login Request Flow
|
||||||
|
|
||||||
|
1. **Client Browser** → `POST https://roa2web.romfast.ro/roa2web/api/auth/login`
|
||||||
|
|
||||||
|
2. **Public IIS** (roa2web.romfast.ro):
|
||||||
|
- Receives: `/roa2web/api/auth/login`
|
||||||
|
- Proxies to: `https://10.0.20.36/roa2web/api/auth/login`
|
||||||
|
- Sets headers: `X-Forwarded-Proto: https`, `X-Forwarded-Host: roa2web.romfast.ro`
|
||||||
|
|
||||||
|
3. **Internal IIS** (10.0.20.36):
|
||||||
|
- Receives: `/roa2web/api/auth/login`
|
||||||
|
- Matches rule: `^roa2web/api/(.*)`
|
||||||
|
- Extracts: `auth/login`
|
||||||
|
- Proxies to: `http://localhost:8000/api/auth/login`
|
||||||
|
|
||||||
|
4. **Backend Service** (localhost:8000):
|
||||||
|
- Receives: `/api/auth/login`
|
||||||
|
- Processes request
|
||||||
|
- Returns response
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frontend Configuration
|
||||||
|
|
||||||
|
### Vite Build Configuration (`vite.config.js`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default defineConfig({
|
||||||
|
// Base path for IIS sub-application
|
||||||
|
base: process.env.NODE_ENV === 'production' ? '/roa2web/' : '/',
|
||||||
|
|
||||||
|
// Development proxy (NOT used in production)
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:8000',
|
||||||
|
changeOrigin: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**IMPORTANT**: In production, `base: '/roa2web/'` ensures:
|
||||||
|
- All asset paths: `/roa2web/assets/...`
|
||||||
|
- Router base: `/roa2web/`
|
||||||
|
- API calls: `/roa2web/api/...` (via axios baseURL)
|
||||||
|
|
||||||
|
### API Service Configuration (`src/App.vue`)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const authApi = axios.create({
|
||||||
|
baseURL: import.meta.env.BASE_URL + 'api', // Results in: '/roa2web/api'
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Issues & Troubleshooting
|
||||||
|
|
||||||
|
### Issue: 404 on API calls
|
||||||
|
|
||||||
|
**Symptoms**:
|
||||||
|
- Frontend loads correctly
|
||||||
|
- API calls return 404
|
||||||
|
- Browser console: `POST https://roa2web.romfast.ro/roa2web/api/auth/login 404`
|
||||||
|
|
||||||
|
**Possible Causes**:
|
||||||
|
|
||||||
|
1. **Internal server web.config missing `/roa2web/` prefix in match rules**
|
||||||
|
|
||||||
|
❌ **WRONG**:
|
||||||
|
```xml
|
||||||
|
<match url="^api/(.*)" />
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **CORRECT**:
|
||||||
|
```xml
|
||||||
|
<match url="^roa2web/api/(.*)" />
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Backend service not running**
|
||||||
|
|
||||||
|
Check on internal server (10.0.20.36):
|
||||||
|
```powershell
|
||||||
|
Get-Service ROA2WEB-Backend
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **IIS ARR not enabled**
|
||||||
|
|
||||||
|
On internal server (10.0.20.36):
|
||||||
|
```powershell
|
||||||
|
# Install ARR
|
||||||
|
Install-WindowsFeature -Name Web-ARR
|
||||||
|
|
||||||
|
# Enable proxy
|
||||||
|
Set-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
|
||||||
|
-Filter "system.webServer/proxy" `
|
||||||
|
-Name "enabled" `
|
||||||
|
-Value "True"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **IIS sub-application not configured at `/roa2web`**
|
||||||
|
|
||||||
|
The frontend must be deployed as IIS sub-application at path `/roa2web`, NOT as root site.
|
||||||
|
|
||||||
|
### Issue: Frontend loads but shows blank page
|
||||||
|
|
||||||
|
**Symptoms**:
|
||||||
|
- Browser shows white screen
|
||||||
|
- Console error: `Failed to load module script`
|
||||||
|
- Assets return 404
|
||||||
|
|
||||||
|
**Solution**: Check `base` in `vite.config.js` matches IIS sub-application path.
|
||||||
|
|
||||||
|
### Issue: CORS errors
|
||||||
|
|
||||||
|
**Symptoms**:
|
||||||
|
- API calls blocked by CORS policy
|
||||||
|
- Console: `Access-Control-Allow-Origin` error
|
||||||
|
|
||||||
|
**Solution**: Backend should see requests as same-origin (via IIS proxy), so CORS shouldn't apply. If you see CORS errors, the proxy is misconfigured.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deployment Checklist
|
||||||
|
|
||||||
|
### Public Server (roa2web.romfast.ro)
|
||||||
|
|
||||||
|
- [ ] SSL certificate installed and valid
|
||||||
|
- [ ] IIS ARR (Application Request Routing) installed
|
||||||
|
- [ ] web.config configured with reverse proxy to 10.0.20.36
|
||||||
|
- [ ] Server variables enabled in IIS
|
||||||
|
- [ ] Firewall allows HTTPS outbound to 10.0.20.36
|
||||||
|
|
||||||
|
### Internal Server (10.0.20.36)
|
||||||
|
|
||||||
|
- [ ] IIS installed and running
|
||||||
|
- [ ] IIS ARR installed
|
||||||
|
- [ ] IIS URL Rewrite module installed
|
||||||
|
- [ ] Sub-application created at `/roa2web`
|
||||||
|
- [ ] Frontend files deployed to `C:\inetpub\wwwroot\roa2web\`
|
||||||
|
- [ ] web.config includes `/roa2web/` prefix in match rules
|
||||||
|
- [ ] Backend service (ROA2WEB-Backend) running
|
||||||
|
- [ ] Backend accessible at `http://localhost:8000/health`
|
||||||
|
- [ ] Firewall allows HTTPS inbound from public server
|
||||||
|
|
||||||
|
### Backend Service
|
||||||
|
|
||||||
|
- [ ] Windows Service created (NSSM)
|
||||||
|
- [ ] Service set to auto-start
|
||||||
|
- [ ] `.env` configured with correct Oracle credentials
|
||||||
|
- [ ] Logs directory exists and writable
|
||||||
|
- [ ] Health check returns 200 OK
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Procedure
|
||||||
|
|
||||||
|
### 1. Test Backend Directly (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Health check
|
||||||
|
Invoke-WebRequest http://localhost:8000/health
|
||||||
|
|
||||||
|
# API test (without auth)
|
||||||
|
Invoke-WebRequest http://localhost:8000/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test Internal IIS Proxy (on 10.0.20.36)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Should proxy to backend
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/api/health
|
||||||
|
|
||||||
|
# Should serve frontend
|
||||||
|
Invoke-WebRequest https://localhost/roa2web/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test Public Access (from any client)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Frontend
|
||||||
|
Invoke-WebRequest https://roa2web.romfast.ro/roa2web/
|
||||||
|
|
||||||
|
# API (will fail without auth, but should return 401 not 404)
|
||||||
|
Invoke-WebRequest https://roa2web.romfast.ro/roa2web/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Test with Playwright (comprehensive)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Use Playwright to test full login flow
|
||||||
|
./start-playwright.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoring & Logs
|
||||||
|
|
||||||
|
### Public Server Logs
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# IIS logs
|
||||||
|
Get-Content C:\inetpub\logs\LogFiles\W3SVC*\*.log -Tail 50
|
||||||
|
|
||||||
|
# Failed Request Tracing (if enabled)
|
||||||
|
Get-ChildItem C:\inetpub\logs\FailedReqLogFiles
|
||||||
|
```
|
||||||
|
|
||||||
|
### Internal Server Logs
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# IIS logs
|
||||||
|
Get-Content C:\inetpub\logs\LogFiles\W3SVC*\*.log -Tail 50
|
||||||
|
|
||||||
|
# Backend service logs
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50 -Wait
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend Application Logs
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Application log
|
||||||
|
Get-Content C:\inetpub\wwwroot\roa2web\backend\logs\app.log -Tail 100
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### SSL/TLS
|
||||||
|
|
||||||
|
- Public server handles SSL termination
|
||||||
|
- Internal communication can use HTTPS (current) or HTTP (simpler)
|
||||||
|
- Certificate management only needed on public server
|
||||||
|
|
||||||
|
### Firewall Rules
|
||||||
|
|
||||||
|
**Public Server**:
|
||||||
|
- Allow inbound: 443 (HTTPS)
|
||||||
|
- Allow outbound: 443 to 10.0.20.36
|
||||||
|
|
||||||
|
**Internal Server**:
|
||||||
|
- Allow inbound: 443 from public server IP only
|
||||||
|
- No need to expose port 8000 externally (backend is localhost-only)
|
||||||
|
|
||||||
|
### Headers
|
||||||
|
|
||||||
|
Public server sets forwarding headers:
|
||||||
|
- `X-Forwarded-Proto: https` - Original protocol
|
||||||
|
- `X-Forwarded-Host: roa2web.romfast.ro` - Original hostname
|
||||||
|
- `X-Real-IP: {CLIENT_IP}` - Client IP address
|
||||||
|
|
||||||
|
Backend can use these for logging and security.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
| Version | Date | Changes |
|
||||||
|
|---------|------|---------|
|
||||||
|
| 1.0.0 | 2025-12-30 | Initial documentation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last Updated: 2025-12-30*
|
||||||
|
*ROA2WEB Two-Tier IIS Deployment Architecture*
|
||||||
@@ -24,7 +24,7 @@ Aplicatie separata pentru introducere date in ERP, cu workflow de aprobare si st
|
|||||||
|
|
||||||
### 2. Separare de Reports-App
|
### 2. Separare de Reports-App
|
||||||
|
|
||||||
**Alegere**: Aplicatie separata in `data-entry-app/`
|
**Alegere**: Aplicatie separata in `backend/modules/data_entry/`
|
||||||
|
|
||||||
**Motivatie**:
|
**Motivatie**:
|
||||||
- Responsabilitati diferite: reports = read-only, data-entry = write
|
- Responsabilitati diferite: reports = read-only, data-entry = write
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Aplicatie pentru introducere bonuri fiscale cu workflow de aprobare si extragere
|
|||||||
#### Backend Setup
|
#### Backend Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd data-entry-app/backend
|
cd backend/modules/data_entry/backend
|
||||||
|
|
||||||
# Create virtual environment
|
# Create virtual environment
|
||||||
python -m venv venv
|
python -m venv venv
|
||||||
@@ -57,7 +57,7 @@ uvicorn app.main:app --reload --port 8003
|
|||||||
#### Frontend Setup
|
#### Frontend Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd data-entry-app/frontend
|
cd backend/modules/data_entry/frontend
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
npm install
|
npm install
|
||||||
@@ -212,7 +212,7 @@ DRAFT → PENDING_REVIEW → APPROVED/REJECTED → (SYNCED in Oracle)
|
|||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
data-entry-app/
|
backend/modules/data_entry/
|
||||||
├── backend/
|
├── backend/
|
||||||
│ ├── app/
|
│ ├── app/
|
||||||
│ │ ├── main.py # FastAPI entry point
|
│ │ ├── main.py # FastAPI entry point
|
||||||
@@ -274,7 +274,7 @@ ORACLE_HOST=localhost
|
|||||||
ORACLE_PORT=1526
|
ORACLE_PORT=1526
|
||||||
ORACLE_SID=ROA
|
ORACLE_SID=ROA
|
||||||
|
|
||||||
# JWT (shared with reports-app)
|
# JWT (shared with Reports module)
|
||||||
JWT_SECRET_KEY=your_secret_key
|
JWT_SECRET_KEY=your_secret_key
|
||||||
JWT_ALGORITHM=HS256
|
JWT_ALGORITHM=HS256
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Preluate din Oracle (read-only):
|
|||||||
- Paginare pentru liste > 50 elemente
|
- Paginare pentru liste > 50 elemente
|
||||||
|
|
||||||
### Securitate
|
### Securitate
|
||||||
- Autentificare JWT (shared cu reports-app)
|
- Autentificare JWT (shared cu Reports module)
|
||||||
- Validare MIME type pentru fisiere
|
- Validare MIME type pentru fisiere
|
||||||
- Sanitizare nume fisiere
|
- Sanitizare nume fisiere
|
||||||
- Acces bazat pe rol
|
- Acces bazat pe rol
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ The bot uses a standalone SQLite database for:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Navigate to telegram-bot directory
|
# Navigate to telegram-bot directory
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
|
|
||||||
# Create virtual environment
|
# Create virtual environment
|
||||||
python3 -m venv venv
|
python3 -m venv venv
|
||||||
@@ -331,7 +331,7 @@ application.add_handler(CommandHandler("mycommand", my_command))
|
|||||||
- **Implementation Summary:** [FAZA1_IMPLEMENTATION_SUMMARY.md](./FAZA1_IMPLEMENTATION_SUMMARY.md)
|
- **Implementation Summary:** [FAZA1_IMPLEMENTATION_SUMMARY.md](./FAZA1_IMPLEMENTATION_SUMMARY.md)
|
||||||
|
|
||||||
**Frontend Changes:**
|
**Frontend Changes:**
|
||||||
- `reports-app/frontend/src/views/TelegramView.vue` - Complete UI refactor
|
- `src/modules/reports/views/TelegramView.vue` - Complete UI refactor
|
||||||
- Added `qrcode.vue` dependency for QR generation
|
- Added `qrcode.vue` dependency for QR generation
|
||||||
- Environment variable: `VITE_TELEGRAM_BOT_USERNAME`
|
- Environment variable: `VITE_TELEGRAM_BOT_USERNAME`
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Transformarea Telegram bot ROA2WEB dintr-o interfață bazată pe comenzi text
|
|||||||
### Structură Fișiere Noi/Modificate
|
### Structură Fișiere Noi/Modificate
|
||||||
|
|
||||||
```
|
```
|
||||||
roa2web/reports-app/telegram-bot/
|
roa2web/backend/modules/telegram/
|
||||||
├── app/
|
├── app/
|
||||||
│ ├── bot/
|
│ ├── bot/
|
||||||
│ │ ├── menus.py ⭐ NOU - Builders pentru tastaturi butoane
|
│ │ ├── menus.py ⭐ NOU - Builders pentru tastaturi butoane
|
||||||
@@ -343,7 +343,7 @@ def test_create_navigation_buttons():
|
|||||||
|
|
||||||
**Rulare teste FAZA 1:**
|
**Rulare teste FAZA 1:**
|
||||||
```bash
|
```bash
|
||||||
cd /mnt/e/proiecte/roa2web/roa2web/reports-app/telegram-bot
|
cd /mnt/e/proiecte/roa2web/roa2web/backend/modules/telegram
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pytest tests/test_menus.py -v
|
pytest tests/test_menus.py -v
|
||||||
```
|
```
|
||||||
@@ -1868,11 +1868,11 @@ Documentație:
|
|||||||
- Backend API endpoints (vezi CLAUDE.md)
|
- Backend API endpoints (vezi CLAUDE.md)
|
||||||
|
|
||||||
### Fișiere Relevante în Proiect
|
### Fișiere Relevante în Proiect
|
||||||
- `roa2web/reports-app/telegram-bot/app/bot/handlers.py` - Handlers principale
|
- `roa2web/backend/modules/telegram/app/bot/handlers.py` - Handlers principale
|
||||||
- `roa2web/reports-app/telegram-bot/app/bot/formatters.py` - Formatteri răspunsuri
|
- `roa2web/backend/modules/telegram/app/bot/formatters.py` - Formatteri răspunsuri
|
||||||
- `roa2web/reports-app/telegram-bot/app/bot/helpers.py` - Helper functions
|
- `roa2web/backend/modules/telegram/app/bot/helpers.py` - Helper functions
|
||||||
- `roa2web/reports-app/telegram-bot/app/main.py` - Setup aplicație
|
- `roa2web/backend/modules/telegram/app/main.py` - Setup aplicație
|
||||||
- `roa2web/reports-app/telegram-bot/TELEGRAM_COMMANDS.md` - Documentație comenzi
|
- `roa2web/backend/modules/telegram/TELEGRAM_COMMANDS.md` - Documentație comenzi
|
||||||
|
|
||||||
### Screenshots Pentru Referință
|
### Screenshots Pentru Referință
|
||||||
- BotFather interface (screenshot.jpg în root) - Model pentru layout butoane
|
- BotFather interface (screenshot.jpg în root) - Model pentru layout butoane
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Before testing Docker deployment:
|
|||||||
### 1. Check Dockerfile Syntax
|
### 1. Check Dockerfile Syntax
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/roa2web/reports-app/telegram-bot
|
cd /path/to/roa2web/backend/modules/telegram
|
||||||
|
|
||||||
# Verify Dockerfile exists and is valid
|
# Verify Dockerfile exists and is valid
|
||||||
cat Dockerfile
|
cat Dockerfile
|
||||||
@@ -71,7 +71,7 @@ cat .dockerignore
|
|||||||
### Test 1: Build Telegram Bot Image
|
### Test 1: Build Telegram Bot Image
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /path/to/roa2web/reports-app/telegram-bot
|
cd /path/to/roa2web/backend/modules/telegram
|
||||||
|
|
||||||
# Build the image
|
# Build the image
|
||||||
docker build -t roa2web/telegram-bot:test --target production .
|
docker build -t roa2web/telegram-bot:test --target production .
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ Before starting manual tests:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Terminal 1: Start backend API (from roa2web/)
|
# Terminal 1: Start backend API (from roa2web/)
|
||||||
cd reports-app/backend
|
cd backend
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
uvicorn app.main:app --reload --port 8001
|
uvicorn app.main:app --reload --port 8001
|
||||||
|
|
||||||
# Terminal 2: Start Telegram bot
|
# Terminal 2: Start Telegram bot
|
||||||
cd reports-app/telegram-bot
|
cd backend/modules/telegram
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
python -m app.main
|
python -m app.main
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pytest -m ""
|
|||||||
|
|
||||||
### 1. Start Backend API
|
### 1. Start Backend API
|
||||||
```bash
|
```bash
|
||||||
cd roa2web/reports-app/backend
|
cd roa2web/backend
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
uvicorn app.main:app --reload --port 8001
|
uvicorn app.main:app --reload --port 8001
|
||||||
```
|
```
|
||||||
@@ -93,7 +93,7 @@ export TEST_PASSWORD="your_password" # Your Oracle password
|
|||||||
|
|
||||||
### 3. Run Integration Tests
|
### 3. Run Integration Tests
|
||||||
```bash
|
```bash
|
||||||
cd roa2web/reports-app/telegram-bot
|
cd roa2web/backend/modules/telegram
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
pytest -m integration -v
|
pytest -m integration -v
|
||||||
```
|
```
|
||||||
@@ -169,7 +169,7 @@ pytest -m "not slow" # Skip slow tests
|
|||||||
### Import Errors
|
### Import Errors
|
||||||
```bash
|
```bash
|
||||||
# Make sure you're in the right directory
|
# Make sure you're in the right directory
|
||||||
cd /mnt/e/proiecte/roa2web/roa2web/reports-app/telegram-bot
|
cd /mnt/e/proiecte/roa2web/roa2web/backend/modules/telegram
|
||||||
|
|
||||||
# Activate virtual environment
|
# Activate virtual environment
|
||||||
source venv/bin/activate
|
source venv/bin/activate
|
||||||
|
|||||||
@@ -1,28 +1,52 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
====================================================================
|
||||||
|
ROA2WEB - Internal Application Server Configuration
|
||||||
|
====================================================================
|
||||||
|
|
||||||
|
⚠️ IMPORTANT - READ BEFORE DEPLOYMENT! ⚠️
|
||||||
|
|
||||||
|
This web.config is for the INTERNAL application server (10.0.20.36)
|
||||||
|
|
||||||
|
**Production Architecture (2-Tier IIS)**:
|
||||||
|
|
||||||
|
Public Server (10.0.20.122) → uses different web.config!
|
||||||
|
└─ Proxies to Internal Server (10.0.20.36) → uses THIS web.config
|
||||||
|
└─ Proxies to Backend (localhost:8000)
|
||||||
|
|
||||||
|
See: deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md
|
||||||
|
|
||||||
|
**Deployment**:
|
||||||
|
- This file is built into dist/ by Vite
|
||||||
|
- Copy to: C:\inetpub\wwwroot\roa2web\web.config (on 10.0.20.36)
|
||||||
|
- For public server config, see: deployment/windows/config/web.config.10.0.20.122-PUBLIC
|
||||||
|
|
||||||
|
====================================================================
|
||||||
|
-->
|
||||||
<configuration>
|
<configuration>
|
||||||
<system.webServer>
|
<system.webServer>
|
||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<!-- Proxy all API requests to unified backend -->
|
<!-- Proxy API requests to unified backend on localhost -->
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
<match url="^api/(.*)" />
|
<match url="^roa2web/api/(.*)" />
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
<!-- Proxy uploads to unified backend -->
|
<!-- Proxy uploads to unified backend on localhost -->
|
||||||
<rule name="Proxy Uploads" stopProcessing="true">
|
<rule name="Proxy Uploads" stopProcessing="true">
|
||||||
<match url="^uploads/(.*)" />
|
<match url="^roa2web/uploads/(.*)" />
|
||||||
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
<!-- SPA fallback - all other routes serve index.html -->
|
<!-- SPA fallback - all other routes serve index.html -->
|
||||||
<rule name="SPA Fallback" stopProcessing="true">
|
<rule name="SPA Fallback" stopProcessing="true">
|
||||||
<match url=".*" />
|
<match url="^roa2web/.*" />
|
||||||
<conditions logicalGrouping="MatchAll">
|
<conditions logicalGrouping="MatchAll">
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
</conditions>
|
</conditions>
|
||||||
<action type="Rewrite" url="/index.html" />
|
<action type="Rewrite" url="/roa2web/index.html" />
|
||||||
</rule>
|
</rule>
|
||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ secrets-backup/
|
|||||||
**Ce face:**
|
**Ce face:**
|
||||||
- Decriptează fișierele .gpg din backup
|
- Decriptează fișierele .gpg din backup
|
||||||
- Le plasează înapoi în locațiile originale
|
- Le plasează înapoi în locațiile originale
|
||||||
- reports-app/backend/.env
|
- backend/.env
|
||||||
- reports-app/backend/.env.prod
|
- backend/.env.prod
|
||||||
- reports-app/telegram-bot/.env
|
- backend/modules/telegram/.env
|
||||||
- reports-app/telegram-bot/.env.prod
|
- backend/modules/telegram/.env.prod
|
||||||
|
|
||||||
**Notă:** Vei fi rugat să introduci parola de decriptare.
|
**Notă:** Vei fi rugat să introduci parola de decriptare.
|
||||||
|
|
||||||
@@ -94,10 +94,10 @@ cp -r secrets-backup /mnt/usb/roa2web-secrets-backup
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Copiază conținutul și salvează în Bitwarden/1Password
|
# Copiază conținutul și salvează în Bitwarden/1Password
|
||||||
cat reports-app/backend/.env
|
cat backend/.env
|
||||||
cat reports-app/backend/.env.prod
|
cat backend/.env.prod
|
||||||
cat reports-app/telegram-bot/.env
|
cat backend/modules/telegram/.env
|
||||||
cat reports-app/telegram-bot/.env.prod
|
cat backend/modules/telegram/.env.prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔒 Best Practices
|
## 🔒 Best Practices
|
||||||
@@ -120,13 +120,13 @@ cat reports-app/telegram-bot/.env.prod
|
|||||||
./scripts/backup-secrets.sh
|
./scripts/backup-secrets.sh
|
||||||
|
|
||||||
# Șterge temporar
|
# Șterge temporar
|
||||||
mv reports-app/backend/.env reports-app/backend/.env.backup
|
mv backend/.env backend/.env.backup
|
||||||
|
|
||||||
# Restore
|
# Restore
|
||||||
./scripts/restore-secrets.sh
|
./scripts/restore-secrets.sh
|
||||||
|
|
||||||
# Verifică
|
# Verifică
|
||||||
diff reports-app/backend/.env reports-app/backend/.env.backup
|
diff backend/.env backend/.env.backup
|
||||||
```
|
```
|
||||||
|
|
||||||
4. **Pentru echipă:**
|
4. **Pentru echipă:**
|
||||||
@@ -159,18 +159,18 @@ sudo apt-get install gnupg
|
|||||||
|
|
||||||
### 1. Manual GPG (un fișier):
|
### 1. Manual GPG (un fișier):
|
||||||
```bash
|
```bash
|
||||||
gpg --symmetric --cipher-algo AES256 reports-app/backend/.env
|
gpg --symmetric --cipher-algo AES256 backend/.env
|
||||||
# Rezultat: .env.gpg
|
# Rezultat: .env.gpg
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Tar + GPG (toate odată):
|
### 2. Tar + GPG (toate odată):
|
||||||
```bash
|
```bash
|
||||||
tar -czf - reports-app/*/.env* | gpg --symmetric --cipher-algo AES256 > secrets-backup.tar.gz.gpg
|
tar -czf - backend/**/.env* | gpg --symmetric --cipher-algo AES256 > secrets-backup.tar.gz.gpg
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Ansible Vault:
|
### 3. Ansible Vault:
|
||||||
```bash
|
```bash
|
||||||
ansible-vault encrypt reports-app/backend/.env.prod
|
ansible-vault encrypt backend/.env.prod
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📝 Deployment pe Windows Server
|
## 📝 Deployment pe Windows Server
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ echo ""
|
|||||||
|
|
||||||
# List of secret files to backup
|
# List of secret files to backup
|
||||||
SECRET_FILES=(
|
SECRET_FILES=(
|
||||||
"reports-app/backend/.env"
|
"backend/.env"
|
||||||
"reports-app/backend/.env.prod"
|
"backend/.env.prod"
|
||||||
"reports-app/telegram-bot/.env"
|
"backend/modules/telegram/.env"
|
||||||
"reports-app/telegram-bot/.env.prod"
|
"backend/modules/telegram/.env.prod"
|
||||||
)
|
)
|
||||||
|
|
||||||
# List of secret directories to backup (will backup all files inside)
|
# List of secret directories to backup (will backup all files inside)
|
||||||
@@ -185,22 +185,22 @@ openssl enc -aes-256-cbc -d -pbkdf2 -in backend-.env.enc -out .env
|
|||||||
# Backend .env
|
# Backend .env
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
||||||
-in backend-.env.enc \\
|
-in backend-.env.enc \\
|
||||||
-out ../../../reports-app/backend/.env
|
-out ../../../backend/.env
|
||||||
|
|
||||||
# Backend .env.prod
|
# Backend .env.prod
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
||||||
-in backend-.env.prod.enc \\
|
-in backend-.env.prod.enc \\
|
||||||
-out ../../../reports-app/backend/.env.prod
|
-out ../../../backend/.env.prod
|
||||||
|
|
||||||
# Telegram Bot .env
|
# Telegram Bot .env
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
||||||
-in telegram-bot-.env.enc \\
|
-in telegram-bot-.env.enc \\
|
||||||
-out ../../../reports-app/telegram-bot/.env
|
-out ../../../backend/modules/telegram/.env
|
||||||
|
|
||||||
# Telegram Bot .env.prod
|
# Telegram Bot .env.prod
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
openssl enc -aes-256-cbc -d -pbkdf2 \\
|
||||||
-in telegram-bot-.env.prod.enc \\
|
-in telegram-bot-.env.prod.enc \\
|
||||||
-out ../../../reports-app/telegram-bot/.env.prod
|
-out ../../../backend/modules/telegram/.env.prod
|
||||||
|
|
||||||
# Decrypt and extract secrets directory
|
# Decrypt and extract secrets directory
|
||||||
openssl enc -aes-256-cbc -d -pbkdf2 -in secrets.tar.enc | \\
|
openssl enc -aes-256-cbc -d -pbkdf2 -in secrets.tar.enc | \\
|
||||||
|
|||||||
@@ -132,13 +132,13 @@ for encrypted_file in "${ENCRYPTED_FILES[@]}"; do
|
|||||||
|
|
||||||
# Determine target path based on filename
|
# Determine target path based on filename
|
||||||
if [[ "$filename" == "backend-.env" ]]; then
|
if [[ "$filename" == "backend-.env" ]]; then
|
||||||
target="reports-app/backend/.env"
|
target="backend/.env"
|
||||||
elif [[ "$filename" == "backend-.env.prod" ]]; then
|
elif [[ "$filename" == "backend-.env.prod" ]]; then
|
||||||
target="reports-app/backend/.env.prod"
|
target="backend/.env.prod"
|
||||||
elif [[ "$filename" == "telegram-bot-.env" ]]; then
|
elif [[ "$filename" == "telegram-bot-.env" ]]; then
|
||||||
target="reports-app/telegram-bot/.env"
|
target="backend/modules/telegram/.env"
|
||||||
elif [[ "$filename" == "telegram-bot-.env.prod" ]]; then
|
elif [[ "$filename" == "telegram-bot-.env.prod" ]]; then
|
||||||
target="reports-app/telegram-bot/.env.prod"
|
target="backend/modules/telegram/.env.prod"
|
||||||
else
|
else
|
||||||
echo -e "${YELLOW}Skipping unknown file: $filename${NC}"
|
echo -e "${YELLOW}Skipping unknown file: $filename${NC}"
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -69,13 +69,13 @@ test_file_structure() {
|
|||||||
run_test "Production compose exists" "test -f docker-compose.production.yml"
|
run_test "Production compose exists" "test -f docker-compose.production.yml"
|
||||||
|
|
||||||
# Backend files
|
# Backend files
|
||||||
run_test "Backend Dockerfile exists" "test -f reports-app/backend/Dockerfile"
|
run_test "Backend Dockerfile exists" "test -f backend/Dockerfile"
|
||||||
run_test "Backend requirements exists" "test -f reports-app/backend/requirements.txt"
|
run_test "Backend requirements exists" "test -f backend/requirements.txt"
|
||||||
|
|
||||||
# Frontend files
|
# Frontend files
|
||||||
run_test "Frontend Dockerfile exists" "test -f reports-app/frontend/Dockerfile"
|
run_test "Frontend Dockerfile exists" "test -f src/Dockerfile"
|
||||||
run_test "Frontend nginx.conf exists" "test -f reports-app/frontend/nginx.conf"
|
run_test "Frontend nginx.conf exists" "test -f src/nginx.conf"
|
||||||
run_test "Frontend package.json exists" "test -f reports-app/frontend/package.json"
|
run_test "Frontend package.json exists" "test -f src/package.json"
|
||||||
|
|
||||||
# Nginx Gateway files
|
# Nginx Gateway files
|
||||||
run_test "Nginx Gateway Dockerfile exists" "test -f nginx/Dockerfile"
|
run_test "Nginx Gateway Dockerfile exists" "test -f nginx/Dockerfile"
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ git push --force-with-lease --tags origin
|
|||||||
```bash
|
```bash
|
||||||
# Update all environment files
|
# Update all environment files
|
||||||
# 1. roa2web/.env
|
# 1. roa2web/.env
|
||||||
# 2. roa2web/reports-app/backend/.env
|
# 2. roa2web/backend/.env
|
||||||
# 3. Production environment variables
|
# 3. Production environment variables
|
||||||
|
|
||||||
# Restart all services
|
# Restart all services
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class GitHistoryCleanup:
|
|||||||
# Files and patterns to remove from history
|
# Files and patterns to remove from history
|
||||||
self.FILES_TO_REMOVE = [
|
self.FILES_TO_REMOVE = [
|
||||||
"app/.env",
|
"app/.env",
|
||||||
"roa2web/reports-app/backend/.env",
|
"roa2web/backend/.env",
|
||||||
"roa2web/.env",
|
"roa2web/.env",
|
||||||
"roa2web/.env.development",
|
"roa2web/.env.development",
|
||||||
"roa2web/.env.production",
|
"roa2web/.env.production",
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ shared/
|
|||||||
└── cache/
|
└── cache/
|
||||||
└── redis_client.py ⚠️ MODIFY - Use real tenant_id (not "default")
|
└── redis_client.py ⚠️ MODIFY - Use real tenant_id (not "default")
|
||||||
|
|
||||||
reports-app/backend/
|
backend/
|
||||||
├── app/
|
├── app/
|
||||||
│ ├── main.py ⚠️ MODIFY - Initialize MultiTenantPoolManager
|
│ ├── main.py ⚠️ MODIFY - Initialize MultiTenantPoolManager
|
||||||
│ └── routers/
|
│ └── routers/
|
||||||
@@ -753,7 +753,7 @@ CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id);
|
|||||||
```
|
```
|
||||||
|
|
||||||
7. **Add background task pentru health monitoring**
|
7. **Add background task pentru health monitoring**
|
||||||
- **Fișier:** `reports-app/backend/app/main.py`
|
- **Fișier:** `backend/app/main.py`
|
||||||
- **Task:** Run every 60 seconds
|
- **Task:** Run every 60 seconds
|
||||||
```python
|
```python
|
||||||
async def monitor_ssh_tunnels():
|
async def monitor_ssh_tunnels():
|
||||||
@@ -824,7 +824,7 @@ CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id);
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. **Update login endpoint să determine tenant_id**
|
2. **Update login endpoint să determine tenant_id**
|
||||||
- **Fișier:** `reports-app/backend/app/main.py` (auth router)
|
- **Fișier:** `backend/app/main.py` (auth router)
|
||||||
- **Logica:**
|
- **Logica:**
|
||||||
- Check `tenant_users` table pentru user_id
|
- Check `tenant_users` table pentru user_id
|
||||||
- Dacă user are access la multiple tenants, return primul (default)
|
- Dacă user are access la multiple tenants, return primul (default)
|
||||||
@@ -921,7 +921,7 @@ CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id);
|
|||||||
- **Flow:** AuthMiddleware decode JWT → TenantMiddleware validate tenant access
|
- **Flow:** AuthMiddleware decode JWT → TenantMiddleware validate tenant access
|
||||||
|
|
||||||
5. **Update toate router-urile să folosească tenant_id din request.state**
|
5. **Update toate router-urile să folosească tenant_id din request.state**
|
||||||
- **Fișiere:** `reports-app/backend/app/routers/*.py`
|
- **Fișiere:** `backend/app/routers/*.py`
|
||||||
- **Pattern:**
|
- **Pattern:**
|
||||||
```python
|
```python
|
||||||
# Înainte (single-tenant)
|
# Înainte (single-tenant)
|
||||||
@@ -945,7 +945,7 @@ CREATE INDEX IF NOT EXISTS idx_audit_tenant ON audit_logs(tenant_id);
|
|||||||
```
|
```
|
||||||
|
|
||||||
6. **Update Telegram bot pentru tenant support**
|
6. **Update Telegram bot pentru tenant support**
|
||||||
- **Fișier:** `reports-app/telegram-bot/app/auth/linking.py`
|
- **Fișier:** `backend/modules/telegram/app/auth/linking.py`
|
||||||
- **Modificări:**
|
- **Modificări:**
|
||||||
- La linking, salvează și `tenant_id` în SQLite
|
- La linking, salvează și `tenant_id` în SQLite
|
||||||
- JWT token include `tenant_id`
|
- JWT token include `tenant_id`
|
||||||
@@ -1590,13 +1590,13 @@ locust -f shared/tests/load/test_multi_tenant_load.py --host=http://localhost:80
|
|||||||
expdp username/password@ROA directory=BACKUP dumpfile=pre_migration.dmp
|
expdp username/password@ROA directory=BACKUP dumpfile=pre_migration.dmp
|
||||||
|
|
||||||
# Backup existing .env files
|
# Backup existing .env files
|
||||||
cp reports-app/backend/.env reports-app/backend/.env.backup
|
cp backend/.env backend/.env.backup
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Document current single-tenant config**
|
- [ ] **Document current single-tenant config**
|
||||||
```bash
|
```bash
|
||||||
# Save current credentials
|
# Save current credentials
|
||||||
cat reports-app/backend/.env > docs/pre_migration_env.txt
|
cat backend/.env > docs/pre_migration_env.txt
|
||||||
|
|
||||||
# Save current SSH tunnel config
|
# Save current SSH tunnel config
|
||||||
./ssh-tunnel-prod.sh status > docs/pre_migration_ssh.txt
|
./ssh-tunnel-prod.sh status > docs/pre_migration_ssh.txt
|
||||||
@@ -1795,7 +1795,7 @@ python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().
|
|||||||
DB_ENCRYPTION_KEY=$(cat .encryption_key)
|
DB_ENCRYPTION_KEY=$(cat .encryption_key)
|
||||||
|
|
||||||
# 3. Update .env
|
# 3. Update .env
|
||||||
cat >> reports-app/backend/.env << EOF
|
cat >> backend/.env << EOF
|
||||||
# Tenant Configuration
|
# Tenant Configuration
|
||||||
TENANT_DB_URL=sqlite:///data/tenant_config.db
|
TENANT_DB_URL=sqlite:///data/tenant_config.db
|
||||||
DB_ENCRYPTION_KEY=$DB_ENCRYPTION_KEY
|
DB_ENCRYPTION_KEY=$DB_ENCRYPTION_KEY
|
||||||
@@ -1892,7 +1892,7 @@ services:
|
|||||||
roa-backend:
|
roa-backend:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./reports-app/backend/Dockerfile
|
dockerfile: ./backend/Dockerfile
|
||||||
image: roa2web/backend:multi-tenant
|
image: roa2web/backend:multi-tenant
|
||||||
container_name: roa-backend
|
container_name: roa-backend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -1942,7 +1942,7 @@ services:
|
|||||||
# Frontend (unchanged)
|
# Frontend (unchanged)
|
||||||
roa-frontend:
|
roa-frontend:
|
||||||
build:
|
build:
|
||||||
context: ./reports-app/frontend
|
context: ./src
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: roa2web/frontend:latest
|
image: roa2web/frontend:latest
|
||||||
container_name: roa-frontend
|
container_name: roa-frontend
|
||||||
@@ -2443,7 +2443,7 @@ Multi-Tenant (10 tenants):
|
|||||||
- **OraclePool:** `shared/database/oracle_pool.py` - Singleton pattern for single-tenant
|
- **OraclePool:** `shared/database/oracle_pool.py` - Singleton pattern for single-tenant
|
||||||
- **JWT Handler:** `shared/auth/jwt_handler.py` - Token creation/validation (needs tenant_id)
|
- **JWT Handler:** `shared/auth/jwt_handler.py` - Token creation/validation (needs tenant_id)
|
||||||
- **Auth Middleware:** `shared/auth/middleware.py` - JWT verification (needs tenant validation)
|
- **Auth Middleware:** `shared/auth/middleware.py` - JWT verification (needs tenant validation)
|
||||||
- **Backend Main:** `reports-app/backend/app/main.py` - Startup logic (needs MultiTenantPoolManager)
|
- **Backend Main:** `backend/app/main.py` - Startup logic (needs MultiTenantPoolManager)
|
||||||
- **SSH Tunnel Script:** `ssh-tunnel-prod.sh` - Single tunnel script (needs per-tenant manager)
|
- **SSH Tunnel Script:** `ssh-tunnel-prod.sh` - Single tunnel script (needs per-tenant manager)
|
||||||
|
|
||||||
### Inspiration & Patterns
|
### Inspiration & Patterns
|
||||||
|
|||||||
@@ -35,13 +35,13 @@
|
|||||||
|
|
||||||
### Fișiere Modificate (7 fișiere)
|
### Fișiere Modificate (7 fișiere)
|
||||||
|
|
||||||
- [ ] `reports-app/backend/requirements.txt` - Adaugă redis>=5.0.0
|
- [ ] `backend/requirements.txt` - Adaugă redis>=5.0.0
|
||||||
- [ ] `reports-app/backend/.env.example` - Adaugă REDIS_* env vars
|
- [ ] `backend/.env.example` - Adaugă REDIS_* env vars
|
||||||
- [ ] `reports-app/backend/app/main.py` - Initialize Redis at startup
|
- [ ] `backend/app/main.py` - Initialize Redis at startup
|
||||||
- [ ] `reports-app/backend/app/services/dashboard_service.py` - Apply caching
|
- [ ] `backend/app/services/dashboard_service.py` - Apply caching
|
||||||
- [ ] `reports-app/backend/app/services/invoice_service.py` - Apply caching
|
- [ ] `backend/app/services/invoice_service.py` - Apply caching
|
||||||
- [ ] `reports-app/backend/app/routers/dashboard.py` - Cache invalidation on mutations
|
- [ ] `backend/app/routers/dashboard.py` - Cache invalidation on mutations
|
||||||
- [ ] `reports-app/backend/app/routers/invoices.py` - Cache invalidation on mutations
|
- [ ] `backend/app/routers/invoices.py` - Cache invalidation on mutations
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
**Tasks:**
|
**Tasks:**
|
||||||
|
|
||||||
1. [ ] **Adaugă dependency în requirements.txt**
|
1. [ ] **Adaugă dependency în requirements.txt**
|
||||||
- Fișier: `reports-app/backend/requirements.txt`
|
- Fișier: `backend/requirements.txt`
|
||||||
- Acțiune: Adaugă linia `redis>=5.0.0` după `httpx>=0.27.0`
|
- Acțiune: Adaugă linia `redis>=5.0.0` după `httpx>=0.27.0`
|
||||||
- Motivație: redis 5.0+ are async support nativ
|
- Motivație: redis 5.0+ are async support nativ
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
- Template (vezi secțiunea Code Templates mai jos)
|
- Template (vezi secțiunea Code Templates mai jos)
|
||||||
|
|
||||||
4. [ ] **Adaugă env variables în .env.example**
|
4. [ ] **Adaugă env variables în .env.example**
|
||||||
- Fișier: `reports-app/backend/.env.example`
|
- Fișier: `backend/.env.example`
|
||||||
- Acțiune: Adaugă la sfârșitul fișierului:
|
- Acțiune: Adaugă la sfârșitul fișierului:
|
||||||
```bash
|
```bash
|
||||||
# Redis Configuration
|
# Redis Configuration
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
5. [ ] **Initialize Redis la startup în main.py**
|
5. [ ] **Initialize Redis la startup în main.py**
|
||||||
- Fișier: `reports-app/backend/app/main.py`
|
- Fișier: `backend/app/main.py`
|
||||||
- Acțiune: În funcția `startup_event()`:
|
- Acțiune: În funcția `startup_event()`:
|
||||||
```python
|
```python
|
||||||
from shared.cache import redis_cache
|
from shared.cache import redis_cache
|
||||||
@@ -254,7 +254,7 @@
|
|||||||
**Tasks:**
|
**Tasks:**
|
||||||
|
|
||||||
1. [ ] **Apply @cached în DashboardService.get_complete_summary()**
|
1. [ ] **Apply @cached în DashboardService.get_complete_summary()**
|
||||||
- Fișier: `reports-app/backend/app/services/dashboard_service.py`
|
- Fișier: `backend/app/services/dashboard_service.py`
|
||||||
- Acțiune: Adaugă decorator la metoda `get_complete_summary`:
|
- Acțiune: Adaugă decorator la metoda `get_complete_summary`:
|
||||||
```python
|
```python
|
||||||
from shared.cache import cached
|
from shared.cache import cached
|
||||||
@@ -268,26 +268,26 @@
|
|||||||
- Motivație: Dashboard e accesat des, datele se schimbă rar
|
- Motivație: Dashboard e accesat des, datele se schimbă rar
|
||||||
|
|
||||||
2. [ ] **Apply @cached în DashboardService.get_trends()**
|
2. [ ] **Apply @cached în DashboardService.get_trends()**
|
||||||
- Fișier: `reports-app/backend/app/services/dashboard_service.py`
|
- Fișier: `backend/app/services/dashboard_service.py`
|
||||||
- Acțiune: Similar, TTL=180 (3 min pentru trends)
|
- Acțiune: Similar, TTL=180 (3 min pentru trends)
|
||||||
- Cache key va include period: `cache:default:dashboard_trends:company-X:period-30d:abc123`
|
- Cache key va include period: `cache:default:dashboard_trends:company-X:period-30d:abc123`
|
||||||
|
|
||||||
3. [ ] **Apply @cached în DashboardService.get_detailed_data()**
|
3. [ ] **Apply @cached în DashboardService.get_detailed_data()**
|
||||||
- Fișier: `reports-app/backend/app/services/dashboard_service.py`
|
- Fișier: `backend/app/services/dashboard_service.py`
|
||||||
- Acțiune: TTL=60 (1 min pentru tabel detalii - se refreshează des)
|
- Acțiune: TTL=60 (1 min pentru tabel detalii - se refreshează des)
|
||||||
- Cache key include page, page_size, search
|
- Cache key include page, page_size, search
|
||||||
|
|
||||||
4. [ ] **Apply @cached în InvoiceService.get_invoices()**
|
4. [ ] **Apply @cached în InvoiceService.get_invoices()**
|
||||||
- Fișier: `reports-app/backend/app/services/invoice_service.py`
|
- Fișier: `backend/app/services/invoice_service.py`
|
||||||
- Acțiune: TTL=60 (1 min)
|
- Acțiune: TTL=60 (1 min)
|
||||||
- Cache key include filter params (partner_type, date_from, date_to, etc.)
|
- Cache key include filter params (partner_type, date_from, date_to, etc.)
|
||||||
|
|
||||||
5. [ ] **Apply @cached în InvoiceService.get_invoice_summary()**
|
5. [ ] **Apply @cached în InvoiceService.get_invoice_summary()**
|
||||||
- Fișier: `reports-app/backend/app/services/invoice_service.py`
|
- Fișier: `backend/app/services/invoice_service.py`
|
||||||
- Acțiune: TTL=180 (3 min pentru summary)
|
- Acțiune: TTL=180 (3 min pentru summary)
|
||||||
|
|
||||||
6. [ ] **Cache invalidation în dashboard mutations (viitor)**
|
6. [ ] **Cache invalidation în dashboard mutations (viitor)**
|
||||||
- Fișier: `reports-app/backend/app/routers/dashboard.py`
|
- Fișier: `backend/app/routers/dashboard.py`
|
||||||
- Acțiune: Pregătește cod pentru invalidation (de activat când există POST/PUT/DELETE):
|
- Acțiune: Pregătește cod pentru invalidation (de activat când există POST/PUT/DELETE):
|
||||||
```python
|
```python
|
||||||
# TODO: Activate când implementăm mutations
|
# TODO: Activate când implementăm mutations
|
||||||
@@ -301,7 +301,7 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
7. [ ] **Cache invalidation în invoice mutations**
|
7. [ ] **Cache invalidation în invoice mutations**
|
||||||
- Fișier: `reports-app/backend/app/routers/invoices.py`
|
- Fișier: `backend/app/routers/invoices.py`
|
||||||
- Acțiune: Când se implementează POST/PUT/DELETE pentru invoices, invalidează:
|
- Acțiune: Când se implementează POST/PUT/DELETE pentru invoices, invalidează:
|
||||||
- `invoices_list`
|
- `invoices_list`
|
||||||
- `invoices_summary`
|
- `invoices_summary`
|
||||||
@@ -601,7 +601,7 @@ ab -n 100 -c 10 http://localhost:8001/api/dashboard/summary?company=123
|
|||||||
|
|
||||||
## 🔧 Configurare Env Variables
|
## 🔧 Configurare Env Variables
|
||||||
|
|
||||||
**File:** `reports-app/backend/.env`
|
**File:** `backend/.env`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -657,7 +657,7 @@ docker-compose exec roa-backend env | grep REDIS
|
|||||||
- [ ] Dependency added: `redis>=5.0.0` în requirements.txt
|
- [ ] Dependency added: `redis>=5.0.0` în requirements.txt
|
||||||
- [ ] Package created: `shared/cache/__init__.py`
|
- [ ] Package created: `shared/cache/__init__.py`
|
||||||
- [ ] Redis client: `shared/cache/redis_client.py`
|
- [ ] Redis client: `shared/cache/redis_client.py`
|
||||||
- [ ] Env vars added: `reports-app/backend/.env.example`
|
- [ ] Env vars added: `backend/.env.example`
|
||||||
- [ ] Main.py updated: Redis initialize at startup
|
- [ ] Main.py updated: Redis initialize at startup
|
||||||
- [ ] Test: `python -c "import asyncio; from shared.cache import redis_cache; asyncio.run(redis_cache.initialize())"`
|
- [ ] Test: `python -c "import asyncio; from shared.cache import redis_cache; asyncio.run(redis_cache.initialize())"`
|
||||||
|
|
||||||
@@ -703,8 +703,8 @@ docker-compose exec roa-backend env | grep REDIS
|
|||||||
|
|
||||||
- **Docker Compose Redis Config:** `docker-compose.yml:147-163`
|
- **Docker Compose Redis Config:** `docker-compose.yml:147-163`
|
||||||
- **Oracle Pool Pattern:** `shared/database/oracle_pool.py` (reference for singleton pattern)
|
- **Oracle Pool Pattern:** `shared/database/oracle_pool.py` (reference for singleton pattern)
|
||||||
- **Backend Services:** `reports-app/backend/app/services/` (where to apply caching)
|
- **Backend Services:** `backend/app/services/` (where to apply caching)
|
||||||
- **Backend Routers:** `reports-app/backend/app/routers/` (where to invalidate cache)
|
- **Backend Routers:** `backend/app/routers/` (where to invalidate cache)
|
||||||
|
|
||||||
### Documentație Externă
|
### Documentație Externă
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Shared Routes for ROA2WEB Applications
|
Shared Routes for ROA2WEB Applications
|
||||||
|
|
||||||
This module provides factory functions for creating common API routers
|
This module provides factory functions for creating common API routers
|
||||||
that can be mounted in both reports-app and data-entry-app.
|
that can be mounted in both the unified monolith backend.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from shared.routes import create_companies_router, create_calendar_router
|
from shared.routes import create_companies_router, create_calendar_router
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Shared Calendar Router Factory for ROA2WEB Applications
|
Shared Calendar Router Factory for ROA2WEB Applications
|
||||||
|
|
||||||
Creates a FastAPI router for /api/calendar endpoints that can be used
|
Creates a FastAPI router for /api/calendar endpoints that can be used
|
||||||
by both reports-app and data-entry-app.
|
by both the unified monolith backend.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from shared.routes.calendar import create_calendar_router
|
from shared.routes.calendar import create_calendar_router
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
Shared Companies Router Factory for ROA2WEB Applications
|
Shared Companies Router Factory for ROA2WEB Applications
|
||||||
|
|
||||||
Creates a FastAPI router for /api/companies endpoints that can be used
|
Creates a FastAPI router for /api/companies endpoints that can be used
|
||||||
by both reports-app and data-entry-app.
|
by both the unified monolith backend.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
from shared.routes.companies import create_companies_router
|
from shared.routes.companies import create_companies_router
|
||||||
|
|||||||
Reference in New Issue
Block a user