Add complete Cospend expense sharing feature

- Add MongoDB models for Payment and PaymentSplit with proper splitting logic
- Implement API routes for CRUD operations and balance calculations
- Create dashboard with balance overview and recent activity
- Add payment creation form with file upload (using $IMAGE_DIR)
- Implement shallow routing with modal side panel for payment details
- Support multiple split methods: equal, full payment, custom proportions
- Add responsive design for desktop and mobile
- Integrate with existing Authentik authentication

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-08 21:15:45 +02:00
parent 95b49ab6ce
commit 815975dba0
21 changed files with 3435 additions and 191 deletions

79
src/models/Payment.ts Normal file
View File

@@ -0,0 +1,79 @@
import mongoose from 'mongoose';
export interface IPayment {
_id?: string;
title: string;
description?: string;
amount: number;
currency: string;
paidBy: string; // username/nickname of the person who paid
date: Date;
image?: string; // path to uploaded image
splitMethod: 'equal' | 'full' | 'proportional';
createdBy: string; // username/nickname of the person who created the payment
createdAt?: Date;
updatedAt?: Date;
}
const PaymentSchema = new mongoose.Schema(
{
title: {
type: String,
required: true,
trim: true
},
description: {
type: String,
trim: true
},
amount: {
type: Number,
required: true,
min: 0
},
currency: {
type: String,
required: true,
default: 'CHF',
enum: ['CHF'] // For now only CHF as requested
},
paidBy: {
type: String,
required: true,
trim: true
},
date: {
type: Date,
required: true,
default: Date.now
},
image: {
type: String,
trim: true
},
splitMethod: {
type: String,
required: true,
enum: ['equal', 'full', 'proportional'],
default: 'equal'
},
createdBy: {
type: String,
required: true,
trim: true
}
},
{
timestamps: true,
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
);
PaymentSchema.virtual('splits', {
ref: 'PaymentSplit',
localField: '_id',
foreignField: 'paymentId'
});
export const Payment = mongoose.model<IPayment>("Payment", PaymentSchema);