ca648ccf8b
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/pop_puller_to_gmail/sessions/dd261f53-4891-437e-bd71-5561ece62d7d
146 lines
5.7 KiB
Markdown
146 lines
5.7 KiB
Markdown
# ADR 008: Use Next.js for Frontend
|
|
|
|
**Status:** Accepted
|
|
**Date:** 2026-02-10
|
|
**Deciders:** Development Team
|
|
|
|
## Context
|
|
|
|
The SaaS platform requires a web frontend that provides:
|
|
|
|
1. User authentication (email/password + Google OAuth)
|
|
2. Mail account management dashboard (CRUD operations)
|
|
3. Processing run history and statistics
|
|
4. Settings and subscription management
|
|
5. Responsive design for mobile and desktop
|
|
|
|
Technical requirements:
|
|
- Type-safe API integration with the FastAPI backend
|
|
- Server-side rendering (SSR) for SEO and initial load performance
|
|
- Static export capability for CDN hosting
|
|
- Easy Docker containerization
|
|
- Modern development tooling (TypeScript, ESLint, hot-reload)
|
|
|
|
## Decision
|
|
|
|
We will use **Next.js 14+** (App Router) with **TypeScript** and **Tailwind CSS** for the frontend.
|
|
|
|
## Alternatives Considered
|
|
|
|
### 1. React (Create React App / Vite SPA)
|
|
- **Pros**: Simpler build setup, no SSR complexity, large ecosystem
|
|
- **Cons**: Client-side rendering only (SEO limitations), no built-in routing, additional setup for SSR
|
|
|
|
### 2. Vue.js / Nuxt.js
|
|
- **Pros**: Excellent developer experience, reactive by default, SSR via Nuxt
|
|
- **Cons**: Smaller ecosystem than React, team less familiar, different component model
|
|
|
|
### 3. Svelte / SvelteKit
|
|
- **Pros**: Very small bundle size, simple reactive model, SSR via SvelteKit
|
|
- **Cons**: Smaller community, fewer UI component libraries, less mature ecosystem
|
|
|
|
### 4. Angular
|
|
- **Pros**: Full framework (routing, forms, HTTP), TypeScript-first
|
|
- **Cons**: Heavy boilerplate, steep learning curve, over-engineered for a dashboard application
|
|
|
|
### 5. Server-Side Templates (Jinja2 / FastAPI with Jinja)
|
|
- **Pros**: Simplest deployment (single backend), no separate frontend build
|
|
- **Cons**: No reactive UI, poor UX for dynamic dashboards, hard to test independently
|
|
|
|
## Rationale
|
|
|
|
Next.js was chosen because:
|
|
|
|
1. **App Router**: File-system based routing with layout nesting simplifies page organization
|
|
2. **TypeScript First**: Strong typing catches API integration errors at compile time
|
|
3. **API Route Proxy**: Next.js Route Handlers allow proxying backend requests at runtime — eliminating CORS issues and enabling `BACKEND_URL` to be set at container runtime (not build time)
|
|
4. **SSR + Static**: Supports both server-rendered pages (authenticated dashboard) and static pages (marketing landing page)
|
|
5. **Tailwind CSS**: Utility-first CSS eliminates the need for a separate CSS framework and enables rapid UI development
|
|
6. **Large Ecosystem**: Extensive component libraries, excellent documentation, widely used
|
|
7. **Docker Friendly**: `next start` serves the production build, easily containerized
|
|
|
|
## Implementation Architecture
|
|
|
|
### Frontend Proxy Pattern
|
|
|
|
The frontend proxies all API calls through a Next.js Route Handler to avoid CORS and build-time URL issues:
|
|
|
|
```
|
|
Browser → Next.js Server (/api/v1/*) → FastAPI Backend (BACKEND_URL/api/v1/*)
|
|
```
|
|
|
|
```typescript
|
|
// src/app/api/v1/[...path]/route.ts
|
|
const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:8000";
|
|
|
|
export async function GET(req: NextRequest, { params }: { params: { path: string[] } }) {
|
|
const path = params.path.join("/");
|
|
const url = `${BACKEND_URL}/api/v1/${path}${req.nextUrl.search}`;
|
|
return fetch(url, { headers: req.headers });
|
|
}
|
|
```
|
|
|
|
This means `BACKEND_URL` is a **runtime** environment variable (set in Docker Compose / Kubernetes), not a build-time variable. The Axios client uses a relative base URL:
|
|
|
|
```typescript
|
|
// src/lib/api.ts
|
|
const api = axios.create({ baseURL: "/api/v1" });
|
|
```
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
frontend/src/
|
|
├── app/ # Next.js App Router pages
|
|
│ ├── page.tsx # Landing page
|
|
│ ├── login/ # Authentication pages
|
|
│ ├── dashboard/ # Main dashboard
|
|
│ ├── accounts/ # Mail account management
|
|
│ ├── settings/ # User settings
|
|
│ └── api/v1/[...path]/ # Backend proxy Route Handler
|
|
├── components/ # Reusable UI components
|
|
│ ├── AddMailAccountModal.tsx
|
|
│ ├── DashboardLayout.tsx
|
|
│ └── AuthGuard.tsx
|
|
├── lib/
|
|
│ └── api.ts # Typed Axios API client
|
|
├── store/
|
|
│ └── authStore.ts # Zustand authentication state
|
|
└── instrumentation.ts # Server startup hook (logs BACKEND_URL)
|
|
```
|
|
|
|
### Authentication State
|
|
|
|
Authentication state is managed via **Zustand** store, with JWT tokens persisted in `localStorage`. The `AuthGuard` component protects all dashboard routes.
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- TypeScript catches API contract mismatches at compile time
|
|
- Proxy pattern eliminates CORS configuration and build-time URL embedding
|
|
- App Router layouts reduce boilerplate for authenticated vs public pages
|
|
- Tailwind CSS enables rapid UI iteration without writing custom CSS
|
|
- Server instrumentation hook logs `BACKEND_URL` at startup for easy debugging
|
|
|
|
### Negative
|
|
- Next.js adds complexity vs a plain React SPA (SSR concepts, server/client component boundary)
|
|
- Node.js 20+ required at runtime (not just build time)
|
|
- Separate Docker container needed (backend and frontend are distinct services)
|
|
- `localStorage` token storage is vulnerable to XSS (future: migrate to `httpOnly` cookies)
|
|
|
|
### Neutral
|
|
- ESLint with `eslint-config-next` enforces Next.js-specific rules
|
|
- `npm ci` used in CI to ensure deterministic installs from `package-lock.json`
|
|
|
|
## Related Decisions
|
|
|
|
- See ADR-007 for JWT tokens consumed by the frontend
|
|
- See ADR-003 for the FastAPI backend the frontend proxies to
|
|
|
|
## References
|
|
|
|
- [Next.js Documentation](https://nextjs.org/docs)
|
|
- [Next.js App Router](https://nextjs.org/docs/app)
|
|
- [Tailwind CSS](https://tailwindcss.com/)
|
|
- [Zustand State Management](https://github.com/pmndrs/zustand)
|