A modern full-stack application built with Next.js for fitness fundraising with escrow simulation. Connect your Strava activities to fundraising campaigns and earn money for causes you care about.
- Frontend & Backend: Next.js 14 with App Router
- Language: TypeScript
- Database: PostgreSQL with Prisma ORM
- Styling: Tailwind CSS
- Validation: Zod
- Authentication: Privy (planned)
- Escrow: In-memory simulation (no real blockchain for hackathon)
- โ Full-Stack: Single codebase for frontend and backend
- โ Server-Side Rendering: Better SEO and performance
- โ API Routes: RESTful API endpoints
- โ Database Integration: Prisma with PostgreSQL
- โ Real-time Updates: Server-side data fetching
- โ Responsive Design: Mobile-first approach
- โ Type Safety: End-to-end TypeScript
- User - Platform users with Privy integration
- Wallet - User wallets (Privy or manual)
- Fundraise - Fundraising campaigns with deadlines
- Pledge - Staker commitments with per-km rates
- Activity - Fitness activities from Strava
- Payout - Escrow transactions and payouts
- Node.js 18+
- PostgreSQL 12+
- npm or yarn
-
Clone and install dependencies
git clone <repository-url> cd bodo-app npm install
-
Set up environment variables
cp env.example .env.local
Edit
.env.localwith your configuration:DATABASE_URL="postgresql://username:password@localhost:5432/bodo_db" JWT_SECRET=your-super-secret-jwt-key-change-in-production STRAVA_WEBHOOK_SECRET=your-strava-webhook-secret
-
Set up database
# Generate Prisma client npm run db:generate # Push schema to database npm run db:push # Seed with sample data npm run db:seed
-
Start the development server
npm run dev
The application will be available at http://localhost:3000
http://localhost:3000/api
POST /api/user
Create a new user
{
"privyUserId": "privy_user_123",
"stravaId": "strava_456",
"status": "active"
}GET /api/user
Get all users (with pagination)
GET /api/user/:userId
Get user details with related data
PUT /api/user/:userId
Update user details
POST /api/fundraise
Create a new fundraise
{
"userId": "user-uuid",
"title": "Marathon for Cancer Research",
"description": "Running a marathon to raise funds",
"targetAmount": 1000,
"deadline": "2024-12-31T23:59:59Z"
}GET /api/fundraise
Get all fundraises (with filters and pagination)
GET /api/fundraise/:fundraiseId
Get fundraise details with pledges and progress
PUT /api/fundraise/:fundraiseId
Update fundraise details
DELETE /api/fundraise/:fundraiseId
Delete a fundraise (only if no pledges exist)
POST /api/pledge
Create a new pledge
{
"stakerUserId": "user-uuid",
"fundraiseId": "fundraise-uuid",
"perKmRate": 2.5,
"totalAmountPledged": 500
}GET /api/pledge
Get all pledges (with filters and pagination)
GET /api/pledge/:pledgeId
Get pledge details with transaction history
PUT /api/pledge/:pledgeId
Update pledge details
POST /api/webhook/strava
Handle Strava activity events (real webhook)
POST /api/webhook/strava/manual
Manual activity creation for testing
{
"fundraiserUserId": "user-uuid",
"distance": 5.2,
"source": "Strava",
"externalActivityId": "strava_activity_123"
}GET /api/webhook/strava/verify
Strava webhook verification endpoint
- Pledge Creation: Stakers create pledges with per-km rates
- Activity Detection: Strava activities trigger webhooks
- Payout Calculation:
payout = min(distance * perKmRate, amountRemaining) - Transaction Simulation: Mock blockchain transactions
- Balance Updates: Automatic pledge amount tracking
// For each active pledge when activity is detected:
const payoutAmount = Math.min(
activity.distance * pledge.perKmRate,
pledge.amountRemaining
);
// Update pledge amounts
pledge.amountRemaining -= payoutAmount;
pledge.amountPaidOut += payoutAmount;
// Mark as completed if fully paid out
if (pledge.amountRemaining <= 0) {
pledge.status = 'completed';
}-
Start the development server
npm run dev
-
Visit the application
- Homepage: http://localhost:3000
- Fundraises: http://localhost:3000/fundraises
- API: http://localhost:3000/api/user
-
Test API endpoints
# Create a user curl -X POST http://localhost:3000/api/user \ -H "Content-Type: application/json" \ -d '{"privyUserId": "test_user", "status": "active"}' # Create a fundraise curl -X POST http://localhost:3000/api/fundraise \ -H "Content-Type: application/json" \ -d '{"userId": "user-uuid", "title": "Test Fundraise", "targetAmount": 100, "deadline": "2024-12-31T23:59:59Z"}' # Test manual activity curl -X POST http://localhost:3000/api/webhook/strava/manual \ -H "Content-Type: application/json" \ -d '{"fundraiserUserId": "user-uuid", "distance": 10, "source": "Strava", "externalActivityId": "test_activity"}'
The seed script creates:
- 3 users with wallets
- 2 fundraises
- 3 pledges with different rates
- 2 activities with processed payouts
bodo-app/
โโโ app/ # Next.js App Router
โ โโโ api/ # API routes
โ โ โโโ user/
โ โ โโโ fundraise/
โ โ โโโ pledge/
โ โ โโโ webhook/
โ โโโ fundraises/ # Fundraises page
โ โโโ dashboard/ # Dashboard page
โ โโโ globals.css # Global styles
โ โโโ layout.tsx # Root layout
โ โโโ page.tsx # Home page
โโโ lib/ # Utilities
โ โโโ prisma.ts # Database client
โ โโโ validations.ts # Zod schemas
โ โโโ escrow.ts # Escrow service
โโโ components/ # React components
โโโ prisma/
โ โโโ schema.prisma # Database schema
โ โโโ seed.ts # Database seeding
โโโ types/ # TypeScript types
npm run dev # Start development server
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint
npm run db:generate # Generate Prisma client
npm run db:push # Push schema to database
npm run db:migrate # Run database migrations
npm run db:studio # Open Prisma Studio
npm run db:seed # Seed database with sample data| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | Required |
JWT_SECRET |
JWT signing secret | Required |
STRAVA_WEBHOOK_SECRET |
Strava webhook secret | Required |
- Homepage (
/) - Landing page with features overview - Fundraises (
/fundraises) - Browse all fundraising campaigns - Dashboard (
/dashboard) - User dashboard (planned) - Fundraise Details (
/fundraise/[id]) - Individual campaign view (planned)
- Responsive Design - Mobile-first approach
- Progress Bars - Visual fundraising progress
- Status Indicators - Campaign and pledge status
- Navigation - Clean, intuitive navigation
- Input Validation - Zod schema validation
- SQL Injection Protection - Prisma ORM
- Error Handling - Comprehensive error responses
- Type Safety - End-to-end TypeScript
- Server-Side Rendering - Secure data fetching
- โ No real blockchain integration
- โ No JWT authentication
- โ No email notifications
- โ No file uploads
- โ No real-time updates
- โ Limited error handling
- โ No audit logging
- Real blockchain integration (Ethereum/Polygon)
- JWT authentication with Privy
- Real-time notifications (WebSocket)
- Email notifications
- File uploads for campaign images
- Advanced analytics and reporting
- Multi-currency support
- Social features and sharing
- Mobile app integration
- Advanced escrow features
- User dashboard with charts
- Campaign creation wizard
- Pledge management interface
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details
For questions or issues:
- Create an issue in the repository
- Check the API documentation
- Review the sample data and tests
Built with โค๏ธ for hackathon innovation using Next.js