← スキル一覧に戻る

expense-sharing
by avifenesh
⭐ 0🍴 0📅 2026年1月25日
SKILL.md
name: expense-sharing description: Expense sharing calculations, split types (EQUAL/PERCENTAGE/FIXED), participant state management, and settlement tracking. Use when working with shared expenses, split calculations, payment status transitions, or settlement balances.
Expense Sharing Domain Knowledge
Schema Overview
SharedExpense Model
model SharedExpense {
id String @id @default(cuid())
transactionId String @unique
ownerId String
splitType SplitType @default(EQUAL)
totalAmount Decimal @db.Decimal(12, 2)
currency Currency @default(USD)
description String?
transaction Transaction @relation(...)
owner User @relation("SharedExpensesOwned", ...)
participants ExpenseParticipant[]
}
ExpenseParticipant Model
model ExpenseParticipant {
id String @id @default(cuid())
sharedExpenseId String
userId String
shareAmount Decimal @db.Decimal(12, 2)
sharePercentage Decimal? @db.Decimal(5, 2)
status PaymentStatus @default(PENDING)
paidAt DateTime?
reminderSentAt DateTime?
@@unique([sharedExpenseId, userId])
}
Split Types
enum SplitType {
EQUAL // Divide total equally among all participants + owner
PERCENTAGE // Each participant gets a specified percentage
FIXED // Each participant gets a fixed amount
}
calculateShares Function
Location: src/app/actions/expense-sharing.ts
export function calculateShares(
splitType: SplitType,
totalAmount: number,
participants: Array<{ email: string; shareAmount?: number; sharePercentage?: number }>,
validEmails: string[],
): Map<string, { amount: number; percentage: number | null }>
EQUAL Split Logic
// Divide among (numParticipants + 1) to include owner
const equalShare = Math.round((totalAmount / (numParticipants + 1)) * 100) / 100
PERCENTAGE Split Logic
// Validation: total percentage must not exceed 100%
const amount = Math.round(totalAmount * (percentage / 100) * 100) / 100
FIXED Split Logic
// Validation: total fixed amounts cannot exceed totalAmount
// Each participant gets their specified shareAmount
Payment Status Transitions
PENDING → PAID (owner marks as received)
PENDING → DECLINED (participant declines)
PAID → (terminal)
DECLINED → (terminal)
Transition Rules:
- Only owner can mark PENDING → PAID via
markSharePaidAction - Only participant can DECLINE their own share via
declineShareAction - Cannot mark DECLINED share as PAID
Action Pipeline
All expense sharing actions follow:
1. parseInput(schema, input) // Zod validation
2. requireCsrfToken(csrfToken) // CSRF protection
3. requireActiveSubscription() // Subscription gate
4. requireAuthUser() // Authentication
5. Authorization check // Ownership/participant verification
6. Business logic
7. revalidatePath('/') // Cache invalidation
8. return success/error
Email Notifications
sendExpenseSharedEmail: Sent to each participant when expense is sharedsendPaymentReminderEmail: 24-hour cooldown (REMINDER_COOLDOWN_HOURS = 24)
Settlement Balance Calculation
Location: src/lib/finance.ts (getSettlementBalances)
Groups by user AND currency to avoid mixing currencies:
// Returns for each user:
{
userId: string
youOwe: number // What you owe them (PENDING expenses they shared with you)
theyOwe: number // What they owe you (PENDING expenses you shared with them)
netBalance: number // theyOwe - youOwe
}
Key Files
src/app/actions/expense-sharing.ts- All sharing actionssrc/lib/finance.ts- calculateShares, getSettlementBalancessrc/schemas/index.ts- shareExpenseSchema, participantSchematests/calculate-shares.test.ts- Unit tests for split calculations
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です