# Submission Routes Contract **Scope**: Anonymous feedback submission web routes (User Story P1) **Authentication**: None (anonymous access) **Response Type**: Server-rendered HTML (no JavaScript required) --- ## GET /submit/{product_slug} Display the feedback submission form for a specific product. ### Request **Path Parameters**: - `product_slug` (string, required): Product's URL-safe identifier **Headers**: None required **Query Parameters**: None ### Response **Success (200 OK)**: ```html Content-Type: text/html
The product you're looking for does not exist or is no longer accepting feedback.
``` ### Functional Requirements Covered - FR-001: Public, unauthenticated submission form - FR-002: Text input up to 10,000 characters - FR-004: Up to 3 file attachments --- ## POST /submit/{product_slug} Submit anonymous feedback for a specific product. ### Request **Path Parameters**: - `product_slug` (string, required): Product's URL-safe identifier **Headers**: - `Content-Type: multipart/form-data` **Form Data**: - `feedback_text` (string, optional): Feedback text (0-10,000 characters) - `attachments` (file[], optional): Up to 3 files, max 10MB each **Example**: ```http POST /submit/acme-app HTTP/1.1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="feedback_text" The app crashes when uploading files over 5MB. ------WebKitFormBoundary Content-Disposition: form-data; name="attachments"; filename="screenshot.png" Content-Type: image/png [binary data] ------WebKitFormBoundary-- ``` ### Response **Success (200 OK)**: ```html Content-Type: text/htmlYour feedback has been submitted successfully.
Your feedback ID: {feedback_id}
``` **Error (400 Bad Request)**: Validation failure ```html Content-Type: text/htmlOne or more files exceed the 10MB limit.
``` **Error (429 Too Many Requests)**: Rate limit exceeded ```html Content-Type: text/html X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1697456789You have exceeded the submission limit of 10 per hour. Please try again later.
``` **Error (451 Unavailable For Legal Reasons)**: Malware detected ```html Content-Type: text/htmlOne or more files failed security scanning. Please ensure your files are safe and try again.
``` ### Validation Rules 1. **Text Validation** (FR-002, FR-003): - Length: 0-10,000 characters - Encoding: UTF-8, any language accepted - Empty allowed if attachments present 2. **Attachment Validation** (FR-004, FR-005, FR-006): - Count: 0-3 files - Size: Max 10MB per file - Types: PDF, DOCX, TXT, JPG, PNG, GIF, WebP - MIME type validation (server-side) 3. **Submission Validation** (FR-011, FR-012): - Must have text OR attachments (not both empty) 4. **Security** (FR-059, FR-060): - ClamAV virus scan before storage - Filename sanitization (remove path traversal) - MIME type validation 5. **Rate Limiting** (FR-061): - 10 submissions per hour per IP address ### Functional Requirements Covered - FR-001 to FR-012: Complete submission flow - FR-055: No IP/session tracking stored - FR-059, FR-060: File security - FR-061: Rate limiting ### Side Effects 1. **File System**: - Creates `data/products/{product_id}/feedback/{feedback_id}/` - Writes `metadata.yaml`, `content.txt` - Writes `attachments/{filename}` if files uploaded 2. **Async Processing**: - Triggers AI analysis background job - Updates feedback status: `submitted` → `analyzing` --- ## POST /submit/{product_slug}/status/{feedback_id} **Note**: This endpoint is OUT OF SCOPE for MVP. Feedback submission is fire-and-forget. Users cannot track submission status anonymously. Future consideration: Anonymous status check via feedback ID (requires balancing anonymity with user experience).