DOC-03: Developer portal generation from OpenAPI and integration examples#605
DOC-03: Developer portal generation from OpenAPI and integration examples#605Chris0Jeky merged 8 commits intomainfrom
Conversation
Add OpenAPI metadata (title, description, version, contact, license), JWT Bearer security definition, and XML comment inclusion to the Swagger generation pipeline. Enable GenerateDocumentationFile in the API project to feed XML comments into the OpenAPI spec. Closes part of #99
Add XML documentation summaries, parameter descriptions, and ProducesResponseType attributes to all endpoints on BoardsController, CardsController, and ColumnsController for richer generated API docs. Part of #99
Add XML documentation summaries, parameter descriptions, and ProducesResponseType attributes to AuthController, CaptureController, ChatController, and OutboundWebhooksController for enriched OpenAPI spec. Part of #99
Create docs/api/ with generated-from-source integration documentation: - QUICKSTART.md: zero-to-authenticated-call in 5 minutes - AUTHENTICATION.md: JWT flow, GitHub OAuth, rate limiting - BOARDS.md: full CRUD reference for boards, columns, cards, and labels Part of #99
- CAPTURE.md: capture pipeline flow with status lifecycle - CHAT.md: LLM chat sessions, streaming, provider health - WEBHOOKS.md: subscription management, payload format, HMAC-SHA256 signature verification with Node.js/Python/C# examples - ERROR_CONTRACTS.md: error codes, HTTP status mapping, retry strategy Part of #99
- reusable-developer-portal.yml: generates OpenAPI spec, builds Redoc static HTML, and bundles integration guides as a CI artifact - export-openapi-spec.sh: local convenience script to fetch the spec from a running API instance Part of #99
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
The actual webhook delivery worker uses:
- X-Taskdeck-Webhook-Signature header with sha256= prefix (not X-Taskdeck-Signature)
- Canonical signing string: {unix_timestamp}.{payload} (not just raw body)
- X-Taskdeck-Webhook-Timestamp header for replay protection
- Additional delivery metadata headers (Delivery-Id, Subscription-Id, Event)
Updated all verification examples (Node.js, Python, C#) accordingly.
Part of #99
Adversarial Self-ReviewIssues found and addressedCritical: Webhook signature verification was wrong (FIXED in b841d73) The initial WEBHOOKS.md documented signature verification incorrectly:
All three verification examples (Node.js, Python, C#) were updated to match the actual Remaining notes (acceptable)
Verification
|
There was a problem hiding this comment.
Code Review
This pull request significantly improves the API documentation and discoverability of the Taskdeck service. It adds comprehensive XML documentation comments and response type attributes to all controllers, configures Swagger to generate a detailed OpenAPI specification with JWT security support, and introduces a full suite of Markdown-based API guides. Feedback focuses on correcting a cryptographic signature verification example in the C# documentation, enhancing Swagger metadata for the streaming chat endpoint, and improving the robustness of the Retry-After logic in the JavaScript integration example.
| ```python | ||
| import hmac | ||
| import hashlib | ||
|
|
||
| def verify_signature(raw_body: str, timestamp: str, signature_header: str, secret: str) -> bool: | ||
| # Strip the "sha256=" prefix | ||
| signature = signature_header.removeprefix("sha256=") | ||
| # Build the canonical signing string | ||
| canonical = f"{timestamp}.{raw_body}" |
There was a problem hiding this comment.
The C# signature verification example is incorrect and will lead to signature mismatches. It compares the UTF-8 byte representation of the hexadecimal strings, rather than the actual hash bytes. This should be corrected to compare the raw byte arrays for the computed hash and the signature from the header.
An incorrect implementation could lead developers to implement a non-constant-time comparison, which is vulnerable to timing attacks.
| ```python | |
| import hmac | |
| import hashlib | |
| def verify_signature(raw_body: str, timestamp: str, signature_header: str, secret: str) -> bool: | |
| # Strip the "sha256=" prefix | |
| signature = signature_header.removeprefix("sha256=") | |
| # Build the canonical signing string | |
| canonical = f"{timestamp}.{raw_body}" | |
| bool VerifySignature(string rawBody, string signature, string secret) | |
| { | |
| using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)); | |
| var computedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody)); | |
| var signatureBytes = Convert.FromHexString(signature); | |
| return CryptographicOperations.FixedTimeEquals(computedHash, signatureBytes); | |
| } |
| /// <response code="404">Chat session not found.</response> | ||
| [HttpGet("sessions/{id}/stream")] | ||
| [EnableRateLimiting(RateLimitingPolicyNames.HotPathPerUser)] | ||
| [Produces("text/event-stream")] |
There was a problem hiding this comment.
To improve OpenAPI/Swagger documentation for this streaming endpoint, you should explicitly declare the possible error responses using [ProducesResponseType]. While the success response is a stream, the error responses are standard JSON error contracts. This will make the API contract clearer for consumers.
[Produces("text/event-stream")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ApiErrorResponse), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(ApiErrorResponse), StatusCodes.Status404NotFound)]| const retryAfter = response.headers.get('Retry-After') || '5'; | ||
| await sleep(parseInt(retryAfter) * 1000); |
There was a problem hiding this comment.
The example for handling the Retry-After header is incomplete. The Retry-After header can specify either a delay in seconds or an HTTP-date. This implementation only handles the delay-seconds format and will not work correctly if an HTTP-date is returned. The code should be updated to handle both formats for robustness.
| const retryAfter = response.headers.get('Retry-After') || '5'; | |
| await sleep(parseInt(retryAfter) * 1000); | |
| const retryAfterHeader = response.headers.get('Retry-After'); | |
| let delayMs = 5000; // Default to 5 seconds | |
| if (retryAfterHeader) { | |
| const delaySeconds = parseInt(retryAfterHeader, 10); | |
| if (isNaN(delaySeconds)) { | |
| // It's a date string | |
| delayMs = new Date(retryAfterHeader).getTime() - Date.now(); | |
| } else { | |
| // It's a delay in seconds | |
| delayMs = delaySeconds * 1000; | |
| } | |
| } | |
| await sleep(Math.max(0, delayMs)); |
Restore Swashbuckle.AspNetCore to 10.1.7 (matching main) and update OpenApi usage for v2.x API: namespace change from Microsoft.OpenApi.Models to Microsoft.OpenApi, use OpenApiSecuritySchemeReference, and Func-based AddSecurityRequirement.
Summary
Implements developer portal generation from OpenAPI contracts with integration examples.
[ProducesResponseType]attributes and XML doc summaries to BoardsController, CardsController, ColumnsController, CaptureController, ChatController, AuthController, and OutboundWebhooksController -- these feed directly into the generated OpenAPI specdocs/api/):QUICKSTART.md-- zero-to-authenticated-call developer quickstartAUTHENTICATION.md-- JWT flow, GitHub OAuth, rate limiting, request correlationBOARDS.md-- full CRUD reference for boards, columns, cards, labels with cURL examplesCAPTURE.md-- capture pipeline flow and status lifecycleCHAT.md-- LLM chat sessions, streaming SSE, provider healthWEBHOOKS.md-- subscription management, payload format, HMAC-SHA256 signature verification with Node.js/Python/C# examplesERROR_CONTRACTS.md-- error codes, HTTP status mapping, retry strategyreusable-developer-portal.ymlgenerates the OpenAPI spec, builds Redoc static HTML, and bundles integration guides as a downloadable artifactscripts/export-openapi-spec.shfor fetching the spec from a running instanceAll docs are generated from or aligned with the actual source contracts -- not hand-maintained copies.
Closes #99
Test plan
dotnet build backend/Taskdeck.sln -c Releasesucceeds (XML doc generation enabled)/swaggerrenders enhanced metadata, security definitions, and XML commentsscripts/export-openapi-spec.shfetches valid JSON from a running instance