Define OpenSpec change for monthly expense tracker v1

This commit is contained in:
2026-03-23 12:10:18 -04:00
commit 5d7e25c015
11 changed files with 326 additions and 0 deletions

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
.next/
node_modules/
.env
.env.local
prisma/dev.db
prisma/dev.db-journal
.opencode/
.claude/
.codex/

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-23

View File

@@ -0,0 +1,63 @@
## Context
The repository starts with a product plan and OpenSpec configuration but no application code. The first version needs a complete local-first implementation using `Next.js`, `Prisma`, `SQLite`, and `OpenAI`, while keeping scope intentionally narrow: one user, manual data entry, fixed categories, and dashboard-only insights. Month boundaries are based on the local machine timezone, which affects date parsing, monthly aggregation, and paycheck coverage calculations.
## Goals / Non-Goals
**Goals:**
- Build a single deployable `Next.js` app with UI views and server routes in one codebase.
- Persist expenses, paychecks, and generated monthly insights in a local SQLite database managed by Prisma.
- Centralize monthly aggregation logic so dashboard reads and AI generation use the same numbers.
- Keep AI integration isolated behind a small service layer that prepares structured monthly context and calls `OpenAI`.
- Make v1 testable with deterministic validation, aggregation, and safe fallback behavior for sparse data.
**Non-Goals:**
- Authentication, multi-user support, bank sync, receipt scanning, background jobs, or email delivery.
- Automatic categorization, editing data through AI, or free-form custom categories in v1.
- Complex financial forecasting beyond simple next-month guidance derived from recent activity.
## Decisions
### Use a single `Next.js` app for UI and APIs
- Rationale: the project is small, local-first, and benefits from one codebase for pages, route handlers, and shared utilities.
- Alternative considered: separate frontend and API service. Rejected because it adds deployment and data-sharing complexity without helping the v1 scope.
### Use Prisma with SQLite for persistence
- Rationale: Prisma provides schema management, typed queries, and straightforward migrations while keeping SQLite as a simple embedded database.
- Alternative considered: raw SQLite queries. Rejected because it slows down schema evolution and validation during initial development.
### Store money as integer cents and dates as local calendar strings
- Rationale: integer cents avoid floating-point issues, and local-date strings such as `YYYY-MM-DD` align with the local machine timezone requirement for monthly boundaries.
- Alternative considered: floating-point amounts or UTC timestamps only. Rejected because both introduce avoidable ambiguity for monthly reporting.
### Put aggregation logic in shared server-side services
- Rationale: dashboard totals, paycheck coverage, category breakdowns, and AI snapshots must stay consistent across endpoints.
- Alternative considered: separate logic per route. Rejected because it risks drift between dashboard and insight generation.
### Add an AI service boundary with structured prompt input and fallback responses
- Rationale: the app needs provider isolation, predictable prompt shape, and safe messaging when data is too sparse for useful advice.
- Alternative considered: calling `OpenAI` directly from a route handler with raw records. Rejected because it couples prompting, aggregation, and transport too tightly.
## Risks / Trade-offs
- [Local timezone handling differs by machine] -> Normalize month calculations around stored local-date strings and test month edges explicitly.
- [SQLite limits concurrency] -> Acceptable for single-user local-first v1; no mitigation beyond keeping writes simple.
- [AI output quality varies with sparse or noisy data] -> Add minimum-data fallback logic and keep prompts grounded in structured aggregates.
- [OpenAI dependency requires API key management] -> Read configuration from environment variables and keep failure messages explicit in the UI/API.
## Migration Plan
1. Scaffold the `Next.js` app and install core dependencies.
2. Add the Prisma schema, create the initial SQLite migration, and generate the client.
3. Implement CRUD routes and UI forms for expenses and paychecks.
4. Implement dashboard aggregation and month filtering.
5. Add the AI insight service and persistence for generated monthly insights.
6. Run automated tests, then exercise the main flows in the browser.
Rollback is straightforward in early development: revert the code change and reset the local SQLite database if schema changes become invalid.
## Open Questions
- Which `OpenAI` model should be the initial default for monthly insight generation?
- Should generated monthly insights overwrite prior insights for the same month or create a historical trail of regenerated summaries?
- Do we want soft confirmation in the UI before deleting expenses or paychecks, or is immediate deletion acceptable for v1?

View File

