Server Overview
The Fast Forward Dev server is an Express application built with TypeScript, MongoDB, and Mongoose. It provides a REST API for authentication, user management, billing, and Stripe integration.
Architecture
src/
├── index.ts # Server entry point
├── routes/ # API endpoint routes
├── models/ # Mongoose database models
├── mailersend/ # Email templates and sending logic
├── utils/ # Helper functions
├── google/ # Google OAuth verification
└── types/ # TypeScript type definitionsTech Stack
Core
- Express - Web framework
- TypeScript - Type-safe development
- Node.js - Runtime environment
Database
- MongoDB - NoSQL database
- Mongoose - ODM (Object Document Mapping)
Authentication
- JWT - JSON Web Tokens for sessions
- pbkdf2 - Password hashing
- Google OAuth - Social login
Payments
- Stripe - Payment processing
- Webhooks - Real-time payment events
- Resend - Email delivery service
- React Email - Email templates
Project Structure
Entry Point (index.ts)
The main server file (src/index.ts) handles:
- Express Initialization: Sets up the app and middleware (CORS, JSON parsing)
- Database Connection: Connects to MongoDB via Mongoose
- Route Registration: Mounts the API routes (
/api/user,/api/stripe, etc.) - Server Startup: Listens on the configured port (default: 5001)
Routes Directory
API endpoints organized by feature:
routes/
├── user/
│ ├── user.ts # GET /api/user (get current user)
│ ├── user-auth.ts # POST /api/user/auth (login)
│ ├── user-signup.ts # POST /api/user/signup (register)
│ ├── user-google-auth.ts # POST /api/user/google-auth (OAuth)
│ ├── user-list.ts # GET /api/user/list (admin)
│ ├── user-detail.ts # GET /api/user/:id (admin)
│ ├── user-update.ts # PUT /api/user/:id (admin)
│ ├── user-delete.ts # DELETE /api/user/:id (admin)
│ ├── user-plan.ts # GET /api/user/plan (get user plan)
│ ├── user-invite.ts # POST /api/user/invite (admin)
│ └── user-link-provider.ts # POST /api/user/link-provider
├── billing/
│ ├── billing.ts # GET /api/billing (get billing info)
│ └── billing-history.ts # GET /api/billing/history
├── stripe/
│ ├── stripe.ts # Stripe checkout session
│ └── stripe-webhook.ts # POST /api/stripe/webhook
└── github-access.ts # GitHub repository accessModels Directory
Mongoose schemas for MongoDB:
models/
├── user.model.ts # User profile data
├── identity.model.ts # Authentication identities
├── billing.model.ts # Billing and subscriptions
├── stripe.model.ts # Stripe-specific data
└── jwt.model.ts # JWT token managementUtils Directory
Helper functions:
utils/
├── auth-token.ts # JWT generation and verification
└── authenticate-token.ts # Middleware for protected routesData Models
Three-Model Architecture
Fast Forward Dev uses a modern three-model architecture:
- User - Core user profile
- Identity - Authentication providers
- Billing - Payment and subscription data
This separation allows:
- Multiple login methods per user
- Pre-purchase billing records
- Clean data organization
- Easy provider additions
API Design
RESTful Conventions
GET- Retrieve dataPOST- Create new resourcesPUT- Update existing resourcesDELETE- Remove resources
Response Format
Success response:
{
"user": {
"id": "123",
"name": "John Doe",
"email": "john@example.com"
},
"accessToken": "jwt-token-here"
}Error response:
{
"error": "User not found"
}Status Codes
200- Success201- Created400- Bad request (validation error)401- Unauthorized (not logged in)403- Forbidden (insufficient permissions)404- Not found409- Conflict (duplicate resource)500- Server error
Authentication Flow
Signup Process
- User purchases a plan (creates Billing record)
- User signs up with email/password
- Server creates User and Identity
- Server links Billing to User
- Server returns JWT token
Login Process
- User submits email/password
- Server finds Identity by email
- Server verifies password hash
- Server loads User and Billing
- Server generates JWT token
- Client stores token in cookie
Protected Routes
Routes use authentication middleware:
import { authenticateToken } from '../utils/authenticate-token'
router.get('/api/user', authenticateToken, async (req, res) => {
// req.user contains decoded JWT
const user = await User.findById(req.user.id)
res.json({ user })
})Environment Variables
Required environment variables (.env):
# Database
MONGODB_URI=mongodb+srv://...
# JWT
JWT_SECRET=your-secret
# Stripe
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Email
RESEND_API_KEY=re_...
# Google OAuth
GOOGLE_CLIENT_ID=...
# Server
NODE_ENV=development
PORT=5001
CLIENT_URL=http://localhost:3000Middleware
CORS
Allows cross-origin requests from the client:
app.use(cors({
origin: process.env.CLIENT_URL,
credentials: true
}))Body Parser
Parses JSON request bodies:
app.use(express.json())Authentication
The authenticateToken middleware is used to protect private routes. It:
- Extracts the JWT from the
Authorizationheader (Bearer <token>) - Verifies the token signature using the
JWT_SECRET - Attaches the decoded user data to
req.user - Returns 401 if invalid or missing
router.get('/protected', authenticateToken, (req, res) => {
// Access user data
console.log(req.user.id)
})Error Handling
All routes follow consistent error handling:
try {
// Route logic
res.json({ success: true })
} catch (error) {
console.error('Error:', error)
res.status(500).json({ error: 'Internal server error' })
}Development vs Production
Development Mode
- Uses test Stripe keys
- Connects to dev MongoDB
- Detailed error logging
- CORS allows localhost
Production Mode
- Uses live Stripe keys
- Connects to production MongoDB
- Minimal error exposure
- CORS restricted to production domain
Database Connection
MongoDB connection with Mongoose:
mongoose.connect(process.env.MONGODB_URI)
.then(() => console.log('MongoDB connected'))
.catch(err => console.error('MongoDB error:', err))Features:
- Automatic reconnection
- Connection pooling
- Schema validation
- Indexes for performance
Performance Considerations
Database Indexes
All models have appropriate indexes:
- User:
primaryEmail - Identity:
provider + providerAccountId,email - Billing:
userId,stripeCustomerId,email
Query Optimization
- Use
.lean()for read-only queries - Select only needed fields
- Use indexes for filtering
- Paginate large result sets
Caching
Consider adding caching for:
- User profile data
- Billing information
- Frequently accessed data
Security Best Practices
Password Security
- Passwords hashed with pbkdf2
- 100,000 iterations
- Unique salt per user
- Never store plain text
JWT Security
- Tokens expire (configurable)
- Signed with secret key
- Verified on every request
- Stored in HTTP-only cookies (client-side)
Input Validation
- Validate all user input
- Sanitize email addresses
- Check password strength
- Prevent SQL injection (Mongoose handles this)
Rate Limiting
Consider adding rate limiting:
import rateLimit from 'express-rate-limit'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
})
app.use('/api/', limiter)Next Steps
- API Routes - Learn about all API endpoints
- Database Models - Understand data structure
- User Authentication - Deep dive into auth system
- Stripe Payments - Payment integration