Ecommerce Template
Next.js·React 등으로 만든 최신 전자상거래 템플릿
작업을 올리고 가격을 정하면 인근 검증된 이웃이 완료, 금액은 완료 시까지 보관
Post a task, name your price, and a verified neighbor nearby gets it done. Your money is held until you say it's finished. Live in Washington, DC and the DMV.
커머스TypeScript · PLpgSQLGitHub @kodaksax온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기The home for Bounty. Quit Your Day Job
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Mobile-first mobile-only micro‑bounty marketplace (iOS & Android). Create → Match → Chat → Complete → Settle. Fast, transparent, escrow‑backed.
Platform note: This project targets iOS and Android only. Avoid adding or relying on web-only dependencies; if CI/tooling requires a web build, add safe web stubs and platform guards rather than importing native-only modules on web.
🚀 Elevator Pitch
BOUNTYExpo makes it fast and safe to post small jobs ("bounties"), get matched with a hunter, coordinate in-app, and settle payment via an escrow flow. Designed for trust, speed, and clarity.README 전문 보기 ↗Mobile-first mobile-only micro‑bounty marketplace (iOS & Android). Create → Match → Chat → Complete → Settle. Fast, transparent, escrow‑backed.
Platform note: This project targets iOS and Android only. Avoid adding or relying on web-only dependencies; if CI/tooling requires a web build, add safe web stubs and platform guards rather than importing native-only modules on web.
BOUNTYExpo makes it fast and safe to post small jobs ("bounties"), get matched with a hunter, coordinate in-app, and settle payment via an escrow flow. Designed for trust, speed, and clarity.
External Beta — Core flows (Create, Match, Chat, Complete, Settle) are feature-complete and stable. The app is now open to external beta testers. See BETA_GUIDE.md for testing instructions and KNOWN_ISSUES.md for documented limitations.
📣 Beta testers: Please report bugs and feedback via GitHub Issues. Check the Beta Guide to get started.
| Term | Meaning |
|---|---|
| Bounty | A task with title, description, amount or isForHonor flag, optional location. |
| Posting | A bounty in the public feed (status = open). |
| Request | A proposal/acceptance record on a bounty (future extension). |
| Conversation | 1:1 or group chat, optionally tied to a bounty. |
| Wallet | Escrow + transaction records (mock for now). |
| Calendar | Date summarization layer (read-only initially). |
// lib/types.ts
export type Money = number; // USD for now
export interface Bounty {
id: string;
user_id: string;
title: string;
description: string;
amount?: Money;
isForHonor?: boolean;
location?: string;
createdAt?: string;
status?: "open" | "in_progress" | "completed" | "archived";
}
export interface Conversation {
id: string;
bountyId?: string;
isGroup: boolean;
name: string;
avatar?: string;
lastMessage?: string;
updatedAt?: string;
}
export interface WalletTransaction {
id: string;
type: "escrow" | "release" | "refund";
amount: Money;
bountyId?: string;
createdAt: string;
}
(Do not redefine these elsewhere—import from lib/types.)
The app uses Expo Router with file-based routing. A single root shell component (e.g. BountyApp) renders the BottomNav once. Screens must NOT duplicate navigation state.
Bottom navigation mapping:
Layout rules:
position: relative; flex: 1; plus paddingBottom to clear nav height.position: absolute; left:0; right:0; bottom:0; zIndex high.paddingBottom accordingly.<BottomNav activeScreen={activeScreen} onNavigate={setActiveScreen} />.activeScreen states.hooks/; remote/services in lib/services/.React.memo, useCallback, useMemo.✕.# Clone the repository
git clone https://github.com/kodaksax/bountyexpo.git
cd bountyexpo
# Run the automated setup script
./scripts/setup.sh
# Start all services with one command
pnpm dev
# In another terminal, start the Expo development server
pnpm start
git clone https://github.com/kodaksax/bountyexpo.git
cd bountyexpo
pnpm install
# Copy environment template
cp .env.example .env
# Edit .env with your configuration (see Environment Variables section below)
# For local development, the defaults work out of the box!
# In a new terminal window
pnpm start
# Follow Expo CLI instructions to:
# - Open in Dev Client (recommended) or Expo Go (legacy)
# - Press 'i' for iOS Simulator
# - Press 'a' for Android Emulator
# - Press 'w' for web browser
Dev client (preferred)
To stop using Expo Go and use a development client instead, follow these steps:
pnpm build:dev-android (alias: eas build --profile development -p android)pnpm build:dev-ios (alias: eas build --profile development -p ios)expo run:androidexpo run:iospnpm start (runs expo start --dev-client)Notes:
expo-dev-client is already included in this repo dependencies.development EAS profile (see eas.json) to produce a development client (developmentClient: true).expo run:android builds and installs a dev client locally.
4. **Start Mobile App**
```bash
# In a new terminal window
pnpm start
# Follow Expo CLI instructions to:
# - Scan QR code with Expo Go app (iOS/Android)
# - Press 'i' for iOS Simulator
# - Press 'a' for Android Emulator
# - Press 'w' for web browser
Your .env file should contain these essential variables:
# Database (automatically configured for local Docker setup)
DATABASE_URL="postgresql://bountyexpo:bountyexpo123@localhost:5432/bountyexpo"
# Stripe (use test keys for development)
STRIPE_SECRET_KEY="sk_test_your_key_here"
EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_your_key_here"
# Supabase (for authentication - REQUIRED)
# Get these from your Supabase project settings:
# 1. Go to https://supabase.com/dashboard
# 2. Select your project > Settings > API
SUPABASE_URL="https://your-project.supabase.co"
EXPO_PUBLIC_SUPABASE_URL="https://your-project.supabase.co"
SUPABASE_ANON_KEY="your-anon-key"
EXPO_PUBLIC_SUPABASE_ANON_KEY="your-anon-key"
SUPABASE_SERVICE_ROLE_KEY="your-service-role-key" # Keep secret, server-side only!
SUPABASE_JWT_SECRET="your-jwt-secret"
# API Configuration
API_BASE_URL="http://localhost:3001"
EXPO_PUBLIC_API_URL="http://localhost:3001"
After running pnpm dev, these services will be available:
| Service | URL | Description |
|---|---|---|
| API Server | http://localhost:3001 | Main BountyExpo API |
| PostgreSQL | localhost:5432 | Database server |
| Redis | localhost:6379 | Cache server |
| Stripe Mock | http://localhost:12111 | Mock payment processing |
| API Health | http://localhost:3001/health | Health check endpoint |
A minimal Express server (server/) handles Stripe payment operations:
Features:
Quick Start:
# Navigate to server directory
cd server
# Install dependencies
npm install
# Configure environment
cp .env.example .env
# Edit .env with your Stripe keys
# Start the server
npm start
Endpoints:
GET /health - Health checkPOST /payments/create-payment-intent - Create payment intentPOST /webhooks/stripe - Handle Stripe webhooksPOST /connect/create-account-link - Stripe Connect onboardingPOST /connect/transfer - Initiate bank transfersConfiguration:
Set these in server/.env:
STRIPE_SECRET_KEY=sk_test_your_key_here
STRIPE_WEBHOOK_SECRET=whsec_your_secret_here
PORT=3001
📖 Full documentation: See STRIPE_INTEGRATION_BACKEND.md
When testing payments from a phone using Expo Go, the client must call your development machine's LAN IP (not localhost). Follow these steps:
# start payments server
npm run payments:server
.env set:EXPO_PUBLIC_API_BASE_URL=http://<YOUR_LAN_IP>:3001
# e.g. EXPO_PUBLIC_API_BASE_URL=http://192.168.0.59:3001
npx expo start --clear
http://<YOUR_LAN_IP>:3001/health
Alternatives:
expo start --tunnel to avoid firewall/LAN issues.ngrok http 3001 and set EXPO_PUBLIC_API_BASE_URL to the ngrok https URL.# Development
pnpm dev # Start infrastructure services (PostgreSQL + Stripe Mock)
pnpm dev:api # Start API server (run in separate terminal)
pnpm start # Start Expo development server
pnpm dev:stop # Stop all services
pnpm dev:logs # View service logs
# Testing
pnpm test:auth # Test authentication endpoints (sign-up/sign-in)
pnpm test:api # Test API endpoints
# Database
pnpm db:init # Initialize database (if needed)
pnpm --filter @bountyexpo/api db:migrate # Run migrations
pnpm --filter @bountyexpo/api db:seed # Seed with sample data
# Code Quality
pnpm type-check # TypeScript checks across all packages
pnpm lint # Lint code
If you're updating from an older version:
pnpm install
# Compare your .env with the new .env.example
# Add any missing variables
# Stop existing services
pnpm dev:stop
# Start fresh with latest schema
pnpm dev
# The database will auto-migrate on startup
pnpm start --clear
BountyExpo uses Supabase for authentication. To set it up:
Create a Supabase Project
Get API Credentials
.env file with these valuesTest Authentication
# Make sure API server is running
pnpm dev:api
# Run auth tests
pnpm test:auth
You should see:
Troubleshooting Auth Issues
.env has all required Supabase variablesSUPABASE_SERVICE_ROLE_KEY (not ANON_KEY) is set for serverAPI Client Package
The @bountyexpo/api-client package provides typed API wrappers and React hooks:
# Build all packages
npm run build
# Type check everything
npm run type-check
http://localhost:3001npm run type-check to identify TypeScript issuesnpx expo start --clearBountyExpo uses a modern, scalable monorepo architecture:
services/api/)packages/domain-types/)# Start everything (recommended)
pnpm dev # Infrastructure: PostgreSQL + Stripe Mock
pnpm dev:api # API server (separate terminal)
pnpm start # Expo development server (separate terminal)
# Individual services
pnpm dev:api # API server only
pnpm dev:stop # Stop all Docker services
pnpm dev:logs # View service logs
# Code quality
pnpm type-check # TypeScript validation across all packages
pnpm lint # ESLint checks
pnpm dev (runs PostgreSQL, API, Stripe Mock)pnpm start (in separate terminal)pnpm type-check before committingpnpm dev:logs for debugging# Direct database access (when services are running)
psql postgresql://bountyexpo:bountyexpo123@localhost:5432/bountyexpo
# API-specific database commands
pnpm --filter @bountyexpo/api db:migrate # Run migrations
pnpm --filter @bountyexpo/api db:seed # Add sample data
pnpm --filter @bountyexpo/api db:studio # Drizzle Studio UI
See services/api/README.md for detailed API documentation.
npx tsc --noEmit
npm run reset-project
(Not typically needed now that base scaffolding is customized.)
app/
(routes...)
components/
BottomNav.tsx
hooks/
useBounties.ts
lib/
types.ts
services/
bountyService.ts
(Actual structure may evolve; keep types centralized.)
Initial phase: mock transactions for UI. Future integration targets: Stripe Connect / Replit Deploy / TBD custody service. Design assumptions:
The app uses Metro bundler caching for faster rebuilds. If you encounter layout issues or stale code:
# Clear Metro cache and restart
npx expo start --clear
# Alternative: Clear all caches
rm -rf node_modules/.cache
rm -rf .expo
npx expo start --clear
The API uses Redis for caching frequently accessed data to improve response times and reduce database load.
Cached Resources:
Cache Invalidation:
Configuration: Set these environment variables to customize caching behavior:
# Redis Configuration
REDIS_HOST=localhost # Redis server host
REDIS_PORT=6379 # Redis server port
REDIS_ENABLED=true # Enable/disable caching
REDIS_TTL_PROFILE=300 # Profile cache TTL (seconds)
REDIS_TTL_BOUNTY=180 # Bounty cache TTL (seconds)
REDIS_TTL_BOUNTY_LIST=60 # Bounty list cache TTL (seconds)
Testing Redis:
# Test Redis connection and caching operations
cd services/api
npx tsx src/test-redis-simple.ts
expo-image instead of React Native's Image for automatic cachingAll FlatLists are optimized with:
windowSize={5} - Renders 5 screens worth of itemsmaxToRenderPerBatch={5} - Batches rendering for smoother scrollingremoveClippedSubviews={true} - Removes off-screen views from memoryinitialNumToRender={5} - Initial render size for faster startupTo analyze bundle size and identify large dependencies:
# Install the analyzer
npm install --save-dev react-native-bundle-visualizer
# Analyze the bundle
npx react-native-bundle-visualizer
Performance is tracked using:
Target Metrics:
# Run all tests
npm test
# Run unit tests only
npm run test:unit
# Run integration tests
npm run test:integration
# Run end-to-end tests
npm run test:e2e
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode during development
npm run test:watch
# Run with verbose output for debugging
npm run test:verbose
Playwright drives the app's web target (react-native-web, via expo start --web) in a real Chromium browser — useful for visually reviewing frontend changes, taking screenshots, and catching rendering regressions that Jest's component tests can't see. It complements, but does not replace, the Jest suites above (__tests__/e2e are still the Node-level API/flow tests behind npm run test:e2e).
# Run all Playwright tests headlessly (auto-starts the web dev server on :8090)
npm run test:e2e:pw
# Open Playwright's interactive UI mode — step through tests, inspect the DOM/network
npm run test:e2e:pw:ui
# Run headed (visible browser window) for a quick visual pass
npm run test:e2e:pw:headed
# Debug a specific test with the Playwright inspector
npm run test:e2e:pw:debug
# View the last HTML report (screenshots, traces, videos for any failures)
npm run test:e2e:pw:report
# Record a new test by clicking through the app in a real browser
npm run test:e2e:pw:codegen
How it's wired up
playwright.config.ts boots npm run web:pw (expo start --web --port 8090) automatically and waits for it to respond before running tests, so npm run test:e2e:pw works standalone. Port 8090 is deliberately different from the default 8081 so it never collides with a native expo start --dev-client session you already have running.retain-on-failure), and a trace on the first retry — open any of these from the HTML report (npm run test:e2e:pw:report) or npx playwright show-trace <trace.zip>.projects in playwright.config.ts) since this is a mobile-first app. Add firefox / webkit projects (after npx playwright install firefox webkit) if you need cross-browser coverage.e2e/utils/ui-inspector.ts has reusable helpers: gotoAndCapture (navigate + attach a full-page screenshot), captureAcrossViewports (same page at mobile/tablet/desktop breakpoints), and collectConsoleErrors (assert a screen renders with no console noise).lib/supabase.ts), so the example tests only cover unauthenticated/public routes (/, /legal/*). e2e/auth.setup.ts documents the pattern for authenticated coverage — it no-ops unless you set E2E_TEST_EMAIL / E2E_TEST_PASSWORD for a dedicated test account, and it's not enabled in playwright.config.ts by default so no real sign-in traffic happens without explicit opt-in.app.json's platforms array now includes "web" (previously ["ios", "android"] only) — required for expo start --web to run at all; it does not affect native iOS/Android builds. react-native-web was also added as a dependency via npx expo install react-native-web since the web target referenced it but it wasn't installed.Writing new tests: add *.spec.ts files under e2e/. Use relative paths with page.goto('/some/route') — baseURL is already configured. Prefer getByRole / getByText locators (matches how the app renders through react-native-web's accessibility mapping) over CSS selectors, which are brittle against Metro's generated class names.
Current Coverage (~20% overall):
Test Organization:
__tests__/unit/ - Unit tests for services, utilities, and components__tests__/integration/ - API integration tests__tests__/e2e/ - End-to-end user flow testsWe're actively working to increase test coverage across the codebase. See COVERAGE_IMPROVEMENT_PLAN.md for:
Note: Coverage thresholds are currently disabled in CI to allow incremental improvement without blocking development. Coverage reports are still generated and uploaded to Codecov for visibility.
Short Term:
The API supports realtime bounty status updates via WebSocket or Supabase Realtime.
WebSocket Connection:
const ws = new WebSocket('ws://localhost:3001/events/subscribe');
ws.on('message', (data) => {
const event = JSON.parse(data);
console.log('Realtime event:', event);
});
Event Payload Format:
{
"type": "bounty.status",
"id": "bounty-id-123",
"status": "in_progress",
"timestamp": "2024-01-01T00:00:00.000Z"
}
Status Values:
open - Bounty is available for acceptancein_progress - Bounty has been accepted and is being worked oncompleted - Bounty work has been completedarchived - Bounty has been archived/cancelledEndpoint Documentation:
/events/subscribe-info - WebSocket connection instructions/events/stats - Current connection statistics/events/subscribe - Realtime event streamRealtime events are published when:
open → in_progress)in_progress → completed)Mid Term:
Long Term:
"Docker not found" or service won't start
# Ensure Docker is running
docker --version
docker-compose --version
# Check if ports are available
lsof -i :5432 # PostgreSQL
lsof -i :3001 # API server
"Database connection failed"
# Check if PostgreSQL container is running
docker ps
# Restart database service
pnpm dev:stop
pnpm dev
# Check database logs
docker logs bountyexpo-postgres
"Expo build fails" or Metro bundler issues
# Clear Metro cache
pnpm start --clear
# Clean node_modules and reinstall
rm -rf node_modules
pnpm install
"TypeScript errors in IDE"
# Run type checking manually
pnpm type-check
# Restart TypeScript language server in your IDE
# VS Code: Cmd/Ctrl + Shift + P → "TypeScript: Restart TS Server"
"API endpoints return 401/403 errors"
.env file has correct Supabase credentialspnpm dev:logs"Stripe payments not working"
sk_test_ and pk_test_)"Redis connection issues"
# Check if Redis container is running
docker ps | grep redis
# Restart Redis service
docker compose restart redis
# Check Redis logs
docker logs bountyexpo-redis
# Test Redis connection
cd services/api
npx tsx src/test-redis-simple.ts
"Cache issues or stale data"
# Flush Redis cache (use with caution)
docker exec bountyexpo-redis redis-cli FLUSHDB
# Or disable caching temporarily
# Set REDIS_ENABLED=false in .env
pnpm dev:logs shows all service logsdocker pspnpm dev:stop then pnpm devgit checkout -b feat/your-feature-name
./scripts/setup.sh # Automated setup
# OR follow the "First Run" section above
Make Your Changes: Edit code with hot reloading enabled
Test Your Changes:
pnpm type-check # TypeScript validation
pnpm lint # Code style checks
pnpm dev:logs # Check for errors in services
git add .
git commit -m "feat: add your feature description"
git push origin feat/your-feature-name
feat:, fix:, docs:, etc.)pnpm type-checkpnpm dev + pnpm startWhen using AI assistance:
StyleSheet as a value from react-native (never as a type-only import).lib/types.ts first.(Choose a license—currently unspecified. Consider MIT for openness.)
Built with Expo + React Native. Inspired by lightweight, trust-centered gig flows.
Questions / ideas? Open a discussion or start a PR.