Development Guide
Development workflows and best practices.
Development Workflow
Daily Workflow
| Bash |
|---|
| # Terminal 1: Backend
task run-backend
# Terminal 2: Frontend
task run-frontend
# Terminal 3: Database (if not running)
task db:docker-start
|
After Backend API Changes
| Bash |
|---|
| # CRITICAL: Regenerate TypeScript client
task frontend:generate-client
# Frontend now has updated types
|
Database Changes
| Bash |
|---|
| # 1. Update model in app/models.py
# 2. Create migration
task db:migrate-create -- "add new field"
# 3. Review migration in migrations/versions/
# 4. Apply migration
task db:migrate-up
|
Clean Architecture Pattern
Always follow: Controllers → Services → Models
1. Define Schema
| Python |
|---|
| # app/schemas/article.py
class ArticleCreate(SQLModel):
title: str
content: str
is_published: bool = False
|
2. Implement Service
| Python |
|---|
| # app/services/article_service.py
class ArticleService:
async def create_article(self, data: ArticleCreate):
article = Article(**data.model_dump())
self.db.add(article)
await self.db.commit()
return article
|
3. Create Controller
| Python |
|---|
| # app/controllers/article.py
@router.post("")
async def create_article(
data: ArticleCreate,
service: ArticleService = Depends(get_article_service)
):
return await service.create_article(data)
|
4. Register Router
| Python |
|---|
| # main.py
app.include_router(article_router, prefix="/api/articles")
|
5. Generate Client
| Bash |
|---|
| task frontend:generate-client
|
6. Create React Hook
| TypeScript |
|---|
| // frontend/src/hooks/api/useArticles.ts
export const useCreateArticle = () => {
return useMutation({
mutationFn: ArticlesService.createArticle,
});
};
|
7. Use in Component
| TypeScript |
|---|
| const Component = () => {
const createMutation = useCreateArticle();
return <Button onClick={() => createMutation.mutate(data)}>Create</Button>;
};
|
Code Style
Python (Backend)
Naming:
- snake_case for functions, variables
- PascalCase for classes
- UPPER_CASE for constants
Type Hints:
| Python |
|---|
| async def create_article(self, data: ArticleCreate) -> ArticleRead:
# Always use type hints
|
Async/Await:
| Python |
|---|
| # Always use async for route handlers
@router.get("/")
async def get_items():
return await service.get_items()
|
TypeScript (Frontend)
Naming:
- PascalCase for components, interfaces
- camelCase for functions, variables
- UPPER_CASE for constants
Components:
| TypeScript |
|---|
| interface Props {
title: string;
}
const Component: React.FC<Props> = ({ title }) => {
return <div>{title}</div>;
};
export default Component;
|
Hooks First:
| TypeScript |
|---|
| const Component = () => {
// 1. Hooks at top
const { data } = useQuery();
const { handleError } = useErrorHandler();
// 2. Event handlers
const handleClick = () => {};
// 3. Early returns
if (!data) return null;
// 4. Render
return <div>Content</div>;
};
|
Testing
Backend Tests
| Bash |
|---|
| # Run all tests
poetry run pytest
# Run specific test
poetry run pytest tests/unit/test_auth.py
# With coverage
poetry run pytest --cov=app
|
Frontend Tests
| Bash |
|---|
| cd frontend
# Run all tests
npm run test
# Watch mode
npm run test -- --watch
# Coverage
npm run test -- --coverage
|
Common Commands
| Bash |
|---|
| # Development
task run-backend
task run-frontend
task frontend:generate-client
# Database
task db:migrate-up
task db:migrate-create -- "description"
task db:docker-start
# Testing
task quality:test
task quality:lint
# Payments (Top G+)
task payments:setup
# Admin (Top G+)
task db:user-create
|
All commands available via task --list
Project Structure
| Text Only |
|---|
| app/
├── controllers/ # HTTP endpoints
├── services/ # Business logic
├── models.py # Database models
├── schemas/ # Request/response models
├── config/ # Configuration
└── core/ # Utilities
frontend/src/
├── pages/ # Route components
├── components/ # Reusable UI
├── hooks/api/ # API hooks
├── client/ # Generated API client
└── theme/ # MUI theme
|
See project files directly in app/ and frontend/src/
Best Practices
Backend
- Use AsyncSession for database
- Validate in service layer
- Handle errors in controllers
- Never commit sensitive data
- Always use type hints
Frontend
- Use unified components from
@/components/ui
- Handle errors with
useErrorHandler
- Use React Query for API calls
- Regenerate client after API changes
- Use TypeScript strict mode
Database
- Create migrations for model changes
- Review auto-generated migrations
- Test migrations in development
- Back up before production migration
External Resources