# Project Audit — Madalice Shoe Customizer

_Audit date: 2026-07-25. Relocated from `evolution/shoe_customizer/` (evolution `shoe-customizer`
branch) into its own repo — this is **not** an Evolution feature; it's a standalone
WooCommerce plugin for the corporatekicks.com.au store._

## 1. What this is

An in-house WooCommerce product customizer for custom-branded sneakers — a from-scratch
replacement for the third-party **Kickflip** (MyCustomizer) iframe currently embedded on
corporatekicks.com.au. It renders a live 2D shoe preview by runtime **multiply-tinting**
white photographic zone slices, presents a stepped/priced option form, and pushes the finished
design (JSON + mockup) into the WooCommerce cart/order.

Full design rationale: [README.md](README.md) and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).

## 2. Phase status

| Phase | Deliverable | Status |
|---|---|---|
| 0 | Runtime-tint compositor POC — 5 shoes + "Pick a shoe" | **DONE** — `poc/` |
| 1 | Data model + no-code admin builder + REST config + seed importer | **DONE** — `plugin/` v0.1.0 |
| 2 | Frontend engine + live canvas via `[shoe_customizer]` shortcode | **DONE** — `plugin/` |
| 3 | Cart / checkout / order integration (design JSON + mockup on the line item) | **DONE** — `plugin/` v0.3.3 |
| 1b | Priced option groups + logo upload (drag/scale) + size-run matrix | **CODE DONE** — v0.4.0/0.4.1, **not WP-runtime-verified** |
| 3b | Size-run + logo on the line item (rides on 1b) | folded into 1b |
| 4 | Production spec sheet / mockup export | not started |
| 5 | "Pick a shoe" step 0 in the plugin + migrate remaining shoe models | not started (data entry, not code) |

## 3. Code inventory

```
plugin/shoe-customizer/          deployable WP/WooCommerce plugin (WP conventions: $wpdb, dbDelta, nonces, wp.media)
  shoe-customizer.php            boot: header, constants, activation→schema, loads REST+admin
  uninstall.php                  drops tables + option (keeps copied assets)
  includes/
    class-sc-install.php         dbDelta schema — 8 tables, prefix wp_sc_*  (sc_db_version = 1)
    class-sc-repo.php            data access + config() builder (REST/frontend contract)
    class-sc-rest.php            GET /wp-json/shoe-customizer/v1/shoes | shoe/<slug>
    class-sc-admin.php           menu + nonce-guarded save/delete/seed/resync handlers
    class-sc-seed.php            copies seed assets → uploads, builds 5 shoes (idempotent per slug)
    class-sc-frontend.php        [shoe_customizer] shortcode + enqueue + SCData localize
    class-sc-cart.php            add-to-cart AJAX: server-side re-validate + re-price; cart/order/admin meta
    class-sc-upload.php          Phase 1b: secured logo upload endpoint
    views/{list,edit}.php        shoe table + no-code editor (meta, zone repeater, palette, options, sizes, print-area)
  assets/{admin,customizer}.{js,css}
  seed/shoes.php + seed/assets/<slug>/*.png   PHP mirror of poc/shoes.js + bundled real slices
poc/                             Phase-0 browser compositor (index.html, shoes.js, assets/<shoe>/)
docs/                            ARCHITECTURE.md, GUIDE_OPTIONS_SIZES_LOGO.md, PHASE_1B_SCOPE.md
plugin/DEPLOY.md                 three deploy paths + smoke test
tests/sc-addtocart-test.mjs      Playwright add-to-cart harness (canonical; was browser-tools/)
```

Data model (8 custom tables, `wp_sc_*`): `shoe`, `zone`, `zone_layer`, `option_group`, `option`,
`visibility_rule`, `swatch_palette`, `design`. Phase 1b needed **no schema change** — the option/
size/logo tables were created (unused) in Phase 1; `sc_db_version` stays at `1`.

## 4. Security posture

