Repository navigation
[W1 — do not merge] API contract v1 - #2
Merged
Merged
Conversation
New mark from scratch: a pen nib pointing up that is also an A (slit and breather hole are the counter, the open feet are the legs). Built like the Bastion and Herald kits: generate.py rebuilds every SVG, PNG, web icon and Stream Deck key; README covers construction, palette (orange #E27A43, dark orange #BE551D on light, ink on the orange tile), clear space and minimum sizes. app_logo.png is now the white lockup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register nest-common's TransformInterceptor globally (bump to ^0.4.0):
single resources, creations and non-paginated lists become { data },
paginate() pages stay { data, meta }. GET article-translations goes from a
bare array to { data: [...] }. No @NoTransform() exemption is needed.
The admin webhook list spread the page to map its rows, which dropped
paginate()'s marker and would have wrapped it twice: rebuilt with
markPaginated.
Swagger documents the envelope: @ApiResponse/@ApiOkResponse/
@ApiCreatedResponse({ type }) on 2xx -> ApiOkData / ApiCreatedData.
openapi.json regenerated.
BREAKING CHANGE: every non-paginated 2xx JSON body is now wrapped in
{ data }. Do not merge before the W4 cutover (platform plan 02).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FileHarborService keeps its policy (MIME/size checks, endpoint check, id
extraction, 404 = already deleted); upload and delete now go through
FileHarborClient from @heyatom/client/fileharbor, one per call because
endpoint and API key are per tenant. Uploads read the { data } envelope of
FileHarbor's new contract. creatorId form field -> X-User-Id (userId).
The axios options this replaces were deliberate, so the client gets
fileHarborFetch: no redirects (the tenant key must not follow a Location)
and a 1 MB response cap; timeouts stay 15 s / 30 s. Their spec moves from
webhook-http.spec.ts into the fileharbor spec.
Drops @nestjs/axios, axios, form-data and the hand-written image DTO.
@heyatom/client points at the local checkout (file:) until the W4 release.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Wave W1 of platform plan
docs/platform/plans/02-api-contract-cutover.md(Articuno part). Do not merge: merges only in the W4 cutover, together with fileharbor, gatherly,@heyatom/client1.0.0 and the consumers.Changes
@heyatom/nest-common^0.3.0 → ^0.4.0; globalTransformInterceptor(APP_INTERCEPTOR).{ data }. Paginated lists unchanged ({ data, meta }, passed through by thepaginate()marker). 204s unchanged.GET /articles/{id}/translationsandGET /admin/articles/{id}/translations: bare array →{ data: [...] }.GET /admin/webhooks: the controller spread the page to map rows, dropping the marker (would have become{data:{data,meta}}); rebuilt withmarkPaginated, with a spec.@ApiResponse/@ApiOkResponse/@ApiCreatedResponse({ type })→ApiOkData/ApiCreatedData.openapi.jsonregenerated.@NoTransform()exemptions: none (no file/stream/redirect/external-format endpoint).Shapes changed (old
X→ new)POST /articles→{data: ArticleDto}GET /articles/{slug}→{data: ArticleDto}PATCH /articles/{id}→{data: ArticleDto}POST /banned-words→{data: BannedWordDto}POST /articles/{id}/translations→{data: ArticleTranslationDto}GET /articles/{id}/translations→{data: [ArticleTranslationSummaryDto]}GET /articles/{id}/translations/{languageCode}→{data: ArticleTranslationDto}PATCH /articles/{id}/translations/{languageCode}→{data: ArticleTranslationDto}POST /bookmarks/{articleId}→{data: BookmarkToggleResultDto}POST /categories→{data: CategoryDto}GET /categories/{slug}→{data: CategoryDto}PATCH /categories/{id}→{data: CategoryDto}POST /comments→{data: CommentDto}GET /comments/{id}→{data: CommentDto}PATCH /comments/{id}→{data: CommentDto}POST /interactions/articles/{articleId}/like→{data: LikeToggleResultDto}GET /interactions/articles/{articleId}/status→{data: ArticleInteractionStatusDto}POST /reports→{data: ReportDto}PATCH /reports/{id}/status→{data: ReportDto}POST /tags→{data: TagDto}GET /tags/{slug}→{data: TagDto}PATCH /tags/{id}→{data: TagDto}POST /users/sync→{data: UserDto}GET /health/live→{data: {...}} (health, body free per api.md §6)GET /health/ready→{data: {...}} (health, body free per api.md §6)POST /admin/articles→{data: ArticleDto}GET /admin/articles/{key}→{data: ArticleDto}PATCH /admin/articles/{id}→{data: ArticleDto}POST /admin/articles/{id}/translations→{data: ArticleTranslationDto}GET /admin/articles/{id}/translations→{data: [ArticleTranslationSummaryDto]}GET /admin/articles/{id}/translations/{languageCode}→{data: ArticleTranslationDto}PATCH /admin/articles/{id}/translations/{languageCode}→{data: ArticleTranslationDto}POST /admin/tags→{data: TagDto}GET /admin/tags/{id}→{data: TagDto}PATCH /admin/tags/{id}→{data: TagDto}POST /admin/categories→{data: CategoryDto}GET /admin/categories/{id}→{data: CategoryDto}PATCH /admin/categories/{id}→{data: CategoryDto}POST /admin/banned-words→{data: BannedWordDto}POST /admin/reports→{data: ReportDto}GET /admin/reports/{id}→{data: ReportDto}PATCH /admin/reports/{id}/status→{data: ReportDto}GET /admin/audits/{id}→{data: AuditLogDto}GET /admin/users/{id}→{data: UserListItemDto}PATCH /admin/users/{id}/status→{data: UserListItemDto}GET /admin/comments/{id}→{data: CommentDto}PATCH /admin/comments/{id}→{data: CommentDto}GET /admin/webhooks/{id}→{data: WebhookEventDto}POST /admin/webhooks/{id}/resend→{data: WebhookEventDto}POST /admin/webhooks/resend-all-failed→{data: WebhookResendAllResultDto}GET /admin/stats/dashboard→{data: DashboardStatsDto}Checks
command grep -rnE "@Api(Ok|Created)Response\(\{ type" src→ emptyW3 — FileHarbor via
@heyatom/clientsrc/modules/fileharbor/: HTTP moves from@nestjs/axios+form-datatoFileHarborClient(@heyatom/client/fileharbor), one client per call (endpoint and API key are per tenant, so not the global Nest module).FileHarborServicekeeps its policy: MIME/size checks, endpoint check, id extraction, 404 on delete = already deleted.POST {endpoint}/images(formdescription,creatorId) →uploadImage(file, { description }, { userId })→.data.fullPath(FileHarbor's new{ data }envelope);DELETE {endpoint}/images/:id→deleteImage(id);error.response?.status === 404→HeyAtomHttpError.status === 404.fileHarborFetch: no redirects (redirect: 'manual', the tenant key never follows aLocation) and a 1 MB response cap; timeouts stay 15 s (delete) / 30 s (upload). Their test moves fromwebhook-http.spec.tsintofileharbor.service.spec.ts.fileharbor/dto/file-harbor.dto.ts,webhook/webhook-http.spec.ts, deps@nestjs/axios,axios,form-data. No env change (Articuno never hadFILEHARBOR_URL/FILEHARBOR_API_KEY).@heyatom/clientisfile:/Users/atombolato/Developer/heyatom/heyatom-clientuntil the W4 release: CI cannot install it, red until then (expected).Note: the branch also carries
6536961 docs(brand): add Articuno logo kit, which was already on it and is not ondevelop.🤖 Generated with Claude Code