# Dashboard Routes Contract **Scope**: Product owner dashboard web routes (User Story P3) **Authentication**: Required (session-based via Flask-Login) **Response Type**: Server-rendered HTML (no JavaScript required) --- ## GET /login Display login form for product owners and administrators. ### Request **Headers**: None required **Query Parameters**: - `next` (string, optional): Redirect URL after successful login ### Response **Success (200 OK)**: ```html Content-Type: text/html Login - Reklamator

Login

``` **Already Authenticated (302 Redirect)**: Redirect to `/dashboard` --- ## POST /login Authenticate product owner or administrator. ### Request **Headers**: - `Content-Type: application/x-www-form-urlencoded` **Form Data**: - `email` (string, required): User email - `password` (string, required): User password ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /dashboard Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax ``` **Error (401 Unauthorized)**: ```html Content-Type: text/html

Login Failed

Invalid email or password.

``` ### Functional Requirements Covered - FR-056: Authentication required for dashboard - FR-063: Password verification against bcrypt hash --- ## GET /logout Log out current user. ### Request **Authentication**: Required (session cookie) ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /login Set-Cookie: session=deleted; expires=Thu, 01 Jan 1970 00:00:00 GMT ``` --- ## GET /dashboard Display product owner dashboard with feedback list. ### Request **Authentication**: Required (session cookie) **Query Parameters**: - `page` (integer, optional, default=1): Page number for pagination - `category` (string, optional): Filter by category (idea/feature_request/bug/complaint) - `language` (string, optional): Filter by original language (ISO 639-1 code) - `status` (string, optional): Filter by status (analyzed/reviewed/in_progress/resolved/rejected) - `date_from` (string, optional): Filter by date range start (ISO 8601 date) - `date_to` (string, optional): Filter by date range end (ISO 8601 date) - `search` (string, optional): Keyword search across text/translation/summary ### Response **Success (200 OK)**: ```html Content-Type: text/html Feedback Dashboard

Feedback Dashboard

ID Date Category Original Lang Summary Status Attachments
a3f2c1d5 2025-10-15 14:32 Bug DE User reports app crashes when uploading large files... Reviewed 2 files
``` **Error (401 Unauthorized)**: Not authenticated ```http HTTP/1.1 302 Found Location: /login?next=/dashboard ``` **Error (403 Forbidden)**: User has no assigned products ```html Content-Type: text/html

No Access

You are not assigned to any products.

``` ### Behavior - Display only feedback for products assigned to current user (FR-033) - Admin users see all products - Default sort: newest first (FR-041) - Pagination: 50 items per page (SC-008: <3s for 1000 items) - Filters preserved in URL for sharing/bookmarking ### Functional Requirements Covered - FR-032: Authenticated dashboard access - FR-033: Product owner access control - FR-034: Display all analysis results - FR-036-FR-041: Filtering and searching - FR-041: Reverse chronological order --- ## GET /feedback/{feedback_id} Display detailed view of a single feedback item. ### Request **Authentication**: Required (session cookie) **Path Parameters**: - `feedback_id` (UUID, required): Feedback identifier ### Response **Success (200 OK)**: ```html Content-Type: text/html Feedback Detail - a3f2c1d5

Feedback Detail

ID: a3f2c1d5-8b4e-4f1a-9c2d-7e6f5a4b3c2d

Product: Acme Mobile App

Submitted: 2025-10-15 14:32:10 UTC

Original Language: German (DE)

Category: Bug (confidence: 0.92)

Status:

AI Analysis Summary

User reports that the app crashes when uploading large files. This appears to be a bug affecting the file upload module, preventing users from submitting documents over 5MB.

Original Text (German)

Die App stürzt ab, wenn ich versuche, große Dateien hochzuladen. Jedes Mal wenn ich eine PDF über 5MB hochlade, friert die App ein und schließt sich.

Translation (English)

The app crashes when I try to upload large files. Every time I upload a PDF over 5MB, the app freezes and closes.

Attachments

``` **Error (401 Unauthorized)**: Not authenticated ```http HTTP/1.1 302 Found Location: /login?next=/feedback/{feedback_id} ``` **Error (403 Forbidden)**: User not authorized for this product ```html Content-Type: text/html

Access Denied

You do not have permission to view this feedback.

``` **Error (404 Not Found)**: Feedback does not exist ```html Content-Type: text/html

Feedback Not Found

``` ### Functional Requirements Covered - FR-034: Display complete feedback details - FR-035: Links to download attachments - FR-042: Status indicators - FR-044: File attachments with icons/thumbnails --- ## POST /feedback/{feedback_id}/status Update the status of a feedback item. ### Request **Authentication**: Required (session cookie) **Path Parameters**: - `feedback_id` (UUID, required): Feedback identifier **Form Data**: - `status` (string, required): New status (analyzed/reviewed/in_progress/resolved/rejected) ### Response **Success (302 Redirect)**: ```http HTTP/1.1 302 Found Location: /feedback/{feedback_id} ``` **Error (403 Forbidden)**: User not authorized for this product **Error (404 Not Found)**: Feedback does not exist ### Side Effects - Updates `metadata.yaml`: `status` field - Preserves timestamp of status change ### Functional Requirements Covered - FR-042: Mark feedback with status indicators - FR-043: Preserve status when filtering --- ## GET /feedback/{feedback_id}/attachment/{filename} Download or view an attached file. ### Request **Authentication**: Required (session cookie) **Path Parameters**: - `feedback_id` (UUID, required): Feedback identifier - `filename` (string, required): Sanitized filename ### Response **Success (200 OK)**: Image file ```http HTTP/1.1 200 OK Content-Type: image/png Content-Disposition: inline; filename="screenshot.png" Content-Length: 245678 [binary image data] ``` **Success (200 OK)**: Document file ```http HTTP/1.1 200 OK Content-Type: application/pdf Content-Disposition: attachment; filename="report.pdf" Content-Length: 1234567 [binary document data] ``` **Error (403 Forbidden)**: User not authorized for this product **Error (404 Not Found)**: File does not exist ### Security - Files served via Flask route (not direct filesystem access per FR-058) - Access control enforced: User must have access to parent product - Path traversal prevention: Filename sanitized - MIME type from stored metadata (not client-provided) ### Functional Requirements Covered - FR-035: Provide links to download/view attachments - FR-058: Prevent unauthorized file access --- ## Rate Limiting Dashboard endpoints are NOT rate limited (authenticated users only).