- **Logo upload (`class-sc-upload.php`) is the primary attack surface.** Controls in place:
  nonce-gated, 5 MB cap, `wp_check_filetype` + `getimagesize` real-image check, **PNG/JPG
  allowlist (no SVG)**, bytes **re-encoded through the WP image editor** to strip EXIF/polyglot
  payloads, randomized filename under `uploads/shoe-customizer/logos/`.
- **Cart/order path re-validates and re-prices every design server-side** — option ids, size
  codes, logo ownership, required-group satisfaction, and size total are all checked against the
  shoe's own config; the browser is never trusted for price or quantity. MOQ (2 pairs) is
  server-enforced.
- Admin save/delete/seed/resync handlers are nonce-guarded.
- **Not yet audited under a live WordPress runtime** — all PHP is `php -l` clean but has never
  executed inside WP (no WP in the dev env). Runtime verification is the top open risk.

## 5. Test status

- `tests/sc-addtocart-test.mjs` — Playwright harness that drives the live product page, applies a
  colourway, adds to cart, and captures console errors + a screenshot. Self-contained (Playwright
  only). Points at `https://corporatekicks.com.au/product/dunk-build-your-own/`.
- `plugin/smoke-test.sh` — read-only REST smoke test (safe on prod): expects 200 from
  `/shoe-customizer/v1/shoes` and `/shoe/af1` once active + seeded.
- Gates: `php -l` on all PHP, `node --check` on JS. **No WP integration tests** — blocked on a WP
  runtime.
- Phase 1b harness extension (assert price delta, size→qty line qty + `_sc_sizes`, logo upload +
  `_sc_logo`, and rejection of tampered ids / hostile uploads / bad size codes) is **scoped, not
  built**.

## 6. Deployment

- Remote was AWS CodeCommit (evolution dev repo). New repo has **no remote yet** — set one before
  relying on CI.
- Install = drop `plugin/shoe-customizer/` into `wp-content/plugins/` (zip upload, or rsync, or
  CI from the repo). `plugin/build.sh` → `dist/shoe-customizer-<version>.zip` (git-ignored).
- After install: **Shoe Customizer → Import seed shoes**. Schema self-upgrades on load via
  `SC_Install::maybe_upgrade()`.
- **Staging first** — never activate on production untested (see [plugin/DEPLOY.md](plugin/DEPLOY.md)).
- Never commit `ck.netrc` / store credentials (git-ignored).

## 7. Open items

1. **WP runtime verification** — install on staging, activate, import seed, exercise the full
   Phase 1b path (paid options, size grid, logo upload/drag/scale, add-to-cart). Nothing here has
   run inside WordPress yet.
2. **Swatch fidelity on dark colours** — confirm multiply-tint doesn't crush stitching on dark
   colourways (a luminance-tuned tint floor landed in 0.4.0; validate on real colourways).
3. **Phase 1b test-harness extension** (§5) — assertions + adversarial upload/tamper cases.
4. **Legacy cutover** — strip the old "Shoes Required / Options" add-on fields from product 8928 at
   go-live.
5. **Phase 4** (production spec / picking sheet: per-zone colour callouts, full-res logo +
   placement, size/name run) — not started.
6. **Phase 5** ("Pick a shoe" step 0 in the plugin + migrate remaining shoe models) — not started.
7. **Zone grouping for the customer UI** (per-panel vs grouped) — merchandising decision, data
   model supports either.
8. **Evolution pull plugin** (later, separate) — reads the stable design JSON into a sales order +
   production spec. Out of this repo's scope; the JSON contract is kept clean for it.

## 8. Provenance

Relocated 2026-07-25 from `evolution/shoe_customizer/` (evolution repo, `shoe-customizer` branch).
Per-commit history up to the move remains in that branch; this repo starts with a fresh initial
commit. The canonical Playwright harness was consolidated from `browser-tools/sc-addtocart-test.mjs`
(newer of two divergent copies) into `tests/`. See [LOG.md](LOG.md) for the timeline.
