Skip to content

karisakib/Bulletproof-SaaS-Boilerplate

Repository files navigation

Bulletproof SaaS Boilerplate

Table of Contents

Overview

The Bulletproof SaaS Boilerplate is a fully scalable, production-grade foundation for building SaaS applications. It follows best practices, enforces strong security, and integrates essential third-party services to accelerate development and deployment.

Tech Stack

React Motion Shadcn/ui TailwindCSS Zustand React Router React Query Express.js Prisma MongoDB PostgreSQL Redis Stripe Swagger Jest Playwright PostHog PM2 Docker GitHub Actions AWS S3 Mailgun Twilio BunnyCDN Mongoose TypeScript Testing Library Cloudinary JSON Web Tokens Vite MDX Immer

Why Bulletproof SaaS?

  • No longer have to hardcode business logic to mock the minimum viable product.
  • No relying on 3rd parties for authentication. 100% owenership of your data.
  • Standardized API responses.
  • Built using battle-tested technologies.
  • Testing pre-configured.
  • Scalable project structure.
  • Global app, header, configs.
  • Auth baked in with best practices.
  • User activity history.
  • System Inactivity Timeout.
  • Admin Dashboard
  • Financial Dashboard
  • OpenAPI Swagger documentation
  • Robust Error Handling

Standardized JSON Reponses

{
 "status": "success",
 "message": "Users fetched successfully",
 "meta": {
  "totalRecords": 2500,
  "limit": 50,
  "offset": 100,
  "currentPage": 3,
  "totalPages": 50,
  "sortBy": "createdAt",
  "sortOrder": "asc",
  "hasNextPage": true,
  "hasPreviousPage": true,
  "nextOffset": 150,
  "previousOffset": 50,
  "nextPage": "/api/users?offset=150&limit=50",
  "previousPage": "/api/users?offset=50&limit=50"
 },
 "data": [
  {
   "id": 101,
   "name": "John Doe",
   "email": "john.doe@example.com",
   "role": "admin",
   "createdAt": "2024-02-17T12:34:56Z",
   "profile": {
    "age": 30,
    "location": "New York, USA",
    "avatarUrl": "https://example.com/avatars/101.jpg"
   }
  },
  {
   "id": 102,
   "name": "Jane Smith",
   "email": "jane.smith@example.com",
   "role": "user",
   "createdAt": "2024-01-05T08:12:30Z",
   "profile": {
    "age": 28,
    "location": "Los Angeles, USA",
    "avatarUrl": "https://example.com/avatars/102.jpg"
   }
  }
 ]
}

Financial Tracking & Analytics:

/summary/annual# Annual summary
/summary/quarterly # Quarterly summary
/summary/monthly # Monthly summary

/earnings/quarterly earnings # Quarterly earnings
/earnings/monthly # Monthly earnings
/earnings/weekly # Weekly earnings

- Monthly Recurring Revenue
- Average Revenue Per User
- Gross Margin
- Monthly Unique Visitors
- Customer Conversion Rate
- Customer Retention Rate
- Customer Lifetime Value
- Recurring Monthly Revenue
- Churn Rate
- Product Sign Up Rate
- Product Referral Rate Per Influencer

// TODO
Customer Acquisition Cost
Support Ticket Creation Rate
Customer Feedback Rate

Database Use Cases

πŸ”Ή PostgreSQL for: βœ… User Accounts – Emails, passwords (hashed), usernames βœ… Authentication & Authorization – Roles, permissions βœ… Subscriptions & Payments – Stripe/PayPal integration βœ… Orders & Transactions – E-commerce, invoices βœ… Relationships between data – Users & orders, followers, etc. βœ… Reports & Analytics – If data is structured and relational

πŸ”Ή MongoDB for: βœ… User Activity Logs – Tracking user logins, errors, analytics βœ… Audit Logs – Storing system events (e.g., password changes) βœ… CMS / Blog Content – Storing articles, comments, etc. βœ… Product Catalog – E-commerce product listings βœ… Notifications / Messages – Storing chat messages, in-app notifications βœ… IoT / Sensor Data – When real-time, unstructured data is needed

πŸ”Ή Redis for: βœ… Session Management – Store user sessions, login tokens βœ… Caching – Cache frequently accessed API responses βœ… Rate Limiting – Prevent abuse by limiting API requests βœ… Leaderboard / Ranking Systems – Store real-time game scores βœ… Background Jobs / Queues – Use with BullMQ to manage tasks

Summary of Speed Ratings

Response Time Rating Notes
Sub-10ms πŸš€ Excellent Unusually fast, likely serving cached content or simple HTML
10-50ms πŸ”₯ Very Good Well-optimized SSR with efficient rendering
50-200ms βœ… Good Normal range for SSR, including API/database calls
200-500ms ⚠️ Needs Optimization Potential slow middleware, DB queries, or API bottlenecks
500ms+ ❌ Bad Poor performance; needs major fixes

Example with Additional Data:

