Splito is an expense-sharing and personal finance companion built with Next.js. It includes a scheduled server-side workflow that generates monthly personalized spending-insight emails using Google's Gemini generative model.
This README is organized so a new contributor can quickly understand the project's purpose, structure, how Gemini is integrated, how to run and test locally, and how to contribute.
- Monthly Inngest cron job that fetches users' expenses from Convex, generates a friendly HTML analysis using Gemini, and sends emails via Resend.
- Primary AI code: lib/inngest/spending-insights.js.
- components.json — project metadata for UI components (when applicable)
- eslint.config.mjs, jsconfig.json — project configuration
- next.config.mjs, middleware.js — Next.js configuration
- package.json — npm scripts and dependencies
- postcss.config.mjs — CSS tooling
- .env.local — local environment variables (not checked in)
- app/ — Next.js app-router pages and server components
- components/ — reusable React components
- convex/ — Convex-generated functions and API types (generated)
- hooks/ — custom React hooks
- lib/ — server-side helpers and integrations
- lib/inngest/ — Inngest functions (cron/workflows)
- lib/inngest/spending-insights.js — monthly spending insights workflow (Gemini call)
- lib/inngest/client.js — inngest client bootstrap (if present)
- lib/inngest/ — Inngest functions (cron/workflows)
- public/ — static assets
Note: a helpful entry point for the AI workflow is lib/inngest/spending-insights.js.
- Data pipeline: fetch users with expenses -> fetch per-user monthly expenses -> compute totals & category breakdowns.
- AI integration: build a prompt containing the expense JSON blob, call Gemini (
gemini-1.5-flash) via@google/generative-ai, extract the first candidate text, and embed that HTML into an email. - Delivery: send the HTML email via Convex action that calls Resend.
- Reliability: uses
step.ai.wrap(Inngest) for retry-aware AI calls and per-user error handling.
- Gemini client initialization:
new GoogleGenerativeAI(process.env.GEMINI_API_KEY)inlib/inngest/spending-insights.js. - Model used:
genAI.getGenerativeModel({ model: "gemini-1.5-flash" }). - Invocation pattern:
step.ai.wrap("gemini", async (p) => model.generateContent(p), prompt)and reading the result fromaiResponse.response.candidates[0].content.parts[0].text. - Files to edit to change prompt/behavior:
lib/inngest/spending-insights.js(prompt text, HTML wrapper, extraction logic).
GEMINI_API_KEY— Google / Gemini API key (server-side)NEXT_PUBLIC_CONVEX_URL— Convex HTTP endpoint forConvexHttpClientRESEND_API_KEY— Resend API key (used by Convex action to send email)- Any other environment keys referenced in
.env.local(open that file for details).
Create a .env.local at the project root containing those keys before running locally. Do NOT commit secrets.
Prerequisites:
- Node.js 18+ (or the version used by the project)
- npm / yarn / pnpm
Install dependencies:
npm installRun the Next dev server:
npm run devNotes on testing the cron function locally:
- The Inngest function runs on a schedule in production. For local development you can:
- Trigger the Inngest function manually (create a small script or dispatch via the Inngest dev tools), or
- Call the underlying server function or route that dispatches the workflow.
- To test AI integration locally, add a test user with test expenses in Convex or mock the Convex responses.
Basic workflow:
- Fork / clone the repo.
- Create a feature branch:
git checkout -b feat/your-feature - Implement changes and add tests where appropriate.
- Run linting and formatting (project scripts may include
npm run lint/npm run format). - Open a PR describing the change and link any relevant issue.
Coding conventions:
- Follow existing file structure and style (ES modules, Next.js app-router components).
- Keep server-only secrets in environment variables and never log them.
Testing & prompts:
- If you modify the AI prompt, add a short test harness (example JSON input + expected structure) under
tools/orscripts/so reviewers can validate output shape. - When changing email templates, preview in an email client or use a staging Resend key.
Reviewers:
- PRs touching AI logic should include the prompt diff and a short rationale for prompt wording (to aid risk review).
- AI returns unexpected text or missing
candidates: add defensive checks before sending email and fallback to a short, safe summary. - Rate-limit or cost spikes: throttle batch sizes and monitor billing for
gemini-1.5-flashusage. - Convex query errors: ensure
NEXT_PUBLIC_CONVEX_URLis correct and that the generatedapifunctions are up to date; regenerate Convex types if needed.
- Prompt + AI call:
lib/inngest/spending-insights.js. - Convex queries/actions:
convex/(generated) and the calls inlib/inngest/*. - Email template: inside the per-user email action in the spending-insights function.
- Keep
GEMINI_API_KEYandRESEND_API_KEYsecure; use environment secrets in production hosting (Vercel/other). - Add logging and alerting around failed emails and failed AI calls; consider storing AI responses (or a hash) in Convex for auditability.