JackerBox is a modern equipment rental platform built with Next.js, Prisma, and TypeScript. It features secure authentication with multiple providers, including Apple Sign In, and robust webhook handling.
- 🔐 Secure authentication with multiple providers (Apple, Google)
- 📱 Responsive design for all devices
- 🔍 Advanced equipment search functionality
- 💳 Stripe integration for payments
- 📸 Image handling with Cloudinary
- 🗄️ PostgreSQL database with Prisma ORM
- 🚀 Deployed on Netlify
- Node.js 20 or later
- PostgreSQL
- Redis (for rate limiting)
- Stripe account
- Apple Developer account
- Cloudinary account
-
Clone the repository:
git clone https://github.com/yourusername/jackerbox.git cd jackerbox -
Install dependencies:
npm install
-
Set up environment variables:
cp .env.example .env # Edit .env with your configuration -
Set up the database:
npx prisma migrate dev npx prisma generate npx prisma db seed
-
Run the development server:
npm run dev
-
Configure your Apple Developer account:
- Add webhook URL:
https://[your-domain]/api/webhooks/apple - Generate webhook public key
- Add the public key to your environment variables
- Add webhook URL:
-
The webhook handles:
- Email disabled events
- Consent revoked events
- Account deletion requests
The webhook endpoints are protected by rate limiting:
- 10 requests per minute per IP
- Uses Upstash Redis for storage
- Configurable limits in the code
-
Set up Netlify:
npm install -g netlify-cli netlify login netlify init
-
Configure build settings:
- Build command:
npm run build - Publish directory:
.next - Environment variables: Copy from
.env
- Build command:
-
Deploy:
git push # Netlify will automatically deploy
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For support, email support@jackerbox.com or open an issue on GitHub.
- User authentication with email/password and social login
- Equipment listings with detailed information and images
- Search and filtering of equipment
- Secure booking and payment processing
- In-app messaging between users
- Reviews and ratings system
- Admin moderation tools
Follow this guide to test the complete user journey and verify all MVP features are working correctly.
-
Create an Account
- Register with email/password
- Complete your profile information
- Add a profile picture
-
Create Equipment Listings
- Navigate to "Equipment" > "Add New Equipment"
- Upload equipment images (minimum 5 required)
- Fill in all required equipment details
- Set daily rates and security deposit
- Save the listing
-
Manage Equipment Listings
- View your listings in the dashboard
- Edit equipment details
- Toggle availability status
- Review incoming rental requests
-
Approve and Complete Rentals
- When rental requests come in, approve them
- Use the messaging system to coordinate with renters
- Mark rentals as completed when equipment is returned
- Respond to any reviews
-
Browse Equipment
- Use search and filters to find equipment
- Review equipment details and images
- Check availability for your desired dates
-
Book Equipment
- Select dates from the calendar
- Submit a booking request
- Complete the mock payment process
-
Manage Bookings
- View your bookings in the dashboard
- Message equipment owners
- Cancel bookings if needed
- Mark rentals as completed
- Leave reviews for completed rentals
-
Content Moderation
- Log in as an admin user
- Review equipment listings
- Approve, flag, or reject equipment
-
User Management
- View and manage user accounts
- Handle verification requests
- Manage user roles
-
Rental Management
- Monitor active rentals
- Handle dispute resolution
- Process refunds if necessary
The application is configured for easy local development:
- Authentication works in development mode
- Payments use a mock system that automatically succeeds
- Image uploads fallback to local storage when Cloudinary is not configured
- Real-time features use a fallback polling mechanism
The following environment variables are required:
# Database
DATABASE_URL=
# Auth
NEXTAUTH_URL=http://localhost:3001
NEXTAUTH_SECRET=
# OAuth (optional)
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Cloudinary (optional - falls back to local storage)
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
MIT
- Frontend: Next.js, React, Tailwind CSS
- Backend: Next.js API routes
- Database: PostgreSQL with Prisma ORM
- Authentication: NextAuth.js
- Styling: Tailwind CSS, Shadcn UI components
- Deployment: Vercel
- Identity Verification: Stripe Identity
- Phone Verification: Firebase Authentication
- Node.js 18+ and npm
- A Stripe account for payment processing
- A Firebase project for phone verification
-
Clone the repository:
git clone https://github.com/yourusername/jackerbox.git cd jackerbox -
Install dependencies:
npm install
-
Set up environment variables:
- Copy
.env.exampleto.env - Fill in the required environment variables
- Copy
-
Set up the database:
npx prisma migrate dev
-
Start the development server:
npm run dev
Jackerbox uses Stripe for payment processing. To set up Stripe:
-
Create a Stripe account at stripe.com
-
Get your API keys from the Stripe Dashboard
-
Add the following to your
.envfile:STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_key NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_your_stripe_publishable_key STRIPE_WEBHOOK_SECRET=whsec_your_stripe_webhook_secret STRIPE_ACCOUNT_COUNTRY=US -
Set up Stripe Connect for owner payouts:
- Enable Connect in your Stripe Dashboard
- Configure the Connect settings for your platform
- Update the Stripe Connect integration in the application
-
Set up Stripe webhooks:
- Create a webhook endpoint in the Stripe Dashboard
- Point it to
https://your-domain.com/api/webhooks/stripe - Select the events you want to listen for (payment_intent.succeeded, etc.)
- Get the webhook signing secret and add it to your
.envfile
Jackerbox uses Stripe Identity for ID verification. To set up Stripe Identity:
- Enable Stripe Identity in your Stripe Dashboard
- Configure the Identity settings for your platform
- Set up Stripe Identity webhooks:
- Create a webhook endpoint in the Stripe Dashboard
- Point it to
https://your-domain.com/api/webhooks/stripe-identity - Select the Identity events you want to listen for (identity.verification_session.verified, etc.)
- Get the webhook signing secret and add it to your
.envfile asSTRIPE_IDENTITY_WEBHOOK_SECRET
Jackerbox uses Firebase Authentication for phone number verification. To set up Firebase:
- Create a Firebase project at firebase.google.com
- Enable Phone Authentication in the Firebase Console
- Add your app to the Firebase project and get the configuration
- Add the following to your
.envfile:NEXT_PUBLIC_FIREBASE_API_KEY=your_firebase_api_key NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project.appspot.com NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_messaging_sender_id NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id - Configure the allowed domains for reCAPTCHA verification in the Firebase Console
To create an admin user:
npm run create-admin your-email@example.comThe database schema is defined in prisma/schema.prisma. To update the schema:
- Edit the schema file
- Run migrations:
npx prisma migrate dev --name your_migration_name
/api/payments/create-intent- Create a payment intent/api/payments/process-payout- Process owner payout/api/webhooks/stripe- Stripe webhook handler/api/webhooks/stripe-identity- Stripe Identity webhook handler/api/stripe/identity-verification- Create a Stripe Identity verification session/api/users/update-phone- Update user's phone number/api/users/verify-phone- Verify user's phone number/api/notifications- Get user notifications
-
Build the application:
npm run build
-
Start the production server:
npm start
This project is licensed under the MIT License - see the LICENSE file for details.
Jackerbox uses AWS S3 for storing and serving files. To set up your S3 bucket:
- Create an AWS account if you don't have one
- Create an IAM user with programmatic access and S3 permissions
- Get your AWS access key and secret key
- Add them to your
.envfile:AWS_REGION=us-east-2 AWS_ACCESS_KEY_ID=your-access-key-id AWS_SECRET_ACCESS_KEY=your-secret-access-key AWS_S3_BUCKET_NAME=your-bucket-name - Run the setup script to create and configure your S3 bucket:
npm run create-s3-bucket
This script will:
- Create a new S3 bucket with the name specified in your
.envfile - Configure CORS settings to allow cross-origin requests
- Set up a bucket policy to allow public read access
- Configure public access settings
For faster content delivery, you can set up a CloudFront distribution for your S3 bucket:
-
Run the CloudFront setup script:
npm run setup-cloudfront
-
Add the CloudFront domain to your
.envfile:CLOUDFRONT_DOMAIN=your-cloudfront-domain.cloudfront.net CLOUDFRONT_DISTRIBUTION_ID=your-distribution-id -
The application will automatically use CloudFront for serving files when available.
Jackerbox uses pre-signed URLs for secure client-side uploads to S3. This approach:
- Prevents unauthorized uploads
- Allows for direct uploads from the browser to S3
- Supports progress tracking
- Reduces server load
To use the file upload component:
import { FileUpload } from '@/components/ui/file-upload';
function MyComponent() {
const handleUploadComplete = (files) => {
console.log('Uploaded files:', files);
};
return (
<FileUpload
onUploadComplete={handleUploadComplete}
folder="profile-images"
multiple={false}
/>
);
}The S3 service provides the following functions:
uploadToS3(file, contentType, folder?, filename?)- Upload a file to S3getSignedUploadUrl(key, contentType, expiresIn?)- Generate a pre-signed URL for uploadinggetSignedDownloadUrl(key, expiresIn?)- Generate a pre-signed URL for downloadinggetPublicS3Url(key)- Get the public URL for an object (uses CloudFront if available)objectExists(key)- Check if an object existslistObjects(prefix?, maxKeys?)- List objects in a foldercopyObject(sourceKey, destinationKey)- Copy an object within S3deleteFromS3(key)- Delete an object from S3invalidateCloudFrontCache(paths)- Invalidate CloudFront cache for specific paths