{
 "level": "info", // Log level (e.g., info, warn, error)
 "message": "Request Log", // A label for the log entry
 "method": "GET", // The HTTP method used for the request
 "url": "http://localhost:3000/users?id=123&name=JohnDoe", // The full request URL with query parameters
 "headers": {
  // HTTP headers sent with the request
  "host": "localhost:3000",
  "connection": "keep-alive",
  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36",
  "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
  "accept-encoding": "gzip, deflate, br",
  "accept-language": "en-US,en;q=0.9",
  "cookie": "sessionId=abc123; userId=456"
 },
 "query": {
  // Parsed query parameters from the URL
  "id": "123",
  "name": "JohnDoe"
 },
 "body": {}, // Parsed request body (empty for GET requests)
 "cookies": {
  // Cookies sent with the request
  "sessionId": "abc123",
  "userId": "456"
 },
 "ip": "::1", // The client's IP address
 "protocol": "http", // The request protocol (HTTP or HTTPS)
 "hostname": "localhost", // The hostname of the server handling the request
 "originalUrl": "/users?id=123&name=JohnDoe", // The original request URL
 "params": {}, // Route parameters (if applicable)
 "secure": false, // Indicates if the request was made over HTTPS
 "subdomains": [], // List of subdomains extracted from the request
 "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36", // User-Agent string from headers
 "customHeaders": {
  // Custom application headers like request ID or authentication tokens
  "X-Request-ID": "abc123456",
  "X-Auth-Token": "Bearer [REDACTED]" // Mask sensitive parts
 },
 "cacheHeaders": {
  // Headers related to cache control
  "Cache-Control": "no-cache",
  "If-None-Match": "W/\"123abc\"",
  "If-Modified-Since": "Mon, 05 Jul 2024 07:28:00 GMT"
 },
 "referrer": "http://example.com", // The referrer URL from which the request originated
 "origin": "http://example.com", // The origin of the request
 "sessionId": "s12345", // Unique session identifier
 "sessionData": {
  // Metadata about the session, if available
  "user": {
   "id": "u123",
   "name": "John Doe"
  }
 },
 "userAgentDetails": {
  // Parsed User-Agent details (browser, OS, device)
  // This can be done using libraries like `useragent` or `ua-parser-js`
  "browser": "Chrome",
  "os": "Windows 10",
  "device": "Desktop"
 },
 "geoLocation": {
  // Estimated geo-location based on IP lookup
  // This requires a third-party API (e.g., MaxMind, IPStack).
  "country": "US",
  "region": "CA",
  "city": "San Francisco"
 },
 "responseStatus": 200, // Response HTTP status code
 "responseContentType": "application/json", // Content type of the response
 "responseSize": "256", // Size of the response in bytes (if available)
 "timestamp": "2024-09-03T12:34:56.789Z" // Timestamp when the log entry was created
}

Optional log objects

Authorization and Authentication

If your application uses authorization or authentication mechanisms, logging related headers such as Authorization or Cookie might be useful. Be cautious about logging sensitive information like tokens or credentials.

authorization: req.get('Authorization'), // Be careful with sensitive info

You might also want to strip out sensitive parts of the authorization header, like:

authorization: req.get('Authorization') ? 'Bearer [REDACTED]' : null,
Custom Application Context

Depending on your application, you might have custom context or metadata that you want to log, such as a user ID (if the user is authenticated), request ID (if you are tracking requests across microservices), or other application-specific data.

userId: req.user ? req.user.id : null,
requestId: req.get('X-Request-ID'),

Error Information stored in dedicated error log table

  • If an error occurs during the request, logging details about the error can be very helpful for debugging. This can include the error message, stack trace, and any relevant request data.
app.use((err, req, res, next) => {
 logger.error("Request Error", {
  errorMessage: err.message,
  errorStack: err.stack,
  method: req.method,
  url: fullUrl,
  body: req.body,
  headers: req.headers,
  ip: req.ip,
 });
 next(err);
});

Testing

Testing The Frontend

Unit Tests (Jest, Testing Library)

Frontend unit tests are conducting using Jest and Testing Library (formerly known as React Testing Library).

E2E Tests (Playwright, Axe)

Frontend End-to-end tests are conducted using Playwright with a11y testing with the playwright axe integration.

Performance Tests (Lighthouse CLI)

Frontend performance tested using Google's Lighthouse CLI. The congif file is preset to 90 as a passing score on each metric.

Testing The Backend

Test users and test data are setup and pre-configured to test user permision, authentication, api resources.

Unit Tests (Jest, Supertest)

Backend unit tests are conducting using Jest and Supertest.

Integration Tests (Jest)

Integration tests are conducted using the Arrange-Act-Assert pattern.

describe("User Service", () => {
 it("Should create a user given correct data", async () => {
  // 1. Arrange - prepare the data, create any objects you need
  const mockUser = {
   // ...
  };
  const userService = createUserService(mockLogger, mockQueryBuilder);

  // 2. Act - execute the logic that you're testing
  const result = userService.create(mockUser);

  // 3. Assert - validate the expected result
  expect(mockLogger).toHaveBeenCalled();
  expect(mockQueryBuilder).toHaveBeenCalled();
  expect(result).toEqual(/** ... */);
 });
});
Load Tests (Artillery)

Load tests are ran using Artillery. See the artillery.yml file.

🀝 Contributing

Clone the repo

git clone https://github.com/xxxxx/xxxxxx
cd xxxxx

Build the project

command

Run the project

command

Run the tests

command

Submit a pull request

If you'd like to contribute, please fork the repository and open a pull request to the main branch.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages