Add ARG CACHEBUST=1 after FROM nginx:alpine to invalidate stale build cache.
HuggingFace was executing old Dockerfile instructions despite correct commit.
This forces a complete rebuild without cached layers.
fix: comprehensive error handling, UI fixes, and transaction protection
Critical fixes for production deployment:
1. Transaction Protection (CRITICAL)
- Wrap deletion + simulation in transaction.atomic()
- Prevents data loss on runtime errors
- All-or-nothing behavior with automatic rollback
2. Enhanced Validation
- Add resource limits: MAX_TEAMS=100, MAX_PROFILES=100, MAX_TOTAL_SECTIONS=10000
- Validate num_teams range (1-100)
- Validate total sections across all profiles
3. Improved Error Messages
- Parse DRF field-specific errors in frontend
- Show detailed validation errors with examples
- Line-specific error messages with actionable guidance
4. UI Fixes
- Format large numbers with K/M/B suffixes (36.3M GD)
- Calculate and display total construction days
- Fix 'N/A days' bug in results view
5. Request Logging
- Log all simulation requests with client IP
- Log validation errors for debugging
- Log successful simulations with stats
6. Code Quality
- Refactor parse_config() to reduce complexity
- Mo…
fix: add database migrations at container startup and deployment tests
- Convert monolithic views.py (226 lines) into focused components
- Create SimulationMixin and ReportingMixin following Django pattern
- Compose ProfileViewSet with mixins for single-ViewSet-per-resource
- Extract ReportingQueries service to eliminate code duplication
- Fix exception handling with proper DRF exceptions (ValidationError, NotFound, APIException)
- Add exception chaining with 'from e' to preserve stack traces
- Update test assertions for DRF exception response format
- Fix router registrations (one ViewSet per resource path)
- All 73 tests passing
feat: add per-section breakdown to ice usage endpoint and remove redundant ruff config
- Fix total_sections assertion to expect int not string
- Fix DailyProgress count in test_simulate_simple_profile (3 not 4)
- Fix ice_amount assertion to match actual Decimal serialization
All 107 tests now passing with 96% coverage.
feat: migrate from TypedDict to Pydantic for type safety
- Add pydantic>=2.10.6 dependency
- Replace all TypedDict classes with Pydantic BaseModel in simulator.py
- Update ConfigParser to return list[ProfileConfig] instead of list[dict]
- Update views.py to mutate Pydantic model attributes
- Update all test files to use Pydantic models
- Fix StopIteration exception handling in _update_state
- Add type annotation for progress_by_day dict
- Disable ruff SIM108 rule (conflicts with explicit if/else requirement)
This provides runtime validation in addition to static type checking,
fixing all 21 MyPy type errors without using Any or type: ignore.
feat: enable DRF browsable API and add root redirect
- Detect container environment by checking /app directory existence
- Use /tmp/db.sqlite3 for containers (writable, resets on restart)
- Use BASE_DIR/db.sqlite3 for local development (persistent)
- Add ruff exception for S108 (temp file usage acceptable for demo)
- Fixes readonly database error on HuggingFace Spaces
fix: use BuildKit cache mounts for proper non-root permissions
- Replace environment variable with BuildKit cache mount during build
- Add UV_LINK_MODE=copy for cache mount compatibility
- Change CMD to use venv interpreter directly
- Cache speeds builds but not persisted in image
- Follows official Astral Docker best practices
fix: set cache directory for non-root container execution
- Configure UV_CACHE_DIR=/tmp/.uv-cache to allow cache writes in non-root containers
- Configure UV_PROJECT_ENVIRONMENT=/app/.venv to explicitly set venv location
- Fixes HuggingFace Space permission denied error on /.cache directory
feat: add uv.lock for reproducible Docker deployments
- Add uv.lock to repository for frozen dependency resolution
- Update .gitignore to exclude test artifacts (.coverage, __pycache__)
- Remove test artifacts from git history
- Required for HuggingFace Space deployment
fix: replace ThreadPoolExecutor with SynchronousExecutor for SQLite compatibility
- Implement SynchronousExecutor for same-thread execution
- Prevents SQLite database locking in Django test transactions
- Normalize all Decimal outputs to 2 decimal places using quantize()
- Update test expectations for consistent decimal formatting
- Fix average_cost_per_day calculation to use quantized decimals
SQLite database locking prevented ThreadPoolExecutor from working with
Django test transactions which require same-thread database access.
fix: replace parallel ThreadPoolExecutor with single-worker serial execution
- Change ThreadPoolExecutor to fixed max_workers=1 for SQLite compatibility
- Remove TESTING flag and conditional worker count logic
- Add exception handling wrapper around future.result() for error context
- Remove calculation_thread field from results
- Remove threading-specific unit tests
- Update docstrings to remove parallel execution references
Serial execution prevents SQLite database locking while maintaining
proper cleanup semantics through shutdown() method.
fix: disable threading in test environment for SQLite compatibility
Add TESTING flag to test settings and make CostAggregatorService use
serial execution (max_workers=1) in test environment.
SQLite does not support concurrent writes from multiple threads within
the same process, causing database locking errors when ThreadPoolExecutor
spawns parallel worker threads during tests.
Changes:
- Add TESTING=True to config/settings/test.py
- Update CostAggregatorService to detect TESTING flag and force serial
execution (max_workers=1) to avoid SQLite locking
- Production environment unaffected (still uses ThreadPoolExecutor with
configurable worker pool size)
Remove -n auto from test configuration to prevent database locking
errors with SQLite. SQLite does not support concurrent writes, causing
test failures when running tests in parallel.
Tests now run serially, which is compatible with SQLite file-based
database used in both local development and HuggingFace deployment.
feat: complete Wall Construction API with nested progress endpoint and HuggingFace deployment
Add DailyProgressRepository with aggregation methods for efficient data
access layer. Implement cost-overview endpoint that returns profile cost
summary and daily breakdown for a date range.
Repository Features:
- get_by_date: Query progress for profile on specific date with select_related
- get_aggregates_by_profile: Aggregate totals, averages, and counts for date range
- Explicit None handling with ternary operators (no implicit defaults)
Endpoint Features:
- Date range validation with proper YYYY-MM-DD format checking
- Summary statistics: total days, total feet/ice/cost, averages
- Daily breakdown showing only days with actual progress
- Uses repository layer for clean separation of concerns
Tests:
- 7 unit tests for repository methods (filtering, aggregation, edge cases)
- 6 integration tests for cost-overview endpoint (success, validation, errors)
All code passes ruff and mypy with zero violations.
feat: implement daily-ice-usage endpoint for Profile API
Add custom action to ProfileViewSet that returns aggregated daily ice usage
for a specific profile and date. Endpoint accepts date query parameter in
YYYY-MM-DD format and returns total feet built, total ice cubic yards, and
per-section breakdowns.
Implementation uses get_object_or_404 for proper 404 handling, explicit None
checking for aggregate results (no implicit defaults), and proper type
annotations throughout.
Tests added for success case, no-data case, invalid profile, and missing
date parameter validation.
feat: add DailyProgress API with auto-calculation
- Add DailyProgressSerializer with auto-calculation of ice_cubic_yards and cost_gold_dragons
- IceUsageCalculator service invoked during serializer create()
- DailyProgressViewSet with filtering on wall_section and date
- Comprehensive unit tests for serializer (6 tests)
- All 43 tests passing with 100% coverage
feat: add DailyProgress model and IceUsageCalculator service
Implemented TDD approach with full type safety:
- DailyProgress model with wall_section FK, date, feet_built, ice_cubic_yards, cost_gold_dragons
- Unique constraint on (wall_section, date)
- Database migration with indexes on date and (wall_section, date)
- IceUsageCalculator service for ice usage and cost calculations
- Constants: ICE_PER_FOOT=195 yd³/ft, COST_PER_CUBIC_YARD=1900 GD/yd³
- Unit tests for model (3 tests) and calculator (6 tests)
- 37 tests passing, 100% coverage, 0 mypy errors
feat: implement TDD for Wall Construction API with full type safety
Complete test-driven development implementation:
- Profile model with full CRUD API (13 tests, django-filter integration)
- WallSection model with height calculations (11 tests, ice/crew validation)
- Django REST Framework serializers and viewsets with comprehensive test coverage
- Full type safety with django-stubs==5.2.6 and djangorestframework-stubs==3.16.4
- Fixed all 61 mypy errors: added type parameters to ModelSerializer[T] and ModelViewSet[T]
- Updated test fixtures with proper APIClient typing (was object)
- Upgraded factory-boy==3.3.3 for native type annotations
- Removed legacy mypy config from other projects
- 24 tests passing, 96% coverage, 0 mypy errors
chore: cleanup demo project - remove redundancies and fix configs