# Features — ipw-frontend

Evidence date: 2026-10-11.

Source: `git@bitbucket.org:overdrive/ipw-frontend.git`, `main` at `798bd76` (2025-06-03).

Status labels:

- **Current** — a page in this revision performs the behaviour, including an API call where one is required.
- **Partial** — the screen exists and the path a user would take is incomplete or broken.
- **Not implemented** — named in the UI or README, with no working handler in this revision.
- **Removed from the active path** — code is present only as comments, or a file is not linked from navigation.

There is no changelog and no feature-flag file. "Recently changed" is the git history of this repository (five commits, 2025-05-28 through 2025-06-03).

## Current

### Public site

| Feature | Where | Notes |
|---|---|---|
| Home | `pages/index.vue` | No login middleware. Seal-requirements PDF by locale |
| Cellars | `pages/cellars.vue` | |
| About us | `pages/about-us.vue` | |
| Manuals | `pages/manuals.vue` | PDFs under `public/documents/` |
| Forms (static PDFs) | `pages/forms.vue` | Not the online evaluation forms |
| Literature and articles | `pages/literature-and-articles.vue` | |
| Audit policy pages | `pages/audit.vue` | Static. Not an audit workflow |
| Useful contacts | `pages/useful-contacts.vue` | |
| Courses | `pages/courses.vue` | |
| Climate change | `pages/climate-change.vue` | README still says `confronting-climate-change` |
| Greenhouse gas protocol | `pages/greenhouse-gas-protocol.vue` | |
| Environment and sustainability | `pages/environment-sustainability-initiatives.vue` | |
| Links | `pages/links.vue` | |
| Contact us | `pages/contact-us.vue` | No mail-send handler in this page |
| English and Afrikaans | `i18n.config.ts` and page-local messages | Locale code `afr` |
| Light and dark favicons | `nuxt.config.js` `app.head` | |
| Adobe Reader prompt | `components/Adobe.vue` | On pages that link PDFs |
| SWSA sidebar image | `components/Sidebar.vue` | Links to `https://www.swsa.co.za/` |
| Forbidden page | `pages/forbidden.vue` | Not used as the administrator redirect |

### Authentication and session

| Feature | Where | Notes |
|---|---|---|
| Login | `pages/login.vue`, `api/auth.js` | `POST /api/auth/login`, then `body.redirect` |
| Logged-in gate | `middleware/isLoggedIn.js` | Sends anonymous visitors to `/login` |
| Logged-out gate | `middleware/isNotLoggedIn.js` | Sends signed-in visitors to `/member/guidelines` |
| Access-token refresh | `composables/useJwt.js` | `POST /api/auth/refresh` |
| Logout | `components/Sidebar.vue` | Expects HTTP 204, then `/` |
| CSRF on API calls | `api/index.js` | `GET /api/csrf`, header `x-csrf-token` |

### Member

| Feature | Where | Notes |
|---|---|---|
| Contact details | `pages/member/contact-details.vue`, `components/forms/MemberForm.vue` | Get and patch |
| Groups and roles | `pages/member/groups-and-roles.vue` | List, request join, cancel pending |
| Profile picker | `components/Sidebar.vue`, `composables/useLocalStorage.js` | Members only (`user_class_id` 2) |
| Guidelines PDFs | `pages/member/guidelines.vue` | Login required. Menu only if member class |
| Codings PDFs | `pages/member/codings.vue` | Same |
| Control-product report | `pages/member/reports.vue`, `api/report.js` | Table and CSV. Menu is not role-gated |
| Document upload | `pages/upload/documents.vue`, `api/upload.js` | Farm or cellar category. Download name `IPW_Document_{date}_{originalname}` |

### Staff (API-backed)

Menu entry "IPW Administration" is shown for role ids 2 or 5. The pages also require role names `System Developer` or `IPW Administrator`.

| Feature | Where |
|---|---|
| List IPW users | `pages/admin/ipw-users/index.vue` |
| Create IPW user | `pages/admin/ipw-users/create-user.vue` |
| Edit IPW user and roles | `pages/admin/ipw-users/edit-user/[id].vue`, `components/forms/RolesForm.vue` |
| Live users | `pages/admin/live-users.vue` |
| Member activity | `pages/admin/member-activity.vue` |
| Create member | `pages/admin/create-member.vue` |
| Find member (A–Z and search) | `pages/admin/find-member/index.vue` |
| Edit member groups and roles | `pages/admin/find-member/edit-member/[id].vue` |
| List and delete groups | `pages/admin/ipw-groups/index.vue` |

### Build and scan

| Feature | Where | Notes |
|---|---|---|
| Dev server script | `package.json` `start` | `nuxi dev` |
| Static generate for dev, staging, production | `package.json` | Staging and production pin the API host |
| SonarQube on `main` | `bitbucket-pipelines.yml` | Scan only. 3072 MB Docker memory |

## Partial

