Skip to content

Commit 3934a0a

Browse files
authored
[saas-microservices] Add new example for an application with 2 backend microservices (#1184)
### Description This is an example SaaS project with 2 API services defined as microservices. - `dashboard` - A [Next.js](https://nextjs.org/) application to show the UI. - `api-dashboard` - A [Nitro](https://nitro.build/) backend serving data displayed in the dashboard. - `api-users` - A [Hono](https://hono.dev/) backend authenticating users and returning user information. These all run under the same domain. Paths to each application are routed using Vercel's [microfrontends](https://vercel.com/docs/microfrontends) support: - `/api/dashboard/*` - Routes to the `api-dashboard` backend - `/api/users/*` - Routes to the `api-users` backend - Everything else - Routes to the `dashboard` application <img width="1595" height="877" alt="Screenshot 2025-08-07 at 4 44 40 PM" src="https://github.com/user-attachments/assets/6fb16706-d64d-419c-aa1f-0dfa558091c5" /> ### Demo URL <!-- Provide a URL to a live deployment where we can test your PR. If a demo isn't possible feel free to omit this section. --> ### Type of Change - [ ] New Example - [ ] Example updates (Bug fixes, new features, etc.) - [ ] Other (changes to the codebase, but not to examples) ### New Example Checklist - [ ] 🛫 `npm run new-example` was used to create the example - [ ] 📚 The template wasn't used but I carefuly read the [Adding a new example](https://github.com/vercel/examples#adding-a-new-example) steps and implemented them in the example - [ ] 📱 Is it responsive? Are mobile and tablets considered?
1 parent 2733b46 commit 3934a0a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+11630
-5
lines changed

.github/CODEOWNERS

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@
22
# https://help.github.com/en/articles/about-code-owners
33

44
# Solutions Eng and Dev Rel are the default owners of everything
5-
* @okbel @lfades @goncy @dominiksipowicz @leerob @lpalmes
5+
* @okbel @lfades @goncy @dominiksipowicz @lpalmes
66

77
# For examples that are a Monorepo we add the Turbo team and some members
88
# from Solutions and Dev Rel
9-
solutions/monorepo @vercel/turbo-oss @goncy @lfades @leerob @lpalmes
10-
solutions/microfrontends @vercel/turbo-oss @goncy @lfades @leerob @lpalmes
11-
solutions/testing @vercel/turbo-oss @goncy @lfades @leerob @lpalmes
9+
solutions/monorepo @vercel/turbo-oss @goncy @lfades @lpalmes
10+
solutions/microfrontends @vercel/turbo-oss @goncy @lfades @lpalmes
11+
solutions/saas-microservices @vercel/ci-cd-workflow @mknichel
12+
solutions/testing @vercel/turbo-oss @goncy @lfades @lpalmes
1213

1314
# For the build output API the engineering team takes care of it.
1415
# A member of Solutions and Dev Rel is also added
15-
build-output-api @tootallnate @EndangeredMassa @lfades @leerob @lpalmes
16+
build-output-api @tootallnate @lfades @lpalmes
1617

1718
vercel-tutor @chibicode
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# Dependencies
4+
node_modules
5+
.pnp
6+
.pnp.js
7+
8+
# Testing
9+
/coverage
10+
11+
# Next.js
12+
.next
13+
out
14+
15+
# Production
16+
build
17+
dist
18+
.output
19+
.nitro
20+
21+
# Misc
22+
.DS_Store
23+
*.pem
24+
tsconfig.tsbuildinfo
25+
26+
# Debug
27+
npm-debug.log*
28+
yarn-debug.log*
29+
yarn-error.log*
30+
31+
# Local ENV files
32+
.env.local
33+
.env.development.local
34+
.env.test.local
35+
.env.production.local
36+
37+
# Vercel
38+
.vercel
39+
40+
# Turborepo
41+
.turbo
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# SaaS Microservices
2+
3+
This is an example SaaS project with 2 API services defined as microservices.
4+
5+
## Getting Started
6+
7+
```sh
8+
pnpm install
9+
pnpm dev
10+
```
11+
12+
Open http://localhost:3024 to view the dashboard. The dashboard will make API calls
13+
to the `users` and `dashboard` microservices for the information to display in the
14+
dashboard.
15+
16+
## How It Works
17+
18+
There are 3 separate applications in this example:
19+
20+
- `dashboard` - A [Next.js](https://nextjs.org/) application to show the UI. This application also controls the `microfrontnds.json` configuration to route API paths to the other microservices (see below).
21+
- `api-dashboard` - A [Nitro](https://nitro.build/) backend serving data displayed in the dashboard.
22+
- `api-users` - A [Hono](https://hono.dev/) backend authenticating users and returning user information.
23+
24+
These all run under the same domain. Paths to each application are routed using Vercel's [microfrontends](https://vercel.com/docs/microfrontends) support:
25+
26+
- `/api/dashboard/*` - Routes to the `api-dashboard` backend
27+
- `/api/users/*` - Routes to the `api-users` backend
28+
- Everything else - Routes to the `dashboard` application
29+
30+
## Running Locally
31+
32+
To run all applications together, run:
33+
34+
```sh
35+
pnpm dev
36+
```
37+
38+
A [local development proxy](https://vercel.com/docs/microfrontends/local-development) is automatically run to stitch requests from each application to the local instance of each service.
39+
40+
A single or subset of applications can also be run:
41+
42+
```sh
43+
pnpm dev:dashboard
44+
pnpm dev:api-dashboard
45+
pnpm dev:api-users
46+
pnpm turbo run dev -F api-users -F api-dashboard
47+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vercel
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//https://nitro.unjs.io/config
2+
export default defineNitroConfig({
3+
compatibilityDate: "2025-07-28",
4+
srcDir: "server",
5+
routeRules: {
6+
"/api/dashboard/**": {
7+
proxy: {
8+
to: "/**",
9+
},
10+
},
11+
},
12+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "api-dashboard",
3+
"private": true,
4+
"scripts": {
5+
"build": "nitro build",
6+
"dev": "nitro dev --port $(microfrontends port)",
7+
"prepare": "nitro prepare",
8+
"preview": "node .output/server/index.mjs",
9+
"typecheck": "tsc --noEmit"
10+
},
11+
"devDependencies": {
12+
"@vercel/microfrontends": "2.0.0",
13+
"nitropack": "latest"
14+
}
15+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
// Fake data generators
2+
const firstNames = [
3+
"Alex",
4+
"Jordan",
5+
"Taylor",
6+
"Morgan",
7+
"Casey",
8+
"Riley",
9+
"Avery",
10+
"Quinn",
11+
"Emma",
12+
"Liam",
13+
"Olivia",
14+
"Noah",
15+
"Ava",
16+
"Ethan",
17+
"Sophia",
18+
"Mason",
19+
"Isabella",
20+
"William",
21+
"Mia",
22+
"James",
23+
"Charlotte",
24+
"Benjamin",
25+
"Amelia",
26+
"Lucas",
27+
"Harper",
28+
"Henry",
29+
"Evelyn",
30+
"Alexander",
31+
"Abigail",
32+
"Michael",
33+
"Emily",
34+
"Daniel",
35+
"Elizabeth",
36+
"Jacob",
37+
"Sofia",
38+
"Logan",
39+
"Avery",
40+
"Jackson",
41+
"Ella",
42+
"Sebastian",
43+
];
44+
45+
const lastNames = [
46+
"Smith",
47+
"Johnson",
48+
"Williams",
49+
"Brown",
50+
"Jones",
51+
"Garcia",
52+
"Miller",
53+
"Davis",
54+
"Rodriguez",
55+
"Martinez",
56+
"Hernandez",
57+
"Lopez",
58+
"Gonzalez",
59+
"Wilson",
60+
"Anderson",
61+
"Thomas",
62+
"Taylor",
63+
"Moore",
64+
"Jackson",
65+
"Martin",
66+
"Lee",
67+
"Perez",
68+
"Thompson",
69+
"White",
70+
"Harris",
71+
"Sanchez",
72+
"Clark",
73+
"Ramirez",
74+
"Lewis",
75+
"Robinson",
76+
"Walker",
77+
"Young",
78+
"Allen",
79+
"King",
80+
"Wright",
81+
"Scott",
82+
"Torres",
83+
"Nguyen",
84+
"Hill",
85+
"Flores",
86+
];
87+
88+
const actions = [
89+
"created a new project",
90+
"deleted a file",
91+
"shared a document",
92+
"commented on a task",
93+
"completed a milestone",
94+
"invited a team member",
95+
"updated project settings",
96+
"exported data report",
97+
"created a new team",
98+
"archived old project",
99+
"updated billing information",
100+
"changed password",
101+
"enabled two-factor authentication",
102+
"uploaded a new file",
103+
"created a backup",
104+
"merged a pull request",
105+
"deployed to production",
106+
"ran automated tests",
107+
"reviewed code changes",
108+
"created a new API key",
109+
"updated integration settings",
110+
"scheduled a meeting",
111+
"published a blog post",
112+
"updated documentation",
113+
"created a new workflow",
114+
"optimized database queries",
115+
"configured monitoring alerts",
116+
"updated security policies",
117+
];
118+
119+
function generateRandomActivity() {
120+
const firstName = firstNames[Math.floor(Math.random() * firstNames.length)];
121+
const lastName = lastNames[Math.floor(Math.random() * lastNames.length)];
122+
const action = actions[Math.floor(Math.random() * actions.length)];
123+
124+
// Generate timestamp within the last 30 days
125+
const now = new Date();
126+
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
127+
const randomTime = new Date(
128+
thirtyDaysAgo.getTime() +
129+
Math.random() * (now.getTime() - thirtyDaysAgo.getTime()),
130+
);
131+
132+
return {
133+
id: Math.random().toString(36).substr(2, 9),
134+
name: `${firstName} ${lastName}`,
135+
action: action,
136+
timestamp: randomTime.toISOString(),
137+
};
138+
}
139+
140+
export default defineEventHandler((event) => {
141+
const activities = Array.from({ length: 20 }, () => generateRandomActivity());
142+
activities.sort(
143+
(a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime(),
144+
);
145+
146+
return {
147+
activities,
148+
total: activities.length,
149+
generated_at: new Date().toISOString(),
150+
};
151+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "./.nitro/types/tsconfig.json"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vercel

0 commit comments

Comments
 (0)