# AgentForms Refactor Plan
**Date:** 2026-07-07
**Source:** Claude senior engineering review
**Goal:** Address structural debt, fix revenue blockers, improve scalability
---
## Phase 1 — Revenue-Critical (Week 1)
### 1.1 Stripe Webhook Validation
**Problem:** Webhook handler exists but has never received a real Stripe event.
**Action:**
- Verify `billing.py` webhook handler validates signatures correctly
- Test with Stripe CLI: `stripe trigger checkout.session.completed`
- Add logging for webhook payload inspection
- Confirm end-to-end: checkout → webhook → user upgraded
### 1.2 API Key-Based Document Endpoint
**Problem:** "API-First" positioning but current API is session-based.
**Action:**
- Build `/api/v2/documents/generate` endpoint
- Accepts JSON payload, returns PDF download URL
- Auth via API key (`afk_*` prefix) — no session required
- Add to OpenAPI/Swagger spec
- Document the endpoint
---
## Phase 2 — Scalability (Week 1-2)
### 2.1 Async PDF Generation via RQ Worker
**Problem:** Synchronous WeasyPrint blocks request threads. Hard ceiling at 4 concurrent PDFs.
**Action:**
- Extract PDF generation to RQ job (`app/tasks/pdf.py`)
- Route returns `202 Accepted` with document ID
- Add `/documents/<id>/status` endpoint for polling
- Add `/documents/<id>/download` for completed PDFs
- Add SSE or webhook callback for completion notification
### 2.2 Split `documents.py`
**Problem:** 900-line file doing everything (builders, renderer, PDF, templates).
**Action:**
- `app/services/document_builders.py` — `build_invoice_data`, `build_proposal_data`, etc.
- `app/services/document_renderer.py` — `render_document_html`, template loading
- `app/services/pdf_generator.py` — `generate_pdf`, WeasyPrint interaction
- `app/services/document_models.py` — data structures, validation schemas
- Keep `documents.py` as the orchestrator that imports from sub-modules
---
## Phase 3 — Architecture (Week 2-3)
### 3.1 Split `app/app.py` (God File)
**Problem:** 25KB file handling factory, config, middleware, error handlers, CORS, CSP, rate limiting.
**Action:**
- `app/config.py` — Config class, env var defaults, validation
- `app/middleware.py` — Before/after request hooks, error handlers
- `app/extensions.py` — DB, CSRF, limiter, CSP initialization
- `app/app.py` — Slim app factory that imports from above
### 3.2 Eliminate Dual-Database Pattern
**Problem:** `auth.db` (raw `sqlite3`) + `relay.db` (SQLAlchemy). Non-atomic operations, raw calls bypass WAL/FK.
**Action:**
- Audit all `sqlite3.connect()` calls in routes/models
- Migrate raw calls to SQLAlchemy models
- Consolidate into single database or at least consistent access pattern
- Ensure all connections use WAL mode, FK enforcement, timeout settings
### 3.3 Config Validation on Startup
**Problem:** Missing env vars surface as runtime errors, not boot failures.
**Action:**
- Add startup check in `app/config.py`
- Validate: SECRET_KEY, STRIPE keys, REDIS_URL, ENCRYPTION_KEY
- Fail fast with clear error messages
- Add `/health` endpoint that checks DB, Redis, Stripe connectivity
---
## Phase 4 — Foundation (Week 3-4)
### 4.1 PostgreSQL Migration
**Problem:** SQLite hard ceiling at ~100 concurrent users.
**Action:**
- Change SQLAlchemy connection string to PostgreSQL
- Update `docker-compose.yml` to add Postgres service
- Migrate data: SQLite dump → Postgres import
- Test all routes with Postgres backend
- Keep SQLite as dev default, Postgres for production
### 4.2 Frontend Componentization
**Problem:** Single inline JS file per page. No state management. Form builder complexity will break vanilla JS.
**Action:**
- Extract form builder JS into module with clear state
- Consider Alpine.js or HTMX for lightweight reactivity
- Componentize: form fields, validation, preview, drag-and-drop
- Keep Tailwind CSS — it's working well
### 4.3 Session Fixation Fix
**Problem:** `login_required` trusts `Content-Type` header. Session may not regenerate on login.
**Action:**
- Add `session.regenerate()` after successful login in `auth.py`
- Fix `login_required` to use `request.is_json` or Accept header instead of Content-Type
---
## Phase 5 — Polish (Week 4+)
### 5.1 Document Validation
**Problem:** No input validation on document data. Missing fields → blank PDFs.
**Action:**
- Add validation schemas per document type
- Return clear errors: "Missing from_name", "Invoice total doesn't match line items"
- Validate before rendering, fail fast
### 5.2 Document Generation Tests
**Problem:** Only 3 tests for the core feature.
**Action:**
- Test each document type renders with minimal data
- Test field mapping for all new types
- Test PDF generation returns valid PDF bytes
- Test async pipeline: queue → poll → download
### 5.3 Template Marketplace / E-Signature / Bulk Generation
**Product differentiation features** — after foundation is solid.
---
## Priority Order (Claude's recommendation)
1. **Fix Stripe webhook** — Revenue
2. **Queue PDF generation** — Scalability
3. **Split `documents.py`** — Maintainability
4. **Build API endpoint** — Positioning
5. **Split `app/app.py`** — Maintainability
6. **Eliminate dual-DB** — Reliability
7. **PostgreSQL** — Future-proofing