Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: CI Pipeline

on:
push:
branches: [ main]
pull_request:
branches: [ main]

env:
NODE_VERSION: '18'

jobs:
playwright:
name: Playwright Tests
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 8

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Install Playwright browsers
run: pnpm dlx playwright install --with-deps

- name: Set up environment variables
run: |
echo "NEXT_PUBLIC_FIREBASE_API_KEY=${{ secrets.FIREBASE_API_KEY }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=${{ secrets.FIREBASE_AUTH_DOMAIN }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_FIREBASE_PROJECT_ID=${{ secrets.FIREBASE_PROJECT_ID }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=${{ secrets.FIREBASE_STORAGE_BUCKET }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=${{ secrets.FIREBASE_MESSAGING_SENDER_ID }}" >> $GITHUB_ENV
echo "NEXT_PUBLIC_FIREBASE_APP_ID=${{ secrets.FIREBASE_APP_ID }}" >> $GITHUB_ENV
echo "FIREBASE_SERVICE_ACCOUNT_KEY=${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY }}" >> $GITHUB_ENV
echo "FIREBASE_PROJECT_ID=${{ secrets.FIREBASE_PROJECT_ID }}" >> $GITHUB_ENV
echo "FIREBASE_CLIENT_EMAIL=${{ secrets.FIREBASE_CLIENT_EMAIL }}" >> $GITHUB_ENV
echo "FIREBASE_PRIVATE_KEY=${{ secrets.FIREBASE_PRIVATE_KEY }}" >> $GITHUB_ENV

- name: Build application
run: pnpm run build

- name: Run Playwright tests
run: pnpm run test:e2e

- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30

- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-results
path: test-results/
retention-days: 30

quality:
name: Code Quality
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 8

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run ESLint
run: pnpm run lint

- name: Run TypeScript type check
run: pnpm run type-check

- name: Check build
run: pnpm run build
235 changes: 225 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This is a ready-to-use template for competitions featuring a Next.js application
```bash
git clone <your-repo-url>
cd your-project-name
npm install
pnpm install
```

### 2. Firebase Configuration
Expand All @@ -32,19 +32,49 @@ Edit `.env.local` with your Firebase config:
```env
NEXT_PUBLIC_FIREBASE_API_KEY=your_api_key_here
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_project_id.firebaseapp.com
NEXT_PUBLIC_FIREBASE_DATABASE_URL=https://your_project_id-default-rtdb.firebaseio.com/
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_project_id_here
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_project_id.appspot.com
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_messaging_sender_id_here
NEXT_PUBLIC_FIREBASE_APP_ID=your_app_id_here

FIREBASE_PROJECT_ID=your_project_id_here
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your_project_id.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYour private key here\n-----END PRIVATE KEY-----\n"
FIREBASE_DATABASE_URL=https://your_project_id-default-rtdb.firebaseio.com/
```

### 4. Run Development Server
```bash
npm run dev
pnpm run dev
```

