Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Splitwiser - AI Coding Guide

This document provides essential context for AI assistants working with the Splitwiser codebase.

## Project Overview

Splitwiser is an expense tracking and splitting application with:
- Backend: FastAPI + MongoDB
- Frontend POC: Streamlit
- Frontend: Expo/React Native (implemented with Google/Firebase authentication)

The app allows users to create groups, add expenses with flexible splitting options, track balances, and handle settlements.

## Architecture

### Backend (FastAPI)
- Located in `/backend/`
- RESTful API using FastAPI with Python 3.9+
- MongoDB for database (nonrelational schema)
- JWT authentication with refresh token rotation
- Modular design with services:
- `app/auth/`: Authentication & user registration
- `app/user/`: User profile management
- `app/groups/`: Group creation & management
- `app/expenses/`: Expense tracking & splitting

### Frontend POC (Streamlit)
- Located in `/ui-poc/`
- `Home.py`: Entry point with login/registration
- `pages/`: Contains main application pages
- `Groups.py`: Group management & expense creation
- `Friends.py`: Friend balance tracking

## Key Development Patterns

### API Communication
```python
# Example API call with retry logic from Groups.py
response = make_api_request(
method="get",
url=f"{API_URL}/groups/{group_id}",
headers={"Authorization": f"Bearer {st.session_state.access_token}"},
max_retries=3
)
```

### State Management
- Backend: MongoDB stores persistent data
- Frontend: Streamlit session state manages user session
```python
# Session state initialization (see Home.py)
if "access_token" not in st.session_state:
st.session_state.access_token = None
```

### Expense Handling
- Support for different split types: equal, unequal, percentage-based
- Each expense has a payer and multiple splits (recipients)
- Settlements track debt resolution between users

## Developer Workflows

### Setup & Running
1. Backend:
```bash
cd backend
pip install -r requirements.txt
uvicorn main:app --reload
```
2. Frontend POC:
```bash
cd ui-poc
pip install -r requirements.txt
streamlit run Home.py
```
3. Test Data Generation:
```bash
cd ui-poc
python setup_test_data.py
```

### Testing
- Backend tests in `/backend/tests/`
- Run tests with: `cd backend && pytest`
- Test data setup script: `/ui-poc/setup_test_data.py`

## Critical Files & Dependencies

- `backend/main.py`: Main FastAPI application entry point
- `backend/app/config.py`: Configuration settings
- `backend/app/database.py`: MongoDB connection
- `ui-poc/Home.py`: Streamlit application entry point
- `ui-poc/openapi.json`: API specification for frontend reference

## Common Tasks

- Adding new API endpoint: Add route to appropriate service router file
- Adding new UI component: Modify files in `/ui-poc/pages/`
- Testing data flow: Use the `setup_test_data.py` to create test scenarios
- Troubleshooting auth: Check JWT token handling in `app/auth/security.py`
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ node_modules/
dist/
web-build/
expo-env.d.ts
eas.json

# Native
.kotlin/
Expand Down
2 changes: 1 addition & 1 deletion backend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ REFRESH_TOKEN_EXPIRE_DAYS=30
# Firebase Config
FIREBASE_PROJECT_ID=your-firebase-project-id
FIREBASE_SERVICE_ACCOUNT_PATH=./firebase-service-account.json

FIREBASE_CREDENTIALS_PATH=./firebase-credentials.json
# CORS Configuration
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173,http://127.0.0.1:3000,http://127.0.0.1:5173
ALLOW_ALL_ORIGINS=False
24 changes: 24 additions & 0 deletions backend/app/firebase_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import firebase_admin
from firebase_admin import credentials, auth

def initialize_firebase():
"""Initialize Firebase Admin SDK with proper error handling."""
try:
# Use environment variable or fallback to relative path
credentials_path = os.getenv(
'FIREBASE_CREDENTIALS_PATH',
'../firebase_service_account.json'
)

if not Path(credentials_path).exists():
raise FileNotFoundError(f"Firebase credentials file not found: {credentials_path}")

cred = credentials.Certificate(credentials_path)
firebase_admin.initialize_app(cred)
print("Firebase Admin SDK initialized successfully")
except Exception as e:
print(f"Failed to initialize Firebase Admin SDK: {e}")
raise

# Initialize Firebase
initialize_firebase()
2 changes: 1 addition & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fastapi==0.115.12
fastapi==0.116.1
uvicorn[standard]==0.34.3
python-jose[cryptography]==3.5.0
passlib[bcrypt]==1.7.4
Expand Down
30 changes: 27 additions & 3 deletions frontend/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,41 @@
"**/*"
],
"ios": {
"supportsTablet": true
}, "android": {
"supportsTablet": true,
"bundleIdentifier": "splitwiser.app",
"infoPlist": {
"ITSAppUsesNonExemptEncryption": false
}
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"googleServicesFile": "./google-services.json",
"package": "splitwiser.app"
"package": "com.splitwiser.app"
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
[
"expo-build-properties",
{
"android": {
"compileSdkVersion": 34,
"targetSdkVersion": 34
},
"ios": {
"deploymentTarget": "13.0"
}
}
]
],
"extra": {
"eas": {
"projectId": "7d966fbc-616f-44d2-974f-36d61a2f9ae7"
}
}
}
}
1 change: 1 addition & 0 deletions frontend/assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/adaptive-icon/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/adaptive-icon/foreground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/google-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/assets/splash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions frontend/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: ['module:react-native-dotenv'] // Add this line
};
};
Loading