feat: choose a product's category from the ones T5DE has seen
A product can be filed under another IMVU category than its parent's: any category path the hub has seen on a revision's parent (and each step of it), within the parent's top-level category, so it stays the same kind of product (the proxy tells clothing, furniture and rooms apart by category). It's an info field like the others: lockable, in the history, undone by the same rules. Lists filter by the chosen path, and products show it. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8793b5afd8
commit
ceceb69eaf
12 files changed
+165
-22
No files matched your search
+3
-2
@@ -87,8 +87,9 @@ sha256 (hex) of `contents` as JSON.
|
||||
## Products, catalogs and libraries
|
||||
|
||||
The routes and tokens are in docs/products.md. Products are `{id, name, description, rating, latest, creator,
|
||||
creatorUsername, parent, image, categories, status, listed, tags, locked, deleted, removed, publishedAt, createdAt,
|
||||
updatedAt}`; `parent`, `image` and `categories` come from the latest revision (its IMVU parent's public info).
|
||||
creatorUsername, parent, image, categories, category, status, listed, tags, locked, deleted, removed, publishedAt,
|
||||
createdAt, updatedAt}`; `parent` and `image` come from the latest revision (its IMVU parent's public info), and
|
||||
`categories` too unless a category was chosen for it (`category`).
|
||||
`GET /api/v1/products` takes `q`, `creator`, `category` (an IMVU category ID), `tag`, `catalog` and `limit` (1-200,
|
||||
default 60).
|
||||
|
||||
|
||||
+3
-2
@@ -473,8 +473,9 @@ Phases for products, catalogs and imports (products.md, console.md, imports.md):
|
||||
**Done** (2026-11-05), except catalog deletion requests and the hosted rooms' scope, which come with cases
|
||||
(phase 3). Built-in roles are code (`apps/api/src/permissions.ts`); the `role` table comes with custom roles.
|
||||
2. Product info: drafts, moderator edits with reasons and locks, info history, unlisted products, tags and category.
|
||||
**Done** (2026-11-05), except a product's own category: the hub has no list of IMVU's categories to choose from,
|
||||
so products are filed under their parent's category path for now (later: IMVU's category tree, cached).
|
||||
**Done** (2026-11-05). A product's category is chosen from the IMVU category paths the hub has seen on parents,
|
||||
within its parent's top-level category; IMVU's own category tree (if it has a public one) would replace those
|
||||
(to look into with the importer spike).
|
||||
3. Cases (reports, appeals, reviews), file blocks and the catalogs' changes feed; notifications; API tokens;
|
||||
two-factor sign-in for sensitive permissions.
|
||||
4. Imports: grants, recorded grants, requests, unclaimed creators, the job queue, `t5de-importer` (after its spike).
|
||||
|
||||
+7
-5
@@ -107,13 +107,14 @@ catalog's). Only approved catalogs with imports on and not paused.
|
||||
| `DELETE /api/v1/catalogs/:id/products/:product` | (`hosting:delist`) `{reason}`: the catalog stops hosting every revision of it; it's in the changes feed. The product stays available from other catalogs hosting it. |
|
||||
| `POST /api/v1/catalogs/:id/suspend`, `.../reinstate` | (`catalog:suspend`) `{reason}`: a suspended catalog's products aren't available from it, it can't register revisions, and its team sees why |
|
||||
| `POST /api/v1/products/upload` | `{catalog, product?}` → `{token, url}`: an upload token and the catalog's upload URL (the catalog's upload policy and rating ceiling apply) |
|
||||
| `GET /api/v1/products?q=&creator=&category=&catalog=&tag=&limit=` | (anyone) `{products}`, newest first: published and listed (and the person's own unlisted ones); adult ones only for people with an adult account. `category`: an IMVU category ID in its latest revision's parent's category path (e.g. 106 Clothing, 128 Tops). `tag`: one tag; `catalog`: those the catalog hosts. `limit`: 1-200, default 60 |
|
||||
| `GET /api/v1/products?q=&creator=&category=&catalog=&tag=&limit=` | (anyone) `{products}`, newest first: published and listed (and the person's own unlisted ones); adult ones only for people with an adult account. `category`: an IMVU category ID in its category path (its own if chosen, else its latest revision's parent's; e.g. 106 Clothing, 128 Tops). `tag`: one tag; `catalog`: those the catalog hosts. `limit`: 1-200, default 60 |
|
||||
| `GET /api/v1/products/:id` | (anyone, adult rule as above; drafts only for their creator and moderators) `{product, revisions, inLibrary?, mine?, available, permissions}` |
|
||||
| `PATCH /api/v1/products/:id` | (`product:edit`) `{name?, description?, rating?, tags?, listed?, reason?}` → `{product, fields}` (the fields that changed; only those go in the history). Description is HTML, cleaned by the allowlist. Tags: up to 10, lowercased, each up to 24 letters, digits, spaces or dashes. Rating may go general → adult; adult → general needs `product:rate-lower` (400 `review_needed`; with cases it opens a `rating-review` case instead), and no revision that isn't retracted may be rated adult (400 `files_adult`). `reason` is required when the person isn't the creator (400 `reason_needed`), and shown to them. Locked fields need `product:edit-locked` (403 `locked`). The creator can't edit a product they deleted; moderators can. |
|
||||
| `PATCH /api/v1/products/:id` | (`product:edit`) `{name?, description?, rating?, tags?, listed?, category?, reason?}` → `{product, fields}` (the fields that changed; only those go in the history). Description is HTML, cleaned by the allowlist. Tags: up to 10, lowercased, each up to 24 letters, digits, spaces or dashes. `category`: the ID of one of its category choices (below), or null for its parent's. Rating may go general → adult; adult → general needs `product:rate-lower` (400 `review_needed`; with cases it opens a `rating-review` case instead), and no revision that isn't retracted may be rated adult (400 `files_adult`). `reason` is required when the person isn't the creator (400 `reason_needed`), and shown to them. Locked fields need `product:edit-locked` (403 `locked`). The creator can't edit a product they deleted; moderators can. |
|
||||
| `GET /api/v1/products/:id/categories` | (`product:edit`) `{choices, parent}`: the category paths it may be filed under, and its parent's. The choices are every IMVU category path the hub has seen on a revision's parent, and each step of them, under the same top-level category as its parent's (any, if that's unknown). Keeping the top level keeps it the same kind of product: the proxy tells clothing, furniture and rooms apart by category. IMVU's own category tree would replace the seen paths if one turns up. |
|
||||
| `POST /api/v1/products/:id/publish` | (`product:publish`) a draft becomes published (409 `published` if it is already) |
|
||||
| `GET /api/v1/products/:id/history` | (`audit:read` at the product: its creator, moderators) the info history, newest first: `{entries: [{id, at, kind ("edit", "revert", "lock", "publish"), by, byCreator, changes: {field: {from, to}}, reason, revertOf}]}` |
|
||||
| `POST /api/v1/products/:id/history/:entry/revert` | (`product:edit`) `{reason?}`: puts back what an edit (or revert) changed, as a new `revert` entry, by the same rules as an edit (locks, reasons, ratings); 409 `unchanged` if the info is already as it was |
|
||||
| `PUT /api/v1/products/:id/locks` | (`product:lock`) `{fields, reason}`: the fields locked from now on (any of name, description, rating, tags, listed; the rest are unlocked). `reason` required; kept in the history |
|
||||
| `PUT /api/v1/products/:id/locks` | (`product:lock`) `{fields, reason}`: the fields locked from now on (any of name, description, rating, tags, listed, category; the rest are unlocked). `reason` required; kept in the history |
|
||||
| `POST /api/v1/products/:id/transfer` | (`product:transfer`) `{to}`; the other person accepts (`.../transfer/accept`) |
|
||||
| `POST /api/v1/products/:id/restore` | (`product:restore`) undo a creator's delete |
|
||||
| `POST /api/v1/products/:id/hosting` | (`hosting:choose`) `{catalog, revision?}`: ask another catalog to mirror it (every revision, or one); the catalog's `mirrors` setting decides (auto, or its team approves) |
|
||||
@@ -131,9 +132,10 @@ catalog's). Only approved catalogs with imports on and not paused.
|
||||
The realtime connection also tells the proxy `{"type": "library"}` when the person's library changes.
|
||||
|
||||
A product (in lists, its page, the library) is `{id, name, description, rating, latest, creator, creatorUsername,
|
||||
parent, image, categories, status ("draft"/"published"), listed, tags, locked, deleted, removed, publishedAt,
|
||||
parent, image, categories, category, status ("draft"/"published"), listed, tags, locked, deleted, removed, publishedAt,
|
||||
imvuProduct, createdAt, updatedAt}` (`imvuProduct` comes with imports). The product's page also has `permissions`: what the
|
||||
person may do to it (the website shows actions by them). `parent`, `image` and `categories` are the latest revision's:
|
||||
person may do to it (the website shows actions by them). `category` is the path chosen for it (null: its parent's), and `categories` the one it's filed under (`category` if
|
||||
chosen); `parent`, `image` and the parent's categories are the latest revision's:
|
||||
`parent` is the IMVU product it derives from (0 if none); `image` (an https address on `*.imvu.com`, or null) and
|
||||
`categories` (`[{id, name}]`, outermost first, e.g. Clothing / Clothing for Female / Tops / Coats & Jackets; `[]` if
|
||||
unknown) are that IMVU product's, from IMVU's public API (`GET https://api.imvu.com/product/product-<id>`).
|
||||
|
||||
Reference in new issue
Block a user