Purpose: Complete workflow for developing features in the SPMS backend.
Related Documentation: Getting Started, Testing Guide, Code Style, CI/CD
This guide walks through the complete process of developing a feature, from planning to deployment. Follow these steps to ensure consistent, high-quality contributions.
develop - Main development branch
- All feature branches created from
develop - All pull requests merge to
develop - Continuous integration runs on every push
main - Production branch
- Only updated via releases
- Protected branch
- Requires pull request approval
- Production deployments require RFC (see Change Management)
-
Create Feature Branch
git checkout develop git pull origin develop git checkout -b feature/your-feature-name
-
Develop and Commit
# Make changes git add . git commit -m "feat: add new feature"
-
Push and Create PR
git push origin feature/your-feature-name # Create pull request on GitHub targeting develop
-
After PR Approval
# PR is merged via GitHub git checkout develop git pull origin develop git branch -d feature/your-feature-name
Use conventional commit format with type prefix:
Format: <type>: <description>
Types:
feat:- New featurefix:- Bug fixdocs:- Documentation changesrefactor:- Code refactoringtest:- Test additions or changesci:- CI/CD changeschore:- Maintenance tasks
Examples:
feat: add user profile export functionality
fix: resolve cache invalidation issue
docs: update API endpoint documentation
refactor: simplify project service logic
test: add unit tests for media validation
ci: update test workflow configuration
chore: update dependencies
Rules:
- Use lowercase for type and description
- Keep description concise (50 characters or less)
- Use imperative mood ("add" not "added")
- No period at the end
Understand requirements:
- Review feature specification or issue
- Clarify acceptance criteria
- Identify affected components
- Estimate complexity
Check existing code:
- Search for similar features
- Review related models and views
- Identify reusable components
- Check for existing tests
Plan approach:
- Sketch data model changes
- Design API endpoints
- Plan service layer methods
- Identify test scenarios
Naming conventions:
feature/short-description # New features
fix/bug-description # Bug fixes
refactor/component-name # Code refactoring
docs/topic # DocumentationCreate branch:
# Ensure develop is up to date
git checkout develop
git pull origin develop
# Create feature branch
git checkout -b feature/project-tags
# Push branch to remote
git push -u origin feature/project-tagsTest-Driven Development (TDD):
- Write failing test:
# projects/tests/test_models.py
def test_project_can_have_tags(self):
"""Test project can be tagged."""
project = Project.objects.create(title="Test")
tag = Tag.objects.create(name="Research")
project.tags.add(tag)
assert tag in project.tags.all()- Run test (should fail):
poetry run pytest projects/tests/test_models.py::test_project_can_have_tags- Implement feature:
# projects/models.py
class Project(models.Model):
# ... existing fields ...
tags = models.ManyToManyField(Tag, related_name="projects")- Run test (should pass):
poetry run pytest projects/tests/test_models.py::test_project_can_have_tags- Refactor if needed
Commit frequently:
# Stage changes
git add projects/models.py projects/tests/test_models.py
# Commit with descriptive message
git commit -m "Add tags field to Project model"Run all tests:
# Run full test suite
poetry run pytest
# Run specific app tests
poetry run pytest projects/tests/
# Run with coverage
poetry run pytest --cov=projectsCheck coverage:
# Generate coverage report
poetry run pytest --cov=. --cov-report=html
# Open htmlcov/index.html
# Ensure new code has >80% coverageTest edge cases:
- Empty inputs
- Null values
- Boundary conditions
- Error conditions
- Permission checks
Run pre-commit hooks:
# Run all hooks
pre-commit run --all-files
# Fix any issues reported
# Stage and commit fixes
git add .
git commit -m "Apply code quality fixes"Check for issues:
# Run flake8
poetry run flake8 projects/
# Run bandit
poetry run bandit -r projects/
# Check migrations
poetry run python manage.py makemigrations --check --dry-runUpdate docstrings:
def calculate_project_score(project, weights):
"""
Calculate weighted score for project.
Args:
project: Project instance
weights: Dictionary of metric weights
Returns:
Float score value
Raises:
ValueError: If weights are invalid
"""
passUpdate README if needed:
- New features
- API changes
- Configuration changes
Add inline comments for complex logic:
# Use exponential decay to favour recent activity
score = sum(
metric.value * (0.95 ** days_old)
for metric in recent_metrics
)Create pull request:
- Push branch:
git push origin feature/project-tags-
Go to GitHub and create PR
-
Fill in PR template:
## Description
Add tagging functionality to projects
## Changes
- Add tags field to Project model
- Create Tag model
- Add API endpoints for tag management
- Add tests for tag functionality
## Testing
- All tests pass
- Coverage: 85%
- Manual testing completed
## Checklist
- [x] Tests added
- [x] Documentation updated
- [x] Pre-commit hooks pass
- [x] No breaking changesPR best practices:
- Keep PRs small (< 500 lines)
- One feature per PR
- Clear description
- Link related issues
- Request specific reviewers
Address feedback:
# Make requested changes
# Commit changes
git add .
git commit -m "Address review feedback"
# Push updates
git push origin feature/project-tagsRespond to comments:
- Acknowledge feedback
- Explain decisions
- Ask clarifying questions
- Mark resolved comments
Monitor CI checks:
- Test workflow (4 shards)
- Coverage check (>80%)
- Pre-commit hooks
- Build check
Fix failures:
# Pull latest changes
git pull origin feature/project-tags
# Fix issues locally
# Run tests
poetry run pytest
# Commit and push
git add .
git commit -m "Fix CI failures"
git push origin feature/project-tagsRequirements:
- All CI checks pass
- Code review approved
- No merge conflicts
- Branch up to date with main
Merge strategies:
Squash and merge (preferred):
- Clean commit history
- Single commit per feature
- Use for feature branches
Merge commit:
- Preserve commit history
- Use for long-running branches
Rebase and merge:
- Linear history
- Use for simple changes
After merge:
# Switch to main
git checkout main
# Pull latest
git pull origin main
# Delete feature branch
git branch -d feature/project-tags
git push origin --delete feature/project-tagsTagging:
# Create release tag
git tag 4.1.2-official
# Push tag
git push origin 4.1.2-officialRelease workflow:
- Tag triggers release workflow
- Tests run (4 shards)
- Docker image built
- Image pushed to GHCR
- Version badge updated
Deployment verification:
# Check deployment in Azure Rancher (preferred method)
# Navigate to: https://rancher.dbca.wa.gov.au
# Select namespace: spms-production
# View deployment status and pod health
# Or via kubectl (if Rancher unavailable)
kubectl get pods -n spms-production
# View logs via Rancher GUI (preferred)
# Navigate to: Workloads → Deployments → spms-deployment-prod
# Click "View Logs" button
# Or via kubectl (if Rancher unavailable)
kubectl logs -f deployment/spms-backend -n spms-production- Create model:
# app/models.py
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name- Create migration:
poetry run python manage.py makemigrations
poetry run python manage.py migrate- Add tests:
def test_tag_creation(self):
tag = Tag.objects.create(name="Research")
assert str(tag) == "Research"- Register in admin:
# app/admin.py
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ["name", "created_at"]- Create serializer:
# app/serializers.py
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ["id", "name", "created_at"]- Create view:
# app/views.py
class TagList(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
tags = Tag.objects.all()
serializer = TagSerializer(tags, many=True)
return Response(serializer.data)- Add URL:
# app/urls.py
urlpatterns = [
path("tags", TagList.as_view()),
]- Add tests:
def test_list_tags(self):
response = self.client.get("/api/v1/tags")
assert response.status_code == 200-
Make changes to models
-
Generate migration:
poetry run python manage.py makemigrations- Review migration:
# View SQL
poetry run python manage.py sqlmigrate app 0001
# Check for issues
poetry run python manage.py makemigrations --check- Test migration:
# Apply migration
poetry run python manage.py migrate
# Test rollback
poetry run python manage.py migrate app 0000
poetry run python manage.py migrate- Commit migration:
git add app/migrations/0001_*.py
git commit -m "Add Tag model migration"Good (< 500 lines):
- Single feature
- Easy to review
- Quick to merge
Bad (> 1000 lines):
- Multiple features
- Hard to review
- Slow to merge
Good:
Add tag filtering to project list API
- Add tags query parameter
- Filter projects by tag IDs
- Add tests for tag filtering
Bad:
Update code
Fix bug
WIP
Do:
- Add new fields as optional
- Deprecate before removing
- Version breaking changes
Don't:
- Remove fields without warning
- Change field types
- Break existing APIs
Unit tests (90%):
- Models
- Serializers
- Services
- Utilities
Integration tests (10%):
- API endpoints
- Multi-model operations
- External integrations
Complete example of adding a feature:
# 1. Create branch
git checkout main
git pull origin main
git checkout -b feature/project-tags
# 2. Write test
# Edit projects/tests/test_models.py
poetry run pytest projects/tests/test_models.py::test_project_tags
# 3. Implement feature
# Edit projects/models.py
poetry run python manage.py makemigrations
poetry run python manage.py migrate
# 4. Run tests
poetry run pytest projects/tests/
poetry run pytest --cov=projects
# 5. Code quality
pre-commit run --all-files
# 6. Commit
git add .
git commit -m "Add tags to Project model"
# 7. Push and create PR
git push -u origin feature/project-tags
# Create PR on GitHub
# 8. Address review feedback
# Make changes
git add .
git commit -m "Address review feedback"
git push origin feature/project-tags
# 9. Merge PR
# Merge via GitHub UI
# 10. Clean up
git checkout main
git pull origin main
git branch -d feature/project-tags- Testing Guide - Testing guidelines
- Code Style - Coding standards
- CI/CD - Deployment pipeline
- Change Management - RFC process for production
- Troubleshooting - Common issues