# Features — nataliehirschman

Evidence date: 2026-10-09. Source: `master` at `f9248b83`.

Status words mean where the feature sits in this tree. "Current" means the code path exists on `master` now.

## Current — public site

| Feature | Behaviour | Evidence |
|---|---|---|
| Home | Title "Natalie Hirschman Fine Art". Static hero "A sculpture dreams - Oil". FASO newsletter widget posts to `https://nataliehirschman.com/webadmin/confirm` | `index.html` |
| Biography | Page shell plus `getPage("about")` filling `#article_body` from `/api/about` | `about.html`, `admin/js/ajaxcalls.js` |
| CV | `getPage('cv')` from `/api/cv` | `cv.html` |
| Works portfolio | Masonry and carousel from `/api/works`. Filters Originals, Limited Editions, Open Editions | `works.html`, `getWorksPage` |
| Artwork zoom | `/api/works/{id}`, pan/zoom on the figure | `workszoom/index.html`, `getImage` |
| Contact form | POST `contact.php`, reCAPTCHA v3, then POST to the admin contact resource | `contact.html`, `contact.php` |
| Email newsletter form | POST `newsletter.php`, reCAPTCHA v3, then POST to the admin newsletter resource | `email-newsletter.html`, `newsletter.php` |
| Newsletter archive | Static FASO page. Subscribe widget posts to `webadmin/confirm`, not `newsletter.php` | `newsletter-archive.html` |
| Galleries page | File exists. Desktop nav item is a dead `#` link. Mobile nav in `index.html` still links the file | `galleries.html`, `index.html` |
| Disabled portfolio headings | Landscape and Still life are non-links in the desktop Works menu | `index.html` |
| Matomo | Site id 3, `analytics.medmin.co.za`, cookie domain `*.nataliehirschman.com` | `index.html` |
| Favicon | `assets/images/favicon.ico` | `index.html` |

## Current — static FASO snapshot

These files are the older hosted-site export. They are still in git. The dynamic portfolio does not read them.

| Area | What it is | Evidence |
|---|---|---|
| Enquire pages | One HTML file per FASO artwork id, plus `inquire/window.location.html` | `inquire/` |
| Works index variants | `works/index.html` and hashed `index*.html`, plus an RSS-style `rssfeed20_works4268.html` | `works/` |
| Zoom pages | `workszoom/{id}/{slug}.html` and a larger `workszoom-all/` tree. Many include "Contact The Artist About This Artwork" linking at `../inquire/{id}.html` | `workszoom/`, `workszoom-all/` |
| Artwork viewer bundle | `home/g21s/public/artwork-viewer/` (`appd609.js`, `manifest46d3.js`, `vendoraf1e.js`) | `home/g21s/` |
| Shared FASO chrome | `styles/master/faso.css`, `styles/wyeth/`, `styles/shared/` | `styles/` |

Newsletter widgets inside the snapshot post to `https://nataliehirschman.fineartstudioonline.com/aspwpadmin/confirm.asp`. Provenance: **Implemented** in those HTML files (sampled from `workszoom/index.html`).

## Current — admin application

CodeIgniter 4 application in `admin.nataliehirschman.com/`. Package name `codeigniter4/adminstarter`, description "Admin Overdrive".

| Feature | Behaviour | Evidence |
|---|---|---|
| Login | Email + password, `password_verify`, session keys `username`, `role`, `isLoggedIn` | `Welcome::index` |
| Register | Public form. Unique email, password confirmation, stored as role `1` | `Welcome::registration`, `common/login.php` |
| Forbidden page | `blocked` renders `common/forbidden` | `Welcome::forbiddenPage` |
| Articles / images | List, filter by content type segment, add, update, delete | `Images`, `Articles`, route `articles` |
| Upload | Save original under `assets/uploads`, thumbnail 500px under `assets/uploads/img_thumbnail`. Validation rules exist and are commented out of the success path | `Upload` |
| Content fields | Title, page, content type (`Image` or `Content`), category (Figurative, Portraits, Landscape, StillLife), medium (Oil, Water, Carole), size, order, active, body | `imageList.php`, `ImageModel` |
| Public read API | `/api/about`, `/api/cv`, `/api/contact`, `/api/works`, `/api/works/{id}` | `Routes.php`, `Api` |
| Contact resource | Insert and list `contacts`. Mail helper is not called | `Contact` |
| Newsletter resource | Insert `newsletter`. `index()` is empty. No list view | `Newsletter` |
| Users and roles | Create, update, delete users and roles. Change menu, category, and submenu permission | `Users`, routes under `users/` |
| Menu management | Create category, menu, submenu. Menu create also tries to write a controller and view | `Developers/MenuManagement` |
| CRUD generator | Generates from an existing table name | `Developers/CRUDGenerator` |
| Employee resource | REST controller for an `employees` table. No route entry and no view. Auto-route could expose it | `Employee`, `EmployeeModel` |
| Session in the database | Committed `env` selects `DatabaseHandler`, table name `sessions`, match IP, regenerate-destroy. `App.php` still says `FileHandler` | `env`, `App.php`, session migration |

