480 lines
14 KiB
Markdown
480 lines
14 KiB
Markdown
# Registration API Implementation
|
|
|
|
This document describes the complete implementation of the user registration feature for the MaplePress frontend, integrated with the MaplePress backend API.
|
|
|
|
## Overview
|
|
|
|
The registration feature allows new users to create an account and automatically sets up their tenant (organization) in a single step. Upon successful registration, users receive authentication tokens and are automatically logged in.
|
|
|
|
## Backend API Endpoint
|
|
|
|
**Endpoint**: `POST /api/v1/register`
|
|
**Authentication**: None required (public endpoint)
|
|
**Documentation**: `/cloud/maplepress-backend/docs/API.md` (lines 66-166)
|
|
|
|
### Request Structure
|
|
|
|
```json
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "SecurePassword123!",
|
|
"confirm_password": "SecurePassword123!",
|
|
"first_name": "John",
|
|
"last_name": "Doe",
|
|
"tenant_name": "Acme Corporation",
|
|
"timezone": "America/New_York",
|
|
"agree_terms_of_service": true,
|
|
"agree_promotions": false,
|
|
"agree_to_tracking_across_third_party_apps_and_services": false
|
|
}
|
|
```
|
|
|
|
### Response Structure
|
|
|
|
```json
|
|
{
|
|
"user_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"user_email": "user@example.com",
|
|
"user_name": "John Doe",
|
|
"user_role": "manager",
|
|
"tenant_id": "650e8400-e29b-41d4-a716-446655440000",
|
|
"tenant_name": "Acme Corporation",
|
|
"tenant_slug": "acme-corp",
|
|
"session_id": "750e8400-e29b-41d4-a716-446655440000",
|
|
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"access_expiry": "2024-10-24T12:00:00Z",
|
|
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"refresh_expiry": "2024-11-24T00:00:00Z",
|
|
"created_at": "2024-10-24T00:00:00Z"
|
|
}
|
|
```
|
|
|
|
## Frontend Implementation
|
|
|
|
### 1. RegisterService (`src/services/API/RegisterService.js`)
|
|
|
|
Handles direct communication with the backend registration API.
|
|
|
|
**Key Features:**
|
|
- Request validation (required fields, terms agreement)
|
|
- Request body formatting (snake_case for backend)
|
|
- Response transformation (camelCase for frontend)
|
|
- User-friendly error message mapping
|
|
- Tenant slug validation and generation utilities
|
|
|
|
**Methods:**
|
|
- `register(data)` - Main registration method
|
|
- `validateTenantSlug(slug)` - Validate slug format
|
|
- `generateTenantSlug(name)` - Auto-generate slug from name
|
|
|
|
**Usage:**
|
|
```javascript
|
|
import RegisterService from './services/API/RegisterService';
|
|
|
|
const response = await RegisterService.register({
|
|
email: "user@example.com",
|
|
password: "SecurePassword123!",
|
|
confirmPassword: "SecurePassword123!",
|
|
first_name: "John",
|
|
last_name: "Doe",
|
|
tenant_name: "Acme Corp",
|
|
agree_terms_of_service: true,
|
|
});
|
|
```
|
|
|
|
### 2. AuthManager (`src/services/Manager/AuthManager.js`)
|
|
|
|
Manages authentication state, token storage, and session lifecycle.
|
|
|
|
**Key Features:**
|
|
- Token management (access & refresh tokens)
|
|
- LocalStorage persistence
|
|
- Token expiry checking
|
|
- User and tenant data storage
|
|
- Session initialization and cleanup
|
|
|
|
**New Methods:**
|
|
- `register(registrationData)` - Register and store auth data
|
|
- `storeAuthData(authResponse)` - Store tokens and user data
|
|
- `clearSession()` - Clear all auth data
|
|
- `isTokenExpired(expiry)` - Check token expiry
|
|
- `getTenant()` - Get current tenant information
|
|
|
|
**Storage Keys:**
|
|
```javascript
|
|
maplepress_access_token
|
|
maplepress_refresh_token
|
|
maplepress_access_expiry
|
|
maplepress_refresh_expiry
|
|
maplepress_user
|
|
maplepress_tenant
|
|
maplepress_session_id
|
|
```
|
|
|
|
### 3. Register Page (`src/pages/Auth/Register.jsx`)
|
|
|
|
Complete registration form with all required fields.
|
|
|
|
**Form Sections:**
|
|
|
|
1. **Personal Information**
|
|
- First Name (required)
|
|
- Last Name (required)
|
|
- Email Address (required)
|
|
- Password (required, min 8 chars)
|
|
- Confirm Password (required)
|
|
|
|
2. **Organization Information**
|
|
- Organization Name (required, slug auto-generated by backend)
|
|
|
|
3. **Terms and Consent**
|
|
- Terms of Service agreement (required)
|
|
- Promotional emails (optional)
|
|
|
|
**Features:**
|
|
- Password match validation (backend-validated)
|
|
- Terms of service requirement
|
|
- Automatic timezone detection
|
|
- Loading state during submission
|
|
- RFC 9457 error message display with field-specific errors
|
|
|
|
## Data Flow
|
|
|
|
```
|
|
User fills form
|
|
↓
|
|
Register.jsx validates data
|
|
↓
|
|
AuthManager.register(data)
|
|
↓
|
|
RegisterService.register(data)
|
|
↓
|
|
HTTP POST to /api/v1/register
|
|
↓
|
|
Backend validates and creates user + tenant
|
|
↓
|
|
Backend returns tokens and user data
|
|
↓
|
|
RegisterService transforms response
|
|
↓
|
|
AuthManager stores tokens in localStorage
|
|
↓
|
|
User redirected to /dashboard
|
|
```
|
|
|
|
## Validation Rules
|
|
|
|
### Frontend Validation
|
|
|
|
1. **Email**: Required, valid email format
|
|
2. **Password**:
|
|
- Required
|
|
- Minimum 8 characters
|
|
3. **Confirm Password**:
|
|
- Required
|
|
- Must match password (validated by backend)
|
|
4. **Name**: Required
|
|
5. **Tenant Name**: Required
|
|
6. **Tenant Slug**:
|
|
- Required
|
|
- Only lowercase letters, numbers, and hyphens
|
|
- Validated by regex: `/^[a-z0-9-]+$/`
|
|
7. **Terms of Service**: Must be checked
|
|
|
|
### Backend Validation
|
|
|
|
Backend performs additional validation:
|
|
- Email normalization and format validation
|
|
- Password strength requirements (uppercase, lowercase, number, special char)
|
|
- Password confirmation matching
|
|
- Tenant slug uniqueness
|
|
- Email uniqueness
|
|
- No HTML in text fields
|
|
- Input sanitization
|
|
|
|
## Error Handling
|
|
|
|
### RFC 9457 (Problem Details for HTTP APIs)
|
|
|
|
The backend returns validation errors in **RFC 9457** format, which provides a structured, machine-readable error response.
|
|
|
|
**Error Response Structure**:
|
|
```json
|
|
{
|
|
"type": "about:blank",
|
|
"title": "Validation Error",
|
|
"status": 400,
|
|
"detail": "One or more validation errors occurred",
|
|
"errors": {
|
|
"email": ["Invalid email format"],
|
|
"password": ["Field is required", "Password must be at least 8 characters"],
|
|
"confirm_password": ["Field is required", "Passwords do not match"],
|
|
"first_name": ["Field is required"],
|
|
"last_name": ["Field is required"],
|
|
"tenant_name": ["Field is required"],
|
|
"agree_terms_of_service": ["Must agree to terms of service"]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Content-Type**: `application/problem+json`
|
|
|
|
**Key Fields**:
|
|
- `type`: URI reference identifying the problem type (uses `about:blank` for generic errors)
|
|
- `title`: Short, human-readable summary of the error type
|
|
- `status`: HTTP status code
|
|
- `detail`: Human-readable explanation of the error
|
|
- `errors`: Dictionary/map of field-specific validation errors (extension field)
|
|
|
|
### Common Validation Errors
|
|
|
|
| Field | Error Message |
|
|
|-------|--------------|
|
|
| email | `email: invalid email format` |
|
|
| email | `email: email is required` |
|
|
| password | `password: password is required` |
|
|
| password | `password: password must be at least 8 characters` |
|
|
| password | `password: password must contain at least one uppercase letter (A-Z)` |
|
|
| password | `password: password must contain at least one lowercase letter (a-z)` |
|
|
| password | `password: password must contain at least one number (0-9)` |
|
|
| password | `password: password must contain at least one special character` |
|
|
| confirm_password | `confirm_password: field is required` |
|
|
| confirm_password | `confirm_password: passwords do not match` |
|
|
| first_name | `first_name: field is required` |
|
|
| first_name | `first_name: first_name must be between 1 and 100 characters` |
|
|
| last_name | `last_name: field is required` |
|
|
| last_name | `last_name: last_name must be between 1 and 100 characters` |
|
|
| tenant_name | `tenant_name: tenant_name is required` |
|
|
| tenant_name | `tenant_name: tenant_name must be between 1 and 100 characters` |
|
|
| agree_terms_of_service | `agree_terms_of_service: must agree to terms of service` |
|
|
|
|
### Frontend Error Parsing
|
|
|
|
The Register page component (`src/pages/Auth/Register.jsx`) includes a `parseBackendError()` function that:
|
|
1. Checks if the error object contains RFC 9457 `validationErrors` structure
|
|
2. Iterates through the errors dictionary and maps each field to its error messages
|
|
3. Joins multiple error messages for the same field with semicolons
|
|
4. Displays field-specific errors with red borders and inline messages
|
|
5. Shows an error summary box at the top with all errors listed
|
|
|
|
**Error Parsing Implementation**:
|
|
```javascript
|
|
const parseBackendError = (error) => {
|
|
const fieldErrors = {};
|
|
let generalError = null;
|
|
|
|
// Check if error has RFC 9457 validation errors structure
|
|
if (error.validationErrors && typeof error.validationErrors === 'object') {
|
|
// Process each field's errors
|
|
Object.entries(error.validationErrors).forEach(([fieldName, errorMessages]) => {
|
|
if (Array.isArray(errorMessages) && errorMessages.length > 0) {
|
|
// Join multiple error messages for the same field
|
|
fieldErrors[fieldName] = errorMessages.join('; ');
|
|
}
|
|
});
|
|
|
|
// Use the detail as general error if available
|
|
if (error.message) {
|
|
generalError = error.message;
|
|
}
|
|
} else {
|
|
// Fallback for non-RFC 9457 errors
|
|
generalError = error.message || "An error occurred. Please try again.";
|
|
}
|
|
|
|
return { fieldErrors, generalError };
|
|
};
|
|
```
|
|
|
|
**Example Error Display**:
|
|
|
|
When submitting an empty form, the user sees:
|
|
- **Error Summary Box**: Lists all validation errors at the top of the form with the general message "One or more validation errors occurred"
|
|
- **Highlighted Fields**: Red border on email, password, first_name, last_name, tenant_name, etc.
|
|
- **Inline Messages**: Error text displayed below each affected field (e.g., "Field is required")
|
|
|
|
### ApiClient Error Handling
|
|
|
|
The `ApiClient` (`src/services/API/ApiClient.js`) automatically parses RFC 9457 error responses and attaches the validation errors to the error object:
|
|
|
|
```javascript
|
|
// Create error with RFC 9457 data if available
|
|
const error = new Error(
|
|
errorData.detail || errorData.message || `HTTP ${response.status}: ${response.statusText}`
|
|
);
|
|
|
|
// Attach RFC 9457 fields to error for parsing
|
|
if (errorData.errors) {
|
|
error.validationErrors = errorData.errors; // RFC 9457 validation errors
|
|
}
|
|
if (errorData.title) {
|
|
error.title = errorData.title;
|
|
}
|
|
if (errorData.status) {
|
|
error.status = errorData.status;
|
|
}
|
|
|
|
throw error;
|
|
```
|
|
|
|
**Note**: The frontend **does not perform field validation** - all validation, including password matching, is handled by the backend. The form submits whatever the user enters, and the backend returns comprehensive validation errors in RFC 9457 format.
|
|
|
|
## Security Features
|
|
|
|
1. **Token Storage**: Tokens stored in localStorage (client-side only)
|
|
2. **Token Expiry**: Automatic expiry checking on initialization
|
|
3. **Password Validation**: Client and server-side validation
|
|
4. **HTTPS Required**: Production should use HTTPS
|
|
5. **Terms Agreement**: Required before account creation
|
|
6. **Input Sanitization**: Backend sanitizes all inputs
|
|
|
|
## Testing the Registration Flow
|
|
|
|
### 1. Start Backend
|
|
|
|
```bash
|
|
cd cloud/mapleopentech-backend
|
|
task dev
|
|
```
|
|
|
|
### 2. Start Frontend
|
|
|
|
```bash
|
|
cd web/maplepress-frontend
|
|
npm run dev
|
|
```
|
|
|
|
### 3. Navigate to Registration
|
|
|
|
Open browser to: `http://localhost:5173/register`
|
|
|
|
### 4. Fill Form
|
|
|
|
- **First Name**: John (required)
|
|
- **Last Name**: Doe (required)
|
|
- **Email**: test@example.com
|
|
- **Password**: SecurePass123!
|
|
- **Confirm Password**: SecurePass123!
|
|
- **Organization Name**: Test Corp (slug auto-generated by backend)
|
|
- **Terms of Service**: ✓ (checked)
|
|
|
|
### 5. Submit
|
|
|
|
Click "Create Account" button
|
|
|
|
### 6. Expected Result
|
|
|
|
- Loading state appears
|
|
- Request sent to backend
|
|
- Tokens stored in localStorage
|
|
- User redirected to `/dashboard`
|
|
- Dashboard shows user information
|
|
|
|
### 7. Verify in Browser Console
|
|
|
|
```javascript
|
|
// Check stored tokens
|
|
localStorage.getItem('maplepress_access_token')
|
|
localStorage.getItem('maplepress_user')
|
|
localStorage.getItem('maplepress_tenant')
|
|
|
|
// Check service instance
|
|
window.maplePressServices.authManager.isAuthenticated()
|
|
window.maplePressServices.authManager.getUser()
|
|
window.maplePressServices.authManager.getTenant()
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
Create `.env` file:
|
|
|
|
```bash
|
|
# Backend API URL
|
|
VITE_API_BASE_URL=http://localhost:8000
|
|
```
|
|
|
|
### Production Configuration
|
|
|
|
For production:
|
|
```bash
|
|
VITE_API_BASE_URL=https://api.maplepress.io
|
|
```
|
|
|
|
## Future Enhancements
|
|
|
|
### Planned Features
|
|
|
|
- [ ] Email verification flow
|
|
- [ ] Password strength indicator
|
|
- [ ] Captcha integration
|
|
- [ ] Social authentication (Google, GitHub)
|
|
- [ ] Organization logo upload
|
|
- [ ] Custom domain support
|
|
- [ ] Invitation codes/referrals
|
|
- [ ] Account recovery flow
|
|
|
|
### Security Improvements
|
|
|
|
- [ ] CSRF token implementation
|
|
- [ ] Rate limiting on frontend
|
|
- [ ] Session fingerprinting
|
|
- [ ] Two-factor authentication
|
|
- [ ] Password breach checking
|
|
- [ ] Secure token storage (HTTP-only cookies)
|
|
|
|
## File Reference
|
|
|
|
### Created Files
|
|
|
|
```
|
|
src/services/API/RegisterService.js
|
|
```
|
|
|
|
### Modified Files
|
|
|
|
```
|
|
src/services/Manager/AuthManager.js
|
|
src/pages/Auth/Register.jsx
|
|
```
|
|
|
|
### Backend Reference Files
|
|
|
|
```
|
|
cloud/maplepress-backend/docs/API.md
|
|
cloud/maplepress-backend/internal/interface/http/dto/gateway/register_dto.go
|
|
cloud/maplepress-backend/internal/interface/http/handler/gateway/register_handler.go
|
|
```
|
|
|
|
## API Client Configuration
|
|
|
|
The `ApiClient` automatically handles:
|
|
- JSON content-type headers
|
|
- Request/response transformation
|
|
- Error parsing
|
|
- Authentication headers (for protected endpoints)
|
|
|
|
### Base Configuration
|
|
|
|
```javascript
|
|
API_CONFIG = {
|
|
baseURL: import.meta.env.VITE_API_BASE_URL || "http://localhost:8000",
|
|
timeout: 30000,
|
|
}
|
|
```
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
1. Check backend logs: `docker logs mapleopentech_backend`
|
|
2. Check frontend console for errors
|
|
3. Verify backend is running on port 8000
|
|
4. Verify frontend environment variables
|
|
5. Test backend endpoint directly with curl (see API.md)
|
|
|
|
## Related Documentation
|
|
|
|
- [ARCHITECTURE.md](./ARCHITECTURE.md) - Frontend architecture overview
|
|
- [README.md](./README.md) - Getting started guide
|
|
- [Backend API Documentation](../../cloud/maplepress-backend/docs/API.md) - Complete API reference
|