Contributing Guide
How to contribute to Syllabi - code style, testing, and PR process.
Getting Started
1. Fork and Clone
# Fork the repository on GitHub
# Then clone your fork
git clone https://github.com/YOUR_USERNAME/syllabi.git
cd syllabi2. Set Up Development Environment
Follow the Local Setup Guide to get your development environment running.
3. Create a Branch
git checkout -b feature/your-feature-name
# or
git checkout -b fix/bug-descriptionBranch naming conventions:
feature/- New featuresfix/- Bug fixesdocs/- Documentation changesrefactor/- Code refactoringtest/- Test additions or changes
Code Style
Frontend (Next.js/React)
TypeScript
- Use TypeScript strictly - no
anytypes unless absolutely necessary - Prefer interfaces over types for object shapes
- Use explicit return types for functions
// Good
interface ChatMessage {
id: string
content: string
role: 'user' | 'assistant' | 'system'
}
function formatMessage(message: ChatMessage): string {
return `${message.role}: ${message.content}`
}
// Avoid
type ChatMessage = any
function formatMessage(message) {
return `${message.role}: ${message.content}`
}React Components
- Use functional components with hooks
- Prefer named exports for components
- Use React.memo for expensive components
- Extract complex logic into custom hooks
// Good
export function ChatMessage({ message }: { message: ChatMessage }) {
const formattedTime = useFormattedTime(message.createdAt)
return (
<div className="message">
<p>{message.content}</p>
<time>{formattedTime}</time>
</div>
)
}
// Avoid default exports
export default function ChatMessage() { ... }CSS/Styling
- Use Tailwind CSS for styling
- CSS variables for theme colors (defined in globals.css)
- Avoid inline styles unless dynamic
// Good
<div className="rounded-lg bg-primary p-4 text-white">
Content
</div>
// Avoid
<div style={{ borderRadius: '8px', padding: '16px' }}>
Content
</div>File Organization
src/
├── app/
│ ├── (auth)/ # Auth-related pages
│ ├── chat/ # Chat interface
│ └── api/ # API routes
├── components/
│ ├── ui/ # Reusable UI components
│ └── providers/ # Context providers
├── lib/
│ ├── db/ # Database utilities
│ ├── ai/ # AI/LLM utilities
│ └── utils/ # General utilities
└── types/ # TypeScript type definitionsBackend (FastAPI/Python)
Python Style
- Follow PEP 8 style guide
- Use type hints for all function parameters and returns
- Use Pydantic models for data validation
- Async/await for I/O operations
# Good
from typing import List
from pydantic import BaseModel
class DocumentChunk(BaseModel):
id: str
text: str
embedding: List[float]
async def get_chunks(chatbot_id: str) -> List[DocumentChunk]:
"""Retrieve document chunks for a chatbot."""
return await db.get_chunks(chatbot_id)
# Avoid
def get_chunks(chatbot_id):
return db.get_chunks(chatbot_id)Error Handling
from fastapi import HTTPException, status
async def get_chatbot(chatbot_id: str, user_id: str):
chatbot = await db.chatbots.find_one({
"_id": chatbot_id,
"user_id": user_id
})
if not chatbot:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Chatbot {chatbot_id} not found"
)
return chatbotFile Organization
backend/
├── app/
│ ├── api/
│ │ └── routes/ # API endpoints
│ ├── services/ # Business logic
│ ├── models/ # Pydantic models
│ └── core/ # Config, dependencies
├── workers/ # Celery tasks
└── tests/ # Test filesTesting
Frontend Tests
We use Jest and React Testing Library.
import { render, screen } from '@testing-library/react'
import { ChatMessage } from './chat-message'
describe('ChatMessage', () => {
it('renders message content', () => {
const message = {
id: '1',
content: 'Hello world',
role: 'user' as const,
}
render(<ChatMessage message={message} />)
expect(screen.getByText('Hello world')).toBeInTheDocument()
})
})Run tests:
cd frontend
npm test # Run all tests
npm test -- --watch # Watch mode
npm test -- --coverage # Coverage reportBackend Tests
We use pytest and pytest-asyncio.
import pytest
from app.services.chunking import chunk_document
@pytest.mark.asyncio
async def test_chunk_document():
text = "Long document text..." * 100
chunks = await chunk_document(text, chunk_size=500)
assert len(chunks) > 1
assert all(len(chunk) <= 500 for chunk in chunks)Run tests:
cd backend
pytest # Run all tests
pytest -v # Verbose output
pytest --cov=app # Coverage report
pytest -k "test_chunk" # Run specific testsPull Request Process
1. Before Submitting
- ✅ Tests pass locally
- ✅ No TypeScript errors (
npm run type-check) - ✅ Code is formatted (Prettier)
- ✅ Lint checks pass (ESLint)
- ✅ Commits are clean and descriptive
# Frontend checks
cd frontend
npm run type-check
npm run lint
npm test
# Backend checks
cd backend
pytest
ruff check .
mypy .2. Commit Messages
Follow Conventional Commits (opens in a new tab):
feat: add document folder organization
fix: resolve streaming text display issue
docs: update database schema documentation
refactor: extract chat logic into custom hook
test: add tests for message componentFormat:
<type>: <description>
[optional body]
[optional footer]Types:
feat- New featurefix- Bug fixdocs- Documentation onlystyle- Formatting changesrefactor- Code restructuringtest- Adding testschore- Maintenance tasks
3. Create Pull Request
Title: Use conventional commit format
feat: Add support for video transcriptionDescription Template:
## What does this PR do?
Brief description of the changes.
## Type of change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## How Has This Been Tested?
Describe the tests you ran and how to reproduce them.
## Screenshots (if applicable)
Add screenshots for UI changes.
## Checklist
- [ ] My code follows the style guidelines
- [ ] I have performed a self-review
- [ ] I have commented my code where needed
- [ ] I have updated the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective
- [ ] New and existing tests pass locally4. Code Review Process
- Automated checks must pass (GitHub Actions)
- At least one approval from maintainers required
- Address review comments promptly
- Keep PR focused - one feature/fix per PR
- Rebase if needed to resolve conflicts
5. After Approval
- Maintainer will merge using Squash and Merge
- Your PR will be included in the next release
- You'll be added to contributors list
Development Workflow
Hot Reload Development
Both frontend and backend support hot reload:
# Terminal 1 - Frontend (auto-reloads on file changes)
cd frontend
npm run dev
# Terminal 2 - Backend (auto-reloads with --reload flag)
cd backend
uvicorn app.main:app --reload
# Terminal 3 - Celery worker (manual restart needed)
cd backend
celery -A app.workers.celery_app worker --loglevel=infoDatabase Migrations
When modifying the database schema:
- Create migration file in
frontend/supabase/migrations/ - Name convention:
YYYYMMDD_description.sql - Include rollback if possible
- Test locally before committing
-- 20240115_add_chatbot_status.sql
-- Add status column
ALTER TABLE chatbots
ADD COLUMN status TEXT DEFAULT 'active'
CHECK (status IN ('active', 'paused', 'archived'));
-- Create index
CREATE INDEX idx_chatbots_status ON chatbots(status);
-- To rollback (commented out):
-- ALTER TABLE chatbots DROP COLUMN status;
-- DROP INDEX idx_chatbots_status;Adding New Dependencies
Frontend
cd frontend
npm install package-nameDocument why the package is needed in PR description.
Backend
cd backend
pip install package-name
pip freeze > requirements.txtUpdate both requirements.txt and pyproject.toml if using Poetry.
Feature Development Guidelines
Adding a New Integration (e.g., Telegram)
-
Backend: Create integration service
# backend/app/services/integrations/telegram.py class TelegramIntegration: async def send_message(self, chat_id: str, text: str): ... -
Frontend: Add UI for configuration
// frontend/src/components/integrations/telegram-config.tsx export function TelegramConfig() { ... } -
Database: Add to integrations table
-- Telegram config stored in integrations.config JSONB { "bot_token": "...", "chat_id": "..." } -
Tests: Integration tests for both ends
-
Documentation: Update user guide
Adding a New Skill/Action
-
Define skill interface
// frontend/src/lib/ai/skills/weather.ts export const weatherSkill = { name: 'getWeather', description: 'Get current weather for a location', parameters: z.object({ location: z.string(), }), execute: async ({ location }) => { // Implementation }, } -
Register in skill registry
-
Add to skill selection UI
-
Write tests
-
Document usage
Performance Considerations
Frontend
- Code splitting: Use dynamic imports for heavy components
- Image optimization: Use Next.js Image component
- Memoization: Use React.memo for expensive renders
- Debouncing: Debounce search inputs and API calls
import dynamic from 'next/dynamic'
// Code splitting
const HeavyComponent = dynamic(() => import('./heavy-component'), {
loading: () => <LoadingSpinner />,
})
// Debouncing
import { useDebouncedCallback } from 'use-debounce'
const debouncedSearch = useDebouncedCallback(
(query: string) => {
performSearch(query)
},
500
)Backend
- Use async/await: For all I/O operations
- Batch operations: Reduce database queries
- Caching: Cache expensive computations
- Background tasks: Use Celery for long operations
from functools import lru_cache
@lru_cache(maxsize=100)
def get_embedding_model():
"""Cache model loading"""
return load_model()Security
Never Commit
- ❌ API keys or secrets
- ❌
.envfiles (use.env.example) - ❌ Personal data or test credentials
- ❌ Database dumps with real data
Always
- ✅ Use environment variables for secrets
- ✅ Validate user input (Pydantic/Zod)
- ✅ Check authorization (RLS policies)
- ✅ Sanitize user-generated content
- ✅ Use parameterized queries
// Good - using environment variables
const apiKey = process.env.OPENAI_API_KEY
// Bad - hardcoded secrets
const apiKey = "sk-..." // NEVER DO THISGetting Help
- 💬 GitHub Discussions - Ask questions
- 🐛 GitHub Issues - Report bugs
- 📖 Documentation - Check existing docs first
- 📧 Email - For security issues: security@syllabi.io
Recognition
Contributors are recognized in:
CONTRIBUTORS.mdfile- Release notes
- GitHub contributors graph
Thank you for contributing to Syllabi! 🎉