SaaS Growth Engine
Northstar — Full-stack B2B SaaS platform for growth operations, team collaboration, and subscription billing
Overview
SaaS Growth Engine (Northstar) is a full-stack B2B SaaS platform for managing growth operations, team collaboration, and subscription billing. Built as a production-ready monorepo with authentication, multi-tenancy, Stripe billing, analytics, and audit logging.
Architecture
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │────▶│ Backend │────▶│ MongoDB │
│ (Angular) │ │ (NestJS) │ │ (Atlas) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Stripe │
│ (Billing) │
└─────────────────┘
│
▼
┌─────────────────┐
│ Resend │
│ (Email) │
└─────────────────┘Key Design Decisions
- Monorepo for shared types, simplified CI, atomic commits
- MongoDB for flexible tenant-scoped documents; indexes created automatically in dev
- Hash-based routing on frontend for static hosting compatibility
- Server-side authority — all billing, auth, and RBAC enforced on backend
Features Implemented
Authentication & Identity
- Email/password signup with organization creation
- Email verification via one-time tokens
- Password reset flow
- JWT access tokens (15 min) + rotated opaque refresh cookies (7 days)
- Invitation acceptance (existing or new users)
Multi-Tenancy & RBAC
- Organizations with unique slugs
- Roles: Admin, Manager, Viewer
- Membership resolution on every protected request
- Minimum-one-admin protection on role changes/removals
- Organization-scoped data access
Team Management
- Invite members with role selection
- Role changes (Admin only)
- Member removal (Admin only, self-protection)
- Pending invitations with revocation
- Paginated member listing
Billing & Subscriptions (Stripe)
- 3 Plans: Starter, Growth, Scale — prices fetched live from Stripe
- Server-created Checkout Sessions (subscription mode)
- Customer Portal for self-service management
- Webhook handling with signature verification
- Idempotent event processing (duplicate-safe)
- Subscription state sync: created/updated/deleted, invoice paid/failed
- Plan availability gated by configured Stripe Price IDs
Analytics Dashboard
- MRR (Monthly Recurring Revenue) with currency support
- Churn rate calculation
- Active subscription count
- New member growth (30-day rolling)
- Monthly growth bar chart
- Date-range filtering (max 366 days)
Audit Logging
- Immutable event log per organization
- Redacted metadata (passwords, tokens, emails masked)
- Admin-only access
- Paginated, newest-first
Workspace Settings
- Organization name update (Admin only)
- Workspace ID display
- Sign out
UI/UX
- Responsive layout (desktop sidebar → mobile bottom nav)
- Light/Dark theme (CSS variables, persisted)
- Loading, empty, and error states
- Accessible markup (ARIA, semantic HTML)
Project Structure
saas-growth-engine/
├── backend/
│ ├── src/
│ │ ├── main.ts # App bootstrap, raw body for webhooks
│ │ ├── app.module.ts # Module imports, global config
│ │ ├── config/environment.ts # Zod-validated env schema
│ │ ├── modules/
│ │ │ ├── database/ # Mongoose models, connection, retry
│ │ │ ├── auth/ # Signup, login, tokens, guards
│ │ │ ├── users/ # Member CRUD, invitations
│ │ │ ├── organizations/ # Org settings, current org
│ │ │ ├── billing/ # Stripe integration, webhooks
│ │ │ ├── analytics/ # Aggregation pipelines
│ │ │ ├── audit/ # Audit log recording
│ │ │ └── email/ # Resend service
│ │ └── ...
│ └── package.json
├── frontend/
│ ├── src/app/
│ │ ├── app.ts # Main component, state, API calls
│ │ ├── app.html # Template (all sections)
│ │ ├── app.scss # Styles (CSS variables, responsive)
│ │ ├── core/
│ │ │ ├── api.service.ts # HTTP client, token refresh
│ │ │ └── auth.interceptor.ts # Auto-attach auth, 401 retry
│ │ └── app.routes.ts # Hash routes for billing pages
│ └── package.json
├── vercel.json # Frontend deploy config
├── render.yaml # Backend deploy config
├── .env.example # Environment template
└── pnpm-workspace.yaml
Challenges & Solutions
Hash routing + static hosting
Avoids server config complexity for SPAs by using hash-based routing.
Idempotent webhooks
Critical for Stripe; use unique event IDs + status locking to prevent duplicate processing.
Retry with backoff
MongoDB Atlas cold starts need connection retries with exponential backoff.
Server-side price fetching
Keeps frontend in sync with Stripe Dashboard by fetching prices at runtime.
Environment validation at startup
Fails fast with clear messages using Zod-validated environment schema.
Future Enhancements
- Team workspaces (multiple orgs per user)
- Usage-based billing / metered prices
- Email templates with React Email
- Webhook retry dashboard
- API keys for programmatic access
- Slack/Discord notifications
- Export analytics to CSV
Deployment
Frontend
Vercel
Backend
Render
Database
MongoDB Atlas
CI/CD
GitHub Actions