feat: implement topic and project management, so documents can be authored

Publishing was impossible on an empty database. Validation requires a topic,
the studio catalog answered zero topics, and nothing in the two implemented
contracts could create one — `studio-management-v1.yaml` owned that surface
and none of its 79 operations existed. Every path to a published record ran
through a door with no handle.

This implements the nine that unblock authoring: topics (list/create/update/
delete) and projects (list/get/create/update/delete). The remaining seventy
stay unimplemented; each has its own consumer and its own moment.

The contract was converted to the response envelope first (ADR-006), which is
what its own header said to do at implementation time. Doing it after would
have meant changing the wire shape of endpoints the frontend had already been
written against.

ManagementError is a separate enum rather than an extension of StudioError.
Each contract enumerates its own ApiError.code set, so a code reachable from
the wrong surface makes that contract false. It deliberately omits
INTERNAL_ERROR: the skeleton's OperationalError owns that code with
retryable=true, and declaring it twice with different values leaves the
registry with no answer. PublicError made the same call for the same reason.

Two contract defects surfaced while implementing. TopicEdit had neither id nor
version, so a listed topic could not be addressed by the `/topics/{id}` path
and a client had no source for the expectedVersion the write operations
require; both are fixed in the design package. The AWS SDK BOM had to be
imported in app-bootstrap as well — module-scoped dependency management does
not propagate to consumers, and this is the first runtime consumer of that
pattern.

Topic and project deletion refuse while records still reference them rather
than cascading. A topic disappearing should not silently reclassify the
documents that used it; moving them first is the caller's decision to make.

ActuatorSecurityHttpTest.healthEndpointIsPermitAll fails on this branch before
this change as well; it is untouched here.
This commit is contained in:
DongHyeonka
2026-08-20 22:54:24 +09:00
parent bde5826cfd
commit bb6d2330bb
34 changed files with 9065 additions and 0 deletions
+2
View File
@@ -2,3 +2,5 @@
6cae9924403d0761f401643a022980b8e04183eea0d890c143c9fbbbbc7431e4 studio-v1.yaml
# source: tech-log-design-package contracts/openapi/public-v1.yaml @ 55a9599 (feature/public-v1-response-envelope)
8ac71425b38658f34641102b4c2e6e21288c811efebdb92c0a46fb9d4790e23e public-v1.yaml
# source: tech-log-design-package contracts/openapi/studio-management-v1.yaml @ 6ef5c1c (master)
ec5e432215fb041abee980787366a6db29ff1ecdd78416aa9c61e09b9b91022f studio-management-v1.yaml