mitlist/mitlist_doc.md
google-labs-jules[bot] f1152c5745 feat: Implement traceable expense splitting and settlement activities
Backend:
- Added `SettlementActivity` model to track payments against specific expense shares.
- Added `status` and `paid_at` to `ExpenseSplit` model.
- Added `overall_settlement_status` to `Expense` model.
- Implemented CRUD for `SettlementActivity`, including logic to update parent expense/split statuses.
- Updated `Expense` CRUD to initialize new status fields.
- Defined Pydantic schemas for `SettlementActivity` and updated `Expense/ExpenseSplit` schemas.
- Exposed API endpoints for creating/listing settlement activities and settling shares.
- Adjusted group balance summary logic to include settlement activities.
- Added comprehensive backend unit and API tests for new functionality.

Frontend (Foundation & TODOs due to my current capabilities):
- Created TypeScript interfaces for all new/updated models.
- Set up `listDetailStore.ts` with an action to handle `settleExpenseSplit` (API call is a placeholder) and refresh data.
- Created `SettleShareModal.vue` component for payment confirmation.
- Added unit tests for the new modal and store logic.
- Updated `ListDetailPage.vue` to display detailed expense/share statuses and settlement activities.
- `mitlist_doc.md` updated to reflect all backend changes and current frontend status.
- A `TODO.md` (implicitly within `mitlist_doc.md`'s new section) outlines necessary manual frontend integrations for `api.ts` and `ListDetailPage.vue` to complete the 'Settle Share' UI flow.

This set of changes provides the core backend infrastructure for precise expense share tracking and settlement, and lays the groundwork for full frontend integration.
2025-05-22 07:05:31 +00:00

18 KiB

MitList - Collaborative List Management & Cost Splitting

Version: 1.1.0 Last Updated: {{Current Date}}

1. Introduction

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.

2. Core Features

  • 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.

3. Technology Stack

  • Backend: Python (FastAPI)
  • Database: PostgreSQL (relational)
  • Frontend: Vue.js (Quasar Framework)
  • Authentication: JWT

4. API Base URL

The API is versioned. All backend routes are prefixed with /api/v1/. Example: http://localhost:8000/api/v1/users/me

5. Data Model Highlights

Key entities in the MitList system:

  • 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).

6. Core User Flows (Summarized)

  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.

7. API Endpoint Highlights (Illustrative)

  • 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

Frontend Implementation Notes & TODOs

The backend for traceable expense splitting and settlement activity logging has been fully implemented and tested.

Frontend development encountered tool limitations preventing the full integration of the "Settle Share" feature into existing components.

Completed Frontend Foundation:

  • 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).

Frontend TODOs (Due to Tooling Issues):

  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:
      // In fe/src/services/api.ts, within the apiClient object:
      settleExpenseSplit: (expenseSplitId: number, activityData: SettlementActivityCreate): Promise<SettlementActivity> => {
        const endpoint = `/api/v1/expense_splits/${expenseSplitId}/settle`; 
        return api.post(endpoint, activityData).then((response: AxiosResponse<SettlementActivity>) => 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.
  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:
      // --- Refs to be added to ListDetailPage.vue ---
      // import { useAuthStore } from '@/stores/auth';
      // import { Decimal } from 'decimal.js';
      // import type { SettlementActivityCreate } from '@/types/expense';
      
      // const authStore = useAuthStore();
      // const showSettleModal = ref(false);
      // const settleModalRef = ref<HTMLElement | null>(null); // For onClickOutside if used
      // const selectedSplitForSettlement = ref<ExpenseSplit | null>(null);
      // const parentExpenseOfSelectedSplit = ref<Expense | null>(null);
      // const settleAmount = ref<string>(''); // Bound to input
      // const settleAmountError = ref<string | null>(null);
      // const isSettlementLoading = computed(() => listDetailStore.isSettlingSplit); // From store
      
      // --- 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;
      // };
      
      // const closeSettleShareModal = () => {
      //   showSettleModal.value = false;
      //   selectedSplitForSettlement.value = null;
      //   parentExpenseOfSelectedSplit.value = null;
      //   settleAmount.value = '';
      //   settleAmountError.value = null;
      // };
      
      // // onClickOutside(settleModalRef, closeSettleShareModal); // If using ref on modal
      
      // 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);
      
      // 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 <SettleShareModal :show="showSettleModal" :split="selectedSplitForSettlement" :paid-amount="currentPaidAmountForModal" :is-loading="isSettlementLoading" @confirm="handleConfirmSettle" @cancel="closeSettleShareModal" /> 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