Commit graph

27 commits

Author SHA1 Message Date
0dd84e90a5
refactor(backend): extract pagination utilities
Issue #4: Pagination logic was repeated across multiple routes.

Changes:
- Add pagination.py with reusable utilities:
  - calculate_total_pages: computes page count from total/per_page
  - calculate_offset: computes offset for given page
  - create_paginated_response: builds PaginatedResponse with metadata
- Update routes/audit.py to use pagination utilities
- Update routes/booking.py to use pagination utilities
- Update routes/invites.py to use pagination utilities

The utilities handle the common pagination math while routes
still manage their own query logic (filters, joins, ordering).
2025-12-22 00:00:24 +01:00
09560296aa
refactor: derive Permission type from generated OpenAPI schema
Issue #3: The frontend Permission enum was manually duplicated from
the backend. While full generation isn't practical, this change
ties the frontend constants to the generated OpenAPI types for
compile-time validation.

Changes:
- Update ConstantsResponse schema to use actual Permission/InviteStatus
  enums (enables OpenAPI to include enum values)
- Import enums in schemas.py (no circular dependency issue)
- Update auth-context.tsx to derive PermissionType from generated schema
- Update meta route to return enum instances instead of string values
- Permission values are now type-checked against the OpenAPI schema

If a permission is added to the backend but not to the frontend's
Permission object, TypeScript will fail to compile. This provides
a safety net without requiring a complex build-time generation step.
2025-12-21 23:55:47 +01:00
21698203fe
refactor(auth): unify authorization patterns with MANAGE_OWN_PROFILE permission
Issue #2: The profile route used a custom role-based check instead
of the permission-based pattern used everywhere else.

Changes:
- Add MANAGE_OWN_PROFILE permission to backend Permission enum
- Add permission to ROLE_REGULAR role definition
- Update profile routes to use require_permission(MANAGE_OWN_PROFILE)
- Remove custom require_regular_user dependency
- Update frontend Permission constant and profile page
- Update invites page to use permission instead of role check
- Update profile tests with proper permission mocking

