{"openapi":"3.0.0","paths":{"/user":{"post":{"operationId":"UserController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserDto"}}}},"responses":{"201":{"description":"User created successfully"}},"summary":"Create a new user","tags":["User"]},"get":{"operationId":"UserController_findAll","parameters":[],"responses":{"200":{"description":"List of users"}},"summary":"List all users","tags":["User"]}},"/user/profile":{"get":{"operationId":"UserController_getProfile","parameters":[],"responses":{"200":{"description":"Current user profile"}},"security":[{"bearer":[]}],"summary":"Get authenticated user profile","tags":["User"]}},"/user/{id}":{"get":{"operationId":"UserController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"User found"}},"summary":"Get user by ID","tags":["User"]},"patch":{"operationId":"UserController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserDto"}}}},"responses":{"200":{"description":"User updated"}},"summary":"Update user","tags":["User"]},"delete":{"operationId":"UserController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"User deleted"}},"summary":"Soft delete user","tags":["User"]}},"/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"JWT access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponseDto"}}}},"401":{"description":"Invalid credentials"}},"summary":"Login with email and password","tags":["Auth"]}},"/group":{"post":{"operationId":"GroupController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupDto"}}}},"responses":{"201":{"description":"Group created"}},"security":[{"bearer":[]}],"summary":"Create a new group","tags":["Group"]}},"/group/joined":{"get":{"operationId":"GroupController_listUserJoinedGroups","parameters":[],"responses":{"200":{"description":"List of groups"}},"security":[{"bearer":[]}],"summary":"List groups the authenticated user has joined","tags":["Group"]}},"/group/{id}/join":{"post":{"operationId":"GroupController_joinGroup","parameters":[{"name":"id","required":true,"in":"path","description":"Group ID","schema":{"format":"uuid","type":"string"}}],"responses":{"201":{"description":"Joined group"}},"security":[{"bearer":[]}],"summary":"Join a group","tags":["Group"]}},"/group/{id}/leave":{"post":{"operationId":"GroupController_leaveGroup","parameters":[{"name":"id","required":true,"in":"path","description":"Group ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Left group"}},"security":[{"bearer":[]}],"summary":"Leave a group","tags":["Group"]}},"/group/{id}/members":{"get":{"operationId":"GroupController_listGroupMembers","parameters":[{"name":"id","required":true,"in":"path","description":"Group ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of group members"}},"security":[{"bearer":[]}],"summary":"List group members","tags":["Group"]}},"/expense":{"post":{"operationId":"ExpenseController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateExpenseDto"}}}},"responses":{"201":{"description":"Expense created with splits"}},"security":[{"bearer":[]}],"summary":"Create a new expense","tags":["Expense"]}},"/expense/upload/{groupId}":{"post":{"operationId":"ExpenseController_uploadExpenses","parameters":[{"name":"groupId","required":true,"in":"path","description":"Group ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"CSV file (max 1MB)"}},"required":["file"]}}}},"responses":{"202":{"description":"Upload accepted for async processing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadAcceptedResponseDto"}}}},"400":{"description":"CSV validation failed"}},"security":[{"bearer":[]}],"summary":"Upload expenses via CSV file","tags":["Expense"]}},"/expense/group/{groupId}":{"get":{"operationId":"ExpenseController_listByGroup","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of expenses"}},"security":[{"bearer":[]}],"summary":"List expenses for a group","tags":["Expense"]}},"/settlement":{"post":{"operationId":"SettlementController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSettlementDto"}}}},"responses":{"201":{"description":"Settlement recorded"}},"security":[{"bearer":[]}],"summary":"Record a settlement between members","tags":["Settlement"]}},"/settlement/group/{groupId}":{"get":{"operationId":"SettlementController_listByGroup","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"List of settlements"}},"security":[{"bearer":[]}],"summary":"List settlements for a group","tags":["Settlement"]}},"/balance/group/{groupId}":{"get":{"operationId":"BalanceController_getGroupBalances","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Group balances","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceResponseDto"}}}}},"security":[{"bearer":[]}],"summary":"Get balances for all members in a group","tags":["Balance"]}},"/balance/group/{groupId}/suggest":{"get":{"operationId":"BalanceController_suggestSettlements","parameters":[{"name":"groupId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Settlement suggestions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SettlementSuggestionDto"}}}}}},"security":[{"bearer":[]}],"summary":"Get suggested settlements to balance the group","tags":["Balance"]}},"/status":{"get":{"operationId":"StatusController_check","parameters":[],"responses":{"200":{"description":"Service status information"}},"summary":"Health check endpoint","tags":["Status"]}}},"info":{"title":"Payment Splitter API","description":"API for splitting payments between users","version":"1.0","contact":{}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"CreateUserDto":{"type":"object","properties":{"name":{"type":"string","example":"John Doe"},"email":{"type":"string","example":"john@example.com"},"password":{"type":"string","example":"password123"}},"required":["name","email","password"]},"UpdateUserDto":{"type":"object","properties":{"name":{"type":"string","example":"Jane Doe"}},"required":["name"]},"LoginDto":{"type":"object","properties":{"email":{"type":"string","example":"user@example.com"},"password":{"type":"string","example":"password123"}},"required":["email","password"]},"LoginResponseDto":{"type":"object","properties":{"access_token":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["access_token"]},"CreateGroupDto":{"type":"object","properties":{"name":{"type":"string","example":"Trip to Paris"}},"required":["name"]},"CreateExpenseDto":{"type":"object","properties":{"groupId":{"type":"string","description":"Group ID","format":"uuid"},"description":{"type":"string","example":"Dinner at restaurant"},"centAmount":{"type":"number","description":"Amount in cents","example":5000},"paidByMemberId":{"type":"string","description":"Member who paid. Defaults to the authenticated user.","format":"uuid"},"includedMemberIds":{"description":"Members to split among. Defaults to all group members.","type":"array","items":{"type":"string"}}},"required":["groupId","description","centAmount"]},"UploadAcceptedResponseDto":{"type":"object","properties":{"message":{"type":"string","example":"Upload accepted for processing"},"s3Key":{"type":"string","example":"expenses/group-id/1234567890-upload.csv"}},"required":["message","s3Key"]},"CreateSettlementDto":{"type":"object","properties":{"groupId":{"type":"string","description":"Group ID","format":"uuid"},"fromMemberId":{"type":"string","description":"Member who is paying","format":"uuid"},"toMemberId":{"type":"string","description":"Member who is receiving","format":"uuid"},"centAmount":{"type":"number","description":"Amount in cents","example":2500},"notes":{"type":"string","description":"Optional notes","maxLength":500}},"required":["groupId","fromMemberId","toMemberId","centAmount"]},"MemberBalanceDto":{"type":"object","properties":{"memberId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"userName":{"type":"string","example":"John Doe"},"userEmail":{"type":"string","example":"john@example.com"},"totalPaid":{"type":"number","description":"Total paid in cents","example":5000},"totalOwed":{"type":"number","description":"Total owed in cents","example":3000},"settlementsReceived":{"type":"number","description":"Settlements received in cents","example":1000},"settlementsPaid":{"type":"number","description":"Settlements paid in cents","example":500},"netBalance":{"type":"number","description":"Net balance in cents (positive = owed money)","example":1500}},"required":["memberId","userId","userName","userEmail","totalPaid","totalOwed","settlementsReceived","settlementsPaid","netBalance"]},"BalanceResponseDto":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"groupName":{"type":"string","example":"Trip to Paris"},"balances":{"type":"array","items":{"$ref":"#/components/schemas/MemberBalanceDto"}},"totalExpenses":{"type":"number","description":"Total expenses in cents","example":15000},"totalSettled":{"type":"number","description":"Total settled in cents","example":5000}},"required":["groupId","groupName","balances","totalExpenses","totalSettled"]},"SettlementSuggestionDto":{"type":"object","properties":{"fromMemberId":{"type":"string","format":"uuid"},"fromUserName":{"type":"string","example":"John Doe"},"toMemberId":{"type":"string","format":"uuid"},"toUserName":{"type":"string","example":"Jane Doe"},"centAmount":{"type":"number","description":"Amount in cents","example":2500}},"required":["fromMemberId","fromUserName","toMemberId","toUserName","centAmount"]}}}}