(null)
+
+ const recurringExpenses = computed(() => expenses.value.filter((expense) => expense.isRecurring))
+
+ const fetchExpenses = async (params?: {
+ list_id?: number
+ group_id?: number
+ isRecurring?: boolean
+ }) => {
+ loading.value = true
+ error.value = null
+ try {
+ expenses.value = await expenseService.getExpenses(params)
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : 'Failed to fetch expenses'
+ throw err
+ } finally {
+ loading.value = false
+ }
+ }
+
+ const createExpense = async (data: CreateExpenseData) => {
+ loading.value = true
+ error.value = null
+ try {
+ const newExpense = await expenseService.createExpense(data)
+ expenses.value.push(newExpense)
+ return newExpense
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : 'Failed to create expense'
+ throw err
+ } finally {
+ loading.value = false
+ }
+ }
+
+ const updateExpense = async (id: number, data: UpdateExpenseData) => {
+ loading.value = true
+ error.value = null
+ try {
+ const updatedExpense = await expenseService.updateExpense(id, data)
+ const index = expenses.value.findIndex((e) => e.id === id)
+ if (index !== -1) {
+ expenses.value[index] = updatedExpense
+ }
+ return updatedExpense
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : 'Failed to update expense'
+ throw err
+ } finally {
+ loading.value = false
+ }
+ }
+
+ const deleteExpense = async (id: number) => {
+ loading.value = true
+ error.value = null
+ try {
+ await expenseService.deleteExpense(id)
+ expenses.value = expenses.value.filter((e) => e.id !== id)
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : 'Failed to delete expense'
+ throw err
+ } finally {
+ loading.value = false
+ }
+ }
+
+ const getExpense = async (id: number) => {
+ loading.value = true
+ error.value = null
+ try {
+ return await expenseService.getExpense(id)
+ } catch (err) {
+ error.value = err instanceof Error ? err.message : 'Failed to fetch expense'
+ throw err
+ } finally {
+ loading.value = false
+ }
+ }
+
+ return {
+ expenses,
+ recurringExpenses,
+ loading,
+ error,
+ fetchExpenses,
+ createExpense,
+ updateExpense,
+ deleteExpense,
+ getExpense,
+ }
+}
diff --git a/fe/src/pages/GroupDetailPage.vue b/fe/src/pages/GroupDetailPage.vue
index 1de7017..8bf38b4 100644
--- a/fe/src/pages/GroupDetailPage.vue
+++ b/fe/src/pages/GroupDetailPage.vue
@@ -101,13 +101,9 @@
{{ chore.name }}
Due: {{ formatDate(chore.next_due_date) }}
-
+
{{ formatFrequency(chore.frequency) }}
-
+
diff --git a/fe/src/services/expenseService.ts b/fe/src/services/expenseService.ts
new file mode 100644
index 0000000..7893575
--- /dev/null
+++ b/fe/src/services/expenseService.ts
@@ -0,0 +1,65 @@
+import type { Expense, RecurrencePattern } from '@/types/expense'
+import { api } from '@/services/api'
+
+export interface CreateExpenseData {
+ description: string
+ total_amount: string
+ currency: string
+ split_type: string
+ isRecurring: boolean
+ recurrencePattern?: {
+ type: 'daily' | 'weekly' | 'monthly' | 'yearly'
+ interval: number
+ daysOfWeek?: number[]
+ endDate?: string
+ maxOccurrences?: number
+ }
+ list_id?: number
+ group_id?: number
+ item_id?: number
+ paid_by_user_id: number
+ splits_in?: Array<{
+ user_id: number
+ amount: string
+ percentage?: number
+ shares?: number
+ }>
+}
+
+export interface UpdateExpenseData extends Partial {
+ version: number
+}
+
+export const expenseService = {
+ async createExpense(data: CreateExpenseData): Promise {
+ const response = await api.post('/expenses', data)
+ return response.data
+ },
+
+ async updateExpense(id: number, data: UpdateExpenseData): Promise {
+ const response = await api.put(`/expenses/${id}`, data)
+ return response.data
+ },
+
+ async deleteExpense(id: number): Promise {
+ await api.delete(`/expenses/${id}`)
+ },
+
+ async getExpense(id: number): Promise {
+ const response = await api.get(`/expenses/${id}`)
+ return response.data
+ },
+
+ async getExpenses(params?: {
+ list_id?: number
+ group_id?: number
+ isRecurring?: boolean
+ }): Promise {
+ const response = await api.get('/expenses', { params })
+ return response.data
+ },
+
+ async getRecurringExpenses(): Promise {
+ return this.getExpenses({ isRecurring: true })
+ },
+}
diff --git a/fe/src/stores/listDetailStore.ts b/fe/src/stores/listDetailStore.ts
index 0401ba7..708ab85 100644
--- a/fe/src/stores/listDetailStore.ts
+++ b/fe/src/stores/listDetailStore.ts
@@ -50,20 +50,14 @@ export const useListDetailStore = defineStore('listDetail', {
this.isSettlingSplit = true
this.error = null
try {
- // TODO: Uncomment and use when apiClient.settleExpenseSplit is available and correctly implemented in api.ts
- // For now, simulating the API call as it was not successfully added in the previous step.
- console.warn(
- `Simulating settlement for split ID: ${payload.expense_split_id} with data:`,
+ // Call the actual API endpoint
+ const response = await apiClient.settleExpenseSplit(
+ payload.expense_split_id,
payload.activity_data,
)
- // const createdActivity = await apiClient.settleExpenseSplit(payload.expense_split_id, payload.activity_data);
- // console.log('Settlement activity created (simulated):', createdActivity);
- await new Promise((resolve) => setTimeout(resolve, 500)) // Simulate network delay
- // End of placeholder for API call
+ console.log('Settlement activity created:', response.data)
- // Refresh list data to show updated statuses.
- // Ensure currentList is not null and its ID matches before refetching,
- // or always refetch if list_id_for_refetch is the source of truth.
+ // Refresh list data to show updated statuses
if (payload.list_id_for_refetch) {
await this.fetchListWithExpenses(payload.list_id_for_refetch)
} else if (this.currentList?.id) {
diff --git a/fe/src/types/expense.ts b/fe/src/types/expense.ts
index c8a1101..c7b90e2 100644
--- a/fe/src/types/expense.ts
+++ b/fe/src/types/expense.ts
@@ -1,74 +1,91 @@
// Defines interfaces related to Expenses, Splits, and Settlement Activities
-import type { UserPublic } from './user';
+import type { UserPublic } from './user'
// Enums for statuses - align these string values with your backend enums
export enum ExpenseSplitStatusEnum {
- UNPAID = "unpaid",
- PARTIALLY_PAID = "partially_paid",
- PAID = "paid",
+ UNPAID = 'unpaid',
+ PARTIALLY_PAID = 'partially_paid',
+ PAID = 'paid',
}
export enum ExpenseOverallStatusEnum {
- UNPAID = "unpaid",
- PARTIALLY_PAID = "partially_paid",
- PAID = "paid",
+ UNPAID = 'unpaid',
+ PARTIALLY_PAID = 'partially_paid',
+ PAID = 'paid',
}
// For creating a new settlement activity via API
export interface SettlementActivityCreate {
- expense_split_id: number;
- paid_by_user_id: number;
- amount_paid: string; // String representation of Decimal for API payload
- paid_at?: string; // ISO datetime string, optional, backend can default to now()
+ expense_split_id: number
+ paid_by_user_id: number
+ amount_paid: string // String representation of Decimal for API payload
+ paid_at?: string // ISO datetime string, optional, backend can default to now()
}
export interface SettlementActivity {
- id: number;
- expense_split_id: number;
- paid_by_user_id: number;
- paid_at: string; // ISO datetime string
- amount_paid: string; // String representation of Decimal
- created_by_user_id: number;
- created_at: string; // ISO datetime string
- updated_at: string; // ISO datetime string
- payer?: UserPublic | null;
- creator?: UserPublic | null;
+ id: number
+ expense_split_id: number
+ paid_by_user_id: number
+ paid_at: string // ISO datetime string
+ amount_paid: string // String representation of Decimal
+ created_by_user_id: number
+ created_at: string // ISO datetime string
+ updated_at: string // ISO datetime string
+ payer?: UserPublic | null
+ creator?: UserPublic | null
}
export interface ExpenseSplit {
- id: number;
- expense_id: number;
- user_id: number;
- user?: UserPublic | null;
- owed_amount: string; // String representation of Decimal
- share_percentage?: string | null;
- share_units?: number | null;
- created_at: string;
- updated_at: string;
-
- status: ExpenseSplitStatusEnum;
- paid_at?: string | null;
- settlement_activities: SettlementActivity[];
+ id: number
+ expense_id: number
+ user_id: number
+ user?: UserPublic | null
+ owed_amount: string // String representation of Decimal
+ share_percentage?: string | null
+ share_units?: number | null
+ created_at: string
+ updated_at: string
+
+ status: ExpenseSplitStatusEnum
+ paid_at?: string | null
+ settlement_activities: SettlementActivity[]
+}
+
+export interface RecurrencePattern {
+ id: number
+ type: 'daily' | 'weekly' | 'monthly' | 'yearly'
+ interval: number
+ daysOfWeek?: number[]
+ endDate?: string
+ maxOccurrences?: number
+ createdAt: string
+ updatedAt: string
}
export interface Expense {
- id: number;
- description: string;
- total_amount: string; // String representation of Decimal
- currency: string;
- expense_date: string;
- split_type: string;
- list_id?: number | null;
- group_id?: number | null;
- item_id?: number | null;
- paid_by_user_id: number;
- paid_by_user?: UserPublic | null;
- created_by_user_id: number;
- created_by_user?: UserPublic | null;
- created_at: string;
- updated_at: string;
- version: number;
- splits: ExpenseSplit[];
+ id: number
+ description: string
+ total_amount: string // String representation of Decimal
+ currency: string
+ expense_date: string
+ split_type: string
+ list_id?: number | null
+ group_id?: number | null
+ item_id?: number | null
+ paid_by_user_id: number
+ paid_by_user?: UserPublic | null
+ created_by_user_id: number
+ created_by_user?: UserPublic | null
+ created_at: string
+ updated_at: string
+ version: number
+ splits: ExpenseSplit[]
- overall_settlement_status: ExpenseOverallStatusEnum;
+ overall_settlement_status: ExpenseOverallStatusEnum
+ isRecurring: boolean
+ nextOccurrence?: string
+ lastOccurrence?: string
+ recurrencePattern?: RecurrencePattern
+ parentExpenseId?: number
+ generatedExpenses?: Expense[]
}
diff --git a/mitlist_doc.md b/mitlist_doc.md
index 7c84204..b1cabba 100644
--- a/mitlist_doc.md
+++ b/mitlist_doc.md
@@ -1,265 +1,177 @@
-# MitList - Collaborative List Management & Cost Splitting
+## Project Documentation: Shared Household Management PWA
-**Version:** 1.1.0
-**Last Updated:** {{Current Date}}
+**Version:** 1.1 (Tech Stack Update)
+**Date:** 2025-04-22
-## 1. Introduction
+### 1. Project Overview
-MitList is a collaborative application designed to simplify list management and cost splitting for shared living, group activities, and personal organization. It allows users to create shared lists, track items, manage chores, and seamlessly divide expenses related to these activities.
+**1.1. Concept:**
+Develop a Progressive Web App (PWA) designed to streamline household coordination and shared responsibilities. The application enables users within defined groups (e.g., households, roommates, families) to collaboratively manage shopping lists, track and split expenses with historical accuracy, and manage recurring or one-off household chores.
-## 2. Core Features
+**1.2. Goals:**
-* **User Authentication:** Secure user registration and login.
-* **Group Management:** Create and manage groups, invite members, and assign roles.
-* **List Management:** Create personal or group-specific lists (e.g., shopping, groceries, TODOs).
-* **Item Tracking:** Add, edit, mark items as complete, and (new!) assign prices to items for cost splitting.
-* **Chore Management:** Assign and track chores within groups or personally.
-* **Cost Splitting:**
- * Record expenses related to lists, groups, or specific items.
- * Define how expenses are split (equally, by exact amounts, percentage, shares, or item-based).
- * Track individual shares and overall expense settlement status.
- * Record payments against specific expense shares using Settlement Activities.
- * View group balance summaries and suggested settlements.
-* **OCR for Item Entry:** (Experimental) Add items to a list by uploading an image of a receipt.
-* **Offline Support:** (Experimental) Basic offline capabilities for list item management.
+- Simplify the creation, management, and sharing of shopping lists.
+- Provide an efficient way to add items via image capture and OCR (using Gemini 1.5 Flash).
+- Enable transparent and traceable tracking and splitting of shared expenses related to shopping lists.
+- Offer a clear system for managing and assigning recurring or single-instance household chores.
+- Deliver a seamless, near-native user experience across devices through PWA technologies, including robust offline capabilities.
+- Foster better communication and coordination within shared living environments.
-## 3. Technology Stack
+**1.3. Target Audience:**
-* **Backend:** Python (FastAPI)
-* **Database:** PostgreSQL (relational)
-* **Frontend:** Vue.js (Quasar Framework)
-* **Authentication:** JWT
+- Roommates sharing household expenses and chores.
+- Families coordinating grocery shopping and household tasks.
+- Couples managing shared finances and responsibilities.
+- Groups organizing events or trips involving shared purchases.
-## 4. API Base URL
+### 2. Key Features (V1 Scope)
-The API is versioned. All backend routes are prefixed with `/api/v1/`.
-Example: `http://localhost:8000/api/v1/users/me`
+The Minimum Viable Product (V1) focuses on delivering the core functionalities with a high degree of polish and reliability:
-## 5. Data Model Highlights
+- **User Authentication & Group Management (using `fastapi-users`):**
+ - Secure email/password signup, login, password reset, email verification (leveraging `fastapi-users` features).
+ - Ability to create user groups (e.g., "Home", "Trip").
+ - Invite members to groups via unique, shareable codes/links.
+ - Basic role distinction (Owner, Member) for group administration.
+ - Ability for users to view groups and leave groups.
+- **Shared Shopping List Management:**
+ - CRUD operations for shopping lists (Create, Read, Update, Delete).
+ - Option to create personal lists or share lists with specific groups.
+ - Real-time (or near real-time via polling/basic WebSocket) updates for shared lists.
+ - CRUD operations for items within lists (name, quantity, notes).
+ - Ability to mark items as purchased.
+ - Attribution for who added/completed items in shared lists.
+- **OCR Integration (Gemini 1.5 Flash):**
+ - Capture images (receipts, handwritten lists) via browser (`input capture` / `getUserMedia`).
+ - Backend processing using Google AI API (Gemini 1.5 Flash model) with tailored prompts to extract item names.
+ - User review and edit screen for confirming/correcting extracted items before adding them to the list.
+ - Clear progress indicators and error handling.
+- **Cost Splitting (Traceable):**
+ - Ability to add prices to completed items on a list, recording who added the price and when.
+ - Functionality to trigger an expense calculation for a list based on items with prices.
+ - Creation of immutable `ExpenseRecord` entries detailing the total amount, participants, and calculation time/user.
+ - Generation of `ExpenseShare` entries detailing the amount owed per participant for each `ExpenseRecord`.
+ - Ability for participants to mark their specific `ExpenseShare` as paid, logged via a `SettlementActivity` record for full traceability.
+ - View displaying historical expense records and their settlement status for each list.
+ - V1 focuses on equal splitting among all group members associated with the list at the time of calculation.
+- **Chore Management (Recurring & Assignable):**
+ - CRUD operations for chores within a group context.
+ - Ability to define chores as one-time or recurring (daily, weekly, monthly, custom intervals).
+ - System calculates `next_due_date` based on frequency.
+ - Manual assignment of chores (specific instances/due dates) to group members via `ChoreAssignments`.
+ - Ability for assigned users to mark their specific `ChoreAssignment` as complete.
+ - Automatic update of the parent chore's `last_completed_at` and recalculation of `next_due_date` upon completion of recurring chores.
+ - Dedicated view for users to see their pending assigned chores ("My Chores").
+- **PWA Core Functionality:**
+ - Installable on user devices via `manifest.json`.
+ - Offline access to cached data (lists, items, chores, basic expense info) via Service Workers and IndexedDB.
+ - Background synchronization queue for actions performed offline (adding items, marking complete, adding prices, completing chores).
+ - Basic conflict resolution strategy (e.g., last-write-wins with user notification) for offline data sync.
-Key entities in the MitList system:
+### 3. User Experience (UX) Philosophy
-* **User:** Represents an individual using the application.
-* **Group:** A collection of users for shared lists, chores, and expenses.
-* **UserGroup:** Association table linking users to groups, defining roles (owner, member).
-* **List:** A list of items, can be personal or belong to a group.
-* **Item:** An entry in a list, can have a name, quantity, completion status, and price.
-* **Chore:** A task that can be assigned within a group or to an individual.
-* **ChoreAssignment:** Links a chore to a user and tracks its completion.
-* **Expense (formerly ExpenseRecords):** Records a financial expenditure.
- * Can be linked to a `Group`, `List`, or `Item`.
- * Stores total amount, currency, payer, date, and split type.
- * Contains multiple `ExpenseSplit` records detailing how the expense is divided.
- * **New:** `overall_settlement_status` (e.g., unpaid, partially_paid, paid), derived from the status of its constituent `ExpenseSplit` records.
-* **ExpenseSplit (formerly ExpenseShares):** Details an individual user's share of an `Expense`.
- * Links to an `Expense` and a `User`.
- * Specifies the `owed_amount` for that user.
- * May include `share_percentage` or `share_units` depending on the `Expense` split type.
- * **New:** `status` field (e.g., unpaid, partially_paid, paid).
- * **New:** `paid_at` field (timestamp when the share became fully paid).
- * **New:** Can have multiple `SettlementActivity` records associated with it, detailing payments made towards this share.
-* **Settlement:** Records a generic P2P payment between users within a group, typically used to clear overall balances rather than specific expense shares.
-* **SettlementActivity (New, formerly SettlementActivities):** Records a specific payment made against an `ExpenseSplit`.
- * Links to the `ExpenseSplit`, records who paid (`paid_by_user_id`), when (`paid_at`), and how much (`amount_paid`).
- * This is the primary mechanism for tracking the settlement of individual expense shares.
- * Also records who created the activity (`created_by_user_id`).
+- **User-Centered & Collaborative:** Focus on intuitive workflows for both individual task management and seamless group collaboration. Minimize friction in common tasks like adding items, splitting costs, and completing chores.
+- **Native-like PWA Experience:** Leverage Service Workers, caching (IndexedDB), and `manifest.json` to provide fast loading, reliable offline functionality, and installability, mimicking a native app experience.
+- **Clarity & Accessibility:** Prioritize clear information hierarchy, legible typography, sufficient contrast, and adherence to WCAG accessibility standards for usability by all users. Utilize **Valerie UI** components designed with accessibility in mind.
+- **Informative Feedback:** Provide immediate visual feedback for user actions (loading states, confirmations, animations). Clearly communicate offline status, sync progress, OCR processing status, and data conflicts.
-## 6. Core User Flows (Summarized)
+### 4. Architecture & Technology Stack
-1. **User Onboarding:** Register -> Verify Email (optional) -> Login.
-2. **Group Creation & Management:** Create Group -> Invite Users -> Manage Members/Roles.
-3. **List Creation & Item Management:** Create List (personal or group) -> Add Items -> Mark Items Complete -> (Optional) Add Prices to Items.
-4. **Chore Cycle:** Create Chore -> Assign to Users -> Mark Complete -> Cycle (for recurring chores).
-5. **Cost Splitting Cycle:**
- * User creates an `Expense` linked to a list, group, or item.
- * Defines how the expense is split (e.g., equally among all group members, by specific item assignments).
- * System generates `ExpenseSplit` records for each participant.
- * Users can view their owed shares and the overall status of expenses.
- * View Expense History -> Participants can now select one of their specific `ExpenseSplit` items and record a payment against it. This action creates a `SettlementActivity` record, updating the share's status (and amount remaining). The parent `Expense`'s overall status is also updated.
- * The generic settlement option (`Settlement` model) might still exist for non-expense related payments or for clearing remaining balances shown in the group summary, but the primary way to settle an expense share is now more direct via `SettlementActivity`.
-6. **View Balances:** Users can view their financial balances within a group, considering all expenses and settlements (including Settlement Activities). The system suggests optimal P2P payments to clear outstanding debts.
+- **Frontend:**
+ - **Framework:** Vue.js (Vue 3 with Composition API, built with Vite).
+ - **Styling & UI Components:** **Valerie UI** (as the primary component library and design system).
+ - **State Management:** Pinia (official state management library for Vue).
+ - **PWA:** Vite PWA plugin (leveraging Workbox.js under the hood) for Service Worker generation, manifest management, and caching strategies. IndexedDB for offline data storage.
+- **Backend:**
+ - **Framework:** FastAPI (Python, high-performance, async support, automatic docs).
+ - **Database:** PostgreSQL (reliable relational database with JSONB support).
+ - **ORM:** SQLAlchemy (version 2.0+ with native async support).
+ - **Migrations:** Alembic (for managing database schema changes).
+ - **Authentication & User Management:** **`fastapi-users`** (handles user models, password hashing, JWT/cookie authentication, and core auth endpoints like signup, login, password reset, email verification).
+- **Cloud Services & APIs:**
+ - **OCR:** Google AI API (using `gemini-1.5-flash-latest` model).
+ - **Hosting (Backend):** Containerized deployment (Docker) on cloud platforms like Google Cloud Run, AWS Fargate, or DigitalOcean App Platform.
+ - **Hosting (Frontend):** Static hosting platforms like Vercel, Netlify, or Cloudflare Pages (optimized for Vite-built Vue apps).
+- **DevOps & Monitoring:**
+ - **Version Control:** Git (hosted on GitHub, GitLab, etc.).
+ - **Containerization:** Docker & Docker Compose (for local development and deployment consistency).
+ - **CI/CD:** GitHub Actions (or similar) for automated testing and deployment pipelines (using Vite build commands for frontend).
+ - **Error Tracking:** Sentry (or similar) for real-time error monitoring.
+ - **Logging:** Standard Python logging configured within FastAPI.
-## 7. API Endpoint Highlights (Illustrative)
+### 5. Data Model Highlights
-* **Authentication:** `/auth/register`, `/auth/jwt/login`, `/auth/jwt/refresh`, `/auth/request-verify-token`, `/auth/verify`
-* **Groups:** `POST /groups`, `GET /groups/{group_id}`, `POST /groups/{group_id}/members`
-* **Lists:** `POST /lists`, `GET /lists/{list_id}`, `POST /lists/{list_id}/items`
-* **Items:** `PUT /items/{item_id}` (e.g., to update price)
-* **Expenses:** `POST /financials/expenses`, `GET /financials/expenses/{expense_id}`
-* **ExpenseSplits & Settlement Activities (New):**
- * `POST /expense_splits/{expense_split_id}/settle` (Creates a `SettlementActivity`)
- * `GET /expense_splits/{expense_split_id}/settlement_activities`
-* **Settlements (Generic):** `POST /financials/settlements`, `GET /financials/settlements/{settlement_id}`
-* **Costs & Balances:** `GET /costs/groups/{group_id}/balance-summary`
+Key database tables supporting the application's features:
-## Frontend Implementation Notes & TODOs
+- `Users`: Stores user account information. The schema will align with `fastapi-users` requirements (e.g., `id`, `email`, `hashed_password`, `is_active`, `is_superuser`, `is_verified`), with potential custom fields added as needed.
+- `Groups`: Defines shared groups (name, owner).
+- `UserGroups`: Many-to-many relationship linking users to groups with roles (owner/member).
+- `Lists`: Stores shopping list details (name, description, creator, associated group, completion status).
+- `Items`: Stores individual shopping list items (name, quantity, price, completion status, list association, user attribution for adding/pricing).
+- `ExpenseRecords`: Logs each instance of a cost split calculation for a list (total amount, participants, calculation time/user, overall settlement status).
+- `ExpenseShares`: Details the amount owed by each participant for a specific `ExpenseRecord` (links to user and record, amount, paid status).
+- `SettlementActivities`: Records every action taken to mark an `ExpenseShare` as paid (links to record, payer, affected user, timestamp).
+- `Chores`: Defines chore templates (name, description, group association, recurrence rules, next due date).
+- `ChoreAssignments`: Tracks specific instances of chores assigned to users (links to chore, user, due date, completion status).
-The backend for traceable expense splitting and settlement activity logging has been fully implemented and tested.
+### 6. Core User Flows (Summarized)
-Frontend development encountered tool limitations preventing the full integration of the "Settle Share" feature into existing components.
+- **Onboarding:** Signup/Login (via `fastapi-users` flow) -> Optional guided tour -> Create/Join first group -> Dashboard.
+- **List Creation & Sharing:** Create List -> Choose Personal or Share with Group -> List appears on dashboard (and shared members' dashboards).
+- **Adding Items (Manual):** Open List -> Type item name -> Item added.
+- **Adding Items (OCR):** Open List -> Tap "Add via Photo" -> Capture/Select Image -> Upload/Process (Gemini) -> Review/Edit extracted items -> Confirm -> Items added to list.
+- **Shopping & Price Entry:** Open List -> Check off items -> Enter price for completed items -> Price saved.
+- **Cost Splitting Cycle:** View List -> Click "Calculate Split" -> Backend creates traceable `ExpenseRecord` & `ExpenseShares` -> View Expense History -> Participants mark their shares paid (creating `SettlementActivity`).
+- **Chore Cycle:** Create Chore (define recurrence) -> Chore appears in group list -> (Manual Assignment) Assign chore instance to user -> User views "My Chores" -> User marks assignment complete -> Backend updates status and recalculates next due date for recurring chores.
+- **Offline Usage:** Open app offline -> View cached lists/chores -> Add/complete items/chores -> Changes queued -> Go online -> Background sync processes queue -> UI updates, conflicts notified.
-**Completed Frontend Foundation:**
+### 7. Development Roadmap (Phase Summary)
-* TypeScript interfaces for all new/updated models (`SettlementActivity`, `ExpenseSplit` statuses, etc.) have been created (`fe/src/types/`).
-* A Pinia store (`listDetailStore.ts`) has been set up to manage expense data, including fetching settlement activities and calculating paid amounts for shares. It includes an action `settleExpenseSplit` (with a placeholder for the direct API call due to tool issues experienced during development).
-* A new `SettleShareModal.vue` component (`fe/src/components/`) has been created to capture payment confirmation for a share. This component is designed to handle the UI aspects of the settlement.
-* Unit tests for `SettleShareModal.vue` and the `listDetailStore.ts` (focusing on the `settleExpenseSplit` action's logic flow and getters) have been implemented.
-* The `ListDetailPage.vue` has been updated to display the detailed status of expenses and shares, including amounts paid via settlement activities. (This refers to the successful overwrite of `ListDetailPage.vue` in subtask 10, which integrated the display logic from subtask 7).
+1. **Phase 1: Planning & Design:** User stories, flows, sharing/sync models, tech stack, architecture, schema design.
+2. **Phase 2: Core App Setup:** Project initialization (Git, **Vue.js with Vite**, FastAPI), DB connection (SQLAlchemy/Alembic), basic PWA config (**Vite PWA plugin**, manifest, SW), **Valerie UI integration**, **Pinia setup**, Docker setup, CI checks.
+3. **Phase 3: User Auth & Group Management:** Backend: Integrate **`fastapi-users`**, configure its routers, adapt user model. Frontend: Implement auth pages using **Vue components**, **Pinia for auth state**, and calling `fastapi-users` endpoints. Implement Group Management features.
+4. **Phase 4: Shared Shopping List CRUD:** Backend/Frontend for List/Item CRUD, permissions, basic real-time updates (polling), offline sync refinement for lists/items.
+5. **Phase 5: OCR Integration (Gemini Flash):** Backend integration with Google AI SDK, image capture/upload UI, OCR processing endpoint, review/edit screen, integration with list items.
+6. **Phase 6: Cost Splitting (Traceable):** Backend/Frontend for adding prices, calculating splits (creating historical records), viewing expense history, marking shares paid (with activity logging).
+7. **Phase 7: Chore Splitting Module:** Backend/Frontend for Chore CRUD (including recurrence), manual assignment, completion tracking, "My Chores" view, recurrence handling logic.
+8. **Phase 8: Testing, Refinement & Beta Launch:** Comprehensive E2E testing, usability testing, accessibility checks, performance tuning, deployment to beta environment, feedback collection.
+9. **Phase 9: Final Release & Post-Launch Monitoring:** Address beta feedback, final deployment to production, setup monitoring (errors, performance, costs).
-**Frontend TODOs (Due to Tooling Issues):**
+_(Estimated Total Duration: Approx. 17-19 Weeks for V1)_
-1. **Integrate `settleExpenseSplit` API Call:**
- * The `apiClient.settleExpenseSplit` function needs to be successfully added to `fe/src/services/api.ts`. The complete code for this function has been defined and attempted multiple times but failed to save due to tool errors ("Edit failed." without specific reasons). The intended code is:
- ```typescript
- // In fe/src/services/api.ts, within the apiClient object:
- settleExpenseSplit: (expenseSplitId: number, activityData: SettlementActivityCreate): Promise => {
- const endpoint = `/api/v1/expense_splits/${expenseSplitId}/settle`;
- return api.post(endpoint, activityData).then((response: AxiosResponse) => response.data);
- }
- ```
- * Once `api.ts` is updated, the placeholder in `listDetailStore.ts`'s `settleExpenseSplit` action should be replaced with the actual call to `apiClient.settleExpenseSplit`.
+### 8. Risk Management & Mitigation
-2. **Integrate Modal into `ListDetailPage.vue`:**
- * The reactive variables and methods for launching and handling the `SettleShareModal.vue` from `ListDetailPage.vue` need to be manually integrated. The core logic for these was defined as:
- ```typescript
- // --- Refs to be added to ListDetailPage.vue ---
- // import { useAuthStore } from '@/stores/auth';
- // import { Decimal } from 'decimal.js';
- // import type { SettlementActivityCreate } from '@/types/expense';
+- **Collaboration Complexity:** (Risk) Permissions and real-time sync can be complex. (Mitigation) Start simple, test permissions thoroughly, use clear data models.
+- **OCR Accuracy/Cost (Gemini):** (Risk) OCR isn't perfect; API calls have costs/quotas. (Mitigation) Use capable model (Gemini Flash), mandatory user review step, clear error feedback, monitor API usage/costs, secure API keys.
+- **Offline Sync Conflicts:** (Risk) Concurrent offline edits can clash. (Mitigation) Implement defined strategy (last-write-wins + notify), robust queue processing, thorough testing of conflict scenarios.
+- **PWA Consistency:** (Risk) Behavior varies across browsers/OS (esp. iOS). (Mitigation) Rigorous cross-platform testing, use standard tools (Vite PWA plugin/Workbox), follow best practices.
+- **Traceability Overhead:** (Risk) Storing detailed history increases DB size/complexity. (Mitigation) Design efficient queries, use appropriate indexing, plan for potential data archiving later.
+- **User Adoption:** (Risk) Users might not consistently use groups/features. (Mitigation) Smooth onboarding, clear value proposition, reliable core features.
+- **Valerie UI Maturity/Flexibility:** (Risk, if "Valerie UI" is niche or custom) Potential limitations in component availability or customization. (Mitigation) Thoroughly evaluate Valerie UI early, have fallback styling strategies if needed, or contribute to/extend the library.
- // const authStore = useAuthStore();
- // const showSettleModal = ref(false);
- // const settleModalRef = ref(null); // For onClickOutside if used
- // const selectedSplitForSettlement = ref(null);
- // const parentExpenseOfSelectedSplit = ref(null);
- // const settleAmount = ref(''); // Bound to input
- // const settleAmountError = ref(null);
- // const isSettlementLoading = computed(() => listDetailStore.isSettlingSplit); // From store
+### 9. Testing Strategy
- // --- Methods to be added to ListDetailPage.vue ---
- // const openSettleShareModal = (expense: Expense, split: ExpenseSplit) => {
- // if (split.user_id !== authStore.user?.id) {
- // notificationStore.addNotification({ message: "You can only settle your own shares.", type: 'warning' });
- // return;
- // }
- // selectedSplitForSettlement.value = split;
- // parentExpenseOfSelectedSplit.value = expense;
- // const alreadyPaid = new Decimal(listDetailStore.getPaidAmountForSplit(split.id));
- // const owed = new Decimal(split.owed_amount);
- // const remaining = owed.minus(alreadyPaid);
- // settleAmount.value = remaining.toFixed(2);
- // settleAmountError.value = null;
- // showSettleModal.value = true;
- // };
+- **Unit Tests:** Backend logic (calculations, permissions, recurrence), Frontend component logic (**Vue Test Utils** for Vue components, Pinia store testing).
+- **Integration Tests:** Backend API endpoints interacting with DB and external APIs (Gemini - mocked).
+- **End-to-End (E2E) Tests:** (Playwright/Cypress) Simulate full user flows across features.
+- **PWA Testing:** Manual and automated checks for installability, offline functionality (caching, sync queue), cross-browser/OS compatibility.
+- **Accessibility Testing:** Automated tools (axe-core) + manual checks (keyboard nav, screen readers), leveraging **Valerie UI's** accessibility features.
+- **Usability Testing:** Regular sessions with target users throughout development.
+- **Security Testing:** Basic checks (OWASP Top 10 awareness), dependency scanning, secure handling of secrets/tokens (rely on `fastapi-users` security practices).
+- **Manual Testing:** Exploratory testing, edge case validation, testing diverse OCR inputs.
- // const closeSettleShareModal = () => {
- // showSettleModal.value = false;
- // selectedSplitForSettlement.value = null;
- // parentExpenseOfSelectedSplit.value = null;
- // settleAmount.value = '';
- // settleAmountError.value = null;
- // };
+### 10. Future Enhancements (Post-V1)
- // // onClickOutside(settleModalRef, closeSettleShareModal); // If using ref on modal
+- Advanced Cost Splitting (by item, percentage, unequal splits).
+- Payment Integration (Stripe Connect for settling debts).
+- Real-time Collaboration (WebSockets for instant updates).
+- Push Notifications (reminders for chores, expenses, list updates).
+- Advanced Chore Features (assignment algorithms, calendar view).
+- Enhanced OCR (handling more formats, potential fine-tuning).
+- User Profile Customization (avatars, etc., extending `fastapi-users` model).
+- Analytics Dashboard (spending insights, chore completion stats).
+- Recipe Integration / Pantry Inventory Tracking.
- // const validateSettleAmount = (): boolean => {
- // settleAmountError.value = null;
- // if (!settleAmount.value.trim()) {
- // settleAmountError.value = 'Please enter an amount.';
- // return false;
- // }
- // const amount = new Decimal(settleAmount.value);
- // if (amount.isNaN() || amount.isNegative() || amount.isZero()) {
- // settleAmountError.value = 'Please enter a positive amount.';
- // return false;
- // }
- // if (selectedSplitForSettlement.value) {
- // const alreadyPaid = new Decimal(listDetailStore.getPaidAmountForSplit(selectedSplitForSettlement.value.id));
- // const owed = new Decimal(selectedSplitForSettlement.value.owed_amount);
- // const remaining = owed.minus(alreadyPaid);
- // if (amount.greaterThan(remaining.plus(new Decimal('0.001')))) { // Epsilon for float issues
- // settleAmountError.value = `Amount cannot exceed remaining: ${formatCurrency(remaining.toFixed(2))}.`;
- // return false;
- // }
- // } else {
- // settleAmountError.value = 'Error: No split selected.'; // Should not happen
- // return false;
- // }
- // return true;
- // };
-
- // const currentListIdForRefetch = computed(() => listDetailStore.currentList?.id);
+### 11. Conclusion
- // const handleConfirmSettle = async (amountFromModal: number) => { // Amount from modal event
- // if (!selectedSplitForSettlement.value || !authStore.user?.id || !currentListIdForRefetch.value) {
- // notificationStore.addNotification({ message: 'Cannot process settlement: missing data.', type: 'error' });
- // return;
- // }
- // // Use amountFromModal which is the confirmed amount (remaining amount for MVP)
- // const activityData: SettlementActivityCreate = {
- // expense_split_id: selectedSplitForSettlement.value.id,
- // paid_by_user_id: authStore.user.id,
- // amount_paid: new Decimal(amountFromModal).toString(),
- // paid_at: new Date().toISOString(),
- // };
-
- // const success = await listDetailStore.settleExpenseSplit({
- // list_id_for_refetch: String(currentListIdForRefetch.value),
- // expense_split_id: selectedSplitForSettlement.value.id,
- // activity_data: activityData,
- // });
-
- // if (success) {
- // notificationStore.addNotification({ message: 'Share settled successfully!', type: 'success' });
- // closeSettleShareModal();
- // } else {
- // notificationStore.addNotification({ message: listDetailStore.error || 'Failed to settle share.', type: 'error' });
- // }
- // };
- ```
- * This includes adding `` to the template.
- * Connecting the `openSettleShareModal` method to a "Settle My Share" button on each relevant expense split.
-
-3. **E2E Testing:** End-to-end tests for the complete 'Settle Share' user flow need to be created once the UI integration is complete.
-4. **Styling and UX Refinements:** Further styling and UX refinements for the settlement modal and display of share statuses based on user feedback.
-
-## 8. Future Considerations
-
-* Enhanced offline support for all modules.
-* Real-time updates using WebSockets.
-* Advanced reporting and analytics.
-* Budgeting features.
-* Support for multiple currencies with conversion.## Subtask Report
-
-**Subtask Description:** Update the `mitlist_doc.md` file to reflect the implemented backend changes for traceable cost splitting and to document the current state of the frontend implementation, including a TODO list for incomplete frontend parts.
-
-**Summary of Actions:**
-
-1. **Read `mitlist_doc.md`**: The existing content of the documentation file was read to prepare for updates.
-2. **Constructed Updated Content**: Based on the subtask instructions, the following sections were updated or added:
- * **Section 5: Data Model Highlights**:
- * Renamed `SettlementActivities` to `SettlementActivity`.
- * Updated the description for `SettlementActivity` to clarify its role in recording payments against `ExpenseSplit` records.
- * In `ExpenseSplit` (referred to as `ExpenseShares` in the doc):
- * Added `status` and `paid_at` fields.
- * Noted its association with multiple `SettlementActivity` records.
- * In `Expense` (referred to as `ExpenseRecords` in the doc):
- * Added `overall_settlement_status` field.
- * **Section 6: Core User Flows (Summarized)**:
- * Updated the "Cost Splitting Cycle" to reflect that participants can now record payments against specific `ExpenseSplit` items, creating `SettlementActivity` records and updating statuses.
- * **New Section: "Frontend Implementation Notes & TODOs"**:
- * This new section was added after the main documentation.
- * It explains that the backend changes for traceable expense splitting are complete and tested.
- * It details the frontend development status, noting that tool limitations prevented full integration of the "Settle Share" feature.
- * **Completed Frontend Foundation**: Lists the TypeScript interfaces, the Pinia store setup (`listDetailStore.ts`), the creation of `SettleShareModal.vue`, unit tests for the modal and store, and the successful update to `ListDetailPage.vue` for displaying new statuses.
- * **Frontend TODOs (Due to Tooling Issues)**: This subsection clearly lists the remaining tasks:
- 1. **Integrate `settleExpenseSplit` API Call**: Details the need to add the `apiClient.settleExpenseSplit` function to `fe/src/services/api.ts` and update the placeholder in `listDetailStore.ts`. The intended TypeScript code for the API client function was embedded.
- 2. **Integrate Modal into `ListDetailPage.vue`**: Explains the need to add the reactive variables and methods (with embedded example code for `setup` scope) to `ListDetailPage.vue` to manage the `SettleShareModal.vue`, including adding the modal tag to the template and connecting event handlers.
- 3. **E2E Testing**: Notes the need for end-to-end tests post-integration.
- 4. **Styling and UX Refinements**: Mentions further refinements.
-3. **Tool Usage**:
- * Used `overwrite_file_with_block` to apply the comprehensive changes to `mitlist_doc.md`.
-
-**Outcome:** The `mitlist_doc.md` file was successfully updated to reflect the backend changes and the current status of the frontend implementation, including a detailed TODO list for the remaining frontend work, with specific code examples provided for clarity. The explanation for the incomplete frontend parts neutrally attributes the cause to tooling limitations encountered during development.
-
-**Succeeded**: True
+This project aims to deliver a modern, user-friendly PWA that effectively addresses common household coordination challenges. By combining collaborative list management, intelligent OCR, traceable expense splitting, and flexible chore tracking with a robust offline-first PWA architecture built on **Vue.js, Pinia, Valerie UI, and FastAPI with `fastapi-users`**, the application will provide significant value to roommates, families, and other shared living groups. The focus on a well-defined V1, traceable data, and a solid technical foundation sets the stage for future growth and feature expansion.