@@ -0,0 +1,28 @@
## Why
The project currently has a product plan but no runnable application, spec artifacts, or implementation scaffold. Formalizing the first version now creates a clear contract for building a local-first expense tracker with reliable monthly summaries and AI-generated guidance.
## What Changes
- Add a local-first web app for tracking expenses and biweekly paychecks without authentication.
- Add dashboard capabilities for month-to-date totals, category breakdowns, cash flow, and spending comparisons.
- Add manual AI insight generation for a selected month using structured aggregates and transaction samples.
- Add local persistence, validation, and API routes for expenses, paychecks, dashboard data, and insight generation.
## Capabilities
### New Capabilities
- `expense-tracking`: Record, list, and delete categorized expenses for a given date.
- `paycheck-tracking`: Record, list, and delete paycheck entries based on actual pay dates.
- `monthly-dashboard`: View month-specific spending, income, and derived financial summaries.
- `monthly-insights`: Generate read-only AI insights from monthly financial activity.
### Modified Capabilities
- None.
## Impact
- Affected code: new `Next.js` application, server routes, UI views, Prisma schema, and AI integration service.
- APIs: `POST/GET/DELETE` routes for expenses and paychecks, `GET /dashboard`, and `POST /insights/generate`.
- Dependencies: `Next.js`, `Prisma`, `SQLite`, and `OpenAI` SDK.
- Systems: local machine timezone handling for month boundaries and persisted local database storage.

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: User can record categorized expenses
The system SHALL allow the user to create an expense with a title, amount, category, and local calendar date using fixed starter categories.
#### Scenario: Valid expense is created
- **WHEN** the user submits a title, positive amount, valid category, and valid local date
- **THEN** the system stores the expense and returns the created record
#### Scenario: Invalid expense is rejected
- **WHEN** the user submits a missing title, invalid amount, invalid category, or invalid date
- **THEN** the system rejects the request with a validation error and does not store the expense
### Requirement: User can review and delete expenses
The system SHALL allow the user to list recorded expenses and delete a specific expense by identifier.
#### Scenario: Expenses are listed
- **WHEN** the user requests expenses for the app
- **THEN** the system returns stored expenses in a stable order with their recorded fields
#### Scenario: Expense is deleted
- **WHEN** the user deletes an existing expense
- **THEN** the system removes that expense and it no longer appears in future listings or aggregates

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: Dashboard shows month-specific financial totals
The system SHALL return month-specific dashboard data for a requested `YYYY-MM` month using the local machine timezone for month boundaries.
#### Scenario: Dashboard totals are calculated for a populated month
- **WHEN** the user requests the dashboard for a month with expenses and paychecks
- **THEN** the system returns total expenses, total paychecks, net cash flow, and a category breakdown for that month
#### Scenario: Dashboard supports partial current-month data
- **WHEN** the user requests the dashboard for the current month before the month is complete
- **THEN** the system returns meaningful month-to-date totals and comparisons using the transactions recorded so far
### Requirement: Dashboard includes derived spending comparisons
The system SHALL provide derived comparisons for the selected month, including highest category, largest expense, average daily spend, and paycheck coverage information.
#### Scenario: Derived comparisons are available
- **WHEN** the selected month contains enough data for comparisons
- **THEN** the system returns the highest category, largest single expense, average daily spend, and spend-versus-paycheck coverage values
#### Scenario: Derived comparisons degrade safely for sparse data
- **WHEN** the selected month has no expenses or otherwise insufficient data for a comparison
- **THEN** the system returns null or empty-safe comparison fields instead of failing

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: User can generate monthly AI insights on demand
The system SHALL allow the user to manually generate AI insights for any month with existing or sparse data by sending structured monthly context to the configured `OpenAI` provider.
#### Scenario: Insights are generated for a month with data
- **WHEN** the user requests insight generation for a month with recorded activity
- **THEN** the system sends monthly aggregates plus transaction samples to the AI service and returns a rendered narrative summary with structured supporting totals
#### Scenario: Prior month insights can be generated
- **WHEN** the user requests insight generation for a previous month that has recorded data
- **THEN** the system generates and stores insight output for that requested month
### Requirement: Insight generation is read-only and safe for sparse months
The system SHALL keep AI insight generation read-only and return a safe fallback summary when a month does not have enough data for meaningful guidance.
#### Scenario: Sparse month returns fallback insight
- **WHEN** the user requests insight generation for a month with empty or near-empty data
- **THEN** the system returns a fallback message instead of low-confidence advice
#### Scenario: AI does not mutate financial records
- **WHEN** the system generates or stores monthly insights
- **THEN** no expense or paycheck records are created, updated, or deleted as part of that request

