A multi-tenant SaaS platform where companies can track user events, build custom dashboards, and manage analytics data.
- Multi-Tenant Architecture: Isolated data per tenant
- Event Tracking: REST API for tracking user events
- GraphQL API: Flexible queries for analytics data
- Authentication: JWT + OAuth (Google)
- Role-Based Access Control: Owner, Admin, Member, Viewer roles
- Real-time Dashboards: Customizable charts and reports
- Backend: Node.js, TypeScript, Express
- Database: PostgreSQL with Prisma ORM
- GraphQL: Apollo Server, Type-GraphQL
- Authentication: Passport.js, JWT
- Caching: Redis
- Security: Helmet, CORS, Rate Limiting
- Node.js (v18+)
- PostgreSQL
- Redis (optional, for caching)
-
Clone the repository
-
Install dependencies:
npm install
-
Set up environment variables: Copy
.env
and update the values:DATABASE_URL="postgresql://username:password@localhost:5432/multi_tenant_analytics" JWT_SECRET="your-secret-key" GOOGLE_CLIENT_ID="your-google-client-id" GOOGLE_CLIENT_SECRET="your-google-client-secret" REDIS_URL="redis://localhost:6379"
-
Set up the database:
npx prisma migrate dev --name init npx prisma generate
-
Build the project:
npm run build
-
Test the API:
node test-api.js
This will test all endpoints with sample data.
The API uses JWT tokens with Google OAuth integration.
- Create a Google OAuth app at Google Cloud Console
- Set redirect URI to:
http://localhost:3000/auth/google/callback
- Update
.env
with your credentials:GOOGLE_CLIENT_ID=your-client-id GOOGLE_CLIENT_SECRET=your-client-secret
GET /auth/google
- Initiate Google OAuthGET /auth/google/callback
- OAuth callbackPOST /auth/refresh
- Refresh access token
Include these headers in requests:
Authorization: Bearer <access_token>
x-tenant-id: <tenant_id>
Track user events from your applications with simple REST endpoints and GraphQL mutations.
POST /api/track
Content-Type: application/json
x-tenant-id: your-tenant-id
{
"event": "user_signup",
"properties": {
"email": "[email protected]",
"plan": "premium"
},
"userId": "user_123",
"sessionId": "session_456",
"timestamp": "2025-01-15T10:00:00Z",
"projectId": "project_789"
}
POST /api/track/bulk
Content-Type: application/json
x-tenant-id: your-tenant-id
{
"events": [
{
"event": "page_view",
"properties": { "page": "/dashboard" },
"userId": "user_123"
},
{
"event": "button_click",
"properties": { "button": "export" },
"userId": "user_123"
}
],
"projectId": "project_789"
}
Access GraphQL playground at http://localhost:3000/graphql
mutation {
trackEvent(
input: {
name: "user_signup"
properties: { "email": "[email protected]" }
userId: "user_123"
}
projectId: "project_789"
) {
id
name
timestamp
}
}
query {
events(
filter: {
eventName: "user_signup"
startDate: "2025-01-01T00:00:00Z"
limit: 50
}
) {
id
name
properties
userId
timestamp
project {
name
}
}
}
query {
eventStats(days: 7) {
totalEvents
eventsByType
period
}
}
query {
eventAnalytics(period: "30d") {
totalEvents
uniqueUsers
topEvents {
event
count
}
timeSeries {
time
events
}
period
startDate
endDate
}
}
query {
eventAggregations(groupBy: "name", filter: { startDate: "2025-01-01T00:00:00Z" }) {
group
count
groupBy
}
}
query {
projects {
id
name
description
eventCount
}
}
mutation {
createProject(input: { name: "My App", description: "Analytics for my app" }) {
id
name
}
}
query {
dashboards {
id
name
description
viewCount
createdAt
}
}
mutation {
createDashboard(input: {
name: "User Analytics Dashboard"
description: "Track user behavior and engagement"
charts: [
{
id: "chart1"
type: "line"
title: "Daily Active Users"
dataSource: {
queryType: "eventAnalytics"
timeRange: "30d"
filters: { eventName: "user_login" }
}
styling: {
colors: ["#3B82F6", "#10B981"]
showLegend: true
}
}
]
}) {
id
name
config
}
}
mutation {
recordDashboardView(dashboardId: "dashboard_id") {
id
viewedAt
}
}
- Custom Chart Configurations: Support for line, bar, pie, area charts
- Flexible Data Sources: Connect to any analytics query
- Real-time Updates: Dashboard changes are tracked
- View Analytics: Track dashboard usage and popularity
- Tenant Isolation: Each tenant has their own dashboards
- Line Charts: Time series data visualization
- Bar Charts: Categorical data comparison
- Pie Charts: Proportion visualization
- Area Charts: Cumulative data trends
Charts can connect to:
eventAnalytics
- Comprehensive analytics dataeventAggregations
- Grouped event datacustom
- Custom query results
Each dashboard contains:
- Chart Array: Multiple charts per dashboard
- Data Sources: Configurable queries and filters
- Styling Options: Colors, legends, dimensions
- Real-time Updates: Automatic refresh capabilities
See prisma/schema.prisma
for the complete database schema including:
- Tenants
- Users
- Projects
- Events
- Dashboards
npm run build
- Compile TypeScriptnpm run start
- Start production servernpm run dev
- Start development server with hot reloadnpm run prisma:generate
- Generate Prisma clientnpm run prisma:migrate
- Run database migrationsnpm run prisma:studio
- Open Prisma Studio
src/
├── index.ts # Main entry point
├── resolvers/ # GraphQL resolvers
├── services/ # Business logic
├── middleware/ # Express middleware
├── auth/ # Authentication logic
└── utils/ # Utility functions
prisma/
├── schema.prisma # Database schema
└── migrations/ # Database migrations
Make sure to set the following in production:
DATABASE_URL
- PostgreSQL connection stringJWT_SECRET
- Secret key for JWTGOOGLE_CLIENT_ID
- Google OAuth client IDGOOGLE_CLIENT_SECRET
- Google OAuth client secretREDIS_URL
- Redis connection stringPORT
- Server port (default: 3000)
npm run build
npm start
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests
- Submit a pull request
ISC