AI travel concierge: personalized advice (neighborhoods, food, day trips). Sponsors fund destination programs; travelers use the agent for free and earn USDC rewards (Circle Gateway nanopayments / ARC Mini Pay).
| Who | What | Where in repo | Stack |
|---|---|---|---|
| Your team (B2B) | Admin web app | apps/admin |
Next.js — runs in the browser |
| Travelers (consumers) | Mobile chatbot agent | apps/mobile |
Expo + Dynamic (auth / embedded wallet) + chat UI calling apps/api |
Backend for AI and data: apps/api — Supabase (Postgres) for sponsors, locations, reward pools, offers, purchases, and user tiers; 0G for chat inference; Circle seller hooks to add.
Shared TypeScript types: packages/shared.
The 0G serving broker uses ethers v6. Dynamic’s React Native SDK does not support Ethers in-app — use Viem (already wired via ViemExtension) for on-device chain actions, and keep 0G inference + processResponse on apps/api.
Reference: 0G Compute Inference.
The Dynamic React Native SDK is not compatible with Expo Go (custom native modules). After installing dependencies:
cd apps/mobile
npx expo prebuild
npx expo run:ios
# or
npx expo run:androidSee the React Native quickstart: set EXPO_PUBLIC_DYNAMIC_ENVIRONMENT_ID, EXPO_PUBLIC_DYNAMIC_APP_ORIGIN, allowlist the origin in the Dynamic dashboard, enable EVM + embedded wallets + a sign-in method, and register your app deeplink scheme for social login.
- Node.js ≥ 20 (0G docs recommend ≥ 22 for compute tooling)
pnpm9.x- 0G-funded server wallet + provider address (
apps/api) - Dynamic environment ID + app origin (
apps/mobile) - Circle Gateway / nanopayments when you wire rewards (Nanopayments)
Use one env file at the repository root:
pnpm install
cp .env.example .env
# Edit .env: Supabase, chat keys (0G proxy or OpenAI or broker), EXPO_PUBLIC_* for mobile, etc.apps/apiloads../../.envautomatically (load-root-env).apps/adminloads the same file fromnext.config.ts(plus optionalapps/admin/.env.localfor overrides).apps/mobileinjects../../.envviadotenv-clionpnpm start/ios/android.
EAS / store builds do not read the repo-root .env; set EXPO_PUBLIC_* (and secrets) in EAS env or your CI.
Run admin + API together (recommended — one origin, same as Vercel):
pnpm dev:admin
# http://127.0.0.1:3000/health , /v1/chat , /v1/admin/* (rewrites to /api/*)Optional standalone API on port 8787 (e.g. mobile pointed at LAN IP):
pnpm dev:apiRun customer mobile chatbot (dev client after prebuild):
pnpm dev:mobile
# alias: pnpm dev:customerAndroid APK (EAS): apps/mobile/eas.json defines a preview profile that builds an APK for internal install. From apps/mobile, run eas login, then pnpm eas:init (links the app to your Expo account and writes expo.extra.eas.projectId in app.json). Configure EXPO_PUBLIC_TRIPGENT_API_URL, EXPO_PUBLIC_DYNAMIC_*, etc. as EAS environment variables for the preview profile, then pnpm eas:build:android. CI can use EXPO_TOKEN instead of eas login.
/v1/admin/*— CRUD for sponsors, locations, reward pools, offers, purchases; dashboard counts. Uses Supabase viaSUPABASE_SERVICE_ROLE_KEY. SetADMIN_API_KEYand sendx-admin-key(orAuthorization: Bearer) in production.GET /v1/admin/sponsors/by-slug/:slug/tier-ratesandGET /v1/admin/sponsors/:id/tier-rates— per-tier USDC rates (after migration002_air_monaco_mock.sql).POST /v1/rewards/accrue— apply sponsor tier rate to pool spend (user + sponsor slug).GET /v1/rewards/accruals— ledger. Requires migration003_reward_accrual_usdc.sql. Auth:ADMIN_API_KEY(same as admin) orAPI_AUTH_BEARER(same as chat).GET /v1/users/profile?external_id=— traveler tier, reputation, purchase history.POST /v1/chat— 0G direct proxy: setZG_COMPUTE_PROXY_URL(e.g.https://…/v1/proxy) +ZG_COMPUTE_SECRET(app-sk-…from CLI) + optionalZG_COMPUTE_MODEL(defaultqwen/qwen-2.5-7b-instruct). Same URL +OPENAI_API_KEYholdingapp-sk-…also works. Otherwise OpenAI-compatible (OPENAI_*/LLM_*) or 0G broker (RPC_URL,PRIVATE_KEY,PROVIDER_ADDRESS). Optional JSON:destination_slug:"monaco"(loads Monaco mock context from DB after migration004_monaco_destination_mocks.sql),user_external_id+ optionaldisplay_name— on success, accrues a micro-reward from the Air Monaco pool per completed reply (reasonmonaco_search; requires003+ tier rates in002).GET /v1/payments/status— Circle nanopayments stub.
Tests: pnpm --filter @tripgent/api test runs tier math always; full DB flow runs only if Supabase env vars are set.
Admin dashboard all zeros after SQL? The API must use SUPABASE_SERVICE_ROLE_KEY = service_role (Supabase → Project Settings → API), not the anon key — with RLS and no policies for anon, selects return no rows. Confirm the Supabase host on the admin home matches the project where you ran SQL; run apps/api/supabase/VERIFY_COUNTS.sql in that project’s SQL editor to compare counts.
Auth: If API_AUTH_BEARER is unset, the API accepts requests without a matching secret (fine for local dev). The mobile app sends Authorization: Bearer <Dynamic JWT> from client.auth.token when the user is signed in. For production, verify that JWT on the server (Dynamic docs) instead of relying on an open API.
The Hono app is mounted from @tripgent/api on apps/admin/src/app/api/[[...path]]/route.ts. Public URLs stay /health and /v1/* via Next rewrites to /api/*.
- Import the Git repo on Vercel.
- Set Root Directory to
apps/admin. - Environment variables (Production / Preview): mirror your local root
.env(see.env.examplein the repo) — at minimumSUPABASE_URL,SUPABASE_SERVICE_ROLE_KEY, plus chat keys (ZG_COMPUTE_*/OPENAI_*/RPC_URL,PRIVATE_KEY,PROVIDER_ADDRESS) as you use locally. AddADMIN_API_KEY,API_AUTH_BEARER,CORS_ORIGINS(comma-separated; include your Expo / web origins when calling from a device) as needed. - Vercel uses
apps/admin/vercel.json: install from the monorepo root with pnpm, then builds@tripgent/apiand@tripgent/admin. - Mobile: set
EXPO_PUBLIC_TRIPGENT_API_URLtohttps://<your-deployment>.vercel.app(no trailing slash). Paths are still/v1/chat, etc. - Function duration:
route.tssetsmaxDuration = 300(requires Vercel Pro or higher for more than 10s). Hobby caps at 10s — long LLM calls may time out unless you upgrade or use a faster model path. - Deployment Protection: If
/healthor the admin dashboard shows 401 and HTML (“Authentication Required”), Vercel is gating the whole deployment — not Tripgent. Either turn off protection for Preview/Production (Project → Settings → Deployment Protection), or enable Protection Bypass for Automation soVERCEL_AUTOMATION_BYPASS_SECRETis set and server-side checks can reach your API.
- Verify Dynamic JWT on
POST /v1/chatwhen you lock down the API. - Circle: fund a Developer-Controlled treasury wallet, deposit into Gateway on Arc testnet, then enable env vars so
reward_wallet_addressreceives mints after accrual (unified balance EVM); use nanopayments only if you charge travelers per request (x402). - Admin UI on Vercel uses the same origin by default (no
NEXT_PUBLIC_TRIPGENT_API_URL). For a separate API host, setNEXT_PUBLIC_TRIPGENT_API_URLand serverTRIPGENT_API_URL. Prefer server-onlyADMIN_API_KEY(avoid exposing secrets withNEXT_PUBLIC_ADMIN_API_KEYon public URLs).
0G skills: .0g-skills/ (see .cursor/rules/0g-skills-context.mdc).