Skip to content

Label administration has no write surface beyond create: no update, no delete, no merge, and the labels table is three columns where tubafrenzy's COMPANY was fourteen #2383

Description

@jakebromberg

Problem

/wxycdb's Manage Labels screen (companyAdmin, linked from webapps/wxycdb/src/main/webapp/jsp/mainmenu.jsp:36) is a full create / read / update / delete / merge surface over tubafrenzy's COMPANY table. Backend-Service serves a fraction of it. apps/backend/routes/labels.route.ts mounts exactly four operations — GET /labels, GET /labels/info, GET /labels/search, POST /labels — of which only the POST writes, and it writes two fields (labels.controller.ts:27-33, taking label_name and an optional parent_label_id).

Today the only writer is dj-site's release-creation mutation, which upserts a label name. Once /wxycdb retires there is no surface anywhere that can rename a mistyped label, merge the several spellings of one imprint, re-parent a subsidiary, or delete a row created by accident — while the create path keeps adding rows to the same table. Write-without-repair is the failure mode.

The gaps, precisely

  1. No update. No PATCH/PUT is mounted. A label name is immutable once created.
  2. No delete. No DELETE is mounted. /wxycdb offers delete only when the label has zero releases and zero child labels (jsp/labelAdmin/labelModify.jsp:105, and the childCount guard in CompanyAdminServlet); Backend's equivalent guard has three reference sources rather than one — see item 5.
  3. No merge. /wxycdb merges N labels into one: lowest ID survives, the rest have their references reassigned and are then deleted, and the survivor is renamed to a librarian-chosen final name (CompanyAdminServlet.processMerge). Nothing here does any part of that.
  4. The column set is three wide where the legacy table was fourteen. shared/database/src/schema.ts:2157-2161 defines labels as id, label_name (unique, varchar 128) and parent_label_id. tubafrenzy's Company (libs/entities/src/main/java/org/wxyc/rotation/Company.java:7-23) carries address, city, stateProvince, zipCode, country, phoneNumber, faxNumber, webSiteUrl, emailAddress, contactPerson, comments, timeLastModified and timeCreated in addition to the three we have. Every one of those is an input on labelModify.jsp, and none of them has a column here. Whether the label-contact fields come across is a real product decision, not a mechanical port — the music department used them to reach promo contacts.
  5. Merge has more work to do here than it did in tubafrenzy. The legacy merge reassigns rotation-release references only, and the merge preview screen says exactly that. In this schema labels.id is referenced from two places — library.label_id (schema.ts:623) and flowsheet.label_id (schema.ts:1201) — and the label name is additionally denormalized into three text columns: library.label (schema.ts:622), flowsheet.record_label (schema.ts:1200) and rotation.record_label (schema.ts:1007). Note that rotation carries no label_id at all, which is the inverse of the legacy arrangement where rotation releases were the FK holders. A merge that repoints only the two FKs leaves three text columns asserting a name that no longer exists.

Contract drift worth fixing in the same pass

api.yaml:10377 declares /labels with a GET and a POST, and nothing else. Two mounted operations are undeclared: GET /labels/info and GET /labels/search. dj-site's lib/features/labels/api.ts already calls /labels/search, so a live consumer depends on an operation the published contract does not contain. Separately, the declared GET /labels q parameter is not read by the handler — labelsController.getLabels calls getAllLabels() with no argument (labels.controller.ts:10-13), so the documented search behaviour on that path does not exist.

Desired end state

An endpoint set sufficient to back a librarian-facing label admin screen in dj-site:

  • read one label by id, with the counts the screens display (releases referencing it, child labels referencing it as parent);
  • update a label's fields;
  • delete a label, refused server-side when references exist rather than pre-checked by the client;
  • merge N labels into one with a librarian-chosen surviving name, atomically, reporting how many references moved.

Reads gated catalog: ['read'], writes catalog: ['write'], matching the existing route file. api.yaml updated to match what is actually mounted, including the two undeclared reads.

Decisions to settle before implementing

  • Which legacy contact fields survive? All eleven, some, or none. If none, labelModify.jsp's field list shrinks to Name + Parent and that divergence gets recorded on the consumer ticket rather than silently dropped.
  • What makes a label undeletable? The legacy rule is "no rotation releases and no child labels". The honest equivalent here is "no library.label_id, no flowsheet.label_id, no child labels" — and possibly also no rotation.record_label text match, which is not a referential check and may not be worth making one.
  • Does merge rewrite the denormalized text columns? If it does, the merge is a multi-table write and wants a transaction plus a stated row-count report. If it does not, the ticket must say so plainly so the consumer screen does not promise a cleanup it will not perform.
  • Is a label rename allowed to leave library.label / flowsheet.record_label / rotation.record_label stale? Same question as above, for update rather than merge.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    concern:contract-changeChanges a published API contracteffort:lTriage effort: cross-packageenhancementNew feature or requestsev:medTriage severity: impact under common conditionstubafrenzyTouches WXYC/tubafrenzy (webhook, legacy mirror, flowsheet ETL, reconcile)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions