# Presence's Outfits Gizmo (outfits.lol)

A personal wardrobe CRUD app: items, outfits, tags, and karma-weighted outfit
suggestions. **Forked from the irev.net portfolio code** (github.com/paulgorman/irevnet).
Personal itch-scratcher, not a product. The roadmap is in **PLAN.md**: read it
before starting work, and work one phase at a time.

## Who you are writing for

Presence is a fifty-one-and-a-half-year-old human operator who has been
hacking PHP and Perl since the late '90s. He reads code in **vim** and finds
things with slash-search. He wants words in his life. Write code he can read
cold, a year from now, at midnight, without a debugger.

## THE RULE: descriptive names, no code golf

**Write descriptive variables and functions for this old human operator, and
when possible, do not code-golf shorthand anything. Big dumb long functions
with lots of newlines.**

### Variable names
- Long, lowercase, `snake_case`, and they say **what is inside them**.
  - Yes: `$every_photo_description`, `$items_in_this_outfit`, `$karma_level`,
    `$search_word_count`
  - No: `$all`, `$out`, `$res`, `$r`, `$tmp`, `$data`, `$arr`, `$x`, `$k`, `$v`
- Loop variables get real names too:
  `foreach ($outfits as $outfit_id => $outfit_details)`, not `foreach ($o as $k => $v)`.
- If you'd have to read three lines up to know what a variable holds, rename it.

### Function names
- `PascalCase`, verb first, longer than necessary is fine:
  `AddItemToOutfitBeingBuilt()`, `GetKarmaForTwoItems()`, `ShowOutfitPage()`.
- Old Presence examples of the house style: `GetKarma`, `ShowStats`, `SamplePage`,
  `TagPage`, `RecordHit`.

### Structure
- Prefer a plain `foreach` with an `if` inside over `array_map` /
  `array_filter` / `array_reduce` with closures.
- No arrow functions (`fn() =>`) when a named function or a loop reads better.
  If PHP demands a callback (like `usort`), give it a named function.
- No nested ternaries. Avoid ternaries entirely unless dead simple.
- One idea per line. Blank lines between steps. Long functions are fine.
- Spell out SQL in full, multi-line, with column names. No `SELECT *`.

### Comments
- Comments explain **why**, in a conversational voice. Presence's comments
  are "special", and that's welcome. Real examples from his old code:
  - `// Be a jerk and limit searches to 100 characters`
  - `// notice where the for loop starts? that $pointer is REALLY important`
  - `// AH HA, no, this special category MUST show full real name!`
- Put a short banner comment above each function saying what it's for.
- Leave the jokes in.

## Old code vs new code (this is a fork)

- The inherited irev.net code uses short `<?` tags, `sprintf()` +
  `mysqli_real_escape_string()`, and its own variable names (`$sampleinfo`,
  `$oid`, `$cid`). **Leave existing functions in their existing style** unless
  a phase is rewriting that function anyway.
- **New code** follows THE RULE above, uses `mysqli` prepared statements, and
  `<?php` in new files. (Short tags stay enabled, so old files keep working.)
  Lint with: `php -d short_open_tag=1 -l file.php`

## Keep it backportable to irev.net

- **Do not rename tables, columns, or existing functions.** Items are still
  `samples`, with `oid`, `cid`, `tid`, etc. Rename only the words people see on
  the page ("Sample" → "Item", "Portfolio" → "Closet").
- Keep each improvement in its own focused commit, so it can be
  `git cherry-pick`ed into irev.net. The irev.net repo is the `irevnet` git remote.
- When something is a backport candidate (EXIF rotation, responsive admin,
  warning fixes), say so in the commit message and add it to the Backport log
  in PLAN.md.

## Working rules

- NEVER print, read aloud, or commit `db.php` (database password; gitignored).
- This directory is the live outfits site. Keep changes small, show diffs,
  commit only when asked, don't push (Presence pushes).
- Editor is vim. When giving terminal edit instructions, say vim, not nano.

## Stack and box

- Host is **irev**: Ubuntu 24.04, PHP 8.3 via mod_fcgid + suexec, MariaDB.
- Database: **MariaDB**, database `outfits` (yes, partly so it shows up on the
  rrdtool qps graph). No ORM.
- Composer into this project's `vendor/` only, and only for TransformersPHP
  (CLIP). No Node, no Docker, no Python venv on irev.
- Model work (CLIP etc.) runs from **CLI scripts** after upload, not inside a
  web request. Load the pipeline once, reuse it. See `classify.php`.
- Look and feel: same CSS and purple color scheme as irev.net. The admin is
  being rebuilt mobile-first with CSS instead of HTML tables.

## Data model (inherited, plus new)

- Inherited: `samples` (= clothing items), `categories` → `subcategories`,
  `tags` + `sampletags`, `media` (photos), `pages`, `admins`, `sitehits`.
- `samples.name` vs `display_name` + `use_display_name`: the old white-label
  "real name vs. alternate name" trick. Here: store listing title vs.
  Presence's own name for the item ("the purple twirly one").
- Unpublished categories hide their items from logged-out visitors
  (`VisibleSampleSQL()`). "Storage" = the out-of-season bin.
- New (see PLAN.md): `outfits`, `outfititems`, `likes` (karma rules),
  a worn log, `closethits`.

## Prior art (Presence's own ancient code, ideas worth reusing)

- **The irev.net codebase itself**, the parent of this fork. It started life
  as a talent agency's entertainment database (piano players, DJs, magicians,
  bands, mermaids), shown on irev.net as /sample/talent-showcase-webapp. That
  is where the real-name vs. display-name white-label trick and the
  never-finished "shopping cart" of performers come from. The outfit builder
  is that cart, finally built. Look for an existing irev.net function before
  writing a new one; it's probably already in `shared.php`.
- **iFetch search engine (early 2000s)**: every matching keyword does
  `$karma[$id]++`, then `arsort($karma)`. That is the outfit matcher: tags vs. the
  `likes` table, karma summed, highest first. Keep the word "karma".
- **vidypic / qtpic (2010)**: photo intake in steps (save, thumbnail, EXIF,
  rotate by EXIF Orientation, detect, log each step with a timestamp). Borrow
  the step ORDER only: the Perl itself is get-it-done spaghetti written to spec
  for a mentalist performer, not a style example.
