verpfuschter stand von codex
This commit is contained in:
@@ -28,3 +28,58 @@ Guest Polling (no WebSockets in v1)
|
||||
|
||||
Webhooks
|
||||
- Payment provider events, media pipeline status, and deletion callbacks. All signed with shared secret per provider.
|
||||
|
||||
## Purchase Wizard Endpoints (Marketing Flow)
|
||||
|
||||
These endpoints support the frontend purchase wizard for package selection, authentication, and payment. They are web routes under `/purchase/` (not `/api/v1`), designed for Inertia.js integration with JSON responses for AJAX/fetch calls. No tenant middleware for auth steps (pre-tenant creation); auth required for payment.
|
||||
|
||||
### Flow Overview
|
||||
1. **Package Selection**: User selects package via marketing page; redirects to wizard with package ID.
|
||||
2. **Auth (Login/Register)**: Handle user creation/login; creates tenant if registering. Returns user data and next_step ('payment' or 'success' for free packages).
|
||||
3. **Payment**: Create intent/order, complete via provider callback, finalize purchase (assign package, update tenant).
|
||||
4. **Success**: Redirect to success page; email welcome if new user.
|
||||
|
||||
Error Handling:
|
||||
- 422 Validation: `{ errors: { field: ['message'] }, message: 'Summary' }` – display in forms without reload.
|
||||
- 401/403: `{ error: 'Auth required' }` – show login prompt.
|
||||
- 500/Other: `{ error: 'Server error' }` – generic alert, log trace_id.
|
||||
- Non-JSON (e.g., 404): Frontend catches "unexpected end of data" and shows "Endpoint not found" or retry.
|
||||
|
||||
All responses: JSON only for AJAX; CSRF-protected.
|
||||
|
||||
### Endpoints
|
||||
|
||||
- **POST /purchase/auth/login**
|
||||
- Body: `{ login: string (email/username), password: string, remember?: boolean }`
|
||||
- Response (200): `{ status: 'authenticated', user: { id, email, name, pending_purchase, email_verified }, next_step: 'payment', needs_verification: boolean }`
|
||||
- Errors: 422 `{ errors: { login: ['Invalid credentials'] } }`
|
||||
|
||||
- **POST /purchase/auth/register**
|
||||
- Body: `{ username, email, password, password_confirmation, first_name, last_name, address, phone, privacy_consent: boolean, package_id?: number }`
|
||||
- Response (200): `{ status: 'registered', user: { ... }, next_step: 'payment'|'success', needs_verification: boolean, package?: { id, name, price, type } }`
|
||||
- Errors: 422 `{ errors: { email: ['Taken'], password: ['Too weak'] } }`; creates tenant/user on success.
|
||||
|
||||
- **POST /purchase/stripe/intent** (auth required)
|
||||
- Body: `{ package_id: number }`
|
||||
- Response (200): `{ client_secret: string, payment_intent_id: string }`
|
||||
- Errors: 422 `{ errors: { package_id: ['Invalid'] } }`
|
||||
|
||||
- **POST /purchase/stripe/complete** (auth required)
|
||||
- Body: `{ package_id: number, payment_intent_id: string }`
|
||||
- Response (200): `{ status: 'completed' }`
|
||||
- Errors: 422 `{ errors: { payment: ['Not succeeded'] } }` – finalizes purchase.
|
||||
|
||||
- **POST /purchase/paypal/order** (auth required)
|
||||
- Body: `{ package_id: number }`
|
||||
- Response (200): `{ order_id: string, status: 'CREATED' }`
|
||||
- Errors: 422 `{ error: 'Order creation failed' }`
|
||||
|
||||
- **POST /purchase/paypal/capture** (auth required)
|
||||
- Body: `{ order_id: string, package_id: number }`
|
||||
- Response (200): `{ status: 'captured' }`
|
||||
- Errors: 422 `{ error: 'Capture incomplete' }` – finalizes purchase.
|
||||
|
||||
- **POST /purchase/free** (auth required)
|
||||
- Body: `{ package_id: number }`
|
||||
- Response (200): `{ status: 'assigned' }`
|
||||
- Errors: 422 `{ errors: { package_id: ['Not free'] } }` – assigns for zero-price packages.
|
||||
|
||||
Reference in New Issue
Block a user