# Customer Request Portal Benchmark Build a small, production-minded customer request portal using Django 5, SQLite, and server-rendered HTML. The goal is a working portal, not a mockup. Keep the implementation simple and readable. ## Required stack and commands - Python 3.12+ - Django 5.x - SQLite - Project package: `portal` - Application package: `requests_portal` - The application must start with `python manage.py runserver 127.0.0.1:8000` - All tests must run with `python manage.py test` - Do not require Node.js, Docker, Redis, PostgreSQL, or a paid external service. ## Users and permissions - Use Django authentication. - Anonymous visitors must be redirected to `/login/` from every portal page. - A normal user can create requests and see only requests they created. - A staff user can see every request. - Only staff users can assign requests or change their status. - Normal users must receive HTTP 403 if they try to use a staff-only action. - Include login and logout. Logout may use POST. - Login must be available at `/login/` and logout at `/logout/`. ## Data model Create a `SupportRequest` model with: - `title`: required text, maximum 200 characters - `description`: required text - `status`: one of `open`, `in_progress`, or `closed`; default `open` - `priority`: one of `low`, `normal`, or `high`; default `normal` - `created_by`: required user - `assignee`: optional user - `created_at` - `updated_at` Create an `ActivityLog` model with: - `support_request`: related support request - actor - `action`: short action description - creation timestamp Creating a request, editing it, assigning it, and changing its status must create an activity entry. When assignment and status change in the same submitted form, one combined activity entry or two separate entries are both acceptable. ## Required pages - `/login/` - `/` — dashboard - `/requests/` — request list - `/requests/new/` — create form - `/requests//` — detail and activity history - `/requests//edit/` — edit title, description, and priority - `/requests//manage/` — staff-only assignment and status form The dashboard must show counts for open, in-progress, and closed requests. Counts must respect the current user's visibility rules. Render each count inside an element with `data-status-count="open"`, `data-status-count="in_progress"`, or `data-status-count="closed"`. This provides a stable semantic hook for accessibility and acceptance testing without prescribing the layout. The list must support: - text search across title and description with `q` - status filtering with `status` - sorting by newest or oldest with `sort` - pagination with 20 requests per page - preservation of active search/filter/sort parameters while changing pages ## User experience - Provide useful validation errors and empty states. - Provide navigation between dashboard, request list, and new request. - Show status and priority clearly without relying on color alone. - Use semantic HTML and associated form labels. - The layout must remain usable at 390 CSS pixels wide without horizontal scrolling. - Do not use a CSS framework CDN. A small local stylesheet is sufficient. ## Seed data Provide `python manage.py seed_portal`. It must create, idempotently: - staff user `admin` with password `portal-admin-2026` - normal user `alice` with password `portal-alice-2026` - normal user `bob` with password `portal-bob-2026` - 100 requests spread across the three users/statuses/priorities - activity records for the seeded requests The first run must add 100 stable benchmark requests. Running the command again must not add more users, requests, or activity records. These credentials are benchmark-only and must be documented in `README.md`. ## Tests and deployment readiness - Write meaningful model, permission, filtering, and view tests. - Include at least 25 Django tests. - Include `requirements.txt` with pinned compatible versions. - Include a `Procfile` containing a one-command production start definition using Gunicorn. - Include a concise `README.md` with setup, migration, seeding, testing, and start commands. - Run migrations and tests before declaring the task complete. ## Definition of done The project is complete only when: - migrations apply to an empty database; - `python manage.py test` passes; - the seed command works twice without duplicating its fixed users; - the seed command works twice without duplicating its benchmark requests or activities; - permission boundaries work server-side; - all required pages return the expected result; - the narrow layout is usable; - no unfinished placeholder or TODO remains in a required feature.