Files
Reklamator/specs/001-build-an-application/contracts/submission_routes.md
T
gurixandClaude c4ae7a0fa6 Rename API contracts to web routes for clarity
Changed terminology from "API" to "Routes" to better reflect server-rendered HTML approach:
- Renamed submission_api.md → submission_routes.md
- Renamed dashboard_api.md → dashboard_routes.md
- Renamed admin_api.md → admin_routes.md
- Updated headers to clarify "Response Type: Server-rendered HTML (no JavaScript required)"
- Updated references in plan.md and quickstart.md

This clarifies that the application uses traditional web routes with form submissions
and HTML responses, not REST API endpoints with JSON.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 13:47:40 +02:00

5.3 KiB

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):

Content-Type: text/html

<!DOCTYPE html>
<html>
  <head><title>Submit Feedback - {Product Name}</title></head>
  <body>
    <h1>Submit Feedback for {Product Name}</h1>
    <form method="POST" action="/submit/{product_slug}" enctype="multipart/form-data">
      <textarea name="feedback_text" maxlength="10000"></textarea>
      <input type="file" name="attachments" multiple accept=".pdf,.docx,.txt,.jpg,.png,.gif,.webp">
      <button type="submit">Submit Feedback</button>
    </form>
  </body>
</html>

Error (404 Not Found): Product does not exist or is archived

Content-Type: text/html

<!DOCTYPE html>
<html>
  <body>
    <h1>Product Not Found</h1>
    <p>The product you're looking for does not exist or is no longer accepting feedback.</p>
  </body>
</html>

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:

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):

Content-Type: text/html

<!DOCTYPE html>
<html>
  <body>
    <h1>Thank You!</h1>
    <p>Your feedback has been submitted successfully.</p>
    <p>Your feedback ID: {feedback_id}</p>
  </body>
</html>

Error (400 Bad Request): Validation failure

Content-Type: text/html

<!DOCTYPE html>
<html>
  <body>
    <h1>Submission Error</h1>
    <ul>
      <li>Feedback must contain text or at least one attachment</li>
      <li>Maximum 3 attachments allowed</li>
      <li>Text cannot exceed 10,000 characters</li>
      <li>File size cannot exceed 10MB per file</li>
      <li>Unsupported file type: {filename}</li>
    </ul>
  </body>
</html>

Error (413 Payload Too Large): File size exceeds limit

Content-Type: text/html
HTTP/1.1 413 Payload Too Large

<!DOCTYPE html>
<html>
  <body>
    <h1>File Too Large</h1>
    <p>One or more files exceed the 10MB limit.</p>
  </body>
</html>

Error (429 Too Many Requests): Rate limit exceeded

Content-Type: text/html
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1697456789

<!DOCTYPE html>
<html>
  <body>
    <h1>Too Many Submissions</h1>
    <p>You have exceeded the submission limit of 10 per hour. Please try again later.</p>
  </body>
</html>

Error (451 Unavailable For Legal Reasons): Malware detected

Content-Type: text/html

<!DOCTYPE html>
<html>
  <body>
    <h1>Security Error</h1>
    <p>One or more files failed security scanning. Please ensure your files are safe and try again.</p>
  </body>
</html>

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: submittedanalyzing

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).