Oracle3
Oracle3: 예측시장 거래 엔진·MCP 서버
Fundxtra는 텔레그램 기반 보상 플랫폼입니다
Fundxtra is a Telegram-first rewards platform. Complete sponsored tasks, earn Naira rewards, refer friends, then withdraw as cash or redeem for airtime, data, Telegram Stars and Telegram Premium.
금융TypeScript · CSSGitHub @giftVisuals온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A Telegram-first rewards platform. Users complete sponsored tasks, earn Naira, refer friends, and withdraw as cash or redeem for airtime, data, Telegram Stars and Telegram Premium.
Complete tasks. Earn rewards. Refer friends.
/app (opened from the Telegram bot)/adminfundxtra/
├─ apps/
│ ├─ api/ Express + TypeScript backend → Railway
│ └─ web/ Next.js frontend → Vercel
│ ├─ app/(marketing)/ public website
│ ├─ app/app/ Telegram Mini App
│ └─ app/admin/ admin console
├─ packages/
│ └─ shared/ types, zod schemas, design tokens, money helpers
├─ firebase/ Firestore rules, indexes, Storage rules
└─ docs/ launch, operations, architecture, data model, security, deployment
One shared package is the reason the three surfaces agree with each other: the API and both frontends compile against the same domain types, validate with the same zod schemas, and read colour from the same tokens.
npm ci
cp .env.example .env # then fill it in — see the file's own notes
npm run build:shared # the API and web app compile against this
npm run dev:api # http://localhost:8080
npm run dev:web # http://localhost:3000
GET http://localhost:8080/health reports exactly which configuration is
missing, so a half-configured environment tells you what to fix rather than
failing at the first request that needs a secret.
Set ALLOW_DEV_AUTH=true and send initData as dev:<telegramId>:<name>:<username>.
It is fenced three ways: the flag must be on, NODE_ENV must not be
production, no bot token may be configured, and it refuses to mint the primary
admin's id. /health warns loudly if it is ever enabled in production.
npm run seed --workspace @fundxtra/api
Creates settings, the primary admin, the reward catalogue and five campaigns across every verification method. It refuses to run against production, and it goes through the real services — so the ₦1,000 per-task cap applies to demo data too.
| Command | What it does |
|---|---|
npm run build | Build shared, then the API and the web app |
npm test | 145 tests across the shared package and the API |
npm run typecheck | Strict TypeScript across every workspace |
npm run lint | ESLint on the web app |
npm run seed | Seed development data |
Money is integer kobo, everywhere. Naira floats are never stored, summed or
compared. formatNaira() in the shared package is the only thing that turns an
amount into text. See packages/shared/src/money.ts.
The ledger is authoritative; the balance is a cache. A balance never moves
outside a Firestore transaction that also writes the immutable ledger row, and
every movement carries an idempotency key written with create() inside that
same transaction — so a retry or a genuine race reuses the original entry
rather than paying twice. Corrections are compensating REVERSAL rows, never
edits. auditUserBalance() recomputes from the ledger and is exposed to admins
for dispute investigation.
Telegram identity is the primary key. The user document id is the Telegram
id, which makes "one account per Telegram user" structural rather than enforced.
initData is verified server-side with the documented HMAC scheme before the
user object inside it is read at all.
Duplicate rewards are impossible by construction. A task reward is only ever
credited by a transaction that also creates taskCompletions/{userId}__{taskId}.
The id is derived from the pair, so a second create() fails and rolls the
credit back with it.
Campaign budgets cannot overspend. spentKobo counts approved completions
plus pending submissions, budget moves in the same transaction as the record
that justifies it, and a task closes itself when it can no longer fund another
reward. A test races five users for one funded reward: exactly one is paid.
Reward fulfilment is behind a provider interface. NasfamPay's public API is
still in development, so NasfamPayProvider contains no endpoints, no auth
scheme and no request bodies — only a precise description of what to implement
when the documentation lands. The default provider fails closed so a
misconfigured deployment cannot take money for undeliverable rewards.
| Document | Contents |
|---|---|
| docs/LAUNCH.md | Owner: what to do before going live or stepping back |
| docs/OPERATIONS.md | Daily work: hand this to whoever reviews and pays |
| docs/ARCHITECTURE.md | How the pieces fit, and why |
| docs/DATA_MODEL.md | Every collection, field and invariant |
| docs/SECURITY.md | Threat model and what defends against what |
| docs/DEPLOYMENT.md | Railway, Vercel, Firebase, custom domain |
| docs/PROVIDERS.md | Wiring NasfamPay when their API ships |
Built and working:
Waiting on an external dependency: