Repository navigation
[Trace] Content audit: enrich thin API reference pages: 21 endpoint pages - #171
Merged
Merged
Conversation
…ining docs/API/*.api.mdx Rolls out the PR #155 pattern (real description, when-to-use, curl example, verified request/response, common-errors table, related links) to every docs/API/*.api.mdx page under 300 live words, excluding the 3 pages #155 already enriched (delete-template, get-templates-and-folders, upload-template-with-optional-default-values) and the turbodocx-api-documentation info page. Covered: 3 template endpoints (edit-template-metadata, get-template-by-id, extract-template-placeholders-and-generate-preview), all 10 TurboSign webhook endpoints (create/get/update/delete/notify/test/regenerate-secret/ list-deliveries/replay-delivery/get-stats), and 8 tag/variable endpoints (create/read/update-tag, delete-tags-by-i-ds, create-image-variable-folder, read-variables-folder, update-variable-by-id, delete-variables-by-i-ds). Every path, method, field, response shape, and error was verified against the route/handler code in RapidDocxBackend (Template, Webhooks, Tag, Variable routes + handlers), not the OpenAPI spec, which is stale in several places. Also fixed two pre-existing frontmatter issues on webhook pages: an em-dash and an inaccurate "soft-delete" claim on delete-webhook (the handler hard-deletes the row).
nicolasiscoding
marked this pull request as ready for review
September 23, 2026 15:57
This was referenced Sep 23, 2026
This branch was successfully deployed
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.
Closes #170
Trace task:
content-audit.mjs(flagged these pages KILL/thin),thin-content-detector.mjs,config/noindex-strategy.json, plus the team rule that thin-but-legitimate pages are improved, never noindexed.Evidence
GSC shows docs.turbodocx.com API endpoint pages (
docs/API/*.api.mdx, generated bydocusaurus-plugin-openapi-docs) rendering only 4-9 words of unique content for Googlebot, and many are "Crawled/Discovered - currently not indexed." PR #155 hand-enriched 3 pages as a prototype and validated the strategy: URL Inspection now showsdelete-templatewent from not-on-Google to Submitted and indexed, andupload-template-with-optional-default-valuesis indexed (get-templates-and-foldershasn't been recrawled since June). This PR rolls that pattern out to the remaining thin pages.origin/developandorigin/mainpoint at the same commit as of this branch's base, and both already contain #155's enrichment (checked viagit log+git diffondelete-template.api.mdxbefore starting). This branch is based onorigin/develop, per the repo's default.What changed
21 of the 24 remaining thin
docs/API/*.api.mdxpages (live word count under 300, excluding the 3 pages #155 already enriched and theturbodocx-api-documentationinfo page) now have: a real frontmatterdescription(<= 160 chars, no em-dashes), an intro paragraph, a "When to use it" section, a runnable curl example, a verified example response, a common-errors table, and related-endpoint links — matching #155's structure exactly.edit-template-metadata,get-template-by-id,extract-template-placeholders-and-generate-previewcreate-webhook,get-webhook,update-webhook,delete-webhook,notify-webhook,test-webhook,regenerate-webhook-secret,list-webhook-deliveries,replay-webhook-delivery,get-webhook-statscreate-tag,read-tag,update-tag,delete-tags-by-i-ds,create-image-variable-folder,read-variables-folder,update-variable-by-id,delete-variables-by-i-dsEvery path, method, request field, response shape, and error was verified against the route/handler code in
RapidDocxBackend(src/routes/Template,src/routes/Webhooks,src/routes/Tag,src/routes/Variable+ their handlers insrc/handlers/), not the OpenAPI spec (tdocxcollection.yml), which is stale in places. Where I could not verify a claim against the handler code, I left it out.Accuracy findings / spec-vs-code discrepancies
delete-webhook's existing frontmatter description said "soft-delete," butdeleteWebhook()inwebhookManagement.tsissues real SQLDELETEs on both the webhook row and its deliveries — it's a hard delete. Fixed the description and documented it correctly.GET /api/webhooks/:name'sdeliveryStats(viaWebhookService.getDeliveryStats) is scoped to the whole organization's deliveries over the last 30 days, not to the single webhook in the URL — documented that explicitly and pointed toGet Webhook Statsfor a per-webhook, custom-window alternative.PUT /Tag/:id(Update Tag) responds with the raw updated tag object (res.send(Tag)), not the{ data: {...} }envelope almost every other endpoint uses — documented as-is rather than assuming the common envelope.PUT /Variable/:variableMapId(Update Variable by ID) responds{ "variable": {...} }, also outside thedataenvelope — documented as-is.create-webhook's andregenerate-webhook-secret's existing frontmatter descriptions was removed per the no-em-dash content rule; both descriptions were also shortened to fit the 160-char limit.Generated-file caveat
These
.api.mdxfiles are generated bydocusaurus-plugin-openapi-docs, and the plugin's configuredoutputDir(docs/api/turbodocx) does not match the served path (docs/API/) — so the regen pipeline isn't actually wired to overwrite these files today, but that's fragile to rely on long-term. Recommended follow-up (not in this PR): enrich the descriptions directly intdocxcollection.ymland fix the plugin'soutputDirso a future regeneration doesn't silently invite someone to overwrite this content.Not covered
docs/API/Deliverable%20API(2603 words, not thin) andturbodocx-api-documentation(info page, excluded by the task) were left untouched, as were the 3 pages #155 already enriched.Test plan
yaml.safe_load)/docs/API/...link added resolves to an existing page (verified against the file list)grepfor em-dashes across changed files returns nothingdescriptionis <= 160 charactersReview vs backend master
Diligence pass against
origin/masterof RapidDocxBackend and the frontend, checking every documented behavior against the actual deployed code. 14 confirmed inaccuracies fixed:summary.failed/summary.errorsonly count a DB error on insert, not HTTP-level delivery failures (deliverWebhookToUrlnever rethrows on a failed HTTP attempt). Doc now points callers at each delivery'sisDelivered/status/errorMessageinstead of the unreliable summary counters.replayDeliverycopiesoriginalDelivery.urlinto the new row). Fixed the frontmatter description and body copy.nameuniqueness check (and its DB index) is scoped to(orgId, name, isActive), so it's unique only among active webhooks; pausing one withisActive: false(as Update/Delete Webhook recommend) and creating another with the same name silently produces two rows with the same name. Doc now says to delete rather than pause before reusing a name.{ "error": "..." }; celebrate/Joi validation failures go through the app'sJoiValidationErrorHandler, which returns{ "message", "type": "ValidationError", "data": { "errors": [...] } }. Fixed both pages' error tables to match the shape used elsewhere in this PR.maxAttemptsfixed at 3; the retry loop only ever reaches the 1-minute and 5-minute delays before the final attempt dead-letters. Corrected the backoff description.isDeliveredandhttpStatusfilters don't work as documented due to a type-coercion bug (celebrate/Joi already converts these to a real boolean/number before the handler's string comparisons run). Added a "known limitation" callout describing current behavior instead of the intended one.GET /Tag/:idexists and returns a single tag. Corrected the claim and linked the endpoint.templatePdfis documented as a base64 string, but it's a JSON-serialized Node.jsBuffer({"type":"Buffer","data":[...]}). Documented the actual shape and how to reconstruct it, matching how the frontend already consumes it.{ }" error was listed under theValidationErrorrow, but it's actually thrown as aTemplateErrorby the same handler as the "placeholder already exists" case. Moved it to the correct row.isGlobal: truerequests are further restricted to administrator/contributor (a second KB-specific middleware rejects theuserrole). Added the row.VariableMaphas notemplateId. Removed the row.isGlobal/templateFolderIdare "exactly one required" or "mutually exclusive", but the Joi rule (oxor) only forbids sending both; neither is required. Changed all three to "at most one, sending both is rejected".idin the body is "not accepted"; it isn't rejected by validation on this route (body validation context is"PATCH", andidis only forbidden under a"PUT"context) and isn't ignored either, aniddiffering from the URL'sTagIdwill overwrite the tag's ownid. Corrected to warn against sending it, rather than claiming it's rejected.Backend defects found during this review (not fixed here, for ticketing)
WebhookService.deliverWebhookToUrl/attemptDelivery: HTTP-level delivery failures never surface inPOST /webhooks/signature/test'ssummary.failed/summary.errors, only DB-insert errors do. A caller pollingsummary.failedto detect a broken receiver sees zero failures even when every attempt 500s.WebhookService.replayDelivery: replays only the single URL the original delivery hit, even though a webhook can have up to 10 URLs; there's no way to replay to all of a webhook's URLs via this endpoint.WebhookModelname-uniqueness is scoped to(orgId, name, isActive)rather than(orgId, name), so pausing a webhook (isActive: false) and creating a new one with the same name produces two rows sharing a name; every by-name lookup endpoint (Get/Update/Delete/Test/Notify/Regenerate/List-deliveries/Replay/Stats) then has ambiguous resolution.GET /webhooks/signature/deliveriesquery filters:isDelivered=trueis coerced tofalseby a=== "true"string comparison against an already-Joi-converted boolean, so it returns the same results asisDelivered=false;httpStatusis dropped entirely by atypeof x === "string"check against an already-converted number, so the filter never applies.PUT /Tag/:id: body validation runs in a"PATCH"Joi context, not the"PUT"context that forbidsid, so a client-suppliedidin the body silently overwrites the tag's ownidcolumn viaupdateAndFetchById. Separately,idhas a Joi.default(() => uuidv4()), so if it's ever coerced onto an absent field, that could overwrite the row'sidwith a fresh random UUID even without user input; worth confirming celebrate'sconvertbehavior doesn't apply defaults back ontoreq.bodyhere before shipping a fix.