We welcome contributions to the Ceboelha API! This guide will help you get started.
Getting Started
Prerequisites
- Bun 1.0 or higher
- MongoDB 7.0 or higher (local or Docker)
- Git
- Code editor (VS Code recommended)
Development Setup
Clone the Repository
git clone https://github.com/yourusername/ceboelha-api.git
cd ceboelha-api
Configure Environment
Copy the example environment file:Update .env with your local configuration:PORT=3333
NODE_ENV=development
MONGODB_URI=mongodb://localhost:27017/ceboelha
JWT_ACCESS_SECRET=dev-access-secret-at-least-32-chars-long-here
JWT_REFRESH_SECRET=dev-refresh-secret-at-least-32-chars-long-here
CORS_ORIGIN=http://localhost:3000
Start MongoDB
Using Docker:docker run -d \
--name ceboelha-db \
-p 27017:27017 \
mongo:7
Or install and run MongoDB locally. Seed Database (Optional)
bun run db:seed
bun run db:seed-foods
Start Development Server
The API will be available at:
Code Style
We use Biome for linting and formatting.
Configuration
Biome is configured in biome.json:
{
"formatter": {
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "asNeeded"
}
}
}
Style Guidelines
- Indentation: 2 spaces (no tabs)
- Line Width: 100 characters maximum
- Quotes: Single quotes for strings
- Semicolons: Only when needed (ASI)
- Imports: Organized automatically by Biome
Running Linter
# Check for issues
bun run lint
# Format code
bun run format
Run bun run format before committing to ensure consistent code style.
Project Structure
src/
├── app.ts # Main application setup
├── index.ts # Entry point
├── config/ # Configuration
│ ├── env.ts # Environment variables
│ └── database.ts # MongoDB connection
├── modules/ # Feature modules
│ ├── auth/ # Authentication
│ ├── users/ # User management
│ ├── foods/ # Food database
│ ├── diary/ # Food diary
│ ├── problematic-foods/
│ ├── insights/
│ ├── news/
│ ├── achievements/
│ └── admin/
├── shared/ # Shared code
│ ├── errors/ # Error handling
│ ├── middlewares/ # Middleware
│ ├── types/ # TypeScript types
│ └── utils/ # Utilities
└── scripts/ # Database seeds, etc.
Development Workflow
Making Changes
Create a Branch
git checkout -b feature/your-feature-name
Branch naming conventions:
feature/ - New features
fix/ - Bug fixes
docs/ - Documentation changes
refactor/ - Code refactoring
test/ - Adding tests
Make Your Changes
- Write clean, readable code
- Follow the existing code style
- Add comments for complex logic
- Update documentation if needed
Test Your Changes
# Run the API in development mode
bun run dev
# Test your endpoints using the Swagger docs
# http://localhost:3333/docs
# Or use curl/Postman/etc.
curl http://localhost:3333/health
Lint and Format
bun run lint
bun run format
Commit Your Changes
Write clear, descriptive commit messages:git add .
git commit -m "feat: add email verification endpoint"
Commit message format:
feat: - New feature
fix: - Bug fix
docs: - Documentation
style: - Formatting
refactor: - Code restructuring
test: - Adding tests
chore: - Maintenance
Push and Create PR
git push origin feature/your-feature-name
Then create a Pull Request on GitHub.
Testing
Manual Testing
Use the Swagger documentation at http://localhost:3333/docs to test endpoints interactively.
Writing Tests
The project uses Bun’s built-in test runner. Test files should end with .test.ts.
Example test structure:
import { describe, expect, test } from 'bun:test'
import { app } from '@/app'
describe('Health Check', () => {
test('GET /health returns 200', async () => {
const response = await app
.handle(new Request('http://localhost/health'))
.then((res) => res.json())
expect(response.success).toBe(true)
expect(response.status).toBe('healthy')
})
})
Run tests:
Pull Request Guidelines
Before Submitting
PR Description
Include in your PR description:
- What: Brief description of changes
- Why: Reason for the changes
- How: Implementation approach
- Testing: How you tested the changes
- Screenshots: If applicable (UI changes)
Example:
## What
Adds email verification for new user registrations
## Why
Enhances security by ensuring users own their email addresses
## How
- Added verification token generation
- Created email sending service
- Added verify-email endpoint
- Updated user model with verified flag
## Testing
- Tested registration flow in development
- Verified email sending works
- Tested token validation
- Tested expired token handling
Review Process
- Maintainers will review your PR
- Address any requested changes
- Once approved, a maintainer will merge your PR
Coding Standards
TypeScript
- Use TypeScript for all code
- Avoid
any type (Biome warns on explicit any)
- Define interfaces for data structures
- Use type inference where appropriate
Error Handling
Use the custom error classes:
import { BadRequestError, NotFoundError, UnauthorizedError } from '@/shared/errors'
// Example
if (!user) {
throw new NotFoundError('User not found')
}
Async/Await
Use async/await instead of promise chains:
// Good
async function getUser(id: string) {
const user = await User.findById(id)
return user
}
// Avoid
function getUser(id: string) {
return User.findById(id).then(user => user)
}
Add comments for:
- Complex business logic
- Non-obvious code
- API endpoint documentation
- Function purposes (JSDoc style)
/**
* Validates and refreshes JWT tokens
* @param refreshToken - The refresh token to validate
* @returns New access and refresh token pair
*/
async function refreshTokens(refreshToken: string) {
// Implementation
}
Module Development
Creating a New Module
Create Module Directory
mkdir -p src/modules/your-module
Create Module Files
src/modules/your-module/
├── index.ts # Export controller
├── controller.ts # Elysia routes
├── service.ts # Business logic
├── model.ts # Mongoose schema
├── types.ts # TypeScript types
└── validation.ts # Input validation
Implement Controller
// controller.ts
import { Elysia } from 'elysia'
import { authMiddleware } from '@/shared/middlewares'
export const yourModuleController = new Elysia({ prefix: '/your-module' })
.use(authMiddleware)
.get('/', async () => {
// Implementation
})
Register in App
// src/app.ts
import { yourModuleController } from '@/modules/your-module'
app.group('/api', (app) =>
app
// ... other modules
.use(yourModuleController)
)
Database Changes
Mongoose Models
- Use TypeScript interfaces for model types
- Add indexes for frequently queried fields
- Include timestamps
- Add validation
Example:
import mongoose from 'mongoose'
interface IExample {
name: string
createdAt: Date
updatedAt: Date
}
const exampleSchema = new mongoose.Schema<IExample>(
{
name: { type: String, required: true, unique: true },
},
{ timestamps: true }
)
exampleSchema.index({ name: 1 })
export const Example = mongoose.model<IExample>('Example', exampleSchema)
Migrations
If you need to migrate existing data:
- Create a script in
src/scripts/
- Document the migration in your PR
- Test on development database first
Documentation
API Documentation
Document endpoints using Elysia’s detail option:
.get('/endpoint', handler, {
detail: {
tags: ['YourModule'],
summary: 'Brief description',
description: 'Detailed description of what this endpoint does',
},
})
Code Documentation
- Add JSDoc comments to functions
- Document complex algorithms
- Explain “why” not just “what”
Getting Help
- Questions: Open a discussion on GitHub
- Bugs: Open an issue with reproduction steps
- Features: Open an issue to discuss before implementing
- Chat: Join our Discord community (if available)
Code of Conduct
Be respectful and constructive:
- Be welcoming to newcomers
- Accept constructive criticism gracefully
- Focus on what’s best for the project
- Show empathy towards other contributors
License
By contributing, you agree that your contributions will be licensed under the MIT License.
Recognition
Contributors will be recognized in:
- GitHub contributors page
- Project README
- Release notes (for significant contributions)