Visit [http://localhost:3000](http://localhost:3000) to see your app.

## 🏗️ Architecture

This template uses a clean, modular architecture designed for maintainability and scalability:

### Configuration Management
- **Centralized Config** - All environment variables managed in `src/config/env.ts`
- **Type Safety** - Full TypeScript support for configuration
- **Separation of Concerns** - Client and admin configs clearly separated

### Logging System
- **Structured Logging** - Consistent log formatting with prefixes
- **Environment Aware** - Debug logs only in development
- **Extensible** - Easy to swap logger implementations

### API Response Standards
- **Consistent Format** - Standardized success/error responses
- **Timestamp Tracking** - All responses include timestamps
- **Error Handling** - Proper error serialization and logging

### Health Monitoring
- **Firebase Health Checks** - Automated connectivity testing
- **Database URL Validation** - Smart detection of misconfigured services
- **Modular Design** - Separate functions for different service checks

## 🛠️ What's Included

### Complete CRUD Operations
Expand All @@ -61,29 +91,175 @@ Visit [http://localhost:3000](http://localhost:3000) to see your app.
- **Firebase Auth** ready for authentication
- **Real-time updates** between UI and database
- **Responsive design**
- **Structured Logging** with custom logger
- **Centralized Configuration** management
- **API Health Checks** and monitoring
- **End-to-End Testing** with Playwright
- **CI/CD Ready** with GitHub Actions

### Project Structure
```
├── src/
│ ├── app/
│ │ ├── page.tsx # Main task manager component
│ │ ├── layout.tsx # Root layout
│ │ └── globals.css # Global styles
│ │ ├── api/
│ │ │ ├── example/ # Example API route
│ │ │ │ └── route.ts # GET/POST examples
│ │ │ └── firebase-test/ # Firebase health check
│ │ │ └── route.ts
│ │ ├── page.tsx # Main task manager component
│ │ ├── layout.tsx # Root layout
│ │ └── globals.css # Global styles
│ ├── config/
│ │ └── env.ts # Centralized environment config
│ └── lib/
│ └── firebase.ts # Firebase configuration
│ ├── firebaseClient.ts # Firebase client configuration
│ ├── firebaseAdmin.ts # Firebase admin configuration
│ ├── firebaseHealth.ts # Firebase connectivity checks
│ ├── logger.ts # Structured logging system
│ └── responses.ts # Standardized API responses
├── tests/
│ └── e2e/
│ ├── foundation.spec.ts # Foundation tests
│ └── homepage.spec.ts # Homepage tests
├── .github/
│ └── workflows/
│ └── ci.yml # CI/CD pipeline
├── playwright.config.ts # Playwright configuration
├── .env.example # Environment variables template
└── package.json
```

## 🔧 Available Scripts

```bash
npm run dev # Start development server
npm run build # Build for production
npm run start # Start production server
npm run lint # Run ESLint
pnpm dev
pnpm build
pnpm start
pnpm lint
pnpm type-check

pnpm test
pnpm test:e2e
pnpm test:e2e:ui
pnpm test:e2e:debug
```

## 🧪 Testing

This template includes foundation testing with **Playwright** (E2E) and **Bruno** (API) to verify that your basic setup works correctly.

### Testing Stack
- **Playwright** - End-to-end testing of frontend user flows
- **Bruno** - API route testing with collection-based approach
- **GitHub Actions** - Automated testing in CI/CD pipeline

### What's Tested

**Playwright (E2E):**
- ✅ Homepage loads correctly
- ✅ Basic UI interactions work
- ✅ API endpoints respond correctly

**Bruno (API):**
- ✅ API health check endpoint
- ✅ Firebase connection test
- ✅ Example API route

### Running Tests Locally

#### Playwright Tests
```bash
pnpm test

pnpm test:e2e:ui

pnpm test:e2e:debug
```

#### Bruno API Tests
```bash
pnpm add -g @usebruno/cli

bru run bruno/"Foundation API Tests"

bru run bruno/"Foundation API Tests"/"Health Check.bru"
```

### Test Structure
```
tests/
└── e2e/
├── foundation.spec.ts # Foundation API tests
└── homepage.spec.ts # Homepage functionality tests
bruno/
└── Foundation API Tests/
├── Health Check.bru # API health test
├── Firebase Test.bru # Firebase connection test
└── Example API.bru # Basic API test
```

### Example Tests

**Playwright (E2E):**
```typescript
import { test, expect } from '@playwright/test'

test('homepage loads correctly', async ({ page }) => {
await page.goto('/')
await expect(page.locator('h1')).toContainText('Task Manager')
})
```

**Bruno (API):**
```javascript
test("Status should be 200", function() {
expect(res.getStatus()).to.equal(200);
});

test("Response should contain status ok", function() {
expect(res.getBody().status).to.equal("ok");
});
```

### CI/CD Testing

GitHub Actions automatically runs tests on every PR and merge:
- **Foundation Tests** - Verify basic setup works
- **Code Quality** - ESLint and TypeScript checks

#### Required GitHub Secrets
For CI/CD to work, add these secrets to your GitHub repository:
```
FIREBASE_API_KEY
FIREBASE_AUTH_DOMAIN
FIREBASE_PROJECT_ID
FIREBASE_STORAGE_BUCKET
FIREBASE_MESSAGING_SENDER_ID
FIREBASE_APP_ID
FIREBASE_SERVICE_ACCOUNT_KEY
FIREBASE_CLIENT_EMAIL
FIREBASE_PRIVATE_KEY
```

### Adding Your Own Tests

**For E2E Tests (Playwright):**
1. Add new test files in `tests/e2e/`
2. Test complete user workflows
3. Focus on critical user journeys

**For API Tests (Bruno):**
1. Create new `.bru` files in Bruno collections
2. Test your custom API endpoints
3. Validate request/response contracts
4. Test error scenarios and edge cases

**Best Practices:**
- Keep tests simple and focused
- Test critical paths first
- Use Bruno for API contract testing
- Use Playwright for user experience validation

## 🎯 Competition Tips

### Quick Customization
Expand All @@ -92,12 +268,51 @@ npm run lint # Run ESLint
3. **Modify the UI** components for your specific needs
4. **Add more pages** in `src/app/` directory

### Using the Template Architecture

**Adding New API Routes:**
```typescript
import { logger } from '@/lib/logger'
import { successResponse, errorResponse } from '@/lib/responses'

export async function GET() {
try {
return NextResponse.json(successResponse({ data: 'success' }))
} catch (error) {
logger.error('Route error:', error)
return NextResponse.json(
errorResponse('Something went wrong'),
{ status: 500 }
)
}
}
```

**Using the Logger:**
```typescript
import { logger } from '@/lib/logger'

logger.info('User action completed')
logger.error('Database error:', error)
logger.debug('Development info')
```

**Adding Health Checks:**
```typescript
import { checkFirestore } from '@/lib/firebaseHealth'

if (await checkFirestore()) {
}
```

### Common Extensions
- Add user authentication with Firebase Auth
- Implement real-time updates with onSnapshot
- Add file upload with Firebase Storage
- Create API routes in `src/app/api/`
- Add more complex data relationships
- Extend logging with external services (Sentry, LogRocket)
- Add caching layer for health checks

### Firebase Firestore Rules
For development, use these rules (update for production):
Expand Down
Loading
Loading