- 🎯 Project Overview
- 📁 Directory Structure
- 🔧 Development Workflow
- 📊 Testing Strategy
- 🎨 Code Style Guide
- 🚀 Deployment Guide
- 📈 Performance & Monitoring
- 🔒 Security Best Practices
Church Volunteer Connect is a modern web application that connects church volunteers with meaningful ministry opportunities through spiritual gifts assessment and personalized matching.
- Role-based Authentication: Volunteers and Ministry Leaders
- Spiritual Gifts Assessment: 5-step interactive assessment with biblical context
- Opportunity Management: Browse, filter, and apply for ministry opportunities
- Application Management: Leaders can review and manage volunteer applications
- Profile Management: Skills, interests, and availability tracking
- Data-Driven Testing: Comprehensive test framework with metrics collection
- Runtime: Bun (primary) / Node.js 18+ (fallback)
- Frontend: Next.js 16, React 19, TypeScript
- Styling: Tailwind CSS
- Authentication: NextAuth.js with JWT strategy
- Database: PostgreSQL (production) / SQLite (development)
- ORM: Prisma
- Testing: Vitest (unit), Playwright (E2E), Cucumber (BDD)
- Deployment: Vercel
church-volunteer-app/
├── 📁 src/ # Source code
│ ├── 📁 app/ # Next.js App Router pages
│ │ ├── 📁 api/ # API routes
│ │ ├── 📁 auth/ # Authentication pages
│ │ ├── 📁 dashboard/ # Main dashboard
│ │ ├── 📁 leader/ # Leader-specific pages
│ │ │ ├── 📁 components/ # Leader UI components
│ │ ├── 📁 hooks/ # Leader data hooks
│ │ └── 📁 types/ # Leader TypeScript types
│ │ └── 📁 volunteer/ # Volunteer-specific pages
│ │ ├── 📁 assessment/ # Assessment pages
│ │ └── 📁 opportunities/ # Opportunity browsing
│ ├── 📁 components/ # Shared React components
│ ├── 📁 data/ # Static data
│ │ └── 📁 spiritualGifts/ # Spiritual gifts data
│ ├── 📁 lib/ # Utility libraries
│ │ ├── 📁 metrics/ # Metrics collection
│ │ └── 📁 test-metrics/ # Test analytics
│ └── 📁 test-data/ # Test data management
│ ├── storage.ts # Test data persistence
│ ├── factory.ts # Test data generation
│ └── applications.ts # Application test data
├── 📁 scripts/ # Build and utility scripts
├── 📁 __tests__/ # Global test files
├── 📁 e2e/ # Playwright E2E tests
├── 📁 features/ # Cucumber BDD features
├── 📁 prisma/ # Database schema and migrations
└── 📁 public/ # Static assets
# Install dependencies
bun install
# Set up environment variables
cp .env.example .env.local
# Initialize database
bunx prisma db push
bunx prisma generate
# Seed demo data
bunx tsx prisma/seed.ts# Start development server
bun run dev
# Access at http://localhost:3000# Lint and format code
bun run lint:fix
bun run format
# Type checking
bunx tsc --noEmit# Run unit tests
bun test
# Run E2E tests
bun test:e2e
# Run BDD tests
bun test:bdd
# Test coverage
bun test:coverage- Unit Tests (70%) - Fast, isolated component and function tests
- Integration Tests (20%) - API route and database interaction tests
- E2E Tests (10%) - Complete user workflow tests
- Location:
src/**/*.test.ts - Focus: Components, hooks, utilities
- Command:
bun test
- Location:
e2e/**/*.spec.ts - Focus: Complete user workflows
- Command:
bun test:e2e
- Location:
features/**/*.feature - Focus: Business requirements validation
- Command:
bun test:bdd
import { testDataFactory } from '@/test-data/factory';
// Generate test data
const user = testDataFactory.user('volunteer');
const opportunity = testDataFactory.opportunity('active');import { testDataStorage } from '@/test-data/storage';
// Save and load test data
testDataStorage.save('user', userData);
const loadedData = testDataStorage.load('user');The comprehensive pre-push hook enforces:
- Minimum 95% test pass rate
- Maximum 5 failing tests
- All security tests must pass
- Code quality checks must pass
- Test data validation must pass
// External libraries first
import { NextRequest, NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
// Internal imports with @ alias
import { prisma } from '@/lib/prisma';
import { useSession } from 'next-auth/react';'use client'; // Add for client components
import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
export default function ComponentName() {
// Hooks first
const { data: session } = useSession();
const router = useRouter();
const [state, setState] = useState();
// Effects
useEffect(() => {
// effect logic
}, [dependencies]);
// Event handlers
const handleSubmit = async () => {
// handler logic
};
// Conditional renders for auth/loading
if (!session) return <div>Please sign in</div>;
// Main JSX return
return (
<div className="tailwind-classes">
{/* Component content */}
</div>
);
}import { NextRequest, NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
export async function POST(request: NextRequest) {
try {
const data = await request.json();
// Validation
if (!data.required) {
return NextResponse.json(
{ error: 'Validation message' },
{ status: 400 }
);
}
// Database operations
const result = await prisma.model.create({ data });
return NextResponse.json({ message: 'Success', data: result });
} catch (error) {
console.error('API Error:', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}- Files: kebab-case (
user-profile.tsx,api-route.ts) - Components: PascalCase (
UserProfile,ApiRoute) - Variables: camelCase (
userData,apiResponse) - Constants: UPPER_SNAKE_CASE (
API_BASE_URL,MAX_RETRIES) - Database Models: PascalCase (
User,Opportunity)
// Use responsive prefixes
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">// Group related classes
<div className="bg-white rounded-lg shadow-lg p-6">// Use semantic color classes
<button className="bg-blue-600 hover:bg-blue-700 text-white">
<button className="bg-red-600 hover:bg-red-700 text-white"># Local development with SQLite
DATABASE_URL="file:./dev.db"# Production with PostgreSQL on Vercel
# Use Vercel environment variables
vercel env pull .env.production.local# Production build with Prisma generation
bun run build
# Start production server
bun run start# Deploy to production
vercel --prod
# Deploy to preview
vercel
# View deployment logs
vercel logs
# List deployments
vercel lsimport { testMetricsCollector } from '@/lib/test-metrics';
// Record test execution
testMetricsCollector.recordTestResult('test-name', true, 150);
// Record test data usage
testMetricsCollector.recordTestDataUsage('application', 'factory', false, 50);- Performance: Tests > 30s duration
- Coverage: Coverage < 80%
- Flakiness: Pass rate 30-70%
- Integration: Test data cache hit rate < 50%
import { logger } from '@/lib/logger';
import { recordError } from '@/lib/metrics';
try {
// Application logic
} catch (error) {
logger.error('Operation failed', { context: 'additional-data' });
recordError('/api/endpoint', error);
}import { recordApiResponse } from '@/lib/metrics';
// API response time tracking
const startTime = Date.now();
// ... operation ...
recordApiResponse('/api/endpoint', Date.now() - startTime, response.status);import bcrypt from 'bcryptjs';
// Hash passwords with sufficient salt rounds
const hashedPassword = await bcrypt.hash(password, 12);
// Verify passwords
const isValid = await bcrypt.compare(password, hashedPassword);import { getServerSession } from 'next-auth';
import { authOptions } from '@/pages/api/auth/[...nextauth]';
// Secure session validation
const session = await getServerSession(authOptions);
if (!session || session.user.role !== 'LEADER') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}import { z } from 'zod';
import { validationErrorResponse } from '@/lib/api-response';
const userSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string().min(2),
});
const result = userSchema.safeParse(requestBody);
if (!result.success) {
return validationErrorResponse(result.error.flatten());
}// Use Prisma ORM for safe database queries
const users = await prisma.user.findMany({
where: {
email: userEmail, // Safe parameterized query
},
});# Never commit sensitive data
.env.local
DATABASE_URL=
NEXTAUTH_SECRET=
JWT_SECRET=import { rateLimit } from '@/lib/rate-limit';
// Apply rate limits
if (!rateLimit(`api:${userId}`, 10, 60 * 60 * 1000)) {
return NextResponse.json({ error: 'Too many requests' }, { status: 429 });
}# Automatically runs before each commit:
- ESLint on changed files
- Prettier formatting
- TypeScript type checking# Comprehensive validation before push:
- Unit tests (98.1% pass rate required)
- E2E tests (must pass)
- Security tests (must pass)
- Code quality checks
- Test data validation# Push schema changes to database
bunx prisma db push
# Generate Prisma client
bunx prisma generate
# Browse database
bunx prisma studio# Populate with demo data
bunx tsx prisma/seed.ts- BDD Testing - Behavior-driven development guide
- E2E Testing - End-to-end testing guide
- Accessibility - WCAG 2.1 AA compliance guide
- Production Best Practices - Production deployment guide
- Observability - Monitoring and logging guide
- OpenAPI/Swagger schema available at
/api/docs - Interactive API documentation with request/response examples
- Agent Guidelines - Development agent instructions
- Code Style - Detailed coding standards
# Development
bun run dev # Start dev server
bun run build # Production build
bun run test # Run unit tests
bun run test:e2e # Run E2E tests
bun run lint:fix # Fix linting issues
bun run format # Format code
# Database
bunx prisma db push # Sync schema
bunx prisma generate # Generate client
bunx prisma studio # Database browser
# Deployment
vercel --prod # Deploy to production
vercel env pull # Sync environment# Volunteer Account
Email: volunteer@demo.com
Password: password123
# Leader Account
Email: leader@demo.com
Password: password123# Required
DATABASE_URL= # Database connection string
NEXTAUTH_URL= # NextAuth URL
NEXTAUTH_SECRET= # NextAuth secret
# Optional
JWT_SECRET= # JWT signing secret
SENTRY_DSN= # Error trackingLast Updated: November 23, 2024