# Project plan — ipw_new

Evidence date: 2026-10-11.

Source of implementation truth: `git@bitbucket.org:overdrive/ipw_new.git`, branch `main`, commit `111772e` (2025-05-26, Dirk, "adding unhead package"). The scan-host path `~/projects/sonar_scan/repos/ipw_new` was not on this machine. The tree was read from that git revision.

There was no existing `silicon_ark/ipw_new/` set. The application repository already contains a root README, a client README, a one-paragraph server README, and `ipw table adjustments.sql`. Those notes disagree with the code in several places. This plan treats the NestJS server and Nuxt client as what is implemented, and marks the README when it describes a different stack.

Silicon Ark already documents a separate repository, `ipw-php`, as a CodeIgniter 4 application for the same IPW programme. `ipw_new` does not mention `ipw-php`. Whether `ipw_new` was replaced by `ipw-php` is **Unknown / Requires Confirmation**.

## Product

**Documented** in the root `README.md`: this repository is a rewrite of the old IPW website and user portal. It is meant to give IPW staff and industry participants:

- general information about Integrated Production of Wine (IPW), the environmental sustainability scheme established by the South African wine industry in 1998
- functions members use to maintain membership and meet regulatory guidelines
- functions for administration of IPW, its members, and the website

**Documented, and contradicted by the code:** the same README says the server is Fastify with Prisma and TypeScript, and the client is Nuxt with Bootstrap and Vue. The server that is in git is NestJS on Express (`server/package.json`, `server/src/main.ts`). Prisma and a Nuxt 3 static client are present.

`server/package.json` names the package `ipw-server`, author Craig van Tonder, description "IPW server application", version `0.0.1`, license `UNLICENSED`. `client/package.json` names `ipw-client`, version `0.0.2`, and points its repository, bugs, and homepage URLs at `https://github.com/WeboonTechnologySolution/ipw.co.za.com`.

## Branch reality

| Line | Tip | Date | What it is |
|---|---|---|---|
| `main` (default; `origin/HEAD`) | `111772e` | 2025-05-26 | Only branch. 8 commits, 2025-04-24 through 2025-05-26 |

No other local or remote branches were present at inspection. Nothing in git is dated after 2025-05-26.

| Commit | Date | Author | What it changed |
|---|---|---|---|
| `450ee4c` | 2025-04-24 | Jaco Brits | Initial commit: root `.gitignore` only |
| `d454848` | 2025-04-24 | Jaco Brits | `sonar-project.properties` |
| `e9bd582` | 2025-04-24 | Jaco Brits | `bitbucket-pipelines.yml` (SonarQube scan) |
| `c1257a5` | 2025-04-24 | Jaco Brits | "init push" — client, server, build scripts, README, SQL adjustments |
| `577708c` | 2025-05-19 | Jaco Brits | Pipeline: Docker service memory 3072 MB |
| `b0dc8a5` | 2025-05-23 | Jason Wandrag | README developer-setup section. Commit subject says "Add new DB dump". The diff only edits `README.md` |
| `c7c54aa` | 2025-05-23 | Jason Wandrag | README wording (4 lines) |
| `111772e` | 2025-05-26 | Dirk | Client dependencies: adds `unhead`, moves Bootstrap and `vue-multiselect` to dependencies, raises `sass` |

## Objectives visible in the repository

No project plan or issue export is in git. The behaviour the tree and README actually describe:

1. Publish public IPW information pages (guidelines, manuals, codings, audit policy, climate, courses, contacts) in English and Afrikaans.
2. Authenticate existing members against the legacy MySQL user table, accepting both the old MD5 password and a newer Argon2 hash.
3. Let an authenticated member see guidelines, codings, contact details, groups and roles, and a control-product report.
4. Let an IPW administrator manage staff users, find members, and read activity and live-session lists.
5. Let selected roles upload and download member documents.
6. Queue registration and reminder email and send it on a schedule through SMTP.

The root README's contributing section also states an objective of pushing the same tree to GitHub remotes named `staging` and `production`. Those remotes are not configured in this clone. Whether they still exist is **Unknown / Requires Confirmation**.

## Scope

### In `main` at `111772e`

1. `client/` — Nuxt 3 static client (`ssr: false`, `target: 'static'`), Bootstrap 5, English and Afrikaans strings.
2. `server/` — NestJS 10 API under the global prefix `api`, Prisma 5 against MySQL, JWT cookies, CSRF, email queue.
3. `server/src/prisma/schema.prisma` — introspected model of the existing IPW MySQL schema plus the newer tables (`email`, `user_password`, `user_refresh_token`, `document_upload`, and related).
4. `ipw table adjustments.sql` — `CREATE TABLE` statements for the newer tables, plus informal row notes for `cronjob`, `document_category`, and `rbac_roles`. It is not a full database dump and it is not a migration runner.
5. `build/build.sh` and `build/build-package.cjs` — shell and Node scripts that compile the server and a staging client into `dist/`.
6. `bitbucket-pipelines.yml` — SonarQube scan on `main` only. It does not build or deploy.
7. `dist/` — compiled server JavaScript is present in the tree. Root `.gitignore` ignores `dist/node_modules` and three PM2 config filenames, not the compiled output. The compiled `dist/users/users.service.js` still reads `HOSTNAME` inside `generateConfirmationLink`, while `server/src/users/users.service.ts` reads `DOMAIN`. The committed build does not match the TypeScript source.