View File

@@ -0,0 +1,23 @@
## ADDED Requirements
### Requirement: User can record paychecks by pay date
The system SHALL allow the user to create a paycheck with a positive amount and a local pay date.
#### Scenario: Valid paycheck is created
- **WHEN** the user submits a positive amount and valid local pay date
- **THEN** the system stores the paycheck and returns the created record
#### Scenario: Invalid paycheck is rejected
- **WHEN** the user submits a missing or invalid amount or date
- **THEN** the system rejects the request with a validation error and does not store the paycheck
### Requirement: User can review and delete paychecks
The system SHALL allow the user to list recorded paychecks and delete a specific paycheck by identifier.
#### Scenario: Paychecks are listed
- **WHEN** the user requests paychecks for the app
- **THEN** the system returns stored paychecks in a stable order with their recorded fields
#### Scenario: Paycheck is deleted
- **WHEN** the user deletes an existing paycheck
- **THEN** the system removes that paycheck and it no longer appears in future dashboard totals or insight inputs

View File

@@ -0,0 +1,31 @@
## 1. Project setup
- [ ] 1.1 Scaffold the `Next.js` app with TypeScript, linting, and baseline project configuration.
- [ ] 1.2 Add runtime dependencies for Prisma, SQLite, validation, charts, and `OpenAI` integration.
- [ ] 1.3 Add development dependencies and scripts for testing, Prisma generation, and local development.
- [ ] 1.4 Add base environment and ignore-file setup for local database and API key configuration.
## 2. Persistence and shared services
- [ ] 2.1 Define Prisma models for `Expense`, `Paycheck`, and `MonthlyInsight` and create the initial SQLite migration.
- [ ] 2.2 Implement shared validation schemas for expenses, paychecks, and month query parameters.
- [ ] 2.3 Implement shared money and local-date utilities for month boundary calculations.
## 3. Expense and paycheck workflows
- [ ] 3.1 Implement expense API routes for create, list, and delete operations.
- [ ] 3.2 Implement paycheck API routes for create, list, and delete operations.
- [ ] 3.3 Build the `Add Expense` view with form submission, validation feedback, and expense listing.
- [ ] 3.4 Build the `Income/Paychecks` view with form submission, validation feedback, and paycheck listing.
## 4. Dashboard and insights
- [ ] 4.1 Implement monthly dashboard aggregation services for totals, category breakdowns, and derived comparisons.
- [ ] 4.2 Implement the dashboard API route and render dashboard sections for month-to-date metrics and comparisons.
- [ ] 4.3 Implement the `OpenAI` insight service with structured monthly snapshot input and sparse-month fallback logic.
- [ ] 4.4 Implement insight generation and display in the dashboard, including persisted monthly insight records.
## 5. Verification
- [ ] 5.1 Add automated tests for validation, persistence, dashboard aggregates, and insight fallback behavior.
- [ ] 5.2 Verify the primary user flows in the browser, including expense entry, paycheck entry, dashboard updates, and insight generation.

20
openspec/config.yaml Normal file
View File

@@ -0,0 +1,20 @@
schema: spec-driven
# Project context (optional)
# This is shown to AI when creating artifacts.
# Add your tech stack, conventions, style guides, domain knowledge, etc.
# Example:
# context: |
# Tech stack: TypeScript, React, Node.js
# We use conventional commits
# Domain: e-commerce platform
# Per-artifact rules (optional)
# Add custom rules for specific artifacts.
# Example:
# rules:
# proposal:
# - Keep proposals under 500 words
# - Always include a "Non-goals" section
# tasks:
# - Break tasks into chunks of max 2 hours

81
plan.md Normal file
View File

