# SaaS Analytics Platform Example

A complete full-stack SaaS application demonstrating frontend-backend integration, real-time features, background processing, and multi-database architecture.

## What This Example Demonstrates

- **Full-Stack Architecture**: React frontend + Express backend + WebSocket server
- **Real-time Features**: WebSocket connections with Redis pub/sub
- **Background Processing**: Async data processing with job queues
- **Multi-Database**: Separate databases for transactional and analytical data
- **Analytics Integration**: Track user behavior and API usage
- **Scalable Services**: Rate limiting, caching, and distributed job processing

## Architecture Overview

```
┌─────────────┐
│   Browser   │
└─────┬───┬───┘
      │   │
      │   │ WebSocket
      │   │
      │   │        ┌──────────┐
      │   └───────►│ Real-time│◄────┐
      │            │  Server  │     │ Redis
      │            └──────────┘     │ Pub/Sub
      │                             │
   HTTP API        ┌──────────┐    │
      │            │  Redis   │◄───┘
      │            └──────────┘
      │                 ▲
   ┌──▼────┐           │
   │  Web  │           │ (Cache, Rate Limit)
   │  App  │           │
   └───────┘       ┌───┴────┐      ┌──────────┐
                   │  API   │─────►│  Queue   │
                   │ Server │      └─────┬────┘
                   └───┬────┘            │
                       │            ┌────▼─────┐   ┌──────────┐
                       │            │Processor │──►│  Email   │
                       │            └──────────┘   └──────────┘
                       │
                   ┌───▼─────────┐
                   │ PostgreSQL  │
                   │  (Primary)  │
                   └─────────────┘
                   ┌─────────────┐
                   │ PostgreSQL  │
                   │ (Analytics) │
                   └─────────────┘
```

## Quick Start

### 1. Generate the Full Stack

```bash
cd examples/saas-fullstack
bang generate saas-platform.workflow.yaml
```

This generates:
- `web/` - React frontend with analytics
- `api/` - Express API with Redis, Queue, Email clients
- `realtime/` - WebSocket server with Redis pub/sub
- `processor/` - Background job processor
- `docker-compose.yml` - Complete local environment
- CI/CD pipelines and deployment configs

### 2. Start Development Environment

```bash
# Start all infrastructure
docker-compose up -d

# Install all dependencies
npm run install:all

# Run database migrations
cd api && npm run migrate

# Start all services in development mode
npm run dev:all

# Or start individually:
# npm run dev:web      # React app on :3000
# npm run dev:api      # API on :4000
# npm run dev:realtime # WebSocket on :4001
# npm run dev:processor # Background worker
```

### 3. Access the Application

- **Web App**: http://localhost:3000
- **API**: http://localhost:4000
- **API Docs**: http://localhost:4000/docs
- **Real-time**: ws://localhost:4001
- **Email UI**: http://localhost:1025 (MailHog)

## Real-World Scenarios

### Scenario 1: Adding User Authentication

**Goal**: Add authentication with session management

**Step 1**: Update API to use Redis for sessions

```typescript
// api/src/index.ts - Already has redis-client.ts generated
import { redisClient } from './services/redis-client';
import session from 'express-session';
import RedisStore from 'connect-redis';

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: process.env.NODE_ENV === 'production',
    maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
  },
}));
```

**Step 2**: Add authentication routes

```typescript
// api/src/routes/auth.ts
import { Router } from 'express';
import { queueClient } from '../services/queue-client';
import { emailClient } from '../services/email-client';

const router = Router();

router.post('/signup', async (req, res) => {
  const user = await User.create(req.body);

  // Queue welcome email
  await queueClient.add('send-welcome-email', {
    userId: user.id,
    email: user.email,
  });

  req.session.userId = user.id;
  res.json(user);
});

export default router;
```

**Step 3**: Process welcome emails

```typescript
// processor/src/jobs/welcome-email.ts
import { queueClient } from '../services/queue-client';
import { emailClient } from '../services/email-client';

queueClient.process('send-welcome-email', async (job) => {
  const { email } = job.data;

  await emailClient.send({
    to: email,
    subject: 'Welcome to Our Platform!',
    template: 'welcome',
    data: { email },
  });
});
```

### Scenario 2: Real-time Dashboard Updates

**Goal**: Push live metrics to all connected clients

**Step 1**: Implement WebSocket server with Redis pub/sub

