feat(api): library write endpoints — POST /libraries/clients, PATCH /libraries/:id#233
Conversation
…libraries/:id Re-enables the demo's Library panel (gated behind libraryWrites in #231). - POST /libraries/clients: create a client-tier library. Body { name, parentLibraryId? }; parent defaults to the Default Company Master (resolved by name), and an explicit parent must be company-tier (422 otherwise). owner is set to the name. 201; 409 on duplicate name; 404 unknown parent. - PATCH /libraries/:id: rename (name only — owner unchanged, §8). Only client-tier libraries are renameable; built-in masters return 422 (renaming them would break name-based resolution). 200; 404 unknown; 409 duplicate. - New updateLibraryName query; openapi documents both; contract gate covers them. Closes #232 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughTwo new library write endpoints are added end-to-end: ChangesLibrary Write Endpoints
Sequence Diagram(s)sequenceDiagram
participant Client
participant Router
participant createClientLibraryHandler
participant renameLibraryHandler
participant DB
rect rgba(70, 130, 180, 0.5)
note over Client,DB: POST /libraries/clients
Client->>Router: POST /libraries/clients {name, parentLibraryId?}
Router->>createClientLibraryHandler: validated request
createClientLibraryHandler->>DB: getLibrary(parentLibraryId) or getDefaultCompanyLibrary()
DB-->>createClientLibraryHandler: parent Library | null
createClientLibraryHandler->>DB: createLibrary(name, parentId)
DB-->>createClientLibraryHandler: Library | unique violation
createClientLibraryHandler-->>Client: 201 Library | 400/404/409/422/500
end
rect rgba(60, 179, 113, 0.5)
note over Client,DB: PATCH /libraries/:id
Client->>Router: PATCH /libraries/:id {name}
Router->>renameLibraryHandler: validated request
renameLibraryHandler->>DB: getLibrary(id)
DB-->>renameLibraryHandler: Library | null
renameLibraryHandler->>DB: updateLibraryName(id, name)
DB-->>renameLibraryHandler: Library | unique violation
renameLibraryHandler-->>Client: 200 Library | 400/404/409/422/500
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/api/libraries.integration.test.ts`:
- Around line 65-71: The companyMasterId function currently filters libraries
only by tier === 'company', which can hide regressions if multiple company-tier
libraries exist. Modify the find condition in companyMasterId to also filter by
the specific name of the seeded default company master library (in addition to
the tier check), ensuring the function correctly validates the default parent
resolution by name requirement rather than just picking the first company-tier
library found.
In `@src/api/libraries.ts`:
- Around line 78-83: In the `resolveClientParent` function, after retrieving the
library with `findLibraryByName(DEFAULT_COMPANY_LIBRARY)`, add a validation
check to ensure the returned library has the correct tier (company tier) before
returning it, not just checking if it exists. This ensures consistency with how
explicit parentLibraryId values are validated elsewhere in the function,
preventing client libraries from being attached to misconfigured non-company
parent libraries.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e2a45b98-5442-4f5e-8ac7-2b25309338ff
📒 Files selected for processing (7)
openapi.yamlsrc/api/contract.integration.test.tssrc/api/libraries.integration.test.tssrc/api/libraries.tssrc/api/router.tssrc/db/index.tssrc/db/queries/libraries.ts
Addresses two CodeRabbit findings on #233: - resolveClientParent now validates the seeded Default Company Master is company-tier (500 if misconfigured), matching the explicit-parent path — defends against a misconfigured seed attaching a client to a non-company parent. - The library test's companyMasterId helper matches by name (Default Company Master), not just tier, so the "default parent resolves by name" contract can't be masked by a stray extra company-tier library. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Why
The web UI demo's Library panel creates and renames client libraries, but those endpoints don't exist on
main(gated behindlibraryWritesby the conform #231). This re-enables that panel. Track A of the demo-backend program (after #227/#229/#231).What
POST /libraries/clients→ create a client-tier library. Body{ name, parentLibraryId? }; parent defaults to the Default Company Master (resolved by name, not a hardcoded id), and an explicit parent must be company-tier (422).owneris set to the name.201;409duplicate name;404unknown parent.PATCH /libraries/:id→ rename (nameonly —ownerunchanged, per spec §8). Only client-tier libraries are renameable — built-in reference/company masters return422(renaming them would break name-based resolution likeresolveDefaultLibraryId).200;404unknown;409duplicate.updateLibraryNamequery;openapi.yamldocuments both (sharedConflict/UnprocessableEntityresponses); contract gate covers them.Testing
libraries.integration.test.ts(25/25 with the read tests + contract gate)POST /projects)pnpm lintclean (eslint + tsc + prettier)🤖 Co-authored by Claude Opus 4.8. Closes #232.
Summary by CodeRabbit
Release Notes
POST /libraries/clients, including optional parent assignment with sensible defaults.PATCH /libraries/{id}.