Contribuire al Progetto
Guida completa per contribuire al progetto Emblema, includendo workflow Git, standard di codice, processo di review e best practices.
π Come Iniziareβ
1. Fork e Cloneβ
# Fork del repository su GitHub
# Poi clona il tuo fork
git clone https://github.com/YOUR_USERNAME/emblema.git
cd emblema
# Aggiungi upstream remote
git remote add upstream https://github.com/emblema-ai/emblema.git
# Verifica remotes
git remote -v
2. Setup Ambienteβ
# Installa dipendenze
pnpm install
# Setup ambiente di sviluppo
./install.sh
# Avvia servizi in sviluppo
docker compose up -d
pnpm dev
3. Verifica Setupβ
# Test che tutto funzioni
pnpm lint
pnpm type-check
pnpm test
# Test sicurezza
pnpm security:scan
πΏ Git Workflowβ
Branch Strategyβ
Utilizziamo Git Flow con le seguenti convenzioni:
main # Produzione stabile
βββ develop # Sviluppo principale
β βββ feature/... # Nuove funzionalitΓ
β βββ fix/... # Bug fixes
β βββ docs/... # Documentazione
βββ release/v1.x.x # Preparazione release
βββ hotfix/... # Fix critici produzione
Naming Conventionsβ
Branch Namesβ
# Features
feature/add-document-search
feature/improve-chat-ui
feature/integrate-whisperx
# Bug fixes
fix/memory-leak-in-chunker
fix/authentication-timeout
fix/file-upload-validation
# Documentation
docs/api-documentation
docs/deployment-guide
docs/contributing-guidelines
# Releases
release/v1.2.0
release/v2.0.0-beta
# Hotfixes
hotfix/security-patch-auth
hotfix/critical-memory-leak
Commit Messagesβ
Seguiamo Conventional Commits:
# Format: <type>(<scope>): <description>
# Types: feat, fix, docs, style, refactor, test, chore
# Examples
feat(chat): add artifact preview functionality
fix(auth): resolve token expiration handling
docs(api): update GraphQL schema documentation
refactor(chunker): optimize memory usage in document processing
test(frontend): add integration tests for document upload
chore(deps): update dependencies to latest versions
# Breaking changes
feat(api)!: redesign document upload API
# With body and footer
feat(chat): add real-time collaboration
Add support for multiple users editing the same document
simultaneously with conflict resolution.
Closes #123
Co-authored-by: Name <email@example.com>
Pull Request Workflowβ
1. Creazione Branchβ
# Sync con upstream
git checkout develop
git pull upstream develop
# Crea nuovo branch
git checkout -b feature/your-feature-name
# Lavora sui cambiamenti
# ... make changes ...
# Commit seguendo convenzioni
git add .
git commit -m "feat(component): add new functionality"
2. Preparazione PRβ
# Sync finale prima di push
git checkout develop
git pull upstream develop
git checkout feature/your-feature-name
git rebase develop
# Push branch
git push origin feature/your-feature-name
3. Creazione Pull Requestβ
Template PR (auto-generato):
## π Descrizione
Breve descrizione dei cambiamenti e motivazione.
Fixes #(issue_number)
## π Tipo di Cambiamento
- [ ] Bug fix (non-breaking change che risolve un problema)
- [ ] Nuova feature (non-breaking change che aggiunge funzionalitΓ )
- [ ] Breaking change (fix o feature che causa problemi di compatibilitΓ )
- [ ] Aggiornamento documentazione
## π§ͺ Test
Descrivi i test eseguiti per verificare i cambiamenti:
- [ ] Test unitari passano
- [ ] Test integrazione passano
- [ ] Test manuali completati
- [ ] Test performance (se applicabile)
## π Checklist
- [ ] Il mio codice segue le guidelines del progetto
- [ ] Ho eseguito self-review del codice
- [ ] Ho commentato codice complesso
- [ ] Ho aggiornato la documentazione
- [ ] I miei cambiamenti non generano warning
- [ ] Ho aggiunto test che provano la fix/feature
- [ ] Tutti i test (nuovi e esistenti) passano
- [ ] Ho aggiornato CHANGELOG.md (se applicabile)
## πΈ Screenshots (se applicabile)
<!-- Aggiungi screenshot per cambiamenti UI -->
## π Issue Collegati
<!-- Link a issue, design docs, etc. -->
π Standard di Codiceβ
1. TypeScript/React Guidelinesβ
Component Structureβ
// β
Good
import React from 'react';
import { useState, useCallback } from 'react';
import { Button } from '@/components/ui/button';
import { useTranslation } from '@/hooks/use-translation';
import { DocumentSchema } from '@/schema/document';
interface DocumentFormProps {
defaultValues?: Partial<DocumentSchema>;
onSubmit: (data: DocumentSchema) => void;
onCancel?: () => void;
}
export const DocumentForm = ({
defaultValues,
onSubmit,
onCancel
}: DocumentFormProps) => {
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = useCallback(async (data: DocumentSchema) => {
setIsLoading(true);
try {
await onSubmit(data);
} finally {
setIsLoading(false);
}
}, [onSubmit]);
return (
<form onSubmit={handleSubmit}>
{/* Component content */}
</form>
);
};
DocumentForm.displayName = 'DocumentForm';
Hook Patternsβ
// β
Custom hook with proper naming and structure
export const useDocumentUpload = () => {
const [progress, setProgress] = useState(0);
const [error, setError] = useState<string | null>(null);
const [isUploading, setIsUploading] = useState(false);
const uploadFile = useCallback(async (file: File) => {
// Implementation
}, []);
const reset = useCallback(() => {
setProgress(0);
setError(null);
setIsUploading(false);
}, []);
return {
uploadFile,
progress,
error,
isUploading,
reset,
};
};
Error Handlingβ
// β
Proper error handling
try {
const result = await apiCall();
return result;
} catch (error) {
if (error instanceof ValidationError) {
toast.error(t("message.error.validation"));
} else if (error instanceof NetworkError) {
toast.error(t("message.error.network"));
} else {
logger.error("Unexpected error", { error, context: "document-upload" });
toast.error(t("message.error.unexpected"));
}
throw error;
}
2. Python/FastAPI Guidelinesβ
Service Structureβ
# β
Good service structure
from typing import List, Optional
from fastapi import HTTPException
from sqlalchemy.orm import Session
from app.models import Document
from app.schemas import DocumentCreate, DocumentUpdate
import logging
logger = logging.getLogger(__name__)
class DocumentService:
"""Service for document operations."""
def __init__(self, db: Session):
self.db = db
async def create_document(
self,
document_data: DocumentCreate,
user_id: str
) -> Document:
"""Create a new document."""
try:
db_document = Document(
**document_data.dict(),
user_id=user_id
)
self.db.add(db_document)
self.db.commit()
self.db.refresh(db_document)
logger.info(
"Document created",
extra={
"document_id": db_document.id,
"user_id": user_id,
"name": document_data.name
}
)
return db_document
except Exception as e:
self.db.rollback()
logger.error(
"Failed to create document",
extra={
"error": str(e),
"user_id": user_id,
"document_name": document_data.name
}
)
raise HTTPException(
status_code=500,
detail="Failed to create document"
)
async def get_documents(
self,
user_id: str,
skip: int = 0,
limit: int = 100,
filters: Optional[dict] = None
) -> List[Document]:
"""Get user documents with pagination and filters."""
query = self.db.query(Document).filter(
Document.user_id == user_id
)
if filters:
if filters.get("status"):
query = query.filter(Document.status == filters["status"])
if filters.get("knowledge_base_id"):
query = query.filter(
Document.knowledge_base_id == filters["knowledge_base_id"]
)
return query.offset(skip).limit(limit).all()
Task Structureβ
# β
Celery task structure
from celery import current_task
from app.celery_app import celery_app
from app.handlers import DocumentHandler
import logging
logger = logging.getLogger(__name__)
@celery_app.task(bind=True, name="process_document")
def process_document(
self,
document_id: str,
config: dict,
retry_count: int = 0
):
"""
Process document with retries and progress tracking.
Args:
document_id: UUID of document to process
config: Processing configuration
retry_count: Current retry attempt
"""
max_retries = 3
try:
# Update task status
self.update_state(
state="PROCESSING",
meta={
"phase": "initialization",
"progress": 0,
"retry_count": retry_count
}
)
handler = DocumentHandler()
# Phase 1: File optimization
self.update_state(
state="PROCESSING",
meta={"phase": "optimization", "progress": 25}
)
optimized_file = handler.optimize_file(document_id)
# Phase 2: Content extraction
self.update_state(
state="PROCESSING",
meta={"phase": "extraction", "progress": 50}
)
content = handler.extract_content(optimized_file)
# Phase 3: Chunking
self.update_state(
state="PROCESSING",
meta={"phase": "chunking", "progress": 75}
)
chunks = handler.create_chunks(content, config)
# Phase 4: Generate embeddings
self.update_state(
state="PROCESSING",
meta={"phase": "embeddings", "progress": 90}
)
embeddings = handler.generate_embeddings(chunks)
# Final result
return {
"status": "completed",
"document_id": document_id,
"chunks_count": len(chunks),
"processing_time": handler.get_processing_time()
}
except Exception as exc:
logger.error(
f"Document processing failed",
extra={
"document_id": document_id,
"error": str(exc),
"retry_count": retry_count
}
)
# Retry logic
if retry_count < max_retries:
logger.info(f"Retrying task (attempt {retry_count + 1})")
raise self.retry(
countdown=60 * (retry_count + 1), # Exponential backoff
max_retries=max_retries,
args=[document_id, config, retry_count + 1]
)
# Final failure
self.update_state(
state="FAILURE",
meta={
"error": str(exc),
"document_id": document_id,
"retry_count": retry_count
}
)
raise
3. Code Quality Rulesβ
ESLint Configurationβ
// .eslintrc.json
{
"extends": [
"next/core-web-vitals",
"@typescript-eslint/recommended",
"prettier"
],
"rules": {
"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"prefer-const": "error",
"no-var": "error",
"react-hooks/exhaustive-deps": "error",
"react/jsx-key": "error"
},
"overrides": [
{
"files": ["**/*.test.ts", "**/*.test.tsx"],
"rules": {
"@typescript-eslint/no-explicit-any": "off"
}
}
]
}
Python Linting (pyproject.toml)β
[tool.ruff]
line-length = 88
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line too long (handled by formatter)
"B008", # do not perform function calls in argument defaults
]
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"] # imported but unused
"tests/**/*.py" = ["B011"] # assert False
[tool.black]
line-length = 88
target-version = ['py310']
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
π Code Review Processβ
1. Review Guidelinesβ
Per Reviewersβ
## Review Checklist
### FunzionalitΓ
- [ ] La feature funziona come specificato
- [ ] Edge cases sono gestiti correttamente
- [ ] Performance impact Γ¨ accettabile
- [ ] Non introduce regressioni
### Codice
- [ ] Codice Γ¨ leggibile e ben strutturato
- [ ] Naming conventions sono rispettate
- [ ] Commenti spiegano il "perchΓ©", non il "cosa"
- [ ] No duplicazione di codice
### Test
- [ ] Test coprono i casi principali
- [ ] Test sono deterministici
- [ ] Mock e fixture sono appropriati
- [ ] Test performance quando necessari
### Sicurezza
- [ ] Input validation Γ¨ presente
- [ ] No hard-coded secrets
- [ ] Error handling non espone info sensibili
- [ ] Permissions/authorization corrette
### Documentazione
- [ ] README aggiornato se necessario
- [ ] API documentation aggiornata
- [ ] Comments inline per logica complessa
- [ ] CHANGELOG aggiornato per breaking changes
Feedback Examplesβ
# β
Good feedback
**Suggestion**: Consider extracting this logic into a separate hook for reusability.
**Issue**: This could cause a memory leak if the component unmounts during the async operation. Consider using `useRef` to track component mount status.
**Performance**: This map operation runs on every render. Consider memoizing with `useMemo`.
**Style**: Let's use the established pattern of destructuring props at the top of the component.
# β Poor feedback
"This is wrong"
"Fix this"
"Bad code"
2. Automated Checksβ
Ogni PR deve passare:
# Required status checks
- β
Tests (Frontend)
- β
Tests (Backend)
- β
Lint & Type Check
- β
Security Scan
- β
Build Check
- β
E2E Tests (for UI changes)
π Documentazioneβ
1. Code Documentationβ
Inline Commentsβ
// β
Good comments - explain "why"
// We use exponential backoff to avoid overwhelming the server
// during high error rates
const retryDelay = Math.min(1000 * Math.pow(2, retryCount), 30000);
// Cache results for 5 minutes to reduce API calls for frequently
// accessed documents during batch operations
const CACHE_TTL = 5 * 60 * 1000;
// β Bad comments - explain "what" (obvious from code)
// Set loading to true
setIsLoading(true);
// Loop through documents
documents.forEach((doc) => {
// ...
});
JSDoc for Functionsβ
/**
* Processes uploaded documents through the AI pipeline.
*
* @param file - The uploaded file to process
* @param options - Processing configuration options
* @param options.chunkingStrategy - Strategy for text chunking
* @param options.language - Language for processing (affects STT/TTS)
* @returns Promise resolving to processing result with task ID
*
* @throws {ValidationError} When file format is not supported
* @throws {QuotaExceededError} When user quota is exceeded
*
* @example
* ```typescript
* const result = await processDocument(file, {
* chunkingStrategy: 'semantic',
* language: 'it'
* });
* console.log(`Task started: ${result.taskId}`);
* ```
*/
export async function processDocument(
file: File,
options: ProcessingOptions,
): Promise<ProcessingResult> {
// Implementation
}
2. API Documentationβ
OpenAPI/Swaggerβ
// API endpoint with proper documentation
/**
* @swagger
* /api/v1/documents:
* post:
* summary: Create a new document
* description: Creates a new document and optionally starts processing
* tags: [Documents]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/CreateDocumentRequest'
* responses:
* 201:
* description: Document created successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Document'
* 400:
* description: Invalid input data
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ValidationError'
* 401:
* description: Authentication required
* 403:
* description: Insufficient permissions
*/
export async function POST(request: Request) {
// Implementation
}
π Bug Reportsβ
Template Issue Bug Reportβ
---
name: π Bug Report
about: Create a report per aiutarci a migliorare
title: "[BUG] "
labels: bug
assignees: ""
---
## π Descrizione Bug
Una descrizione chiara e concisa del bug.
## π Passi per Riprodurre
1. Vai a '...'
2. Clicca su '....'
3. Scrolla fino a '....'
4. Vedi errore
## β
Comportamento Atteso
Descrizione chiara di cosa ti aspettavi che accadesse.
## β Comportamento Effettivo
Descrizione chiara di cosa Γ¨ accaduto invece.
## πΈ Screenshots
Se applicabile, aggiungi screenshots per spiegare il problema.
## π₯οΈ Ambiente
- OS: [e.g. macOS 13.0, Ubuntu 22.04]
- Browser: [e.g. Chrome 120.0, Firefox 121.0]
- Node Version: [e.g. 20.11.0]
- Docker Version: [e.g. 24.0.7]
## π± Mobile (se applicabile)
- Device: [e.g. iPhone 15, Pixel 8]
- OS: [e.g. iOS 17.1, Android 14]
- Browser: [e.g. Safari, Chrome Mobile]
## π Contesto Aggiuntivo
Qualsiasi altra informazione sul problema.
## π Log/Error Messages
Incolla qui eventuali log di errore o stack traces
## β
Checklist
- [ ] Ho cercato issue simili esistenti
- [ ] Ho testato con l'ultima versione
- [ ] Ho fornito tutti i dettagli richiesti
π Feature Requestsβ
Template Issue Feature Requestβ
---
name: π Feature Request
about: Suggerisci un'idea per questo progetto
title: "[FEATURE] "
labels: enhancement
assignees: ""
---
## π― Problema/Motivazione
Una descrizione chiara del problema che questa feature risolverebbe.
Es: Sono sempre frustrato quando [...]
## π‘ Soluzione Proposta
Una descrizione chiara e concisa di cosa vorresti che accadesse.
## π Alternative Considerate
Una descrizione chiara di eventuali soluzioni alternative considerate.
## π Acceptance Criteria
- [ ] Criterio 1
- [ ] Criterio 2
- [ ] Criterio 3
## π¨ Mockups/Designs (se applicabile)
Aggiungi mockups, wireframes o designs per feature UI.
## π§ Considerazioni Tecniche
- Impact su performance
- CompatibilitΓ con esistente
- Sicurezza
- AccessibilitΓ
## π PrioritΓ
- [ ] Must have (critica)
- [ ] Should have (importante)
- [ ] Could have (utile)
- [ ] Won't have (non prioritaria)
## π― Target Users
Chi beneficerebbe di questa feature?
- [ ] Sviluppatori
- [ ] End users
- [ ] Admin
- [ ] Tutti
## π Success Metrics
Come misureremo il successo di questa feature?
- Metric 1: [descrizione]
- Metric 2: [descrizione]
π Riconoscimentiβ
Contributorsβ
Riconosciamo tutti i contributori nel file CONTRIBUTORS.md e attraverso:
- GitHub Contributors graph
- All Contributors bot per riconoscimenti automatici
- Release notes menzionando contributori
- Social media shoutouts per contributi significativi
Badges e Rewardsβ
- π₯ First Contribution: Prima PR merged
- π Bug Hunter: 5+ bug fixes
- β¨ Feature Creator: 3+ feature implementate
- π Documentation Master: Contributi significativi docs
- π Code Reviewer: 20+ review di qualitΓ
- π¨ Security Champion: Trova/risolve problemi sicurezza
π Supportoβ
Dove Chiedere Aiutoβ
- GitHub Discussions: Domande generali, idee, showcase
- GitHub Issues: Bug reports, feature requests
- Discord/Slack: Chat in tempo reale (se disponibile)
- Email: security@emblema.ai per problemi di sicurezza
Response Timesβ
- Bug critici: 24-48 ore
- Bug normali: 3-7 giorni
- Feature requests: 1-2 settimane per valutazione
- Domande: 2-5 giorni
Grazie per contribuire a Emblema! π Ogni contributo, piccolo o grande, fa la differenza nella costruzione di una piattaforma AI migliore per tutti.