feat: add per-space timezone settings and improve booking management

- Add timezone configuration per space with fallback to system default
- Implement timezone-aware datetime display and editing across frontend
- Add migration for per_space_settings table
- Update booking service to handle timezone conversions properly
- Improve .gitignore to exclude build artifacts
- Add comprehensive testing documentation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-02-11 15:54:51 +00:00
parent 6edf87c899
commit 9c2846cf00
17 changed files with 1322 additions and 40 deletions

142
IMPLEMENTATION_SUMMARY.md Normal file
View File

@@ -0,0 +1,142 @@
# Implementation Summary: Timezone Fix + Per-Space Settings
## Overview
Fixed timezone display issues and added per-space scheduling settings to the space booking system.
## Changes Implemented
### Part A: Frontend Timezone Fix ✅
**File: `frontend/src/utils/datetime.ts`**
- Added `ensureUTC()` function to handle naive datetime strings from backend
- Applied `ensureUTC()` to all `new Date()` calls in:
- `formatDateTime()`
- `formatTime()`
- `formatDateTimeWithTZ()`
- `isoToLocalDateTime()`
**File: `frontend/src/views/Dashboard.vue`**
- Imported `ensureUTC` from utils
- Applied to booking date comparisons in `upcomingBookings` computed property
**Impact:** MyBookings now correctly shows times in user's timezone (e.g., 10:00-17:00 Bucharest instead of 08:00-15:00 UTC).
---
### Part B: Per-Space Scheduling Settings (Database) ✅
**File: `backend/app/models/space.py`**
- Added 4 nullable columns:
- `working_hours_start` (Integer)
- `working_hours_end` (Integer)
- `min_duration_minutes` (Integer)
- `max_duration_minutes` (Integer)
**File: `backend/app/schemas/space.py`**
- Added 4 optional fields to `SpaceBase` and `SpaceResponse`
**File: `backend/migrations/004_add_per_space_settings.sql`**
- Created migration (already applied to database)
**Impact:** Spaces can now override global settings. NULL = use global default.
---
### Part C: Timezone-Aware Validation ✅
**File: `backend/app/services/booking_service.py`**
- Imported `Space` model and timezone utilities
- Added `user_timezone` parameter to `validate_booking_rules()`
- Load per-space settings with fallback to global
- Convert UTC times to user timezone for working hours validation
- Fix max bookings per day to use local date boundaries
**File: `backend/app/api/bookings.py`**
Updated 6 endpoints to pass `user_timezone`:
1. **POST /bookings (create)** - Line ~251
2. **POST /bookings/recurring** - Line ~376
- Also fixed: Now converts local times to UTC before storage
3. **PUT /bookings/{id} (update)** - Line ~503
4. **PUT /admin/.../approve** - Line ~682
- Uses booking owner's timezone
5. **PUT /admin/.../update** - Line ~865
- Uses booking owner's timezone
6. **PUT /admin/.../reschedule** - Line ~1013
- Uses booking owner's timezone
**Impact:**
- Working hours validation now uses user's local time (9:00 Bucharest is valid, not rejected as 7:00 UTC)
- Per-space settings are respected
- Recurring bookings now store correct UTC times
---
### Part D: Admin UI for Per-Space Settings ✅
**File: `frontend/src/views/Admin.vue`**
- Added form section "Per-Space Scheduling Settings"
- Added 4 input fields with placeholders indicating global defaults
- Updated `formData` reactive object
- Updated `startEdit()` to load space settings
- Updated `resetForm()` to clear settings
- Added CSS for form-section-header, form-row, and help-text
**File: `frontend/src/types/index.ts`**
- Extended `Space` interface with 4 optional fields
**Impact:** Admins can now configure per-space scheduling rules via UI.
---
## Testing Checklist
### Timezone Display
- [ ] User with `Europe/Bucharest` timezone sees correct local times in MyBookings
- [ ] Booking created at 09:00 Bucharest shows as 09:00 (not 07:00)
### Working Hours Validation
- [ ] Booking at 09:00 Bucharest (07:00 UTC) is accepted (not rejected by 8-20 rule)
- [ ] User sees error message with correct timezone-aware hours
### Per-Space Settings
- [ ] Create space with custom working hours (e.g., 10-18)
- [ ] Booking outside custom hours is rejected
- [ ] Space without settings uses global defaults
- [ ] Admin UI displays and saves per-space settings correctly
### Recurring Bookings
- [ ] Recurring bookings now store correct UTC times
- [ ] Bookings created for multiple occurrences have consistent timezone handling
---
## Files Modified
| # | File | Changes |
|---|------|---------|
| 1 | `frontend/src/utils/datetime.ts` | Added `ensureUTC()` + applied to 4 functions |
| 2 | `frontend/src/views/Dashboard.vue` | Import and use `ensureUTC` |
| 3 | `backend/app/models/space.py` | Added 4 nullable columns |
| 4 | `backend/app/schemas/space.py` | Added 4 optional fields |
| 5 | `backend/migrations/004_add_per_space_settings.sql` | DB migration (applied) |
| 6 | `backend/app/services/booking_service.py` | Timezone-aware validation |
| 7 | `backend/app/api/bookings.py` | Updated 6 callers + recurring fix |
| 8 | `frontend/src/views/Admin.vue` | Admin UI for per-space settings |
| 9 | `frontend/src/types/index.ts` | Extended Space interface |
---
## Known Limitations
1. **SQLite**: COMMENT ON COLUMN not supported (documented in migration file)
2. **Backward Compatibility**: Existing bookings created before fix may have incorrect times (data migration not included)
---
## Next Steps
1. Run frontend ESLint: `cd frontend && npx eslint src/utils/datetime.ts src/views/Dashboard.vue src/views/Admin.vue`
2. Run backend tests: `cd backend && pytest` (if tests exist)
3. Manual testing per checklist above
4. Consider data migration for existing bookings if needed