A premium, multi-tenant expense management system built with Next.js 14, Prisma, and PostgreSQL. Designed for businesses to streamline employee expense submissions, approval workflows, and financial oversight with an enterprise-grade user experience.
Reimbursor automates the expense reimbursement process by providing:
- For Employees: Easy expense submission with multi-currency support and real-time status tracking
- For Managers: Multi-level approval workflows with sequential/parallel step support
- For Admins: Complete visibility, powerful overrides, and user management across the organization
| Category | Technology |
|---|---|
| Frontend | Next.js 14 (App Router), React 18, Tailwind CSS, shadcn/ui |
| Backend | Next.js API Routes, Prisma ORM |
| Database | PostgreSQL |
| Authentication | NextAuth.js (JWT Strategy) |
| Nodemailer (SMTP) | |
| Monitoring | Sentry |
| Validation | Zod |
| AI | Groq API through the OpenAI-compatible SDK; Tesseract OCR for receipt text |
| Role | Capabilities |
|---|---|
| Employee | Submit expenses, view own expense history, receive status notifications |
| Manager | Approve/reject team expenses, view pending approvals, see converted amounts |
| Admin | View all company expenses, override any approval, manage users, manage workflows |
- User Registration - Sign up with company creation
- Login/Logout - Secure session-based authentication
- Password Reset - Forgot/reset password via email
- Role-based Access - Middleware-protected routes
- JWT Sessions - Secure token-based authentication
- Auto Company Creation - New signup creates company automatically
- Role Assignment - Assign Employee, Manager, or Admin roles
- Manager Relationships - Link employees to managers
- User CRUD - Create, read, update, delete users (Admin only)
- User Dashboard - View all users with role statistics
- Create Expense - Submit with amount, category, description, date
- Multi-currency Support - Submit in any currency with exchange rate
- Currency Conversion - Automatic conversion to company base currency
- Expense Categories - Travel, Meals, Accommodation, Transportation, Supplies, Equipment, Other
- Expense History - View all submitted expenses with status
- Expense Details - View individual expense with full information
- Idempotency Keys - Prevent duplicate submissions
- ApprovalWorkflow Model - Configurable company-level workflows
- ApprovalStep Model - Define sequential/parallel approval steps
- Step Types:
SEQUENTIAL- Complete current step before nextPARALLEL- Multiple approvers vote simultaneouslyANY_ONE- Single approval/rejection ends the step
- Conditional Rules:
- Percentage-based approval (e.g., 60% required)
- Specific approver override (e.g., CFO required)
- Hybrid logic (percentage OR specific approver)
- Workflow Engine - Modular functions for:
createApprovalWorkflow()- Initialize workflowhandleApprovalAction()- Process decisionsevaluateStep()- Calculate step completionmoveToNextStep()- Advance workflow
- Idempotency - Prevent duplicate approval actions
- State Transitions:
PENDING → APPROVED → NEXT STEPREJECTED → TERMINATE FLOW
- View All Expenses - See every expense in the company
- Force Approve/Reject - Override any expense decision
- Override Comments - Record reason for override
- Override Tracking - Log who overrode and when
- Summary Cards - Total, Pending, Overridden, Rejected counts
- Advanced Filters - Search, status, employee, date range
- Export CSV - Download expense data
- Bulk Actions - Select multiple for batch approve/reject
- Pagination - Navigate large datasets
- Empty States - Contextual guidance when no data
- Real-time Notifications - Bell icon with unread count
- Event-driven Architecture - Centralized notification service
- Notification Types:
EXPENSE_SUBMITTED- New expense submittedAPPROVAL_REQUIRED- Approval neededAPPROVAL_ACTION- Expense approved/rejectedEXPENSE_APPROVED- Fully approvedEXPENSE_REJECTED- Rejected with reasonSTEP_ACTIVATED- New approval step startedSTEP_COMPLETED- Approval step finished
- Idempotency - No duplicate notifications
- Deep Linking - Click to navigate to expense
- Mark as Read - Individual or mark all
AI is optional and disabled unless configured. AI output is advisory: it does not approve, reject, or submit expenses.
- Receipt extraction - Scans receipt images with Tesseract OCR, then uses Groq to normalize merchant, amount, currency, date, and category. Shows confidence and warnings and falls back to deterministic parsing when AI is disabled or unavailable. Employees must review the fields before submitting.
- Expense review - Managers and admins can request an AI validation or approval summary from a pending expense's detail page. Results use expense fields and approval history, are labeled advisory, and are stored in the AI review audit tables.
- Expense assistant -
/assistantanswers general questions about using the app. It does not read company policy or live expense data.
AI review limitations: validation is not backed by configured company policy rules; summaries do not inspect receipt evidence; assistant responses are general guidance. Treat results as suggestions and verify them before acting. There is no automated accuracy evaluation or test suite yet, so enable AI only for a controlled pilot until those controls exist.
- Pine and lime visual system - Shared across the landing page, authenticated workspace, login, and registration screens
- Responsive landing page - Includes a scroll-driven, animated expense journey and reduced-motion fallback
- Workspace navigation - App Router links prefetch on hover or keyboard focus; route loading states keep navigation responsive while data loads
- Readable status badges and tables - Theme-aware surfaces, text, hover states, and controls
- Demo workspace - Login's "Try a demo workspace" button creates a fresh sample company with users, an active multi-step workflow, approval rules, and example expenses
- Owner expense example - Each new demo workspace includes an editable draft in the owner's Expenses tab; team claims are available under Admin → All Expenses
- Input Validation - Zod schemas for all API endpoints
- Error Boundaries - Graceful error handling
- Structured Logging - Performance monitoring
- Database Indexing - Optimized queries
- Query Optimization - Parallel queries, N+1 prevention
src/
├── app/
│ ├── (app)/ # Protected routes (with navbar + sidebar)
│ │ ├── admin/
│ │ │ ├── expenses/ # Admin expense management
│ │ │ ├── users/ # User management
│ │ │ └── settings/ # Company settings
│ │ ├── approvals/ # Manager approval page
│ │ ├── assistant/ # General-purpose expense app assistant
│ │ ├── dashboard/ # User dashboard
│ │ ├── expenses/ # Expense list & detail
│ │ │ ├── [id]/ # Expense detail page
│ │ │ └── new/ # Create expense
│ │ ├── notifications/ # Notification center
│ │ ├── loading.tsx # Shared authenticated route loading state
│ │ └── layout.tsx # Authenticated app layout with topbar/sidebar
│ ├── (auth)/ # Public routes (no navbar)
│ │ ├── forgot-password/ # Password reset request
│ │ ├── login/ # Login page
│ │ ├── reset-password/ # Password reset form
│ │ ├── signup/ # Registration
│ │ └── layout.tsx # Auth layout
│ ├── api/ # API Routes
│ │ ├── auth/ # Auth endpoints
│ │ ├── approvals/ # Approval actions
│ │ ├── company/ # Company management
│ │ ├── dashboard/ # Dashboard data
│ │ ├── expenses/ # Expense CRUD & submit
│ │ ├── ai/ # Receipt extraction, expense review, assistant APIs
│ │ ├── notifications/ # Notification management
│ │ ├── users/ # User management
│ │ └── workflow/ # Workflow management
│ ├── actions/ # Server actions
│ ├── global-error.tsx # Global error boundary
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Public product landing page
│ └── providers.tsx # Session provider
├── components/
│ ├── ui/ # shadcn/ui components
│ │ ├── button.tsx # Theme-aware action buttons
│ │ ├── card.tsx # Theme-aware cards
│ │ ├── dialog.tsx # Glassmorphic dialogs
│ │ ├── input.tsx # Theme-aware inputs
│ │ ├── table.tsx # Theme-aware tables
│ │ └── timeline.tsx # Approval flow timeline
│ ├── AdminExpenseTable.tsx # Admin dashboard table
│ ├── AdminOverrideDialog.tsx # Admin override modal
│ ├── CompanySetupModal.tsx # Company setup wizard
│ ├── ExpenseAmountCell.tsx # Currency display
│ ├── ExpenseList.tsx # Expense listing
│ ├── Navbar.tsx # Glassmorphic navbar
│ ├── Notifications.tsx # Notification bell & list
│ ├── Sidebar.tsx # Active sidebar
│ └── SubmitExpenseButton.tsx # Submit action
└── lib/
├── auth.ts # NextAuth configuration
├── demo/ # Demo workspace data and receipt generation
├── dashboard.ts # Dashboard data fetching
├── email.ts # Email service
├── logger.ts # Logging utilities
├── notifications/ # Notification system
│ ├── eventDispatcher.ts # Event handling
│ ├── notificationService.ts
│ └── index.ts
├── prisma.ts # Prisma client
├── utils.ts # Utility functions
├── validations.ts # Zod schemas
└── workflow/ # Approval workflow engine
├── engine.ts # WorkflowEngine class
└── index.ts
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/signup |
Register new user & company |
| POST | /api/auth/forgot-password |
Request password reset |
| POST | /api/auth/reset-password |
Reset password with token |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/users |
List all company users |
| POST | /api/users |
Create new user |
| GET | /api/users/[id] |
Get user details |
| PATCH | /api/users/[id] |
Update user (role, manager) |
| DELETE | /api/users/[id] |
Delete user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/expenses |
List user's expenses |
| POST | /api/expenses |
Create new expense |
| GET | /api/expenses/[id] |
Get expense details |
| POST | /api/expenses/[id]/submit |
Submit for approval |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/approvals |
Get pending approvals |
| POST | /api/approvals |
Approve or reject expense |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/ai/expenses/extract |
OCR and AI receipt extraction for a draft |
| POST | /api/ai/expenses/[id]/review |
Run VALIDATION or APPROVAL_SUMMARY for an expense (manager/admin) |
| POST | /api/ai/assistant |
General app usage assistant |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/workflow |
Get workflow configuration |
| POST | /api/workflow |
Create workflow |
| PATCH | /api/workflow/[id] |
Update workflow |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/notifications |
Get user notifications |
| PATCH | /api/notifications |
Mark as read |
- Company - Multi-tenant organization
- User - Employees with roles and manager relationships
- Expense - Expense claims with multi-currency support
- ApprovalWorkflow - Company-level workflow configurations
- ApprovalStep - Individual steps with type, thresholds, approvers
- ApprovalAction - Individual approval decisions with idempotency
- Notification - User notifications with idempotency
- Receipt - Attached receipt files
- SendPasswordToken - Password reset tokens
- AiExpenseReview, AiFinding, AiFeedback - AI review results, findings, and feedback
@@index([employeeId, status]) // Expense
@@index([companyId, status]) // Expense
@@index([createdAt]) // Expense
@@index([userId, read]) // Notification
@@index([userId, createdAt]) // Notification
@@index([approverId, action]) // ApprovalAction
@@index([expenseId, stepOrder]) // ApprovalAction
@@index([workflowId, stepOrder]) // ApprovalStep# Database
DATABASE_URL="postgresql://..."
# Auth
AUTH_SECRET="your-secret"
NEXTAUTH_SECRET="your-secret"
NEXTAUTH_URL="http://localhost:3000"
# Email (SMTP)
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="user"
SMTP_PASS="password"
EMAIL_FROM="noreply@example.com"
# Optional AI (Groq). Keep the API key server-side; never use NEXT_PUBLIC_ here.
GROQ_API_KEY=""
AI_ENABLED="true"
AI_PROVIDER="groq"
AI_DEFAULT_MODEL="openai/gpt-oss-120b"
AI_EXPENSE_EXTRACTION_ENABLED="false"
AI_EXPENSE_VALIDATION_ENABLED="false"
AI_APPROVAL_SUMMARY_ENABLED="false"
AI_ASSISTANT_ENABLED="false"
AI_REQUEST_TIMEOUT_MS="45000"
AI_MAX_RETRIES="2"
AI_MAX_OUTPUT_TOKENS="2000"
# Optional
DEFAULT_COUNTRY="United States"
NEXT_PUBLIC_SENTRY_DSN=""Create a local .env.local file for development and keep it out of version control. Set GROQ_API_KEY on the server and set AI_ENABLED=true plus the individual feature flags you want to use. Restart the server after changing environment variables. A missing API key, AI_ENABLED=false, or a disabled feature flag turns that feature off. Use your deployment platform's secret manager for production credentials.
Set NEXTAUTH_URL to the origin you use to open the app, including its port (for example, http://localhost:3000). If port 3000 is occupied and Next.js starts on 3001, use http://localhost:3001 instead. Sign-out returns to the current browser origin.
On the login page, choose Try a demo workspace — no email required. The app creates and signs into a new sample workspace each time. It includes an active approval workflow, approval rules, multiple demo users, example claims, and an editable owner draft. Use Admin → Workflow to view the active steps, Admin → Approval Rules to view the separate fallback/high-value rules, and Admin → All Expenses to browse team claims. The owner's Expenses tab shows their draft claim.
- Node.js 18+
- PostgreSQL database
- SMTP server (optional)
# Install dependencies
npm install
# Generate Prisma client
npx prisma generate
# Push schema to database
npx prisma db push
# Start development server
npm run devFor production database changes, use the committed Prisma migrations (npx prisma migrate deploy) rather than db push. Back up the database before applying migrations. The repository currently has no automated test script or committed test suite; run npm run build, npm run lint, and npx tsc --noEmit as basic checks, then perform the manual checks in the AI section below.
The checked-in seed script creates accounts with fixed development passwords. Review prisma/seed.ts before running it, and never run it against a production database. Create production accounts through the registration/admin flows and use unique credentials.
- Parallel Queries - Independent company, expense, approval, and workflow reads run concurrently with
Promise.all - Route Feedback - Shared App Router loading UI appears while authenticated page data is loading
- Intent Prefetching - Sidebar routes prefetch when hovered or focused
- Dashboard Startup - Session data comes from the authenticated server page; dashboard data and company details load concurrently
- Reduced Query Work - Dashboard totals share a grouped aggregation; admin expenses omit unused approval-action joins
- Database Indexes - Optimized for common queries
- Selective Fields - Only fetch required data
- Idempotent Operations - Prevent duplicate processing
- Event-driven Notifications - Decoupled from business logic
- Memoized Filters - Client-side filtering with useMemo
- Password hashing with bcrypt
- JWT session strategy
- Role-based middleware protection
- Input validation with Zod
- SQL injection prevention (Prisma)
- Idempotency keys for critical operations
After configuring a development Groq key and enabling a feature, sign in and verify:
- Upload a clear receipt image and confirm extracted values are editable and remain a draft until submitted.
- Disable extraction or remove the API key and confirm receipt processing uses its fallback or reports the expected configuration state without silently submitting anything.
- As a manager/admin, run both AI review actions on a pending expense; confirm the output is advisory and that a human approval action is still required.
- As an employee, try the review endpoint and confirm it denies access. Try an expense from another company and confirm it is not returned.
- Ask a general app usage question at
/assistant; confirm it states that it cannot see company policy or live expense data.
These are manual smoke checks, not a substitute for automated authorization, workflow, and AI quality tests. Do not send real financial records to an external model until the company has approved the data handling and retention terms.
This repository is a development/MVP foundation, not a production-certified expense platform. Before handling real financial data, add automated tests (especially tenant isolation and workflow transitions), shared/distributed rate limiting, production monitoring and alerting, backup/restore validation, operational migration procedures, and explicit data retention/privacy controls for receipt OCR and third-party AI processing. Validate security and deployment configuration in the target environment.