### Docker Deployment (Bash) Source: https://context7.com/rjdmacedo/knots/llms.txt Commands for building and running the Knots application using Docker. It includes instructions for building the Docker image, configuring environment variables via `container.env`, and starting the PostgreSQL and application containers. Assumes Docker and npm are installed. ```bash # Build the Docker image npm run build-image # Configure container environment cp container.env.example container.env # Edit container.env with your settings # Start PostgreSQL and Knots containers npm run start-container # Access the application # http://localhost:3000 # Docker Compose includes: # - PostgreSQL database with automatic schema migrations # - Knots web application # - Volume mounts for persistent data # - Health checks for monitoring ``` -------------------------------- ### Docker Deployment Source: https://context7.com/rjdmacedo/knots/llms.txt Instructions for deploying Knots using Docker containers, including building the image, configuring the environment, and starting the services. ```APIDOC ## Docker Deployment ### Description Deploy Knots using Docker containers. ### Steps: 1. **Build the Docker image:** ```bash npm run build-image ``` 2. **Configure container environment:** Copy the example environment file and edit it with your settings: ```bash cp container.env.example container.env # Edit container.env ``` 3. **Start PostgreSQL and Knots containers:** ```bash npm run start-container ``` ### Access the application: `http://localhost:3000` ### Docker Compose includes: - PostgreSQL database with automatic schema migrations - Knots web application - Volume mounts for persistent data - Health checks for monitoring ``` -------------------------------- ### GET /groups/balances/list Source: https://context7.com/rjdmacedo/knots/llms.txt Fetches pre-calculated balance information showing who owes whom in a group. ```APIDOC ## GET /groups/balances/list ### Description Retrieve calculated balances for all participants in a group, showing net amounts owed or due. ### Method GET ### Endpoint /groups/balances/list ### Parameters #### Query Parameters - **groupId** (string) - Required - The ID of the group whose balances to calculate. ### Response #### Success Response (200) - Returns an object mapping participant IDs to their balance information. - **paid** (number) - Total amount paid by participant in cents. - **paidFor** (number) - Total share of expenses for participant in cents. - **total** (number) - Net balance (positive = owed to participant, negative = owes). #### Response Example { "participant-alice-id": { "paid": 50000, "paidFor": 30000, "total": 20000 }, "participant-bob-id": { "paid": 20000, "paidFor": 35000, "total": -15000 }, "participant-charlie-id": { "paid": 30000, "paidFor": 35000, "total": -5000 } } ``` -------------------------------- ### Environment Configuration (.env file) Source: https://context7.com/rjdmacedo/knots/llms.txt Defines essential environment variables for configuring the Knots deployment. This includes database connection strings, default currency, and settings for optional features like document uploads, AI receipt scanning, and category suggestions, with examples for AWS S3 and MinIO. ```bash # .env file configuration # Database (Required) POSTGRES_PRISMA_URL=postgresql://postgres:password@localhost:5432/knots POSTGRES_URL_NON_POOLING=postgresql://postgres:password@localhost:5432/knots # Default currency for new groups NEXT_PUBLIC_DEFAULT_CURRENCY_CODE=USD # Enable expense document uploads (Optional) NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS=true S3_UPLOAD_KEY=AKIAIOSFODNN7EXAMPLE S3_UPLOAD_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY S3_UPLOAD_BUCKET=knots-expense-documents S3_UPLOAD_REGION=us-east-1 S3_UPLOAD_ENDPOINT=https://s3.us-east-1.amazonaws.com # Alternative: Use MinIO instead of AWS S3 S3_UPLOAD_ENDPOINT=http://minio:9000 # Enable AI receipt scanning (Optional - requires S3) NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT=true OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx # Enable AI category suggestions (Optional) NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT=true OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx ``` -------------------------------- ### Calculate Group Balances from Expenses in TypeScript Source: https://context7.com/rjdmacedo/knots/llms.txt This example computes participant balances and suggests reimbursements based on a list of group expenses fetched via tRPC. It relies on custom utility functions getBalances and getSuggestedReimbursements, with inputs being expense data and outputs including balance objects (paid, paidFor, total) and reimbursement suggestions minimizing transactions. Limitations include client-side calculation which may be inefficient for large datasets and assumes expenses are already loaded. ```typescript import { getBalances, getSuggestedReimbursements } from '@/lib/balances' import { trpc } from '@/trpc/client' const BalanceCalculationExample = () => { const { data: expenses } = trpc.groups.expenses.list.useQuery({ groupId: 'group-123' }) if (!expenses) return
Loading...
// Calculate balances from expenses const balances = getBalances(expenses) // Example balances result: // { // "participant-alice-id": { paid: 50000, paidFor: 30000, total: 20000 }, // "participant-bob-id": { paid: 20000, paidFor: 35000, total: -15000 }, // "participant-charlie-id": { paid: 30000, paidFor: 35000, total: -5000 } // } // Get optimized reimbursement suggestions const reimbursements = getSuggestedReimbursements(balances) // Result minimizes number of transactions: // [ // { from: "participant-bob-id", to: "participant-alice-id", amount: 15000 }, // { from: "participant-charlie-id", to: "participant-alice-id", amount: 5000 } // ] return (

