Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
480
web/maplepress-frontend/docs/API/REGISTRATION_API.md
Normal file
480
web/maplepress-frontend/docs/API/REGISTRATION_API.md
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
# 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue