Skip to content

DOC-03: Developer portal generation from OpenAPI and integration examples#605

Merged
Chris0Jeky merged 8 commits intomainfrom
docs/99-developer-portal-openapi
Mar 30, 2026
Merged

DOC-03: Developer portal generation from OpenAPI and integration examples#605
Chris0Jeky merged 8 commits intomainfrom
docs/99-developer-portal-openapi

Conversation

@Chris0Jeky
Copy link
Copy Markdown
Owner

Summary

Implements developer portal generation from OpenAPI contracts with integration examples.

  • Enhanced Swagger/OpenAPI configuration: Added API metadata (title, description, version, contact, license), JWT Bearer security definition, and XML comment inclusion to the Swagger pipeline
  • XML documentation on key controllers: Added [ProducesResponseType] attributes and XML doc summaries to BoardsController, CardsController, ColumnsController, CaptureController, ChatController, AuthController, and OutboundWebhooksController -- these feed directly into the generated OpenAPI spec
  • Integration example docs (docs/api/):
    • QUICKSTART.md -- zero-to-authenticated-call developer quickstart
    • AUTHENTICATION.md -- JWT flow, GitHub OAuth, rate limiting, request correlation
    • BOARDS.md -- full CRUD reference for boards, columns, cards, labels with cURL examples
    • CAPTURE.md -- capture pipeline flow and status lifecycle
    • CHAT.md -- LLM chat sessions, streaming SSE, 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
  • CI workflow: reusable-developer-portal.yml generates the OpenAPI spec, builds Redoc static HTML, and bundles integration guides as a downloadable artifact
  • Local export script: scripts/export-openapi-spec.sh for fetching the spec from a running instance

All 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 Release succeeds (XML doc generation enabled)
  • All backend tests pass (1393+ tests, 0 failures)
  • Swagger UI at /swagger renders enhanced metadata, security definitions, and XML comments
  • scripts/export-openapi-spec.sh fetches valid JSON from a running instance
  • CI workflow generates Redoc artifact on pull request

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
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

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
@Chris0Jeky
Copy link
Copy Markdown
Owner Author

Adversarial Self-Review

Issues found and addressed

Critical: Webhook signature verification was wrong (FIXED in b841d73)

The initial WEBHOOKS.md documented signature verification incorrectly:

  • Used X-Taskdeck-Signature header name — actual is X-Taskdeck-Webhook-Signature with sha256= prefix
  • Documented signing over raw body only — actual canonical string is {unix_timestamp}.{payload} per OutboundWebhookSignature.Compute()
  • Missing X-Taskdeck-Webhook-Timestamp header needed for verification and replay protection
  • Missing documentation of all delivery metadata headers (Delivery-Id, Subscription-Id, Event, Timestamp)

All three verification examples (Node.js, Python, C#) were updated to match the actual OutboundWebhookDeliveryWorker implementation.

Remaining notes (acceptable)

  1. Webhook event types table is illustrative: The exact event type strings depend on the WebhookBoardMutationNotifier implementation. The documented event types (card.created, card.moved, etc.) are representative but should be verified against the notifier code if consumers depend on exact string matching. This is a documentation gap, not an error.

  2. Webhook payload format is representative: The inner payload shape depends on the serialization in WebhookBoardMutationNotifier. The example shows a plausible structure but is not extracted from the actual code. Consumers should rely on the OpenAPI spec or a test delivery for exact shapes.

  3. Labels controller not annotated: Only the 7 most critical controllers (Auth, Boards, Cards, Columns, Capture, Chat, Webhooks) received full XML doc annotations. Other controllers (Labels, Archive, Audit, Export, etc.) would benefit from similar treatment in follow-up work.

  4. Reusable workflow not yet wired into CI gate: reusable-developer-portal.yml is created but not called from ci-required.yml or ci-nightly.yml. This is intentional — the portal generation is optional and should be wired in when the team decides to publish it.

  5. No doc versioning yet: The AC mentions "version-aware" docs. The OpenAPI spec includes the v1 version from the Swagger doc, but the docs themselves do not have a version-gating mechanism. This could be added when the API introduces breaking changes.

Verification

  • Build: dotnet build backend/Taskdeck.sln -c Release — 0 errors, 1 pre-existing warning
  • Tests: dotnet test backend/Taskdeck.sln -c Release -m:1 — all 1393+ tests pass, 0 failures

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread docs/api/WEBHOOKS.md
Comment on lines +176 to +184
```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}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

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.

Suggested change
```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")]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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)]

Comment on lines +99 to +100
const retryAfter = response.headers.get('Retry-After') || '5';
await sleep(parseInt(retryAfter) * 1000);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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.
@Chris0Jeky Chris0Jeky merged commit 499ba2f into main Mar 30, 2026
18 checks passed
@github-project-automation github-project-automation bot moved this from Pending to Done in Taskdeck Execution Mar 30, 2026
@Chris0Jeky Chris0Jeky deleted the docs/99-developer-portal-openapi branch March 30, 2026 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

DOC-03: Developer portal generation from OpenAPI and integration examples

1 participant