- 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>
11 KiB
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 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 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):
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
-
Client Browser →
POST https://roa2web.romfast.ro/roa2web/api/auth/login -
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
- Receives:
-
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
- Receives:
-
Backend Service (localhost:8000):
- Receives:
/api/auth/login - Processes request
- Returns response
- Receives:
Frontend Configuration
Vite Build Configuration (vite.config.js)
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)
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:
-
Internal server web.config missing
/roa2web/prefix in match rules❌ WRONG:
<match url="^api/(.*)" />✅ CORRECT:
<match url="^roa2web/api/(.*)" /> -
Backend service not running
Check on internal server (10.0.20.36):
Get-Service ROA2WEB-Backend Invoke-WebRequest http://localhost:8000/health -
IIS ARR not enabled
On internal server (10.0.20.36):
# Install ARR Install-WindowsFeature -Name Web-ARR # Enable proxy Set-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" ` -Filter "system.webServer/proxy" ` -Name "enabled" ` -Value "True" -
IIS sub-application not configured at
/roa2webThe 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-Originerror
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
.envconfigured 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)
# 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)
# 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)
# 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)
# Use Playwright to test full login flow
./start-playwright.sh
Monitoring & Logs
Public Server Logs
# 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
# 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
# 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 protocolX-Forwarded-Host: roa2web.romfast.ro- Original hostnameX-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