ADR 001: Build FastAPI Alongside Flask
Status: Accepted
Context: SeedTrust backend architecture
Context
The original SeedTrust backend is a Flask monolith (seedtrust_flask). By 2022–2023, the platform needed to support a mobile Progressive Web App and integrate with the Huntington Bank API — requirements that exposed several limitations of the Flask codebase:
- Flask uses synchronous SQLAlchemy. Async I/O is impractical to retrofit into a mature synchronous codebase.
- Flask is tightly coupled to Jinja2 server-rendered templates. It was not designed to serve as a pure JSON API. Adding a clean REST API layer would require significant restructuring.
- The Flask codebase is large and complex.
reports.pyalone is ~2,500 lines of raw SQL. The cron server (app_cron.py) is 66KB of unstructured procedural code. Introducing async patterns into this codebase carried high regression risk. - Flask uses bcrypt session-cookie auth. The mobile PWA required stateless JWT auth that is portable across devices and compatible with standard OAuth flows.
The alternative was to extend Flask with Flask-RESTX or similar, add JWT support via Flask-JWT-Extended, and migrate to async patterns incrementally. This was considered but rejected due to the scope of change and the risk of destabilizing a system actively processing financial transactions.
Decision
Build a new FastAPI service (seedtrustapi) that runs alongside Flask, sharing the same MySQL database.
- FastAPI handles: All new features, the mobile PWA API surface, Huntington Bank integration, async background jobs (Huey), and push notifications.
- Flask handles: The existing desktop admin UI, NACHA batch generation, report generation, legacy email notifications, and critical bug fixes.
- Both services share: The MySQL database, the
seedtrust_schemapackage (shared SQLAlchemy column definitions), and the same user records and business data.
All new features are built in FastAPI. Flask receives only critical bug fixes.
Consequences
Positive:
- FastAPI async support enables efficient handling of Huntington API calls, background jobs, and SSE streaming without blocking
- Clean separation: FastAPI modules have a consistent structure (
route.py,service.py,models.pyper feature) - JWT-based auth is portable and stateless — no session affinity required
- Pydantic validation is enforced at the API boundary
- OpenAPI documentation is generated automatically
Negative:
- Dual maintenance burden. Two backends means two deployments, two test suites, two auth systems, and two sources of truth for business logic that hasn’t been migrated yet
- Feature parity gap. Some Flask features (full RBAC permission system, NACHA generation, report endpoints) do not exist in FastAPI. Developers must know which service owns which feature
- Shared database, separate ORMs. Both services write to the same tables but use different ORM instances. Schema changes must be compatible with both. Flask uses sync SQLAlchemy; FastAPI uses async SQLAlchemy. Migrations are currently managed separately per service
tokenErrorin sessions. If the FastAPI refresh token expires, the user remains “logged in” in NextAuth but all API calls fail. Automatic sign-out on token expiry is not yet implemented
Current State
FastAPI remains a production support surface for the mobile PWA and integrations it already owns, but it is no longer the active destination for new product ownership. The current long-term plan is to consolidate behavior back into Flask and make seedtrust_flask the single primary application (see ADR 003).
See also: Migration Guide, Authentication & Permissions