```typescript
// realtime/src/index.ts
import { WebSocketServer } from 'ws';
import { redisClient } from './services/redis-client';

const wss = new WebSocketServer({ port: 4001 });
const subscriber = redisClient.duplicate();

// Subscribe to dashboard updates
subscriber.subscribe('dashboard-updates', (message) => {
  // Broadcast to all connected clients
  wss.clients.forEach(client => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(message);
    }
  });
});

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    // Handle client messages
  });
});
```

**Step 2**: Publish updates from API

```typescript
// api/src/routes/analytics.ts
import { redisClient } from '../services/redis-client';

router.post('/track-event', async (req, res) => {
  const event = await Event.create(req.body);

  // Publish to real-time subscribers
  await redisClient.publish('dashboard-updates', JSON.stringify({
    type: 'event',
    data: event,
  }));

  res.json(event);
});
```

**Step 3**: Connect from React frontend

```tsx
// web/src/hooks/useRealtime.ts
import { useEffect, useState } from 'react';

export function useRealtime() {
  const [ws, setWs] = useState<WebSocket | null>(null);
  const [metrics, setMetrics] = useState({});

  useEffect(() => {
    const socket = new WebSocket('ws://localhost:4001');

    socket.onmessage = (event) => {
      const update = JSON.parse(event.data);
      setMetrics(update.data);
    };

    setWs(socket);

    return () => socket.close();
  }, []);

  return { ws, metrics };
}
```

### Scenario 3: Background Report Generation

**Goal**: Generate and email weekly analytics reports

**Step 1**: Schedule recurring jobs

```typescript
// processor/src/index.ts
import { queueClient } from './services/queue-client';

// Schedule weekly reports every Monday at 9 AM
queueClient.addRepeatable('generate-weekly-report', {}, {
  cron: '0 9 * * 1',
});
```

**Step 2**: Process report generation

```typescript
// processor/src/jobs/weekly-report.ts
import { queueClient } from '../services/queue-client';
import { emailClient } from '../services/email-client';

queueClient.process('generate-weekly-report', async (job) => {
  // Query analytics database
  const stats = await queryAnalyticsDB(`
    SELECT
      user_id,
      COUNT(*) as events,
      COUNT(DISTINCT session_id) as sessions
    FROM events
    WHERE created_at >= NOW() - INTERVAL '7 days'
    GROUP BY user_id
  `);

  // Send reports to all users
  for (const stat of stats) {
    const user = await User.findByPk(stat.user_id);

    await emailClient.send({
      to: user.email,
      subject: 'Your Weekly Analytics Report',
      template: 'weekly-report',
      data: {
        name: user.name,
        events: stat.events,
        sessions: stat.sessions,
      },
    });
  }
});
```

### Scenario 4: Rate Limiting with Redis

**Goal**: Protect API from abuse

```typescript
// api/src/middleware/rate-limit.ts
import { redisClient } from '../services/redis-client';

export async function rateLimit(req, res, next) {
  const key = `rate-limit:${req.ip}`;
  const limit = 100; // requests per minute
  const ttl = 60; // seconds

  const current = await redisClient.incr(key);

  if (current === 1) {
    await redisClient.expire(key, ttl);
  }

  if (current > limit) {
    return res.status(429).json({
      error: 'Too many requests',
      retryAfter: await redisClient.ttl(key),
    });
  }

  res.setHeader('X-RateLimit-Limit', limit);
  res.setHeader('X-RateLimit-Remaining', limit - current);

  next();
}

// Apply to all routes
app.use(rateLimit);
```

## Version Management Examples

### Adding a New Service (Stripe Payments)

```bash
# 1. Update workflow
vim saas-platform.workflow.yaml

# Add to api.expected_dependencies:
# - service: payments
#   usage: Process subscription payments
#   required: true

# Add to stages.production.services:
# payments:
#   provider: stripe
#   connection: "{{secrets.STRIPE_API_KEY}}"

# 2. Verify changes
bang verify saas-platform.workflow.yaml
# ⚠️ Missing dependency 'payments' - expected but not detected

# 3. Generate payment client
bang generate saas-platform.workflow.yaml
# ✓ Generated api/src/services/payments-client.ts

# 4. Implement payment logic
# ... add subscription handling ...

# 5. Verify implementation
bang verify saas-platform.workflow.yaml
# ✅ No issues found

# 6. Create version
git add .
git commit -m "feat: add Stripe payment integration"
bang version create 1.1.0 -w saas-platform.workflow.yaml
```

### Migrating from Local to Hosted Services

