- Remove EUR_TRADE_MIN, EUR_TRADE_MAX, PREMIUM_PERCENTAGE from shared_constants.py
- Remove eurTradeMin, eurTradeMax, premiumPercentage from shared/constants.json
- Update validate_constants.py to not require removed fields
- Update seed.py and seed_e2e.py to use defaults if fields don't exist
- Update tests to handle missing constants gracefully
- Update ExchangeService to load pricing config from database
- Update validate_eur_amount to use direction-specific limits
- Update apply_premium_for_direction to calculate base + extra premium
- Update create_exchange to use new premium calculation
- Add tests for premium calculation (small trade extra, large trade base only, direction-specific)
- Update existing tests to account for new premium calculation
- Update ExchangeConfigResponse schema with direction-specific fields
- Remove premium_percentage from PriceResponse (now in config)
- Update price endpoint to load pricing config from database
- Update frontend to use direction-specific min/max and calculate premium
- Update tests to seed pricing config
- Add logic to clamp amount when direction changes
- Add PricingConfigResponse and PricingConfigUpdate schemas
- Create PricingService with validation logic
- Add GET and PUT endpoints in routes/pricing.py
- Add MANAGE_PRICING permission to admin role
- Register pricing router in main.py
- Add comprehensive API tests for permissions and validation
- Add seed_pricing_config() function to seed.py
- Seed initial values from shared/constants.json
- Add seeding to seed_e2e.py for E2E tests
- Add tests for seeding functionality
- Create PricingConfig model with all required fields (premium settings, trade limits)
- Implement PricingRepository with singleton pattern (get_current, create_or_update)
- Add comprehensive tests for repository functionality
- Export model and repository in __init__.py files
- Add commit() method to AvailabilityRepository for transaction control
- Add refresh() method to UserRepository
- Update AvailabilityService to use repository.commit() instead of db.commit()
- Update AuthService to use UserRepository.refresh() instead of db.refresh()
- All services now consistently delegate ALL persistence to repositories
- Add create() and update() methods to ExchangeRepository
- Update ExchangeService to use repository methods instead of direct db operations
- All persistence operations now go through repositories consistently
- Fix indentation errors in ExchangeService
- Add create(), update(), and reload_with_relationships() methods to InviteRepository
- Update InviteService to use repository methods instead of direct db operations
- Add create() and update() methods to UserRepository
- Update ProfileService to use repository.update()
- Update AuthService to use repository.create()
- Add create() and create_multiple() methods to AvailabilityRepository
- Update AvailabilityService to use repository methods instead of direct db operations
- Add get_available_slots() and _expand_availability_to_slots() to ExchangeService
- Update routes/exchange.py to use ExchangeService.get_available_slots()
- Remove all business logic from get_available_slots endpoint
- Add AvailabilityRepository to ExchangeService dependencies
- Add Availability and BookableSlot imports to ExchangeService
- Fix import path for validate_date_in_range (use date_validation module)
- Remove unused user_repo variable and import from routes/invites.py
- Fix mypy error in ValidationError by adding proper type annotation
- Create AvailabilityService with get_availability_for_range(), set_availability_for_date(), and copy_availability()
- Move slot validation logic to service
- Update routes/availability.py to use AvailabilityService
- Remove all direct database queries from routes
- Create PriceService with get_recent_prices() and fetch_and_store_price()
- Update routes/audit.py to use PriceService instead of direct queries
- Use PriceHistoryMapper consistently
- Update test to patch services.price.fetch_btc_eur_price
Replace hardcoded (0, 15, 30, 45) tuple with computed range based on
the SLOT_DURATION_MINUTES constant. This ensures the validation stays
in sync if the slot duration is ever changed.
Add test to verify slot minute boundary validation.
- Fix E2E test assertion for buy/sell direction change
- Add data-testid to date buttons for reliable e2e selection
- Update e2e tests to use data-testid instead of fragile weekday matching
- Add tests for regular user cannot complete/no-show trades (COMPLETE_EXCHANGE permission)
- Add endpoint to search users by email (case-insensitive)
- Limit results to 10 for autocomplete purposes
- Require VIEW_ALL_EXCHANGES permission (admin only)
- Add tests for search functionality and access control
The complete_trade and mark_no_show endpoints now use the dedicated
COMPLETE_EXCHANGE permission instead of CANCEL_ANY_EXCHANGE, which
better reflects the semantics of these operations.
The agreed_price depends on trade direction (buy/sell) and must be
calculated on the frontend. Returning a buy-side-only agreed_price
from the API was misleading and unused.
Frontend already calculates the direction-aware price correctly.
- Updated auth-context.tsx to use new exchange permissions
(CREATE_EXCHANGE, VIEW_OWN_EXCHANGES, etc.) instead of old
appointment permissions (BOOK_APPOINTMENT, etc.)
- Updated exchange/page.tsx, trades/page.tsx, admin/trades/page.tsx
to use correct permission constants
- Updated profile/page.test.tsx mock permissions
- Updated admin/availability/page.tsx to use constants.exchange
instead of constants.booking
- Added /api/exchange/slots endpoint to return available slots
for a date, filtering out already booked slots
- Fixed E2E tests:
- exchange.spec.ts: Wait for button to be enabled before clicking
- permissions.spec.ts: Use more specific heading selector
- price-history.spec.ts: Expect /exchange redirect for regular users
Admin trade management:
- GET /api/admin/trades/upcoming: Upcoming booked trades (sorted by time)
- GET /api/admin/trades/past: Past trades with filters
- status, start_date, end_date, user_search
- POST /api/admin/trades/{id}/complete: Mark as completed (after slot time)
- POST /api/admin/trades/{id}/no-show: Mark as no-show (after slot time)
- POST /api/admin/trades/{id}/cancel: Admin cancel trade
AdminExchangeResponse includes user contact info for admin view.
Add GET /api/exchange/price endpoint:
- Available to regular users (BOOK_APPOINTMENT permission)
- Returns current BTC/EUR price with admin premium applied
- Uses cached price from PriceHistory if not stale
- Fetches fresh price from Bitfinex if needed
- Returns is_stale flag when price is older than 5 minutes
- Includes exchange configuration (min/max EUR, increment)
- Handles fetch failures gracefully (returns stale price with error)