# Architecture Decision Records (ADR)

This document records important architectural decisions made during ROA2WEB development.

---

## ADR-001: Ultrathin Monolith Architecture (2025-12-24)

**Status:** Accepted

**Context:**
Originally designed as separate microservices (Reports, Data Entry, Telegram Bot as independent services).

**Decision:**
Consolidated into **ultrathin monolith** - single FastAPI application with modular structure.

**Consequences:**
- ✅ Single Windows service to manage
- ✅ Shared database connection pool
- ✅ Simpler deployment
- ✅ Lower memory usage
- ✅ Easier debugging
- ⚠️ Requires careful module isolation

**Implementation:**
- All modules under `backend/modules/`
- Single `ROA2WEB-Backend` service
- Module enable/disable via `.env` flags

---

## ADR-002: Single Worker Configuration (2025-12-29)

**Status:** Accepted

**Context:**
Telegram bot integration causes conflicts when multiple uvicorn workers run simultaneously. Each worker spawns its own bot instance, but Telegram API allows only ONE bot to poll for updates.

**Problem:**
```
telegram.error.Conflict: terminated by other getUpdates request
```

**Decision:**
**Always use `--workers 1` for the unified backend service.**

**Rationale:**
1. **Telegram Bot Requirement:** Single bot instance only
2. **SQLite Cache:** Multiple workers cause locking conflicts
3. **Performance:** Async I/O means single worker handles 100+ concurrent requests
4. **Resources:** Lower memory (~400 MB vs ~1.6 GB with 4 workers)

**Consequences:**
- ✅ Telegram bot works perfectly
- ✅ No SQLite cache conflicts
- ✅ Cache stats endpoint works (no 502 errors)
- ✅ Lower memory usage
- ✅ Same performance (I/O bound, not CPU bound)
- ⚠️ Cannot scale horizontally with multiple processes

**Implementation:**
- Configured in NSSM: `--workers 1`
- NOT configurable in `.env`
- Documented in `TELEGRAM-BOT-DEPLOYMENT.md`

**Alternatives Considered:**
- Separate bot service: More complexity, no significant benefit
- Redis pub/sub for bot: Over-engineering for current scale

**Performance Characteristics:**
- Concurrent users: 100+
- Requests per minute: 1000+
- Response time: 50-200ms (DB query time)
- Adequate for: 50-100 concurrent users

---

## ADR-003: IIS Sub-Application Deployment (2025-12-29)

**Status:** Accepted

**Context:**
Application deployed at `/roa2web` path on IIS, not at root.

**Decision:**
Use Vite `base: '/roa2web/'` and axios `baseURL: import.meta.env.BASE_URL + 'api'` for all frontend API calls.

**Consequences:**
- ✅ Works correctly on production sub-path
- ✅ Works correctly on development root path
- ⚠️ All axios instances must use BASE_URL
- ⚠️ Router must use base path

**Implementation:**
- `vite.config.js`: `base: process.env.NODE_ENV === 'production' ? '/roa2web/' : '/'`
- All `axios.create()`: `baseURL: import.meta.env.BASE_URL + 'api/...'`
- IIS `web.config`: Reverse proxy rules for `/api/*` → `localhost:8000`

---

## ADR-004: Pydantic v2 Migration (2025-12-29)

**Status:** In Progress

**Context:**
Pydantic v2 changed `schema_extra` → `json_schema_extra`.

**Decision:**
Update all models incrementally to use `json_schema_extra`.

**Implementation:**
- ✅ `backend/modules/reports/models/trial_balance.py` updated
- ✅ `backend/modules/data_entry/schemas/ocr.py` already correct
- ⚠️ Warning eliminated in logs

---

## ADR-005: Web.config as Static File (2025-12-29)

**Status:** Accepted

**Context:**
IIS requires `web.config` for URL rewrite rules, but it wasn't consistently deployed.

**Decision:**
1. Store canonical `web.config` in `deployment/windows/config/`
2. Create `Create-WebConfig.ps1` script for manual creation
3. Include in deployment package

**Consequences:**
- ✅ Consistent configuration across deployments
- ✅ Easy to recreate if deleted
- ✅ Version controlled

**Implementation:**
- Canonical: `deployment/windows/config/web.config`
- Deployed to: `C:\inetpub\wwwroot\roa2web\frontend\web.config`
- Creation script: `Create-WebConfig.ps1`

---

## Future Decisions to Document

### Pending Considerations

1. **Horizontal Scaling:**
   - If needed: Load balancer + multiple app instances
   - Alternative: Separate bot service to allow multiple workers
   - Current decision: Single worker sufficient

2. **Cache Strategy:**
   - Current: SQLite L2 cache + memory L1
   - Alternative: Redis for distributed cache
   - Decision: Keep SQLite for simplicity

3. **Database Connection Pool:**
   - Current: Shared pool across all modules
   - Sizing: 5-10 connections
   - Per-module pools: Not needed yet

---

## Decision Process

When making architectural decisions:

1. **Document the context** - Why is this decision needed?
2. **List alternatives** - What other options exist?
3. **Explain rationale** - Why this option over others?
4. **Note consequences** - What are the trade-offs?
5. **Implementation details** - How is this implemented?
6. **Reference documentation** - Where to find more details?

---

**Last Updated:** 2025-12-29