| Feature | Where | What is missing |
|---|---|---|
| Password reminder | `pages/reminder.vue` | `POST /api/auth/reset` is called. Success assigns `username.value` (not defined). The error branch never sets a message |
| Registration | `pages/registration.vue` | Form renders and links to SAWIS. Submit calls `auth.login` and then reads a password that is not on the form. The logged-out middleware is commented out |
| Confirmation links | `pages/confirm/[type]/[hash]/[token].vue` | Three empty submit functions. `hash` and `token` are unused |
| Member registrations | `pages/admin/member-registrations.vue` | Calls `admin.newRegistrations()`, which is not a method on `api/admin.js`. The tab is commented out in `components/navs/IpwAdministrationNav.vue` |
| Create-user reset | `pages/admin/ipw-users/create-user.vue` | `resetForm` writes cleared values into `form.title` for first name, last name, and telephone |
| Create-user last name | same file | Length check uses `form.firstname` |
| Afrikaans biodiversity guideline | `pages/member/guidelines.vue` | `afr` href is the English PDF |
| Document menu vs page | Sidebar vs `pages/upload/documents.vue` | Menu is role-gated. Page middleware is only `is-logged-in` |
| Administrator middleware | `middleware/isAdministrator.js` | Returns true/false and `console.log`s roles. Does not open `/forbidden` |
| Evaluation-form empty states | `pages/admin/evaluation-forms/templates.vue`, `control-products.vue` | Empty-state row commented out in `798bd76`, so sample rows always show |

## Not implemented

These routes exist, use the administrator middleware, and do not call the API. Sample rows or forms are hardcoded. Several templates call `submitForm` with no function in the script.

| Area | Routes |
|---|---|
| Evaluation forms | `pages/admin/evaluation-forms/setup.vue`, `templates.vue`, `control-products.vue`, `edit/form.vue`, `form-items.vue`, `form-items-edit.vue`, `form-tables.vue`, `form-tables-edit.vue`, `form-tables-edit-item.vue`, `form-activity.vue` |
| Member forms | `pages/admin/member-forms/index.vue`, `search-results.vue`, `members-not-complete.vue`, `edit/view-farm.vue`, `view-cellar.vue`, `view-demo.vue`, `view-activity.vue`, `view-1316685.vue`, `view-1316686.vue`, `view-1316693.vue`, `view-1316702.vue`, `view-1316703.vue` |
| Probation | `pages/admin/probation/current.vue`, `history.vue` |
| Certificates | `pages/admin/certificates.vue` |
| SAWIS | `pages/admin/sawis-search.vue`, `sawis-compliance.vue` |
| Add group / edit group | `pages/admin/add-group.vue`, `pages/admin/ipw-groups/edit-group/[id].vue` |

Sidebar links for evaluation forms, member forms, probation, certificates, SAWIS compliance, and reports are shown to every signed-in user. Opening the admin ones still hits `is-administrator`.

`pages/reset-instructions.vue` is a static page. Nothing in the reminder flow navigates to it by name in the script that was read.

## Removed from the active path

| Item | Evidence |
|---|---|
| Pinia | `@pinia/nuxt` is a dependency. The module line in `nuxt.config.js` is commented out |
| Select-profile API | `api/user.js` `selectProfile` and `selectedProfile` are commented out. The sidebar uses `localStorage` |
| Role add/remove via `api/role.js` | `addToUser` and `removeFromUser` are commented out. Live calls are `api/admin.js` `addUserRole` and `removeUserRole` |
| App-level auth middleware | `app.vue` `router.beforeEach` auth block is commented out. Gates live in `middleware/` |
| Member-registrations tab | Commented in `IpwAdministrationNav.vue` |
| "Other groups" tab | Commented. Route `/admin/other-groups` is not a page |
| Login "create account" link | Commented in `pages/login.vue` |
| Older form kit | `forms/`, `notifications/`, and `modules/data/` import each other only. No page imports them |
| `useJwt.old.txt` | File at the repo root. Not imported |
| `nuxt_runtime_keys.readme` | Dump of Nuxt auto-import keys. Not application behaviour |

Unlinked duplicates:

- `pages/member/edit.vue` — copy of the reports page.
- `pages/management/list-members.vue` — copy of the document upload page.

## Planned

No roadmap file exists. The only future-looking notes are code comments:

- Toast and modal stacking (`components/Toast.vue`, `components/Modal.vue`).
- Admins or managers joining a group on behalf of someone else (`api/user.js`).
- CSRF and bearer error handling marked TODO in `api/index.js`.
- After creating a member, redirect to user administration so roles can be added (`pages/admin/create-member.vue`). The comment is a TODO. Whether the current success path already redirects was not re-checked past the 201 handling.

These are comments, not an approved plan.

## Recently changed

`798bd76` (2025-06-03), subject "Fix document upload naming convention":

- `api/upload.js` download URL is `GET /api/upload/download-document/{id}`.
- Empty-state `<tr>` blocks in `templates.vue` and `control-products.vue` are commented out.

The download filename pattern `IPW_Document_{date}_{originalname}` is in `pages/upload/documents.vue` and was not part of that diff. The commit message and the diff do not describe the same lines. The URL change is what the diff shows.

The application itself arrived in `37208b5` ("first commit") on 2025-05-28. Earlier commits that day only add the pipeline and Sonar properties.