### Out of scope / not in this repository

- The full live database dump. The README says to import `ipw_live.sql` from SharePoint. That file is not in git. Commit `b0dc8a5` did not add it.
- PM2 files `development.config.js`, `staging.config.js`, and `production.config.js`. `server/package.json` and `build/build.sh` copy or start them. They are not in `server/`. The root `.gitignore` ignores those names under `dist/`.
- A Nest module that edits evaluation forms, probation, certificates, SAWIS compliance, or audits. The Prisma models and many Vue pages exist. The controllers `group`, `member`, `audit`, `management`, and `public` declare a path and no routes.
- Tests that exercise the database. Spec files are Nest boilerplate (`should be defined`). `server/test/app.e2e-spec.ts` expects `GET /` to return `"Hello World!"`. `AppController` has no `GET /` handler.
- `sonarqube_scan.bat`. The onboarding scan listed it beside the git files. It is not in this revision.
- Any reference to the CodeIgniter application in `ipw-php`.

## System shape

```text
Browser
  → Nuxt static client (dev template: 127.0.0.1:8080)
       public pages (no API)
       login / reminder / registration page
       member and admin pages
  → NestJS on Express, prefix /api (dev template: 127.0.0.1:9000)
       AccessTokenGuard + RolesGuard
       CSRF (csrf-csrf double submit)
       Prisma → MySQL (template database name: ipw_development)
       node-schedule → email table → nodemailer SMTP
       document files under UPLOAD_DIRECTORY
  → same Nest process can serve the generated client as static files
```

Production and staging hostnames appear only as client build arguments: `https://ipw.co.za` and `https://staging.ipw.co.za` in `client/package.json` scripts `build:production` and `build:staging`. How those hosts are deployed is **Unknown / Requires Confirmation**. The pipeline does not deploy.

## Major components

| Component | Path | Role |
|---|---|---|
| HTTP entry | `server/src/main.ts` | Nest/Express, prefix `api`, CORS, cookie parser, CSRF, email scheduler, listen |
| Auth | `server/src/auth/` | Local login, JWT access and refresh, logout, empty confirm handler |
| Users | `server/src/users/` | Profile, group join, create member, delete user |
| Admin | `server/src/admin/` | Staff user list, member search, roles, groups, activity, live sessions |
| Roles | `server/src/roles/` | RBAC role names from `rbac_roles` |
| Reports | `server/src/reports/` | Assessment years, groups, control products, CSV |
| Upload | `server/src/upload/` | Document categories, save, list, download |
| Email | `server/src/email/` | Queue plus scheduled SMTP send |
| Client shell | `client/app.vue`, `client/layouts/default.vue`, `client/components/Sidebar.vue` | Navigation |
| Client API | `client/api/` | `fetch` wrappers for auth, user, admin, role, report, upload |

## Milestones

There is no milestone file. The git history is one import plus small follow-ups:

1. 2025-04-24 — Sonar project key and pipeline, then the application tree in a single commit (`c1257a5`).
2. 2025-05-19 — more Docker memory for the Sonar pipe.
3. 2025-05-23 — README setup notes, including the known blank-page frontend issue.
4. 2025-05-26 — `unhead` added on the client. No application logic change.

## Known dependencies

Runtime (from the two `package.json` files):

- Server: NestJS 10, Express platform, Prisma 5 / `@prisma/client`, `passport` local and JWT, `argon2`, `md5`, `csrf-csrf`, `nodemailer`, `ejs`, `node-schedule`, `luxon`, `sqids`, `uuid`, `fast-csv`. `@casl/ability`, `@casl/prisma`, and `nest-casl` are dependencies. No file under `server/src` imports them.
- Client: Nuxt `^3.17.4`, Vue via Nuxt, Bootstrap `^5.3.6`, `@nuxtjs/i18n`, `sass`, `unhead`, `jwt-decode`, `owasp-password-strength-test`, `email-regex`, `google-libphonenumber`, `vue-multiselect`. `@pinia/nuxt` is a dependency. The Pinia module line in `client/nuxt.config.js` is commented out.
- Database: MySQL, connection string `DATABASE_URL`. Template example uses database `ipw_development`.
- Mail: SMTP variables in `server/.env.template`. No provider name is set.
- Analysis: Bitbucket Pipelines pipe `sonarsource/sonarqube-scan:3.0.2`. Host and token are pipeline variables.

`express-session` and `express-mysql-session` are dependencies. `main.ts` says to remove them. The session middleware block is commented out.

## Current status

**Implemented and reachable from both a controller and a client page:** login, logout, token refresh, password-reminder screen (the API does not reset a password), member contact details, groups and roles, member reports, document upload, staff user administration, member search, member activity, and live users.

**Present as pages, with the API import commented out or with no API module:** evaluation-form editor, member-form views, probation, certificates, SAWIS search, SAWIS compliance, add group, edit group.

**Present as schema and static copy, without a matching Nest route:** public information pages, evaluation forms, audits, probation, SAWIS tables.

**Documented as a known defect** in the root README (2025-05-23): the frontend page is blank, attributed to a newer Dart Sass dropping old syntax, with a link to a Nuxt issue. This inspection did not run the client, so that defect was not re-tested.

**Inactive in git since 2025-05-26.** `ipw-php` in Silicon Ark has commits after that date. That does not by itself prove this repository was retired.
