Skip to content

Encore.ts SaaS Starter Template #203

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ts-saas-starter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea
144 changes: 144 additions & 0 deletions ts-saas-starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Full-Stack SaaS Template with Encore.ts, BetterAuth, and Stripe

A modern, production-ready template for building subscription-based SaaS applications with TypeScript. This template combines the power of Encore.ts for backend development, BetterAuth for authentication, and Stripe for subscription management.

## Tech Stack

### Backend
- [Encore.ts](https://encore.dev/) - Microservice architecture platform
- [BetterAuth](https://github.com/better-auth/better-auth) - Authentication library
- [Stripe](https://stripe.com/) - Payment processing
- PostgreSQL - Database

### Frontend
- [Next.js 15](https://nextjs.org/) - React framework with App Router
- [React 19](https://react.dev/) - UI library
- [Tailwind CSS 4](https://tailwindcss.com/) - Utility-first CSS framework
- [Radix UI](https://www.radix-ui.com/) - Unstyled, accessible UI components
- [Lucide React](https://lucide.dev/) - Icon set

## Getting Started

Follow these steps to set up and run your SaaS application.

### Stripe Setup

1. **Create a Stripe Developer Account**
- Head to [Stripe Dashboard](https://dashboard.stripe.com/register) and create a developer account
- Create a recurring product subscription
- Copy the `price_id` of your subscription product for later use

2. **Get Your API Keys**
- From the Stripe Dashboard, copy your Secret Key (this will be your `StripeSecretKey`)

2.5. **Set up Stripe webhooks**
- Create a webhook endpoint in your Stripe dashboard pointing to:
```
https://your-domain.com/api/auth/stripe/webhook
```
- Note: You don't need an actual URL at this point; this is just an example
- `/api/auth` is the default path for the auth server
- Make sure to select at least these events:
* `checkout.session.completed`
* `customer.subscription.updated`
* `customer.subscription.deleted`

3. **Set Up Stripe CLI for Webhooks**
- Install the [Stripe CLI](https://stripe.com/docs/stripe-cli)
- Log in with your Stripe account:
```
stripe login
```
- Start the webhook forwarding:
```
stripe listen --forward-to <BACKEND_URL>/api/auth/stripe/webhook
```
- Save the webhook signing secret (this will be your `StripeWebhookKey`)
- Have this open for Development

### Backend Setup

1. **Install Dependencies**
```bash
cd backend
npm install
```

2. **Initialize Encore App**
```bash
encore app init
```

3. **Configure Client Generation**
- From the generated Encore config, copy your app ID
- Update the `client` script in the backend's `package.json` with your app ID

4. **Configure Environment Variables**
- Set up the required environment variables in Encore:
- `StripeSecretKey`: Your Stripe Secret Key
- `StripeWebhookKey`: Your Stripe Webhook Signing Secret
- You want to set the environment to local

5. **Update Subscription Configuration**
- In `encore.service.ts`, update the BetterAuth config with your Stripe `price_id`

6. **Start the Backend**
```bash
npm start
```

7. **Generate Client File**
```bash
npm client
```

8. **Validate Environment Keys**
A Personal Problem of Mine was the keys on first set were not properly set, if you had to go into the dashboard to update make sure after setting you rerun the backend (npm start)

### Frontend Setup

1. **Install Dependencies**
```bash
cd frontend
npm install
```

2. **Configure Backend Connection**
- If your frontend is running on a port other than 3000, update the `trustedOrigins` in the backend's Encore auth configuration

3. **Start the Development Server**
```bash
npm run dev
```
NOTE: When making a Stripe Payment becuase of local test redirect will not work, you can go back to the dashboard and see that the payment has been updated!

## Features

- 🔐 User Authentication with BetterAuth
- 💳 Subscription Management with Stripe
- 🚀 Type-safe API using Encore.ts
- 🎨 Modern UI with Next.js and Tailwind CSS
- 🔄 Webhook handling for subscription events
- 📱 Responsive design with mobile support

## Project Structure

```
/
├── backend/ # Encore.ts backend
│ ├── encore.service.ts # Main Encore service configuration
│ ├── package.json # Backend dependencies
│ └── ...
├── frontend/ # Next.js frontend
│ ├── lib/ # Shared utilities
│ │ └── encore_client.ts # Generated Encore client
│ ├── package.json # Frontend dependencies
│ └── ...
└── README.md # Project documentation
```

## Acknowledgements

- [Encore](https://encore.dev/) for the backend development platform
- [BetterAuth](https://better-auth.com) for the authentication library
- [Stripe](https://stripe.com/) for payment processing
6 changes: 6 additions & 0 deletions ts-saas-starter/backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.encore
encore.gen.go
encore.gen.cue
/.encore
node_modules
/encore.gen
160 changes: 160 additions & 0 deletions ts-saas-starter/backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# REST API Starter

This is a RESTful API Starter with a single Hello World API endpoint.

## Prerequisites

**Install Encore:**
- **macOS:** `brew install encoredev/tap/encore`
- **Linux:** `curl -L https://encore.dev/install.sh | bash`
- **Windows:** `iwr https://encore.dev/install.ps1 | iex`

## Create app

Create a local app from this template:

```bash
encore app create my-app-name --example=ts/hello-world
```

## Run app locally

Run this command from your application's root folder:

```bash
encore run
```
### Using the API

To see that your app is running, you can ping the API.

```bash
curl http://localhost:4000/hello/World
```

### Local Development Dashboard

While `encore run` is running, open [http://localhost:9400/](http://localhost:9400/) to access Encore's [local developer dashboard](https://encore.dev/docs/observability/dev-dash).

Here you can see traces for all requests that you made, see your architecture diagram (just a single service for this simple example), and view API documentation in the Service Catalog.

## Development

### Add a new service

To create a new microservice, add a file named encore.service.ts in a new directory.
The file should export a service definition by calling `new Service`, imported from `encore.dev/service`.

```ts
import { Service } from "encore.dev/service";

export default new Service("my-service");
```

Encore will now consider this directory and all its subdirectories as part of the service.

Learn more in the docs: https://encore.dev/docs/ts/primitives/services

### Add a new endpoint

Create a new `.ts` file in your new service directory and write a regular async function within it. Then to turn it into an API endpoint, use the `api` function from the `encore.dev/api` module. This function designates it as an API endpoint.

Learn more in the docs: https://encore.dev/docs/ts/primitives/defining-apis

### Service-to-service API calls

Calling API endpoints between services looks like regular function calls with Encore.ts.
The only thing you need to do is import the service you want to call from `~encore/clients` and then call its API endpoints like functions.

In the example below, we import the service `hello` and call the `ping` endpoint using a function call to `hello.ping`:

```ts
import { hello } from "~encore/clients"; // import 'hello' service

export const myOtherAPI = api({}, async (): Promise<void> => {
const resp = await hello.ping({ name: "World" });
console.log(resp.message); // "Hello World!"
});
```

Learn more in the docs: https://encore.dev/docs/ts/primitives/api-calls

### Add a database

To create a database, import `encore.dev/storage/sqldb` and call `new SQLDatabase`, assigning the result to a top-level variable. For example:

```ts
import { SQLDatabase } from "encore.dev/storage/sqldb";

// Create the todo database and assign it to the "db" variable
const db = new SQLDatabase("todo", {
migrations: "./migrations",
});
```

Then create a directory `migrations` inside the service directory and add a migration file `0001_create_table.up.sql` to define the database schema. For example:

```sql
CREATE TABLE todo_item (
id BIGSERIAL PRIMARY KEY,
title TEXT NOT NULL,
done BOOLEAN NOT NULL DEFAULT false
-- etc...
);
```

Once you've added a migration, restart your app with `encore run` to start up the database and apply the migration. Keep in mind that you need to have [Docker](https://docker.com) installed and running to start the database.

Learn more in the docs: https://encore.dev/docs/ts/primitives/databases

### Learn more

There are many more features to explore in Encore.ts, for example:

- [Request Validation](https://encore.dev/docs/ts/primitives/validation)
- [Streaming APIs](https://encore.dev/docs/ts/primitives/streaming-apis)
- [Cron jobs](https://encore.dev/docs/ts/primitives/cron-jobs)
- [Pub/Sub](https://encore.dev/docs/ts/primitives/pubsub)
- [Object Storage](https://encore.dev/docs/ts/primitives/object-storage)
- [Secrets](https://encore.dev/docs/ts/primitives/secrets)
- [Authentication handlers](https://encore.dev/docs/ts/develop/auth)
- [Middleware](https://encore.dev/docs/ts/develop/middleware)

## Deployment

### Self-hosting

See the [self-hosting instructions](https://encore.dev/docs/self-host/docker-build) for how to use `encore build docker` to create a Docker image and configure it.

### Encore Cloud Platform

Deploy your application to a free staging environment in Encore's development cloud using `git push encore`:

```bash
git add -A .
git commit -m 'Commit message'
git push encore
```

You can also open your app in the [Cloud Dashboard](https://app.encore.dev) to integrate with GitHub, or connect your AWS/GCP account, enabling Encore to automatically handle cloud deployments for you.

## Link to GitHub

Follow these steps to link your app to GitHub:

1. Create a GitHub repo, commit and push the app.
2. Open your app in the [Cloud Dashboard](https://app.encore.dev).
3. Go to **Settings ➔ GitHub** and click on **Link app to GitHub** to link your app to GitHub and select the repo you just created.
4. To configure Encore to automatically trigger deploys when you push to a specific branch name, go to the **Overview** page for your intended environment. Click on **Settings** and then in the section **Branch Push** configure the **Branch name** and hit **Save**.
5. Commit and push a change to GitHub to trigger a deploy.

[Learn more in the docs](https://encore.dev/docs/how-to/github)


## Testing

To run tests, configure the `test` command in your `package.json` to the test runner of your choice, and then use the command `encore test` from the CLI. The `encore test` command sets up all the necessary infrastructure in test mode before handing over to the test runner. [Learn more](https://encore.dev/docs/ts/develop/testing)

```bash
encore test
```
Loading