Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
SplitFinance - A Splitwise-Style Expense Sharing App
A full-stack expense-splitting app: track shared expenses across a group,
let an AI categorise, parse and read them (typed or photographed), ask it
about your balances, and simplify group debt into at most n−1 settlement
payments.
🔗 Live at splitfinance.org · API health check: api.splitfinance.org
A group in detail — balances, AI-categorised insights, and the add-expense formREADME 전문 보기 ↗A full-stack expense-splitting app: track shared expenses across a group, let an AI categorise, parse and read them (typed or photographed), ask it about your balances, and simplify group debt into at most n−1 settlement payments.
🔗 Live at splitfinance.org · API health check: api.splitfinance.org
React (Vite) · Node/Express · PostgreSQL + Prisma · Socket.IO · Cohere · Docker · Terraform on AWS EC2 · GitHub Actions CI/CD
Both images are generated by driving the real app in a browser (
e2e/tests/screenshots.spec.js), so they can't drift from what the app actually renders — regenerating them isnpm run screenshots.
flowchart LR
U["Browser"] -->|HTTPS| C
subgraph EC2["AWS EC2 · Docker Compose"]
C["Caddy<br/>auto-TLS · CSP · security headers"]
F["React SPA<br/>vite build, served static"]
A["Express API<br/>JWT auth · Prisma"]
DB[("PostgreSQL<br/>persistent EBS volume")]
C --> F
C --> A
F -->|Socket.IO| A
A --> DB
end
A --> CO["Cohere<br/>categorisation · NL parsing<br/>receipt vision · assistant"]
A -->|security logs| CW["CloudWatch Logs"]
A --> RE["Resend<br/>password-reset email"]
SSM["SSM Parameter Store<br/>secrets fetched at boot"] -.-> EC2
GH["GitHub Actions<br/>test · lint · deploy via OIDC"] -.-> EC2
28 REST endpoints across 8 resources. Full tech stack, package layout, and subsystem-by-subsystem detail (AI, WebSockets, spending insights, password reset) are in docs/ARCHITECTURE.md.
Everything below is the detail — Features first, then the algorithm and money write-ups, then Getting Started. Security, testing, the database schema, and deployment each have their own doc, linked from the matching section below.
User.isAdmin flag with no self-service way to
set it (set directly in the database)If Alice owes Bob $10, Bob owes Carol $10, and Carol owes Alice $10, naively
that's 3 transactions — but the net effect is zero. This app implements a
greedy cash-flow reduction (server/src/services/simplifyDebts.js) that:
Each pass zeroes out at least one person's balance, which is what guarantees the n−1 bound — so an O(n²) worst-case payment graph always collapses to O(n) transactions.
Worth being precise about what this does not claim: finding the true minimum number of transactions is NP-hard (it reduces to partitioning the balances into as many zero-sum subsets as possible), so this is a heuristic — the same one Splitwise uses in practice — not a provably optimal solver. It's guaranteed to settle the group correctly and to stay within the n−1 bound; it just isn't guaranteed to find the very shortest possible list of payments in every case.
Four Cohere-backed features, all optional - the app works fully without an API key, each one just falls back or becomes unavailable - and all gated on a confirmed email address, since a free, instant signup is the cheap route to someone else's metered quota:
"Other"The prompts, the response sanitization, the upload path, and the assistant's tool boundary are all in docs/ARCHITECTURE.md.
Full detail, including the reasoning behind each one, is in docs/SECURITY.md. A few highlights:
localStorage; a password change bumps a tokenVersion that revokes every
earlier session immediately, not just at its natural expirynpm audit on every change and weekly on a schedule, plus Dependabot
upgrade PRs that run the full test suite before anyone merges them^22.12 || ^24, jsdom needs >=22.22)git clone https://github.com/rmeera-projs/splitfinance.git
cd splitfinance
# Start Postgres
docker-compose up -d db
# Backend
cd server
cp .env.example .env
npm install
npx prisma migrate dev --name init
npm run dev
# Frontend (in a new terminal)
cd client
cp .env.example .env
npm install
npm run dev
Backend runs on http://localhost:5000, frontend on http://localhost:5173.
Auto-categorization, natural-language expense entry, receipt scanning and the
balances assistant all need a Cohere API key. Add it to server/.env:
COHERE_API_KEY="your-key-here"
This is optional — without it, every expense is categorized as "Other"
natural-language entry falls back to a much cruder regex-only parse (see
expenseParsingService.js),
receipt scanning and the assistant are simply unavailable (a 503), but
everything else works normally. No key is needed to run the test
suite; the Cohere client is fully mocked in tests.
Password reset emails need a Resend API key (free
tier, no domain verification required to start — their default
[email protected] sender works immediately). Add it to server/.env:
RESEND_API_KEY="your-key-here"
This is optional — without it, forgot-password still responds
successfully (so it never leaks whether an email is registered), but the
reset link is only logged to the server's console instead of emailed,
which is enough to test the flow locally. No key is needed to run the test
suite; Resend is fully mocked in tests.
Once a domain is verified in Resend (Domains tab in its dashboard — add
the DKIM/SPF/MX records it gives you at your DNS provider), set
RESEND_FROM_ADDRESS too so emails send from that domain instead of the
shared [email protected] testing address:
RESEND_FROM_ADDRESS="SplitFinance <[email protected]>"
docker-compose up --build
The server container reads its environment from docker-compose.yml, not
from server/.env — so to enable auto-categorization or real password
reset emails under Docker, put the keys in a .env file at the repo
root (not server/.env) instead:
COHERE_API_KEY="your-key-here"
RESEND_API_KEY="your-key-here"
RESEND_FROM_ADDRESS="SplitFinance <[email protected]>"
docker-compose.yml picks them up via
${COHERE_API_KEY}/${RESEND_API_KEY}/${RESEND_FROM_ADDRESS}
substitution. This root .env is git-ignored, same as server/.env.
See DEPLOYMENT.md for step-by-step Railway and AWS/Terraform
deployment guides, and the GitHub Actions pipeline that auto-deploys AWS on
every merge to main via SSM (no SSH, no stored AWS key). This is what's
actually running the live deploy at https://splitfinance.org.
Every migration ships with a rollback path, enforced by two test layers - see docs/DATABASE.md for how that works and how to use it.
643 tests across three layers - a fast mocked layer for logic, a real-database layer for everything mocks structurally can't prove, and a browser layer for the flows a user actually performs. What each layer catches (with examples) and full setup instructions for integration/e2e are in docs/TESTING.md.
| Layer | Count | What's real |
|---|---|---|
| Unit | 547 (317 backend, 230 frontend) | the Express app, React components |
| Integration | 78 | Postgres, Prisma, migrations, the whole request path |
| End-to-end | 19 | everything — real browser, real API, real database |
# Unit - fast, no Docker, no network. Runs on every save.
cd server && npm test # 317 (Jest + Supertest, Prisma mocked)
cd client && npm test # 230 (Vitest + React Testing Library)
Every amount in this app — in the database, over the API, and through every
calculation — is an integer number of cents. $10.23 is 1023.
Money used to be a JavaScript number, and binary floating point can't
represent most decimal fractions exactly (0.1 + 0.2 === 0.30000000000000004).
That forced a tolerance into the check that an expense's splits summed to its
total — which meant a split genuinely off by up to a cent passed validation.
With integers the same check is exact equality:
if (Math.abs(splitTotal - data.amount) > 0.01) // before
if (splitTotal !== data.amount) // now
The other thing integers force you to be honest about is remainders. $60.50
three ways is 2016.66… cents each, which no set of equal whole cents can make
— splitEvenly hands the leftover cents out one at a time, so the parts always
reconcile against the total exactly.
Full schema and the money-handling code path: docs/DATABASE.md.
Nothing queued right now - see Later below.
simplifyDebts.js's output to
proactively suggest who should settle up next, phrased in plain language
("Alice and Bob settling up clears 2 of the 3 outstanding debts") rather
than just listing raw balances; would also give the "Email notifications"
item below actual content worth sending instead of a plain transactional
emailSee docs/CHANGELOG.md for the full history, newest first.
MIT