Fixed critical issues with the profile page (/dashboard/profile):
1. **Form data not persisting on page refresh**:
- Added useEffect to update form values when user data loads
- Forms now properly populate after auth context loads user data
2. **Blank page on refresh**:
- Added loading and error states for better UX
- Handle case where user is not loaded yet (loading spinner)
- Handle case where user fails to load (retry button)
3. **Password change API endpoint correction**:
- Fixed: POST /api/v1/users/change-password (incorrect)
- Corrected to: PATCH /api/v1/users/me/password (matches backend)
- Updated return type to include { message: string }
The root cause was that useForm defaultValues were set once at
component mount when user was still null. The form never updated
when user data was subsequently loaded by the auth context.
Now the form properly resets with user data via useEffect, and
proper loading/error states prevent showing a blank page.
Refs: apps/frontend/app/dashboard/profile/page.tsx:68-78
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix password change feature that was previously non-functional:
- Add changePassword function in frontend API (src/lib/api/users.ts)
- Update API endpoint to match backend: PATCH /api/v1/users/me/password
- Connect profile page to real API instead of mock implementation
- Export changePassword function from API index
The backend endpoint was already implemented but frontend was using
a placeholder Promise.resolve(). Now properly calls the backend API.
Refs: apps/frontend/app/dashboard/profile/page.tsx:87-105
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace full logo (1875x1699) with simplified icon (512x512) optimized for favicon display
- Implement CSS media queries for automatic theme adaptation:
* Dark mode: white X (#FFFFFF) with cyan dot (#34CCCD)
* Light mode: dark blue X and dot (#1D3865)
- Remove old logo files (xpeditis-icon.svg, xpeditis-logo.svg)
- Simplified design with clean X shape and accent dot for better visibility at small sizes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace the icon with the full Xpeditis logo (logo-black.svg) as requested.
Updated references in:
- app/icon.svg (favicon)
- app/layout.tsx (metadata and social cards)
- public/manifest.json (PWA icon)
Note: The full logo (1875x1699px) will be scaled down in browser tabs.
Consider creating a square optimized version for better display in small sizes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add site favicon and enhance metadata for better SEO and social sharing:
- Added app/icon.svg from existing logo for browser tab icon
- Enhanced metadata with Open Graph and Twitter card support
- Created manifest.json for PWA support
- Added metadataBase for proper social image resolution
- Updated .env.example with NEXT_PUBLIC_APP_URL
The Xpeditis logo (blue background with cyan X) now appears in:
- Browser tabs (favicon)
- Bookmarks
- Mobile home screen (PWA)
- Social media shares (Open Graph)
Configuration for different environments:
- Dev: NEXT_PUBLIC_APP_URL=http://localhost:3000
- Preprod: NEXT_PUBLIC_APP_URL=https://app.preprod.xpeditis.com
- Prod: NEXT_PUBLIC_APP_URL=https://xpeditis.com🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace hardcoded localhost:4000 URLs with NEXT_PUBLIC_API_URL environment variable
in carrier portal pages to support different environments (dev/staging/production).
Pages updated:
- app/carrier/accept/[token]/page.tsx
- app/carrier/reject/[token]/page.tsx
This fixes the issue where preprod environment (app.preprod.xpeditis.com) was calling
localhost:4000 instead of the correct API endpoint (api.preprod.xpeditis.com).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Problems Fixed:
1. **User Creation (Invite)**
- ❌ Missing password field (required by API)
- ❌ Hardcoded organizationId 'default-org-id'
- ❌ Wrong role format (lowercase instead of ADMIN/USER/MANAGER)
- ✅ Now uses currentUser.organizationId from auth context
- ✅ Added password field with validation (min 8 chars)
- ✅ Fixed role enum to match backend (ADMIN, USER, MANAGER, VIEWER)
2. **Role Change (PATCH)**
- ❌ Used 'as any' masking type errors
- ❌ Lowercase role values
- ✅ Proper typing with uppercase roles
- ✅ Added success/error feedback
- ✅ Disabled state during mutation
3. **Toggle Active (PATCH)**
- ✅ Was working but added better feedback
- ✅ Added disabled state during mutation
4. **Delete User (DELETE)**
- ✅ Was working but added better feedback
- ✅ Added disabled state during mutation
5. **UI Improvements**
- Added success messages with auto-dismiss (3s)
- Added error messages with auto-dismiss (5s)
- Added loading states on all action buttons
- Fixed role badge colors to use uppercase keys
- Better form validation before API call
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Problem:
- CSV files uploaded to MinIO via admin panel
- But getAvailableCsvFiles() only listed local filesystem
- Result: rate search returned 0 results even though files exist in MinIO
Solution:
- Modified getAvailableCsvFiles() to check MinIO first
- Lists files from csv_rate_configs table with minioObjectKey
- Falls back to local filesystem if MinIO not configured
- Logs clearly which source is being used
This ensures rate search uses the uploaded CSV files from MinIO storage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changes:
- Moved all Traefik labels from root level to deploy.labels for Swarm compatibility
- Added deploy.restart_policy to backend, frontend, and MinIO services
- Removed restart: unless-stopped (incompatible with Swarm mode)
- Keeps depends_on for startup ordering
This fixes Gateway Timeout errors by ensuring Traefik can properly discover
and route to services when running in Docker Swarm mode.
Services updated:
- xpeditis-backend: Deploy labels + restart policy
- xpeditis-frontend: Deploy labels + restart policy
- xpeditis-minio: Deploy labels + restart policy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed test user migration to use real Argon2id hash for Password123!
- Replaced random uuidv4() with fixed UUIDs in organization seeds
- Updated auth.service.ts to use DEFAULT_ORG_ID constant
- Added ON CONFLICT DO UPDATE to migration for existing users
- Ensures consistent UUIDs across environments (dev/preprod/prod)
Fixes:
- Registration 500 error (foreign key constraint violation)
- Login 401 error (invalid password hash)
- Organization ID mismatch between migrations and application code
Test users (Password: Password123!):
- admin@xpeditis.com (ADMIN)
- manager@xpeditis.com (MANAGER)
- user@xpeditis.com (USER)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL FIX: Frontend was serving raw CSS with uncompiled @tailwind directives,
resulting in completely unstyled pages (plain text without any CSS).
Root cause:
- postcss.config.js and tailwind.config.js/ts were excluded in .dockerignore
- This prevented PostCSS/Tailwind from compiling CSS during Docker builds
- Local builds worked because config files were present
Changes:
1. apps/frontend/.dockerignore:
- Commented out postcss.config.js exclusion
- Commented out tailwind.config.js/ts exclusions
- Added explanatory comments about why these files are needed
2. apps/backend/Dockerfile:
- Copy src/ directory to production stage for CSV upload paths
- Create csv-storage/rates directory with proper permissions
- Fix EACCES errors when uploading CSV files
3. apps/backend/src/application/controllers/admin/csv-rates.controller.ts:
- Add getCsvUploadPath() helper function
- Support both local dev and Docker environments
- Use absolute paths instead of relative paths
4. docker-compose.dev.yml:
- Change backend port mapping to 4001:4000 (avoid local dev conflicts)
- Change frontend port mapping to 3001:3000
- Update CORS_ORIGIN and NEXT_PUBLIC_API_URL accordingly
Impact:
- ✅ Fixes completely broken frontend CSS in Docker/production
- ✅ Applies to CI/CD builds (uses apps/frontend/.dockerignore)
- ✅ Applies to Portainer deployments (pulls from CI/CD images)
- ✅ Fixes CSV upload permission errors in backend
- ✅ Enables local Docker testing on Mac ARM64
Testing:
- Local Docker build now shows compiled Tailwind CSS (60KB+)
- Frontend displays properly styled pages at http://localhost:3001
- Backend CSV uploads work without permission errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add docker-compose.local.yml with all services
- Use production images from Scaleway registry
- Configure local PostgreSQL, Redis, MinIO
- Add comprehensive testing guide in LOCAL_TESTING.md
- Includes debugging commands and troubleshooting
This allows testing production Docker images locally before
deploying to Portainer.
- Remove SHA-based tags (preprod-<sha>)
- Remove semver and PR tags
- Keep only branch-based tag (preprod)
- Keep latest tag for default branch
- Add Portainer debugging documentation
This ensures Portainer always pulls the stable branch tag
instead of commit-specific tags.
- Add fs and path imports at top of file
- Remove inline require() statements that violated ESLint rules
- Fixes 6 @typescript-eslint/no-var-requires errors
- Change backend image from DockerHub to Scaleway registry
- Change frontend image from :latest to :preprod tag
- Fix S3 bucket name to match CSV rates system
- Add comprehensive deployment fix documentation
This fixes container startup issues where Portainer was trying
to pull images from DockerHub instead of Scaleway Container Registry.
- Export S3StorageAdapter directly from StorageModule
- Import StorageModule and ConfigModule in CsvRateModule
- Fix dependency injection for S3StorageAdapter in CSV controllers
- Upload CSV files to MinIO/S3 after validation
- Store MinIO object key in database metadata
- Support loading CSV from MinIO with fallback to local files
- Delete from both MinIO and local storage when removing files
- Add migration script to upload existing CSV files to MinIO
- Graceful degradation if MinIO is not configured