Login success redirects to `articles`, not to a dashboard. The seed still has a Dashboard menu item aimed at `home`, and the explicit `home` route is commented out.

## Current — admin HTML theme that is not the app

`admin/` is a static dashboard theme (pages, scss, vendors, gulp). The public site's relative script `admin/js/ajaxcalls.js` is the piece the live pages use. `admin/index.html` and `admin/index_old.html` are theme pages, not the CodeIgniter login.

## Planned

No planned-feature list, ticket, or TODO file describes future work.

These look unfinished in the code. They are **not** recorded as a plan:

- Landscape and Still life nav items are non-links.
- Galleries is disabled on desktop and still linked on mobile.
- `sendMail` inside `Contact::create` is commented out.
- AWS SDK, mPDF, and PhpSpreadsheet are in `composer.json` and have no references under `app/`.
- `Employee` has no dedicated route or screen.
- Image validation is written and not enforced.

## In development

Nothing is on a branch other than `master`. The latest commits (2025-10-01 to 2025-10-03) only edit deploy config. No in-progress product change is visible.

## Recently changed

| When | Commit | Change |
|---|---|---|
| 2025-10-03 | `f9248b83` | Commented out the Bitbucket `pipelines:` block, including git-ftp push |
| 2025-10-02 | `5ef04ef1` and neighbours | git-ftp deploy, vendor excluded via `.git-ftp-ignore` |
| 2025-10-02 | `c896fbd4` | "CI 4 Upgrade v2 with rsync" — rsync `--delete` to `$FTP_HOST:/public_html/`, then replaced the same week by git-ftp |
| 2025-10-01 | `57fb64c5`, `d99cc3c7` | "CI 4 Upgrade"; pipeline Python image note |
| 2024-11-01 | `211ff23b` | Removed `robots.txt` |
| 2023-11-01 | `9df5dc8e` | Added `robots.txt` |
| 2023-07-11 | `cb52ed78`, `2305fb43` | Desktop pan/zoom fixes; resize large images on small screens |
| 2023-06 | `bdcd2053`, `78a80de1` | Lightbox carousel and further pan fixes |
| 2023-05 | CV page, image order column, thumbnails, jQuery UI, Font Awesome, page title removed from one view | Uriel Balela commits `3d5470db` through `5531646e` |

`admin.nataliehirschman.com/public/robots.txt` still exists and allows all user agents (`Disallow:` empty). The root `robots.txt` added in 2023 is gone.

## Removed or replaced

| Item | What happened | Evidence |
|---|---|---|
| Root `robots.txt` | Added 2023-11-01, removed 2024-11-01 | Commits `9df5dc8e`, `211ff23b`. File is absent at the root of `f9248b83` |
| Active Bitbucket pipeline | Last enabled form was git-ftp on 2025-10-02. Commented out 2025-10-03 | `bitbucket-pipelines.yml` |
| Rsync deploy | Introduced 2025-10-02 and replaced by git-ftp before the pipeline was disabled | Commit `a783c74b` diff |
| SonarQube pipeline step | Present only inside comments | `bitbucket-pipelines.yml`, `sonar-project.properties` |
| `sonarqube_scan.bat` | Named in the onboarding task's file list. Not in `master` | Working tree listing at `f9248b83` |

## Not in git

- Production `.env` if one exists only on the server. The committed file is `env`, not `.env`.
- MySQL data: pages, images, contacts, newsletter subscribers, users beyond the seeder.
- Uploaded artwork binaries on the server. The repo has a stock of FASO JPEGs under `assets/images/`, which are the static snapshot, not the admin upload directory.
- Bitbucket variable values (`FTP_*`, `SONAR_*`).

## Deprecated or leftover behaviour that is still reachable

| Item | Why it is leftover | Still in the tree |
|---|---|---|
| FASO enquire and confirm forms | Post to FASO or `/webadmin/confirm`, which this PHP app does not implement | Snapshot HTML and the home widget |
| `Employee` REST controller | Starter-style CRUD, no menu seed | `Employee.php` |
| Role methods copied onto `Images` and `Articles` | `createRole` on `Images` calls `userModel->createRole` and redirects to `users` | `Images::createRole` |
| `Articles` controller | Parallel of `Images`. Routes use `Images` for the list and `Articles::addImage` / `Articles::delete` for writes | `Routes.php` |
| AWS, mPDF, PhpSpreadsheet | Required by Composer, unused by `app/` | `composer.json` |
| `test` route | `$routes->get('test', 'Welcome::index')` shows the same login as `/` | `Routes.php` |
