Development SOPs
Standard operating procedures for code development across Burdenoff products.
Development Environment Setup
Prerequisites
# Required tools
- Node.js 18+
- Python 3.12+
- Docker & Docker Compose
- Git
- GitHub CLI (gh)
- Azure CLI (az)
- kubectl
- Helm
Repository Setup
# Clone repository
gh repo clone algoshred/[product]-[service]
# Install dependencies
cd [product]-[service]
# Frontend
npm install
# Python backend
poetry install
poetry shell
# Run development server
npm run dev # or poetry run python main.py
Environment Variables
# Copy example env file
cp .env.example .env.local
# Edit with your values
# Required variables:
- DATABASE_URL
- JWT_SECRET
- REDIS_URL
- API_KEY (if applicable)
Code Development
Feature Development
1. Create Feature Branch
# Update main branch
git checkout main
git pull origin main
# Create feature branch
git checkout -b feature/add-user-profile
# Push to remote
git push -u origin feature/add-user-profile
2. Write Code
// Follow coding standards
// Use strict typing
// Add error handling
// Write clear comments
interface UserProfile {
id: string;
name: string;
email: string;
}
async function getUserProfile(userId: string): Promise<UserProfile> {
try {
const profile = await db.users.findUnique({ where: { id: userId } });
if (!profile) {
throw new Error('User not found');
}
return profile;
} catch (error) {
logger.error('Failed to fetch user profile', { userId, error });
throw error;
}
}
3. Write Tests
import { describe, it, expect } from 'vitest';
import { getUserProfile } from './user-profile';
describe('getUserProfile', () => {
it('should return user profile when user exists', async () => {
const profile = await getUserProfile('user-123');
expect(profile).toBeDefined();
expect(profile.id).toBe('user-123');
});
it('should throw error when user does not exist', async () => {
await expect(getUserProfile('invalid')).rejects.toThrow('User not found');
});
});
4. Run Tests
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode
npm run test:watch
# Run specific test
npm test -- user-profile.test.ts
5. Lint and Format
# Check formatting
npm run format:check
# Fix formatting
npm run format
# Run linter
npm run lint
# Fix linting issues
npm run lint:fix
Code Review Checklist
Before Creating PR
- All tests pass
- Code is formatted
- No linting errors
- No TypeScript errors
- Documentation updated
- Changelog updated
- Commit messages clear
- No console.log statements
- No commented code
- Environment variables documented
Code Quality
- Functions are small and focused
- Variables have descriptive names
- No magic numbers
- Error handling implemented
- Edge cases handled
- Performance considered
- Security best practices followed
Testing
- Unit tests written
- Integration tests (if applicable)
- Test coverage >80%
- Edge cases tested
- Error cases tested
Pull Request Process
Creating a PR
# Ensure branch is up to date
git checkout main
git pull origin main
git checkout feature/add-user-profile
git rebase main
# Push changes
git push origin feature/add-user-profile
# Create PR using GitHub CLI
gh pr create --title "Add user profile feature" \
--body "$(cat <<EOF
## Description
Implements user profile functionality with CRUD operations.
## Changes
- Add user profile model
- Implement profile API endpoints
- Add profile UI components
- Write tests
## Testing
- Unit tests: ✅ Passing
- Integration tests: ✅ Passing
- Manual testing: ✅ Complete
## Screenshots
[Add screenshots if applicable]
EOF
)"
PR Template
## Description
Brief description of what this PR does
## Type of Change
- [ ] Bug fix (non-breaking change)
- [ ] New feature (non-breaking change)
- [ ] Breaking change (fix or feature that would break existing functionality)
- [ ] Documentation update
- [ ] Refactoring
- [ ] Performance improvement
## Related Issues
Closes #123
Related to #456
## Changes Made
- Change 1
- Change 2
- Change 3
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] E2E tests pass (if applicable)
- [ ] Manual testing completed
## Screenshots
(if applicable)
## Checklist
- [ ] Code follows style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated
- [ ] No new warnings
- [ ] Tests added/updated
- [ ] All tests passing
Review Process
Reviewer Responsibilities
- Review within 24 hours
- Check code quality
- Test locally if needed
- Provide constructive feedback
- Approve or request changes
Addressing Feedback
# Make requested changes
git add .
git commit -m "Address review feedback"
git push origin feature/add-user-profile
# Respond to comments in GitHub
# Mark resolved when complete
Database Changes
Creating Migrations
Prisma (Node.js)
# Create migration
npm run migrate:dev -- --name add_user_profile
# Apply migration
npm run migrate:deploy
# Generate client
npm run gendb
Alembic (Python)
# Auto-generate migration
poetry run alembic revision --autogenerate -m "Add user profile table"
# Review generated migration
# Edit if needed
# Apply migration
poetry run alembic upgrade head
# Rollback if needed
poetry run alembic downgrade -1
Migration Guidelines
- Always review auto-generated migrations
- Add data migrations separately
- Test migrations locally
- Include rollback plan
- Document breaking changes
API Development
REST API
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
router = APIRouter()
class UserProfileCreate(BaseModel):
name: str
email: str
class UserProfileResponse(BaseModel):
id: str
name: str
email: str
@router.post("/profiles", response_model=UserProfileResponse)
async def create_profile(
profile: UserProfileCreate,
current_user = Depends(get_current_user)
):
"""Create a new user profile."""
try:
new_profile = await db.profiles.create({
"user_id": current_user.id,
"name": profile.name,
"email": profile.email
})
return new_profile
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
GraphQL API
import { builder } from './builder';
const UserProfile = builder.objectType('UserProfile', {
fields: (t) => ({
id: t.exposeID('id'),
name: t.exposeString('name'),
email: t.exposeString('email'),
}),
});
builder.queryField('userProfile', (t) =>
t.field({
type: UserProfile,
args: {
id: t.arg.id({ required: true }),
},
resolve: async (_, { id }, ctx) => {
return ctx.db.userProfile.findUnique({ where: { id } });
},
})
);
Frontend Development
Component Development
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
interface UserProfileProps {
userId: string;
}
export function UserProfile({ userId }: UserProfileProps) {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await apiClient.post('/profiles', { name, email });
// Handle success
} catch (error) {
// Handle error
}
};
return (
<form onSubmit={handleSubmit}>
<Input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<Input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
type="email"
/>
<Button type="submit">Save Profile</Button>
</form>
);
}
Styling Guidelines
// Use semantic tokens (defined in theme)
// Don't hardcode colors
// Good
<div className="bg-background text-foreground border border-border">
// Avoid
<div className="bg-white text-black border border-gray-300">
// Use Tailwind utilities
<div className="flex items-center gap-4 p-4 rounded-lg shadow-md">
Documentation
Code Documentation
/**
* Fetches user profile by ID
*
* @param userId - The unique identifier of the user
* @returns Promise resolving to UserProfile
* @throws {Error} If user is not found
*
* @example
* ```ts
* const profile = await getUserProfile('user-123');
* console.log(profile.name);
* ```
*/
async function getUserProfile(userId: string): Promise<UserProfile> {
// Implementation
}
README Updates
# Feature: User Profiles
## Overview
User profiles allow users to manage their personal information.
## API Endpoints
### Create Profile
`POST /api/profiles`
Request:
```json
{
"name": "John Doe",
"email": "[email protected]"
}
Response:
{
"id": "prof-123",
"name": "John Doe",
"email": "[email protected]"
}
## Performance Optimization
### Best Practices
- Lazy load components
- Memoize expensive calculations
- Optimize images
- Use pagination
- Implement caching
- Profile performance
### Example
```typescript
import { useMemo } from 'react';
function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
return data.map(item => {
// Expensive processing
return processItem(item);
});
}, [data]);
return <div>{processedData}</div>;
}