Who Owes What

{Object.entries(balances).map(([participantId, balance]) => (

Paid: ${(balance.paid / 100).toFixed(2)}

Share: ${(balance.paidFor / 100).toFixed(2)}

{balance.total > 0 ? `Owed $${(balance.total / 100).toFixed(2)}` : `Owes $${(Math.abs(balance.total) / 100).toFixed(2)}` }

))}

Suggested Payments

{reimbursements.map((reimb, idx) => (
{reimb.from} should pay {reimb.to}: ${(reimb.amount / 100).toFixed(2)}
))}
) } ``` -------------------------------- ### List Group Expenses with Filtering in TypeScript Source: https://context7.com/rjdmacedo/knots/llms.txt This example retrieves and renders a table of all group expenses using tRPC, including details like date, title, payer, amount, and split mode, with reimbursement marking. It requires the tRPC client for the groups.expenses.list query, inputs groupId, and outputs an array of expense objects. Limitations include basic rendering without pagination or advanced filtering, and handles optional original currency. ```typescript import { trpc } from '@/trpc/client' const ExpenseListExample = () => { const { data: expenses, isLoading } = trpc.groups.expenses.list.useQuery({ groupId: 'group-123' }) if (isLoading) return
Loading expenses...
return ( {expenses?.map(expense => ( ))}
Date Title Paid By Amount Split
{new Date(expense.expenseDate).toLocaleDateString()} {expense.title} {expense.isReimbursement && (Reimbursement)} {expense.paidBy.name} {expense.originalCurrency ? `${expense.originalCurrency} ${(expense.originalAmount! / 100).toFixed(2)}` : `$${(expense.amount / 100).toFixed(2)}` } {expense.splitMode}
) } ``` -------------------------------- ### Create Expense with Percentage Split (TypeScript) Source: https://context7.com/rjdmacedo/knots/llms.txt This example shows how to create an expense split by custom percentages. It utilizes the `trpc.groups.expenses.create.useMutation` hook and specifies `splitMode: "BY_PERCENTAGE"`. The `shares` field represents percentages multiplied by 100, and the sum of shares must equal 10000 (100%). ```typescript import { trpc } from '@/trpc/client' const PercentageSplitExample = () => { const createExpense = trpc.groups.expenses.create.useMutation() const handlePercentageExpense = async (groupId: string) => { await createExpense.mutateAsync({ groupId: groupId, expenseFormValues: { title: "Rental Car for Road Trip", amount: 60000, // $600.00 expenseDate: new Date(), category: 8, // Transportation paidBy: "participant-bob-id", paidFor: [ { participant: "participant-alice-id", shares: 5000 }, // 50% = $300 { participant: "participant-bob-id", shares: 3000 }, // 30% = $180 { participant: "participant-charlie-id", shares: 2000 } // 20% = $120 ], splitMode: "BY_PERCENTAGE", // Shares represent percentages * 100 isReimbursement: false, saveDefaultSplittingOptions: false, documents: [], recurrenceRule: "NONE" } }) // Total must equal 10000 (100.00%) } return } ``` -------------------------------- ### Create Expense with Multi-Currency Conversion (TypeScript) Source: https://context7.com/rjdmacedo/knots/llms.txt This example demonstrates creating an expense in a different currency than the group's default currency, with automatic conversion. It uses the `trpc.groups.expenses.create.useMutation` hook and includes `originalAmount`, `originalCurrency`, and `conversionRate` fields. The expense is stored in the group's currency, but the original details are preserved. ```typescript import { trpc } from '@/trpc/client' const MultiCurrencyExpenseExample = () => { const createExpense = trpc.groups.expenses.create.useMutation() const handleMultiCurrencyExpense = async (groupId: string) => { // Group uses USD, but expense was in EUR await createExpense.mutateAsync({ groupId: groupId, // Group with currency: "$" and currencyCode: "USD" expenseFormValues: { title: "Museum Tickets in Paris", amount: 4591, // $45.91 USD (converted amount in cents) originalAmount: 4200, // €42.00 EUR (original amount in cents) originalCurrency: "EUR", conversionRate: 1.093, // 1 EUR = 1.093 USD expenseDate: new Date(), category: 10, // Entertainment paidBy: "participant-alice-id", paidFor: [ { participant: "participant-alice-id", shares: 1 }, { participant: "participant-bob-id", shares: 1 } ], splitMode: "EVENLY", isReimbursement: false, saveDefaultSplittingOptions: false, documents: [], recurrenceRule: "NONE" } }) // Expense shown as €42.00, calculated in group's USD currency } return } ``` -------------------------------- ### Create Expense with Uneven Split by Amount (TypeScript) Source: https://context7.com/rjdmacedo/knots/llms.txt This example demonstrates how to create an expense that is split among participants based on exact amounts. It uses the `trpc.groups.expenses.create.useMutation` hook and requires `groupId` and `expenseFormValues` including `splitMode: "BY_AMOUNT"` and specific `shares` for each participant. ```typescript import { trpc } from '@/trpc/client' const UnevenSplitExample = () => { const createExpense = trpc.groups.expenses.create.useMutation() const handleUnevenExpense = async (groupId: string) => { await createExpense.mutateAsync({ groupId: groupId, expenseFormValues: { title: "Hotel Room - 3 nights", amount: 45000, // $450.00 total expenseDate: new Date(), category: 6, // Accommodation category paidBy: "participant-alice-id", paidFor: [ { participant: "participant-alice-id", shares: 15000 }, // Alice: $150 { participant: "participant-bob-id", shares: 20000 }, // Bob: $200 { participant: "participant-charlie-id", shares: 10000 } // Charlie: $100 ], splitMode: "BY_AMOUNT", // Exact amounts mode isReimbursement: false, saveDefaultSplittingOptions: false, documents: [], recurrenceRule: "NONE" } }) // Alice paid $450 but owes $150, so she's owed $300 // Bob owes $200, Charlie owes $100 } return } ``` -------------------------------- ### Get Group Activity Feed (TypeScript) Source: https://context7.com/rjdmacedo/knots/llms.txt Fetches and displays the activity feed for a specific group using TRPC. It handles different activity types like creating, updating, and deleting expenses, as well as group updates. Requires TRPC client setup and a valid groupId. ```typescript import { trpc } from '@/trpc/client' const ActivityFeedExample = () => { const { data: activities } = trpc.groups.activities.list.useQuery({ groupId: 'group-123' }) return (

Recent Activity

{activities?.map(activity => { const timestamp = new Date(activity.time).toLocaleString() let description = '' switch (activity.activityType) { case 'CREATE_EXPENSE': description = `Created expense: ${activity.expenseId}` break case 'UPDATE_EXPENSE': description = `Updated expense: ${activity.expenseId}` break case 'DELETE_EXPENSE': description = `Deleted expense: ${activity.expenseId}` break case 'UPDATE_GROUP': description = 'Updated group information' break } return (

{description}

{activity.data &&
{activity.data}
}
) })}
) } ``` -------------------------------- ### GET /groups/expenses/list Source: https://context7.com/rjdmacedo/knots/llms.txt Retrieves all expenses for a specified group, including regular expenses and reimbursements. ```APIDOC ## GET /groups/expenses/list ### Description Fetch all expenses recorded for a specific group, with optional filtering capabilities. ### Method GET ### Endpoint /groups/expenses/list ### Parameters #### Query Parameters - **groupId** (string) - Required - The ID of the group whose expenses to list. ### Response #### Success Response (200) - Returns an array of expense objects with full details including dates, amounts, participants, and reimbursement status. #### Response Example [ { "id": "expense-123", "groupId": "group-123", "title": "Dinner at Italian Restaurant", "amount": 12500, "expenseDate": "2023-01-10T00:00:00.000Z", "paidBy": "participant-alice-id", "paidFor": [ { "participant": "participant-alice-id", "shares": 5000 }, { "participant": "participant-bob-id", "shares": 5000 }, { "participant": "participant-charlie-id", "shares": 2500 } ], "isReimbursement": false, "createdAt": "2023-01-10T20:15:30.000Z" }, { "id": "expense-456", "title": "Bob pays Alice back for groceries", "amount": 7500, "expenseDate": "2023-01-15T00:00:00.000Z", "paidBy": "participant-bob-id", "paidFor": [ { "participant": "participant-alice-id", "shares": 7500 } ], "isReimbursement": true, "createdAt": "2023-01-15T12:34:56.789Z" } ] ``` -------------------------------- ### GET /groups/list Source: https://context7.com/rjdmacedo/knots/llms.txt Retrieves a list of all expense groups accessible to the authenticated user. This endpoint is used to display all groups the user is a part of. ```APIDOC ## GET /groups/list ### Description Retrieve all expense groups accessible to the user. ### Method GET ### Endpoint /groups/list ### Parameters None ### Request Example (No request body needed for GET request) ### Response #### Success Response (200) - **groups** (array) - A list of group objects. - **id** (string) - The unique identifier for the group. - **name** (string) - The name of the group. - **currency** (string) - The currency symbol of the group. - **participants** (array) - A list of participants in the group. - **name** (string) - The name of the participant. - **createdAt** (string) - The date and time the group was created (ISO format). #### Response Example ```json [ { "id": "group-123", "name": "European Vacation 2025", "currency": "€", "participants": [ { "name": "Alice Johnson" }, { "name": "Bob Smith" }, { "name": "Charlie Davis" } ], "createdAt": "2025-01-10T10:00:00Z" } ] ``` ``` -------------------------------- ### Get Group Statistics using TRPC Source: https://context7.com/rjdmacedo/knots/llms.txt Fetches and displays spending analytics for a given group using TRPC queries. It shows total spending, breakdown by category, and spending by participant. Includes loading and no-data states. Requires the TRPC client. ```typescript import { trpc } from '@/trpc/client' const GroupStatsExample = () => { const { data: stats, isLoading } = trpc.groups.stats.get.useQuery({ groupId: 'group-123' }) if (isLoading) return
Loading statistics...
if (!stats) return
No stats available
return (

Group Statistics

Total Spending

${(stats.totalSpent / 100).toFixed(2)}

By Category

{stats.byCategory.map(cat => (
{cat.categoryName}: ${(cat.amount / 100).toFixed(2)} ({cat.percentage.toFixed(1)}%)
))}

By Participant

{stats.byParticipant.map(part => (
{part.participantName}: Paid ${(part.paidAmount / 100).toFixed(2)}
))}
) } ``` -------------------------------- ### Get Group Activity Feed Source: https://context7.com/rjdmacedo/knots/llms.txt Retrieve a feed of all changes and events within a specific group. This endpoint is useful for tracking group activity over time. ```APIDOC ## GET /groups/{groupId}/activities ### Description Track all changes and events in a group. ### Method GET ### Endpoint /groups/{groupId}/activities ### Parameters #### Path Parameters - **groupId** (string) - Required - The ID of the group to retrieve activities for. #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **id** (string) - Unique identifier for the activity. - **groupId** (string) - The ID of the group the activity belongs to. - **time** (string) - The timestamp of the activity. - **activityType** (string) - The type of activity (e.g., CREATE_EXPENSE, UPDATE_EXPENSE, DELETE_EXPENSE, UPDATE_GROUP). - **expenseId** (string) - The ID of the expense related to the activity (if applicable). - **data** (object) - Additional data associated with the activity (if applicable). #### Response Example ```json [ { "id": "activity-1", "groupId": "group-123", "time": "2024-01-01T10:00:00Z", "activityType": "CREATE_EXPENSE", "expenseId": "expense-abc", "data": {} } ] ``` ``` -------------------------------- ### Create Reimbursement Expense using tRPC in TypeScript Source: https://context7.com/rjdmacedo/knots/llms.txt This snippet demonstrates recording a direct reimbursement payment between group participants using a tRPC mutation. It requires the tRPC client and depends on group and participant IDs. Inputs include expense details like amount, date, and split mode; outputs trigger the creation of a reimbursement expense marked as such, with no return value shown. Limitations include fixed currency handling in cents and no error handling in the example. ```typescript import { trpc } from '@/trpc/client' const ReimbursementExample = () => { const createExpense = trpc.groups.expenses.create.useMutation() const handleReimbursement = async (groupId: string) => { await createExpense.mutateAsync({ groupId: groupId, expenseFormValues: { title: "Bob pays Alice back for groceries", amount: 7500, // $75.00 expenseDate: new Date(), category: 0, // General/Uncategorized paidBy: "participant-bob-id", // Bob pays paidFor: [ { participant: "participant-alice-id", shares: 7500 } // Alice receives ], splitMode: "BY_AMOUNT", isReimbursement: true, // Mark as reimbursement saveDefaultSplittingOptions: false, documents: [], recurrenceRule: "NONE" } }) // This is a settlement, not a new expense } return } ``` -------------------------------- ### Environment Configuration Source: https://context7.com/rjdmacedo/knots/llms.txt Configure Knots deployment using environment variables. Covers database, currency, file uploads, and AI features. ```APIDOC ## Environment Configuration ### Description Configure Knots deployment with environment variables. ### Example `.env` file configuration: ```dotenv # Database (Required) POSTGRES_PRISMA_URL=postgresql://postgres:password@localhost:5432/knots POSTGRES_URL_NON_POOLING=postgresql://postgres:password@localhost:5432/knots # Default currency for new groups NEXT_PUBLIC_DEFAULT_CURRENCY_CODE=USD # Enable expense document uploads (Optional) NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS=true S3_UPLOAD_KEY=AKIAIOSFODNN7EXAMPLE S3_UPLOAD_SECRET=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY S3_UPLOAD_BUCKET=knots-expense-documents S3_UPLOAD_REGION=us-east-1 S3_UPLOAD_ENDPOINT=https://s3.us-east-1.amazonaws.com # Alternative: Use MinIO instead of AWS S3 # S3_UPLOAD_ENDPOINT=http://minio:9000 # Enable AI receipt scanning (Optional - requires S3) NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT=true OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx # Enable AI category suggestions (Optional) NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT=true OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxxx ``` ``` -------------------------------- ### POST /groups/create Source: https://context7.com/rjdmacedo/knots/llms.txt Creates a new expense sharing group with specified participants and currency settings. This endpoint is essential for initiating any expense tracking within a new context. ```APIDOC ## POST /groups/create ### Description Creates a new expense sharing group with participants and currency settings. ### Method POST ### Endpoint /groups/create ### Parameters #### Request Body - **groupFormValues** (object) - Required - Contains the details for the new group. - **name** (string) - Required - The name of the group. - **information** (string) - Optional - Additional details about the group. - **currency** (string) - Required - The primary currency symbol for the group (e.g., "€"). - **currencyCode** (string) - Required - The ISO currency code (e.g., "EUR"). - **participants** (array) - Required - A list of participants to add to the group. - **name** (string) - Required - The name of the participant. ### Request Example ```json { "groupFormValues": { "name": "European Vacation 2025", "information": "Our amazing trip to Spain and France", "currency": "€", "currencyCode": "EUR", "participants": [ { "name": "Alice Johnson" }, { "name": "Bob Smith" }, { "name": "Charlie Davis" } ] } } ``` ### Response #### Success Response (200) - **groupId** (string) - The unique identifier for the newly created group. #### Response Example ```json { "groupId": "new-group-id-123" } ``` ``` -------------------------------- ### POST /groups/balances/suggestions Source: https://context7.com/rjdmacedo/knots/llms.txt Calculates optimized reimbursement suggestions to settle group balances with minimal transactions. ```APIDOC ## POST /groups/balances/suggestions ### Description Generate optimized reimbursement suggestions to settle all group balances with the fewest possible transactions. ### Method POST ### Endpoint /groups/balances/suggestions ### Parameters #### Request Body - **balances** (object) - Required - Current balances from all group participants. - **[participantId]** (object) - Balance details for each participant. - **paid** (number) - Total paid by participant in cents. - **paidFor** (number) - Total share of expenses for participant in cents. - **total** (number) - Net balance (positive = owed to participant, negative = owes). ### Request Example { "balances": { "participant-alice-id": { "paid": 50000, "paidFor": 30000, "total": 20000 }, "participant-bob-id": { "paid": 20000, "paidFor": 35000, "total": -15000 }, "participant-charlie-id": { "paid": 30000, "paidFor": 35000, "total": -5000 } } } ### Response #### Success Response (200) - Returns an array of suggested reimbursement transactions. - **from** (string) - ID of participant who should pay. - **to** (string) - ID of participant who should receive. - **amount** (number) - Amount to transfer in cents. #### Response Example [ { "from": "participant-bob-id", "to": "participant-alice-id", "amount": 15000 }, { "from": "participant-charlie-id", "to": "participant-alice-id", "amount": 5000 } ] ``` -------------------------------- ### Application Health Check Endpoints (Bash) Source: https://context7.com/rjdmacedo/knots/llms.txt Provides bash commands to check the application's health using curl. It includes endpoints for readiness (checking database connectivity) and liveness (checking if the application is running). Useful for production deployment monitoring. ```bash # Check if application is ready to serve requests (includes database) curl https://your-app.com/api/health # or curl https://your-app.com/api/health/readiness # Response on success: # HTTP 200 OK # { "status": "healthy", "database": "connected" } # Response on database failure: # HTTP 503 Service Unavailable # { "status": "unhealthy", "database": "disconnected" } # Check if application is running (no database check) curl https://your-app.com/api/health/liveness # Response: # HTTP 200 OK # { "status": "alive" } ``` -------------------------------- ### List All Groups using tRPC Source: https://context7.com/rjdmacedo/knots/llms.txt Shows how to fetch and display a list of all expense groups accessible to the current user using tRPC. It handles loading and error states, displaying group names, currencies, participant counts, and creation dates. ```typescript import { trpc } from '@/trpc/client' const GroupListExample = () => { // Automatically fetches and caches group data const { data: groups, isLoading, error } = trpc.groups.list.useQuery() if (isLoading) return
Loading groups...
if (error) return
Error loading groups: {error.message}
return ( ) } ``` -------------------------------- ### Export Expenses to JSON Source: https://context7.com/rjdmacedo/knots/llms.txt Download all expenses for a specific group in JSON format, including full expense details. ```APIDOC ## Export Expenses to JSON ### Description Download group expenses in structured JSON format. ### Method GET ### Endpoint /groups/{groupId}/expenses/export/json ### Parameters #### Path Parameters - **groupId** (string) - Required - The ID of the group whose expenses are to be exported. #### Query Parameters None #### Request Body None ### Request Example ```bash curl https://your-app.com/groups/group-123/expenses/export/json -o expenses.json ``` ### Response #### Success Response (200) - **File Content** (JSON) - The downloaded file contains full expense details including participants and split information. #### Response Example (JSON Structure - illustrative) ```json { "expenses": [ { "id": "expense-abc", "groupId": "group-123", "description": "Dinner at Restaurant", "amount": 125.00, "currency": "USD", "date": "2025-01-15T00:00:00Z", "paidBy": "Alice", "participants": ["Alice", "Bob", "Charlie"], "splitMode": "EVENLY" } ] } ``` ``` -------------------------------- ### Export Expenses to CSV Source: https://context7.com/rjdmacedo/knots/llms.txt Download all expenses for a specific group in CSV format for external analysis. ```APIDOC ## Export Expenses to CSV ### Description Download group expenses as CSV for external analysis. ### Method GET ### Endpoint /groups/{groupId}/expenses/export/csv ### Parameters #### Path Parameters - **groupId** (string) - Required - The ID of the group whose expenses are to be exported. #### Query Parameters None #### Request Body None ### Request Example ```bash curl https://your-app.com/groups/group-123/expenses/export/csv -o expenses.csv ``` ### Response #### Success Response (200) - **File Content** (CSV) - The downloaded file contains expense data in CSV format. #### CSV Format `Date,Description,Category,Amount,Currency,Paid By,Paid For,Split Mode` `2025-01-15,"Dinner at Restaurant","Food & Drink",125.00,USD,"Alice","Alice, Bob, Charlie",EVENLY` ``` -------------------------------- ### Health Check Endpoints Source: https://context7.com/rjdmacedo/knots/llms.txt Monitor the status of the application for production deployments. Includes readiness and liveness checks. ```APIDOC ## Health Check Endpoints ### Description Monitor application status for production deployments. ### Method GET ### Endpoint /api/health /api/health/readiness /api/health/liveness ### Parameters None ### Request Example ```bash curl https://your-app.com/api/health ``` ### Response #### Success Response (200) - **status** (string) - The current status of the application (e.g., "healthy", "alive"). - **database** (string) - The connection status of the database (e.g., "connected", "disconnected") for `/api/health` and `/api/health/readiness`. #### Response Example (Success) ```json { "status": "healthy", "database": "connected" } ``` #### Response Example (Database Failure) ```json { "status": "unhealthy", "database": "disconnected" } ``` #### Response Example (Liveness) ```json { "status": "alive" } ``` ``` -------------------------------- ### Create a Group using tRPC Source: https://context7.com/rjdmacedo/knots/llms.txt Demonstrates how to create a new expense sharing group using the tRPC client. It requires group details like name, currency, and participants. The function returns a group ID upon successful creation. ```typescript import { trpc } from '@/trpc/client' // Client-side usage in a React component const CreateGroupExample = () => { const createGroup = trpc.groups.create.useMutation() const handleCreateGroup = async () => { try { const result = await createGroup.mutateAsync({ groupFormValues: { name: "European Vacation 2025", information: "Our amazing trip to Spain and France", currency: "€", currencyCode: "EUR", participants: [ { name: "Alice Johnson" }, { name: "Bob Smith" }, { name: "Charlie Davis" } ] } }) console.log(`Group created with ID: ${result.groupId}`) // Navigate to /groups/${result.groupId} } catch (error) { console.error('Failed to create group:', error) } } return } ``` -------------------------------- ### List Expense Categories using TRPC Source: https://context7.com/rjdmacedo/knots/llms.txt Retrieves a list of available expense categories using TRPC queries and renders them as options in a select dropdown. Includes an 'Uncategorized' option. Requires the TRPC client. ```typescript import { trpc } from '@/trpc/client' const CategoriesExample = () => { const { data: categories } = trpc.categories.list.useQuery() return ( ) // Categories include: // - Food & Drink (Restaurant, Groceries, Bar) // - Transportation (Car, Bus, Train, etc.) // - Accommodation (Hotel, Airbnb) // - Entertainment (Movies, Sports, Music) // - Shopping // - Utilities // - And more... } ``` -------------------------------- ### POST /groups/expenses/create Source: https://context7.com/rjdmacedo/knots/llms.txt Creates a new expense or reimbursement record between group participants. Reimbursements are marked with the isReimbursement flag. ```APIDOC ## POST /groups/expenses/create ### Description Record a direct payment between participants, either as a regular expense or as a reimbursement. ### Method POST ### Endpoint /groups/expenses/create ### Parameters #### Request Body - **groupId** (string) - Required - The ID of the group where the expense is being recorded. - **expenseFormValues** (object) - Required - Details of the expense/reimbursement. - **title** (string) - Required - Description of the expense. - **amount** (number) - Required - Amount in cents (e.g., 7500 for $75.00). - **expenseDate** (string) - Required - Date of the expense in ISO format. - **category** (number) - Required - Expense category identifier. - **paidBy** (string) - Required - ID of participant who paid. - **paidFor** (array) - Required - List of participants who benefited from the expense. - **participant** (string) - Required - ID of participant. - **shares** (number) - Required - Amount owed by this participant in cents. - **splitMode** (string) - Required - How the expense is split (e.g., "BY_AMOUNT"). - **isReimbursement** (boolean) - Required - True if this is a reimbursement. - **saveDefaultSplittingOptions** (boolean) - Required - Whether to save splitting options as defaults. - **documents** (array) - Required - Any attached documents (empty array if none). - **recurrenceRule** (string) - Required - Recurrence rule ("NONE" for one-time expenses). ### Request Example { "groupId": "group-123", "expenseFormValues": { "title": "Bob pays Alice back for groceries", "amount": 7500, "expenseDate": "2023-01-15T00:00:00.000Z", "category": 0, "paidBy": "participant-bob-id", "paidFor": [ { "participant": "participant-alice-id", "shares": 7500 } ], "splitMode": "BY_AMOUNT", "isReimbursement": true, "saveDefaultSplittingOptions": false, "documents": [], "recurrenceRule": "NONE" } } ### Response #### Success Response (200) - Returns the created expense object with all details including generated ID. #### Response Example { "id": "expense-456", "groupId": "group-123", "title": "Bob pays Alice back for groceries", "amount": 7500, "expenseDate": "2023-01-15T00:00:00.000Z", "category": 0, "paidBy": "participant-bob-id", "paidFor": [ { "participant": "participant-alice-id", "shares": 7500 } ], "splitMode": "BY_AMOUNT", "isReimbursement": true, "createdAt": "2023-01-15T12:34:56.789Z" } ``` -------------------------------- ### Import Expenses from Splitwise using TRPC Source: https://context7.com/rjdmacedo/knots/llms.txt Enables importing expenses from a Splitwise CSV export into Knots using TRPC mutations. It handles file uploads, reads CSV content, and sends it for processing. Requires the TRPC client and a CSV file. ```typescript import { trpc } from '@/trpc/client' const SplitwiseImportExample = () => { const importExpenses = trpc.groups.expenses.importSplitwise.useMutation() const handleImport = async (groupId: string, csvFile: File) => { try { // Read CSV file content const csvContent = await csvFile.text() const result = await importExpenses.mutateAsync({ groupId: groupId, csvContent: csvContent }) console.log(`Imported ${result.count} expenses from Splitwise`) } catch (error) { console.error('Import failed:', error) } } const handleFileUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file && file.type === 'text/csv') { handleImport('group-123', file) } } return (

Import from Splitwise

Export your Splitwise data as CSV and upload it here

) } ``` -------------------------------- ### Query Group Balances via tRPC in TypeScript Source: https://context7.com/rjdmacedo/knots/llms.txt This snippet fetches pre-calculated balances for a group using a tRPC query, displaying owed/owes amounts for each participant. It depends on the tRPC client for the groups.balances.list endpoint, with input as groupId and output as a balances object with total amounts in cents. Limitations include loading state handling but no error management, and assumes server-side calculation. ```typescript import { trpc } from '@/trpc/client' const GroupBalancesExample = () => { const { data: balances, isLoading } = trpc.groups.balances.list.useQuery({ groupId: 'group-123' }) if (isLoading) return
Calculating balances...
return (

Group Balances

{balances && Object.entries(balances).map(([participantId, balance]) => { const amount = balance.total / 100 const status = amount > 0 ? 'owed' : 'owes' const absAmount = Math.abs(amount).toFixed(2) return (
Participant {participantId} {status} ${absAmount}
) })}
) } ``` -------------------------------- ### Export Expenses to JSON (Bash) Source: https://context7.com/rjdmacedo/knots/llms.txt Exports all group expenses in a structured JSON format using curl. The output is saved to a file named 'expenses.json'. This format includes full expense details, participant information, and split details. ```bash # Export all expenses as JSON curl https://your-app.com/groups/group-123/expenses/export/json \ -o expenses.json # JSON includes full expense details with participants and split information ``` -------------------------------- ### POST /groups/expenses/create Source: https://context7.com/rjdmacedo/knots/llms.txt Creates a new expense within a specified group, allowing for various splitting methods. This is the core endpoint for recording shared costs. ```APIDOC ## POST /groups/expenses/create ### Description Create a new expense with a specified split mode among participants. ### Method POST ### Endpoint /groups/expenses/create ### Parameters #### Request Body - **groupId** (string) - Required - The ID of the group the expense belongs to. - **expenseFormValues** (object) - Required - The details of the expense. - **title** (string) - Required - The title or description of the expense. - **amount** (number) - Required - The total amount of the expense (in cents). - **expenseDate** (string) - Required - The date of the expense (ISO format). - **category** (number) - Required - The ID of the expense category. - **paidBy** (string) - Required - The ID of the participant who paid for the expense. - **paidFor** (array) - Required - Details of how the expense is split among participants. - **participant** (string) - Required - The ID of the participant. - **shares** (number) - Optional - Number of shares for percentage/evenly splits. - **percentage** (number) - Optional - Percentage for percentage splits. - **amount** (number) - Optional - Exact amount for exact amount splits. - **splitMode** (string) - Required - The mode used for splitting the expense (e.g., "EVENLY", "BY_SHARES", "BY_PERCENTAGE", "BY_EXACT_AMOUNTS"). - **isReimbursement** (boolean) - Required - Whether this is a reimbursement. - **saveDefaultSplittingOptions** (boolean) - Required - Whether to save this splitting configuration as default. - **documents** (array) - Optional - List of document IDs associated with the expense. - **recurrenceRule** (string) - Optional - Rule for recurring expenses (e.g., "NONE"). ### Request Example ```json { "groupId": "group-123", "expenseFormValues": { "title": "Dinner at Italian Restaurant", "amount": 12500, "expenseDate": "2025-01-15T00:00:00Z", "category": 1, "paidBy": "participant-alice-id", "paidFor": [ { "participant": "participant-alice-id", "shares": 1 }, { "participant": "participant-bob-id", "shares": 1 }, { "participant": "participant-charlie-id", "shares": 1 } ], "splitMode": "EVENLY", "isReimbursement": false, "saveDefaultSplittingOptions": false, "documents": [], "recurrenceRule": "NONE" } } ``` ### Response #### Success Response (200) - **expenseId** (string) - The unique identifier for the newly created expense. #### Response Example ```json { "expenseId": "new-expense-id-456" } ``` ```