This ensures consistent authorization patterns across all routes.
2025-12-21 23:50:06 +01:00
18284c5e63
Use explicit join in random-jobs endpoint to avoid potential N+1 query
- Changed from using scalars().all() with lazy='joined' relationship
- Now uses explicit join similar to other audit endpoints
- Guarantees single query regardless of SQLAlchemy async behavior
2025-12-21 23:14:08 +01:00
b3ed81e8fd
Phase 4: API Endpoint
- Add RandomNumberOutcomeResponse schema to schemas.py
- Add GET /api/audit/random-jobs endpoint to routes/audit.py
- Returns list of outcomes (newest first, no pagination)
- Requires VIEW_AUDIT permission
- Add tests: admin can access, regular user forbidden, unauthenticated 401
2025-12-21 22:53:54 +01:00
6ca0ae88dd
Phase 2: Job enqueueing from counter
- Add backend/jobs.py with enqueue_random_number_job function
- Modify counter increment endpoint to enqueue job after incrementing
- Add mock_enqueue_job fixture to conftest.py for all tests
- Add test_increment_enqueues_job_with_user_id to verify correct user_id
- Job is enqueued synchronously; failure causes request to fail
2025-12-21 22:44:31 +01:00
607f872c71
fix pre-commit hook and code quality fixes 2025-12-21 22:14:48 +01:00
6c218130e9
Add ruff linter/formatter for Python
- Add ruff as dev dependency
- Configure ruff in pyproject.toml with strict 88-char line limit
- Ignore B008 (FastAPI Depends pattern is standard)
- Allow longer lines in tests for readability
- Fix all lint issues in source files
- Add Makefile targets: lint-backend, format-backend, fix-backend
2025-12-21 21:54:26 +01:00
3369a71271
Improve availability error messages with date context
- Added date to slot overlap error message
- Added date to invalid time range error message
- Makes errors more actionable for users
2025-12-21 17:59:18 +01:00
131477b7f3
Make error messages more descriptive
- Added specific slot time and date to availability error message
- Added appointment ID and context to 'not found' errors
- Added formatted appointment time to past appointment cancellation errors
- Added date context to slot overlap error messages
- All errors now provide actionable information to users
2025-12-21 17:59:08 +01:00
4d5673f181
Standardize timezone usage to timezone.utc
- Replaced all UTC imports with timezone imports
- Changed all datetime.now(UTC) to datetime.now(timezone.utc)
- Consistent with booking.py and more explicit about timezone usage
- Updated models.py, routes/auth.py, and routes/invites.py
2025-12-21 17:58:43 +01:00
1a478f7583
Make copy operation atomic with explicit transaction handling
- Wrapped copy operation in try/except with explicit rollback
- Added comments explaining atomicity
- Ensures all-or-nothing behavior for copying to multiple dates
2025-12-21 17:57:42 +01:00
c24597edb4
Be explicit about eager loading in queries
- Added explicit joinedload(Appointment.user) to admin appointment queries
- Makes the eager loading intention clear and explicit
- Replaced comment-based documentation with actual query options
2025-12-21 17:57:23 +01:00
208278bddb
Use MIN_ADVANCE_DAYS constant globally instead of hardcoded value
- Updated availability.py to use MIN_ADVANCE_DAYS constant instead of hardcoded timedelta(days=1)
- Ensures consistency between booking and availability date ranges
- Both now use the same constant from shared_constants
2025-12-21 17:53:47 +01:00
a14405a998
Derive slot validation from config instead of hardcoded values
- Created _get_valid_minute_boundaries() helper that derives valid minutes from SLOT_DURATION_MINUTES
- Replaced hardcoded (0, 15, 30, 45) with dynamic calculation
- Error message now includes valid minute values for better clarity
2025-12-21 17:53:35 +01:00
d24acfd322
Extract duplicate AppointmentResponse construction to helper
- Created _to_appointment_response() helper function
- Replaced 5 duplicate AppointmentResponse constructions with helper calls
- Helper handles both explicit user_email and eager-loaded user relationship cases
2025-12-21 17:49:37 +01:00
77e7f98e1e
Fix: Add pagination to admin appointments endpoint
- Added pagination with page/per_page query params
- Fixed N+1 query by using eager-loaded user relationship
- Removed unused _get_user_email helper function
- Updated frontend to handle paginated response
- Regenerated API types
2025-12-21 17:32:25 +01:00
1cd60b4bbc
Fix: Load booking constants from shared/constants.json
Created shared_constants.py module that loads constants from the
shared JSON file. Updated availability.py and booking.py to import
from this module instead of hardcoding values.

This ensures backend and frontend stay in sync with the same source
of truth for booking configuration.
2025-12-21 17:29:39 +01:00
19c313767c
Fix: Validate source_date in copy availability endpoint
Added validation to ensure source_date is within the allowed range
(tomorrow to +30 days) for consistency with target_dates validation.
2025-12-21 17:28:21 +01:00
63cf46c230
Fix: Prevent cancellation of past appointments
Add check to both user and admin cancel endpoints to reject
cancellation of appointments whose slot_start is in the past.
This matches the spec requirement that cancellations can only
happen 'before the appointment'.

Added tests for both user and admin cancel endpoints.

Also includes frontend styling updates.
2025-12-21 17:27:23 +01:00
b3e00b0745
Phase 6: Admin appointments view and cancellation with UI and backend tests 2025-12-21 00:30:09 +01:00
5108a620e7
Phase 5: User appointments view and cancellation with UI and e2e tests 2025-12-21 00:24:16 +01:00
06817875f7
Phase 3: Appointment model & booking API with timezone fix 2025-12-21 00:03:34 +01:00
64d2e99d73
Phase 1: Add Availability model and API
- Create Availability model with date, start_time, end_time
- Add availability schemas with 15-minute boundary validation
- Add admin endpoints:
  - GET /api/admin/availability - query by date range
  - PUT /api/admin/availability - set slots for a date
  - POST /api/admin/availability/copy - copy to multiple days
- Add 26 tests covering permissions, CRUD, and validation
2025-12-20 23:36:11 +01:00
d3638e2e69
implemented 2025-12-20 23:06:05 +01:00
a31bd8246c
reviewed 2025-12-20 22:38:39 +01:00
a56a4c076a
first implementation 2025-12-20 22:18:14 +01:00