尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Multi-tenant ticketing and check-in platform for party fishing boat operators. Each operator gets their own isolated deployment (Vercel + Neon Postgres) from this shared codebase.
The mate check-in app (QR scanner, offline manifest, PIN auth) is built from the same apps/mobile codebase using the mate EAS build profile (EXPO_PUBLIC_APP_VARIANT=mate).檢視完整 README ↗Multi-tenant ticketing and check-in platform for party fishing boat operators. Each operator gets their own isolated deployment (Vercel + Neon Postgres) from this shared codebase.
| App | Description |
|---|---|
apps/web | Next.js 14 — marketing site, booking calendar, checkout, boarding passes, admin dashboard, API routes |
apps/mobile | Expo SDK 53 — consumer booking app (trips calendar, Stripe Payment Sheet, offline tickets wallet, Account tab with OTP sign-in) + mate check-in app (same codebase, separate EAS profile) |
packages/db | Drizzle ORM schema + migrations (shared source of truth) |
The mate check-in app (QR scanner, offline manifest, PIN auth) is built from the same apps/mobile codebase using the mate EAS build profile (EXPO_PUBLIC_APP_VARIANT=mate).
npm install -g pnpm)npm install -g expo-cli)npm install -g eas-cli) — for mobile device buildsbrew install stripe/stripe-cli/stripe) — for local webhook forwardinggit clone <repo>
cd open-boat-fishing
pnpm install
Create a Neon project. Copy the connection string.
# In packages/db — run migrations against the new database
DATABASE_URL="postgres://..." pnpm db:migrate
Then seed development data (creates one operator row, 4 vessels, products, prices, and ~150 trips):
DATABASE_URL="postgres://..." pnpm --filter @openboat/db seed
For production, replace the seed script with real operator data or use the admin dashboard.
acct_...).Create apps/web/.env.local:
# Database
DATABASE_URL=postgres://...
# Stripe (platform account)
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_... # from `stripe listen` in dev; from Stripe dashboard in prod
STRIPE_CONNECTED_ACCOUNT_ID=acct_... # operator's connected account
# App
NEXT_PUBLIC_APP_URL=https://yourclient.com # used in boarding pass links in emails
# Email (Resend)
RESEND_API_KEY=re_...
# Auth (signs mate + customer tokens)
SESSION_SECRET=<32+ char random hex> # generate with: openssl rand -hex 32
# Vercel cron auth (required for push notification reminders)
CRON_SECRET=<32+ char random hex> # must also be set in Vercel dashboard
Create apps/mobile/.env.local for local dev:
EXPO_PUBLIC_API_URL=http://localhost:3000
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
# Apple Pay / Google Pay
EXPO_PUBLIC_APPLE_MERCHANT_ID=merchant.com.yourclient.app
EXPO_PUBLIC_URL_SCHEME=yourclientapp
EXPO_PUBLIC_MERCHANT_NAME=Your Client Name
# Set to "mate" to run the mate check-in app instead of the consumer app
# EXPO_PUBLIC_APP_VARIANT=mate
For EAS builds, set these in apps/mobile/eas.json under the appropriate build profile (see Mobile builds below).
app.json — per-operator mobile identityEdit apps/mobile/app.json to match the operator:
{
"expo": {
"name": "Your Operator Name",
"slug": "your-operator-slug",
"scheme": "youroperatorapp",
"ios": {
"bundleIdentifier": "com.youroperator.fishing"
},
"android": {
"package": "com.youroperator.fishing"
}
}
}
Each operator needs a unique bundle ID and scheme. For a second operator, either fork the repo or use EAS build profiles to override these values.
# Start everything (Turborepo — web + mobile Metro in parallel)
pnpm dev
# Or individually:
pnpm --filter @openboat/web dev # Next.js on :3001 (or :3000)
pnpm --filter @openboat/mobile dev -- --clear # Expo Metro on :8081
# Forward Stripe webhooks to local server (required for booking confirmation + wallet sync)
stripe listen --forward-to localhost:3001/api/webhooks/stripe
Webhook note: booking status only transitions to
confirmed(and tickets appear in the mobile wallet) afterpayment_intent.succeededfires. In local dev this requiresstripe listenrunning.
pnpm --filter @openboat/mobile ios
The app opens automatically. Use test card 4242 4242 4242 4242 with any future expiry and any CVC.
Requires an EAS development build — see Mobile builds. The simulator build won't install on a device.
# Run migrations
DATABASE_URL="..." pnpm db:migrate
# Generate migration from schema changes
pnpm --filter @openboat/db generate
# Open Drizzle Studio (visual DB browser)
DATABASE_URL="..." pnpm db:studio
The mobile app uses Expo EAS Build. Builds run in the cloud — you don't need Xcode installed for production builds, but you do need an Apple Developer account.
apps/mobile/eas.json)| Profile | Purpose |
|---|---|
development | Dev client build — installs on device, connects to local Metro for fast iteration |
preview | Internal distribution (TestFlight / direct APK) — for QA and stakeholder review |
consumer | App Store / Google Play production build |
mate | Internal distribution — mate check-in app (TestFlight / internal Play track) |
cd apps/mobile
# Log in to your Expo account
eas login
# Link to an EAS project (creates one if needed)
eas init
# Configure credentials (Apple Developer account required for iOS)
eas credentials
cd apps/mobile
# iOS device build (requires Apple Developer account)
eas build --profile development --platform ios
# Install on your device via QR code shown after build completes
# Then start Metro and the app will connect to it:
pnpm --filter @openboat/mobile dev
Update
EXPO_PUBLIC_API_URLin thedevelopmentprofile ineas.jsonto your machine's LAN IP so the physical device can reach your local web server:http://192.168.x.x:3001
eas submit --profile consumer --platform ios
Fill in the Apple IDs in eas.json under submit.consumer.ios first.
apps/mobile/app.json with operator's app name and bundle IDseas.json → run eas build --profile consumermerchant.com.operator.app in Apple Pay merchant registrationTime estimate: ~2–3 hours for web, ~1–2 hours per mobile platform.
apps/web/src/app/api/) deployed as Vercel serverless functions. No separate server.application_fee_amount: 150).FOR UPDATE row-lock inside a transaction — race-condition-safe without application-level locks./boarding/[bookingId]. CSS @media print handles layout. No server-side PDF generation.expo-sqlite in the mobile app. Boarding pass QR works with no cell signal at the dock.See CLAUDE.md for the full build order, data model, and architectural decisions.
Complete (steps 1–9):
payment_intent.succeeded + payment_intent.canceled), confirmation email via ResendRemaining before launch:
eas.json submit section)