@@ -0,0 +1,81 @@
# Monthly Expense Tracker With AI Insights
## Summary
Build a single-user, local-first web app for manually recording daily expenses and biweekly paychecks, then generating month-to-date and end-of-month spending insights with next-month guidance.
The first version is optimized for fast daily entry and a dashboard-first review flow. It uses fixed starter categories, a simple local database, and an in-app AI summary rather than email or exports.
## Implementation Changes
- App shape:
- Build a web app with 3 primary views: `Dashboard`, `Add Expense`, and `Income/Paychecks`.
- Keep it single-user and local-first with no authentication in v1.
- Core data model:
- `Expense`: `id`, `date`, `title`, `amount`, `category`, `createdAt`.
- `Paycheck`: `id`, `payDate`, `amount`, `createdAt`.
- `MonthlyInsight`: `id`, `month`, `year`, `generatedAt`, `summary`, `recommendations`, `inputSnapshot`.
- Categories:
- Ship with fixed starter categories such as `Rent`, `Food`, `Transport`, `Bills`, `Shopping`, `Health`, `Entertainment`, `Misc`.
- Store category as a controlled value so monthly summaries can group reliably.
- Dashboard behavior:
- Show current month totals for expenses, category breakdown, paycheck total, and net cash flow.
- Include month-to-date charts and simple comparisons like highest category, largest single expense, average daily spend, and spend vs paycheck coverage.
- Provide a `Generate Insights` action that works any time during the month, not only at month-end.
- AI insight generation:
- Build a summarization pipeline that prepares structured monthly aggregates plus recent transaction samples, then sends that context to the AI model.
- Ask the model to return:
- spending pattern summary
- unusual categories or spikes
- paycheck-to-spend timing observations
- practical next-month suggestions
- Keep AI read-only in v1: it does not edit data or auto-categorize entries.
- Storage and architecture:
- Use a simple embedded database for local-first persistence, preferably SQLite.
- Implement the app with `Next.js` for the web UI and server routes.
- Use `Prisma` for the data layer and migrations.
- Keep the AI integration behind a small service boundary so the model/provider can be swapped later without changing UI code.
- Use `OpenAI` for insight generation in v1.
- Public interfaces / APIs:
- `POST /expenses`, `GET /expenses`, `DELETE /expenses/:id`
- `POST /paychecks`, `GET /paychecks`, `DELETE /paychecks/:id`
- `GET /dashboard?month=YYYY-MM`
- `POST /insights/generate?month=YYYY-MM`
- Insight response should include structured fields for totals and a rendered narrative summary for the dashboard.
## Implementation Checklist
- [ ] Scaffold the `Next.js` app and set up base project config.
- [ ] Add `Prisma` with a SQLite database and define `Expense`, `Paycheck`, and `MonthlyInsight` models.
- [ ] Build shared validation and month/date helpers using local machine time.
- [ ] Implement expense CRUD routes and forms.
- [ ] Implement paycheck CRUD routes and forms.
- [ ] Build dashboard aggregation logic for totals, categories, cash flow, and comparisons.
- [ ] Add the insight generation service boundary and `OpenAI` integration.
- [ ] Render AI insight output in the dashboard with fallback behavior for sparse months.
- [ ] Add tests for validation, aggregates, persistence, and insight generation.
- [ ] Verify all month-boundary behavior using local timezone dates.
## Test Plan
- Expense entry:
- Create valid expense with title, amount, date, and category.
- Reject missing or invalid amount/date/category.
- Paycheck tracking:
- Record multiple biweekly paychecks in one month and across month boundaries.
- Verify dashboard cash-flow totals use actual paycheck dates, not monthly averaging.
- Dashboard calculations:
- Category totals, monthly totals, average daily spend, and net cash flow are correct.
- Current-month partial data still renders meaningful month-to-date views.
- Insight generation:
- AI request uses aggregated monthly inputs plus transaction samples.
- Manual generation works for current month and prior months with existing data.
- Empty or near-empty months return a safe fallback message instead of low-quality advice.
- Persistence:
- Data remains available after app restart.
- Deleting an expense or paycheck updates dashboard and future insight results correctly.
## Assumptions And Defaults
- First version is for your own use only, with no login or multi-user support.
- Expense entry is fully manual; receipt scanning and bank sync are out of scope.
- AI insights appear only inside the dashboard.
- The app supports month-to-date previews as well as end-of-month review.
- Fixed starter categories are sufficient for v1; custom categories can be added later.
- Income is modeled as discrete biweekly paychecks because that materially affects next-month guidance and intra-month cash-flow interpretation.
- Month and paycheck boundaries use the local machine timezone.