# Admin Routes Contract **Scope**: Product and user management web routes (User Story P4) **Authentication**: Required (admin role only) **Response Type**: Server-rendered HTML (no JavaScript required) --- ## GET /admin/products Display list of all registered products. ### Request **Authentication**: Required (admin role) ### Response **Success (200 OK)**: ```html Content-Type: text/html Product Management

Product Management

+ Create New Product
ID Name Status Submission URL Target Language Feedback Count Assigned Owners Actions
001-acme-app Acme Mobile App Active /submit/acme-app English (en) 127 2 owners Edit | Archive
``` **Error (403 Forbidden)**: User is not an administrator ```html Content-Type: text/html

Access Denied

Administrator privileges required.

``` ### Functional Requirements Covered - FR-045: List all products - FR-054: Display product statistics --- ## GET /admin/products/new Display form to create a new product. ### Request **Authentication**: Required (admin role) ### Response **Success (200 OK)**: ```html Content-Type: text/html

Create New Product

``` ### Functional Requirements Covered - FR-045: Form to register new products - FR-047: Set preferred target language - FR-048: Assign product owners --- ## POST /admin/products Create a new product. ### Request **Authentication**: Required (admin role) **Form Data**: - `id` (string, required): Unique product identifier (URL-safe, lowercase, hyphens allowed) - `name` (string, required): Display name (1-100 characters) - `description` (string, optional): Description (max 500 characters) - `target_language` (string, required): ISO 639-1 language code - `submission_url_slug` (string, required): URL-safe slug (unique) - `assigned_owner_ids` (string[], required): At least one product owner ID ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/products ``` **Error (400 Bad Request)**: Validation failure ```html Content-Type: text/html

Validation Error

``` ### Side Effects 1. **File System**: - Creates `data/products/{product_id}/` - Writes `data/products/{product_id}/config.yaml` - Creates `data/products/{product_id}/feedback/` directory 2. **Config File** (`config.yaml`): ```yaml id: "001-acme-app" name: "Acme Mobile App" description: "Customer feedback for Acme's flagship mobile application" target_language: "en" submission_url_slug: "acme-app" created_date: "2025-10-15" status: "active" assigned_owner_ids: - "owner-001" - "owner-002" statistics: total_feedback_count: 0 last_submission: null ``` ### Functional Requirements Covered - FR-045: Register new products - FR-046: Unique product identifier - FR-047: Set target language - FR-048: Assign product owners - FR-049: Generate unique submission URL --- ## GET /admin/products/{product_id}/edit Display form to edit an existing product. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `product_id` (string, required): Product identifier ### Response **Success (200 OK)**: Same form as create, pre-populated with existing values **Error (404 Not Found)**: Product does not exist ### Functional Requirements Covered - FR-051: Update product details --- ## POST /admin/products/{product_id} Update an existing product. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `product_id` (string, required): Product identifier **Form Data**: Same as POST /admin/products (except `id` is immutable) ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/products ``` **Error (400 Bad Request)**: Validation failure **Error (404 Not Found)**: Product does not exist ### Side Effects - Updates `data/products/{product_id}/config.yaml` - Product `id` cannot be changed (immutable) - Changing `target_language` affects future feedback translations only (FR-048) ### Functional Requirements Covered - FR-048: Update product owner assignments - FR-051: Update product details --- ## POST /admin/products/{product_id}/archive Archive a product (stop accepting new feedback). ### Request **Authentication**: Required (admin role) **Path Parameters**: - `product_id` (string, required): Product identifier ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/products ``` **Error (404 Not Found)**: Product does not exist ### Side Effects - Updates `data/products/{product_id}/config.yaml`: Sets `status: "archived"` - Submission form (GET /submit/{product_slug}) returns 404 for archived products (FR-053) - Historical feedback preserved (FR-052) ### Functional Requirements Covered - FR-052: Archive products without deleting feedback - FR-053: Prevent new submissions to archived products --- ## POST /admin/products/{product_id}/unarchive Reactivate an archived product. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `product_id` (string, required): Product identifier ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/products ``` ### Side Effects - Updates `data/products/{product_id}/config.yaml`: Sets `status: "active"` - Submission form becomes available again ### Functional Requirements Covered - Allow reversing archive operation (not explicitly in FR but useful) --- ## GET /admin/users Display list of all users (product owners and admins). ### Request **Authentication**: Required (admin role) ### Response **Success (200 OK)**: ```html Content-Type: text/html

User Management

+ Create New User
ID Email Name Role Assigned Products Last Login Actions
owner-001 jane.smith@example.com Jane Smith Product Owner 2 products 2025-10-15 09:23 Edit | Delete
``` ### Functional Requirements Covered - User management interface (implied by FR-048: assigning owners) --- ## GET /admin/users/new Display form to create a new user. ### Request **Authentication**: Required (admin role) ### Response **Success (200 OK)**: ```html Content-Type: text/html

Create New User

``` --- ## POST /admin/users Create a new user. ### Request **Authentication**: Required (admin role) **Form Data**: - `email` (string, required): Valid email address (unique) - `name` (string, required): Display name (1-100 characters) - `password` (string, required): Password (min 8 characters) - `role` (string, required): "product_owner" or "admin" ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/users ``` **Error (400 Bad Request)**: Validation failure ```html Content-Type: text/html

Validation Error

``` ### Side Effects - Appends new user to `data/users.yaml` - Password hashed with bcrypt (cost factor 12) before storage (FR-063) - Generates unique user ID (e.g., "owner-001", "admin-002") ### Functional Requirements Covered - FR-063: Secure password storage (bcrypt) - User creation for product owner assignment --- ## GET /admin/users/{user_id}/edit Display form to edit an existing user. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `user_id` (string, required): User identifier ### Response **Success (200 OK)**: Same form as create, pre-populated (except password field empty) **Error (404 Not Found)**: User does not exist --- ## POST /admin/users/{user_id} Update an existing user. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `user_id` (string, required): User identifier **Form Data**: - `email` (string, required): Valid email address - `name` (string, required): Display name - `password` (string, optional): New password (if changing) - `role` (string, required): "product_owner" or "admin" ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/users ``` ### Side Effects - Updates user entry in `data/users.yaml` - If password provided, re-hash with bcrypt - Email and role can be updated --- ## POST /admin/users/{user_id}/delete Delete a user. ### Request **Authentication**: Required (admin role) **Path Parameters**: - `user_id` (string, required): User identifier ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /admin/users ``` **Error (400 Bad Request)**: Cannot delete self ```html Content-Type: text/html

Cannot Delete

You cannot delete your own account.

``` ### Side Effects - Removes user from `data/users.yaml` - User automatically unassigned from all products - Historical feedback metadata unchanged (no user tracking in feedback) --- ## Access Control All admin endpoints enforce: 1. User must be authenticated (session cookie) 2. User role must be "admin" 3. Otherwise: 403 Forbidden response ### Functional Requirements Covered - FR-045: Admin can register products - FR-048: Admin can assign product owners - FR-051: Admin can update products - FR-052: Admin can archive products