10 SaaS Ideas You Can Build with Eden Stack (By Industry)
January 29, 2025 · Magnus Rødseth
10 SaaS Ideas You Can Build with Eden Stack (By Industry)
Eden Stack isn't just a template—it's a foundation for production SaaS applications. But what kinds of applications? Let's break down specific use cases across industries, showing how each component of the stack maps to real business needs.
The Pattern: Full-Stack AI-Powered SaaS
Every modern SaaS shares a common architecture:
| Component | Purpose | Eden Stack |
|---|---|---|
| Web Dashboard | Admin panel, analytics, settings | TanStack Start |
| API Layer | Serve multiple clients, expose services | Elysia + Eden Treaty |
| Database | Store user data, application state | Neon + Drizzle |
| Background Jobs | Long-running tasks, webhooks, AI processing | Inngest |
| Authentication | User management, OAuth, sessions | Better Auth |
| Payments | Subscriptions, one-time purchases | Stripe |
| Observability | Error tracking, analytics | Sentry + PostHog |
Now let's see this pattern applied across industries.
1. Education: AI Lesson Planner
The Product: An AI-powered tool for teachers to generate lesson plans, assessments, and curriculum materials.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Teacher dashboard to manage classes | TanStack Start SSR |
| REST API for school district integrations | Elysia endpoints |
| Generate lesson plans with GPT-4/Claude | Inngest background jobs |
| Store curricula, student progress | Drizzle + Neon |
| School admin SSO | Better Auth |
| Per-teacher or per-school pricing | Stripe subscriptions |
Key Technical Requirements
// Inngest handles long-running AI generation
inngest.createFunction(
{ id: "generate-lesson-plan" },
{ event: "lesson/generate.requested" },
async ({ event, step }) => {
const outline = await step.run("create-outline", () =>
generateOutlineWithAI(event.data.topic)
);
const materials = await step.run("generate-materials", () =>
generateMaterialsWithAI(outline)
);
await step.run("notify-teacher", () =>
sendEmail({ to: event.data.teacherEmail, lessonPlan: materials })
);
}
);Why Eden Stack: Teachers can't wait 30 seconds staring at a spinner. Inngest processes AI generation in the background and emails the completed plan.
2. Fitness: Personal Training Platform
The Product: AI workout generator with progress tracking, available on web and mobile.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Workout calendar and progress charts | TanStack Start |
| Sync workouts across devices | Elysia API |
| AI-generated custom workout plans | Inngest + AI APIs |
| Exercise library, user history | Drizzle relations |
| Social login for quick onboarding | Better Auth (GitHub, Google) |
| Monthly subscription tiers | Stripe recurring |
Key Technical Requirements
// Type-safe API with Eden Treaty — same code works on web AND mobile
const { data } = await api.workouts.generate.post({
fitnessLevel: "intermediate",
equipment: ["dumbbells", "pull-up-bar"],
duration: 45,
focus: "upper-body"
});
// data is fully typed: { workout: Workout, estimatedCalories: number }Built-in Cross-Platform Parity
Fitness apps need both web (for detailed planning) and mobile (for gym use). Eden Stack includes a cross-platform sync hook that automatically detects web changes and prompts you to implement mobile equivalents:
╔══════════════════════════════════════════════════════════════════╗
║ 📱 CROSS-PLATFORM SYNC: Mobile Implementation Required ║
╚══════════════════════════════════════════════════════════════════╝
Web route modified: src/routes/_authenticated/workouts.tsx
Route: /workouts
⚠️ ACTION REQUIRED: Update your todo list with these mobile tasks:
1. Create/update `apps/mobile/src/screens/WorkoutsScreen.tsx`
2. Wire up navigation to WorkoutsScreen
3. Ensure API calls use same Eden Treaty client pattern
4. Match form validation logic from web implementationThe hook (.claude/hooks/cross-platform-sync.py) fires whenever you modify a web route, ensuring you never ship a web feature without considering mobile. Combined with the ui-patterns skill that covers React Native patterns, you get consistent UX across platforms.
Why Eden Stack: Full type safety from database schema to mobile app. Change a field in Drizzle, get compile errors everywhere it's used. The cross-platform hook ensures feature parity without manual tracking.
3. PropTech: Property Management Dashboard
The Product: Landlord portal for managing properties, tenants, maintenance, and rent collection.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Property portfolio overview | TanStack Start with SSR |
| Tenant portal API | Elysia routes |
| Rent reminders, lease renewal workflows | Inngest cron + events |
| Properties, tenants, payments, maintenance | Drizzle schema |
| Landlord + tenant authentication | Better Auth multi-tenant |
| Rent payments, subscription for landlords | Stripe Connect |
Key Technical Requirements
// Elysia cron for automated rent reminders
import { cron } from "@elysiajs/cron";
app.use(
cron({
name: "rent-reminder",
pattern: "0 9 1 * *", // 9am on the 1st of each month
async run() {
const upcomingRent = await db.query.leases.findMany({
where: (lease, { lte }) => lte(lease.nextDueDate, addDays(new Date(), 7))
});
await Promise.all(upcomingRent.map(lease =>
inngest.send({ name: "rent/reminder", data: lease })
));
}
})
);Why Eden Stack: Multi-tenant architecture with Stripe Connect for marketplace-style payments. Landlords pay SaaS fee, tenants pay rent through the platform.
4. Construction: Project Management Software
The Product: Construction project tracker with document management, progress photos, AI-powered reporting, and subcontractor coordination.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Project timeline, Gantt charts | TanStack Start |
| Field worker mobile app API | Elysia |
| Daily report generation, document processing | Inngest |
| AI photo analysis & progress detection | Inngest + Vision APIs |
| Projects, phases, workers, documents | Drizzle + Neon |
| Per-company accounts, role-based access | Better Auth + custom roles |
| Per-project or per-seat pricing | Stripe metered billing |
Key Technical Requirements
// Schema for construction-specific data
export const projects = pgTable("projects", {
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
name: text("name").notNull(),
status: text("status", { enum: ["planning", "active", "on-hold", "completed"] }),
startDate: timestamp("start_date"),
estimatedCompletion: timestamp("estimated_completion"),
actualCompletion: timestamp("actual_completion"),
budget: integer("budget"),
companyId: text("company_id").references(() => companies.id),
});
export const progressReports = pgTable("progress_reports", {
id: text("id").primaryKey(),
projectId: text("project_id").references(() => projects.id),
reportDate: timestamp("report_date").defaultNow(),
weatherConditions: text("weather_conditions"),
workersOnSite: integer("workers_on_site"),
notes: text("notes"),
photos: jsonb("photos").$type<string[]>(),
aiAnalysis: jsonb("ai_analysis").$type<AIProgressAnalysis>(),
});AI-Powered Progress Reports
Field workers snap photos. AI analyzes them and generates structured reports:
// Inngest processes site photos with AI vision
inngest.createFunction(
{ id: "analyze-site-photos" },
{ event: "construction/photos.uploaded" },
async ({ event, step }) => {
const { photos, projectId, reportId } = event.data;
// Analyze each photo for progress indicators
const analyses = await step.run("analyze-photos", async () => {
return Promise.all(photos.map(async (photoUrl) => {
const response = await openai.chat.completions.create({
model: "gpt-4o",
messages: [{
role: "user",
content: [
{ type: "text", text: "Analyze this construction site photo. Identify: 1) Work completed, 2) Safety concerns, 3) Weather impact, 4) Estimated completion % for visible tasks." },
{ type: "image_url", image_url: { url: photoUrl } }
]
}]
});
return response.choices[0].message.content;
}));
});
// Generate structured report
const report = await step.run("generate-report", () =>
generateStructuredReport(analyses)
);
// Update database with AI analysis
await step.run("save-analysis", () =>
db.update(progressReports)
.set({ aiAnalysis: report })
.where(eq(progressReports.id, reportId))
);
// Alert project manager if safety issues detected
if (report.safetyIssues.length > 0) {
await step.run("alert-safety", () =>
sendSafetyAlert(projectId, report.safetyIssues)
);
}
}
);Why Eden Stack: Drizzle's type-safe schema handles complex project hierarchies. Inngest processes uploaded photos in the background—workers don't wait. AI analysis runs automatically with built-in retries for API failures.
5. Data Analytics: Business Intelligence Dashboard
The Product: Connect data sources, build dashboards, schedule automated reports.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Dashboard builder, chart library | TanStack Start |
| Data source connectors API | Elysia |
| ETL pipelines, scheduled refreshes | Inngest workflows |
| Cached queries, user dashboards | Drizzle + Neon |
| Team workspaces with SSO | Better Auth |
| Usage-based pricing (queries/month) | Stripe metered |
Key Technical Requirements
// Inngest for scheduled data refresh
inngest.createFunction(
{ id: "refresh-dashboard-data" },
{ cron: "0 */6 * * *" }, // Every 6 hours
async ({ step }) => {
const dashboards = await step.run("get-active-dashboards", () =>
db.query.dashboards.findMany({ where: eq(dashboards.autoRefresh, true) })
);
await Promise.all(
dashboards.map(dashboard =>
step.run(`refresh-${dashboard.id}`, () => refreshDashboardData(dashboard))
)
);
}
);Why Eden Stack: Inngest's durable execution handles flaky data sources with automatic retries. Failed refreshes don't break the entire pipeline.
6. Healthcare: Patient Portal
The Product: Secure patient communication, appointment booking, and health record access.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Patient dashboard | TanStack Start |
| EHR integration API | Elysia with FHIR |
| Appointment reminders, lab result notifications | Inngest |
| Appointments, messages, documents | Drizzle (encrypted) |
| Patient + provider authentication | Better Auth |
| Per-provider monthly subscription | Stripe |
Key Technical Requirements
// Better Auth with role-based access
export const auth = betterAuth({
database: drizzleAdapter(db),
plugins: [
organization({
roles: ["patient", "nurse", "doctor", "admin"],
permissions: {
patient: ["read:own-records", "book:appointments"],
nurse: ["read:patient-records", "update:vitals"],
doctor: ["read:patient-records", "write:prescriptions", "write:notes"],
admin: ["manage:users", "manage:billing"],
},
}),
],
});Why Eden Stack: Better Auth's organization plugin handles complex healthcare permission hierarchies. Drizzle's type safety prevents accidental data exposure.
7. Legal: Case Management System
The Product: Law firm case tracker with document management, time tracking, and client portal.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Case dashboard, calendar | TanStack Start |
| Client portal API | Elysia |
| Document OCR, deadline reminders | Inngest |
| Cases, clients, time entries, documents | Drizzle |
| Attorney + client + staff roles | Better Auth |
| Per-attorney seat licensing | Stripe |
Key Technical Requirements
// Time tracking with type-safe schema
export const timeEntries = pgTable("time_entries", {
id: text("id").primaryKey(),
caseId: text("case_id").references(() => cases.id),
attorneyId: text("attorney_id").references(() => users.id),
description: text("description").notNull(),
durationMinutes: integer("duration_minutes").notNull(),
billableRate: integer("billable_rate"), // cents
billable: boolean("billable").default(true),
invoiceId: text("invoice_id").references(() => invoices.id),
createdAt: timestamp("created_at").defaultNow(),
});
// Calculate billable amounts type-safely
const unbilledTime = await db
.select({
totalMinutes: sql<number>`sum(${timeEntries.durationMinutes})`,
totalAmount: sql<number>`sum(${timeEntries.durationMinutes} * ${timeEntries.billableRate} / 60)`,
})
.from(timeEntries)
.where(and(
eq(timeEntries.caseId, caseId),
isNull(timeEntries.invoiceId)
));Why Eden Stack: Drizzle's SQL builder maintains type safety for complex billing calculations. Inngest ensures court deadline reminders are never missed.
8. HR Tech: Employee Onboarding Platform
The Product: Automate new hire paperwork, training assignments, and equipment provisioning.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| HR admin dashboard | TanStack Start |
| HRIS integrations (Workday, BambooHR) | Elysia |
| Onboarding workflow orchestration | Inngest |
| Employees, tasks, documents | Drizzle |
| HR + manager + employee roles | Better Auth |
| Per-employee pricing | Stripe |
Key Technical Requirements
// Inngest orchestrates multi-step onboarding
inngest.createFunction(
{ id: "employee-onboarding" },
{ event: "employee/hired" },
async ({ event, step }) => {
const { employeeId, startDate } = event.data;
await step.run("create-accounts", () =>
createGoogleWorkspaceAccount(employeeId)
);
await step.run("assign-training", () =>
assignRequiredTraining(employeeId)
);
await step.sleepUntil("wait-for-start", startDate);
await step.run("send-welcome", () =>
sendWelcomeEmail(employeeId)
);
await step.sleep("check-in-delay", "7 days");
await step.run("first-week-checkin", () =>
sendCheckInSurvey(employeeId)
);
}
);Why Eden Stack: Inngest's sleepUntil and sleep enable long-running workflows that span weeks—impossible with traditional job queues.
9. E-commerce: Inventory Management
The Product: Multi-channel inventory sync for Shopify, Amazon, and WooCommerce sellers.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Inventory dashboard | TanStack Start |
| Marketplace APIs | Elysia |
| Sync jobs, low stock alerts | Inngest |
| Products, inventory, channels | Drizzle |
| Multi-store accounts | Better Auth |
| GMV-based pricing | Stripe |
Key Technical Requirements
// Webhook handling with durable processing
app.post("/webhooks/shopify", async ({ body }) => {
// Immediately acknowledge webhook
await inngest.send({
name: "shopify/order.created",
data: body,
});
return { received: true };
});
// Inngest handles the actual processing with retries
inngest.createFunction(
{ id: "sync-shopify-order", retries: 5 },
{ event: "shopify/order.created" },
async ({ event, step }) => {
const order = event.data;
await step.run("update-inventory", () =>
decrementInventory(order.line_items)
);
await step.run("sync-to-amazon", () =>
syncInventoryToAmazon(order.line_items)
);
}
);Why Eden Stack: Stripe webhook + Inngest pattern ensures no order is ever lost, even if downstream APIs are temporarily down.
10. Finance: Expense Management
The Product: Receipt scanning, expense categorization, and approval workflows.
How Each Layer Maps
| Feature | Stack Component |
|---|---|
| Expense dashboard, reports | TanStack Start |
| Mobile receipt upload API | Elysia |
| OCR processing, approval workflows | Inngest |
| Expenses, receipts, approvals | Drizzle |
| Employee + manager + finance roles | Better Auth |
| Per-employee pricing | Stripe |
Key Technical Requirements
// Type-safe expense schema with audit trail
export const expenses = pgTable("expenses", {
id: text("id").primaryKey(),
userId: text("user_id").references(() => users.id),
amount: integer("amount").notNull(), // cents
currency: text("currency").default("USD"),
category: text("category", {
enum: ["travel", "meals", "software", "equipment", "other"]
}),
description: text("description"),
receiptUrl: text("receipt_url"),
ocrData: jsonb("ocr_data").$type<OCRResult>(),
status: text("status", {
enum: ["draft", "submitted", "approved", "rejected", "reimbursed"]
}).default("draft"),
submittedAt: timestamp("submitted_at"),
approvedBy: text("approved_by").references(() => users.id),
approvedAt: timestamp("approved_at"),
});Why Eden Stack: PostHog analytics track approval bottlenecks. Sentry catches OCR failures. Full observability stack included.
Choosing Your Industry
Every example above uses the same core pattern:
- Web dashboard for admins (TanStack Start)
- Type-safe API for integrations (Elysia + Eden Treaty)
- Background processing for heavy lifting (Inngest)
- Structured data with relations (Drizzle + Neon)
- Authentication with roles (Better Auth)
- Payments with flexibility (Stripe)
- Observability for production (Sentry + PostHog)
The stack doesn't change. The schema and business logic do.