Passa al contenuto principale

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​

  1. GitHub Discussions: Domande generali, idee, showcase
  2. GitHub Issues: Bug reports, feature requests
  3. Discord/Slack: Chat in tempo reale (se disponibile)
  4. 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.

Questa pagina ti Γ¨ stata utile?