```bash
# Current: Using local Redis
# Goal: Migrate to Upstash Redis for production

# 1. Check current version
bang version list

# 2. Update workflow (change production Redis to Upstash)
# Already configured in the workflow!

# 3. Compare changes
bang version diff 1.0.0 1.1.0

# 4. Deploy with new configuration
git push origin 1.1.0
# CI/CD automatically uses new Upstash connection in production
```

## Project Structure

```
saas-fullstack/
├── saas-platform.workflow.yaml
├── web/                          # React frontend
│   ├── src/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── hooks/
│   │   │   └── useRealtime.ts    # WebSocket hook
│   │   ├── services/
│   │   │   └── analytics-client.ts # Generated
│   │   └── App.tsx
│   ├── package.json
│   └── vite.config.ts
├── api/                          # Express API
│   ├── src/
│   │   ├── routes/
│   │   ├── services/
│   │   │   ├── redis-client.ts   # Generated
│   │   │   ├── queue-client.ts   # Generated
│   │   │   ├── email-client.ts   # Generated
│   │   │   └── analytics-client.ts # Generated
│   │   ├── middleware/
│   │   └── index.ts
│   └── package.json
├── realtime/                     # WebSocket server
│   ├── src/
│   │   ├── services/
│   │   │   └── redis-client.ts   # Generated
│   │   └── index.ts
│   └── package.json
├── processor/                    # Background worker
│   ├── src/
│   │   ├── jobs/
│   │   ├── services/
│   │   │   ├── queue-client.ts   # Generated
│   │   │   └── email-client.ts   # Generated
│   │   └── index.ts
│   └── package.json
├── docker-compose.yml
├── .env.example
└── .bangstack/
    └── manifest.json
```

## Testing

### Unit Tests

```bash
# Test individual components
cd api && npm test
cd ../web && npm test
cd ../realtime && npm test
cd ../processor && npm test
```

### Integration Tests

```bash
# Start infrastructure
docker-compose up -d

# Run integration tests
npm run test:integration
```

### End-to-End Tests

```bash
# Start all services
npm run dev:all

# Run E2E tests
npm run test:e2e
```

## Deployment

### Development Deploy

```bash
# Deploy to personal dev environment
git push origin feature/my-feature
# Vercel/Netlify preview deploy
```

### Staging Deploy

```bash
# Merge to develop
git checkout develop
git merge feature/my-feature
git push origin develop

# Auto-deploys to staging.myplatform.com
```

### Production Deploy

```bash
# Create production version
git checkout main
git merge develop

# Verify everything is ready
bang verify saas-platform.workflow.yaml
npm run test:all

# Create version and deploy
bang version create 2.0.0 -w saas-platform.workflow.yaml
git push origin 2.0.0

# Deploys to app.myplatform.com
```

## Monitoring

### Application Metrics

```typescript
// api/src/services/analytics-client.ts (generated)
import { analyticsClient } from './services/analytics-client';

// Track API calls
app.use((req, res, next) => {
  analyticsClient.track('api_call', {
    endpoint: req.path,
    method: req.method,
    userId: req.session?.userId,
  });
  next();
});
```

### Real-time Dashboard

```tsx
// web/src/pages/Dashboard.tsx
import { useRealtime } from '../hooks/useRealtime';

export function Dashboard() {
  const { metrics } = useRealtime();

  return (
    <div>
      <h1>Live Metrics</h1>
      <div>Active Users: {metrics.activeUsers}</div>
      <div>Requests/min: {metrics.requestsPerMinute}</div>
    </div>
  );
}
```

## Common Issues

### WebSocket Connection Fails

```bash
# Check Redis pub/sub is working
redis-cli
> SUBSCRIBE dashboard-updates
> PUBLISH dashboard-updates "test"

# Check realtime server logs
docker-compose logs realtime
```

### Queue Jobs Not Processing

```bash
# Check processor is running
docker-compose ps processor

# View queue status
cd api && npm run queue:status

# Manually process stuck jobs
npm run queue:process
```

### Rate Limiting Too Aggressive

```typescript
// Adjust limits in middleware
const limit = process.env.RATE_LIMIT || 100;
const ttl = process.env.RATE_LIMIT_WINDOW || 60;
```

## Learn More

- [Full Documentation](../../README.md)
- [E-commerce Example](../ecommerce-api/)
- [API Platform Example](../api-platform/)
- [Version Management](../../README.md#version-management)

## Next Steps

1. Explore the generated code in each component
2. Try adding a new service (e.g., file storage with S3)
3. Implement a new feature end-to-end
4. Deploy to staging and test version rollback
5. Set up monitoring and alerts
