Spensara Spensara Knowledge Base & Documentation Repository

Repository Docs & Knowledge Base

Consolidated Spensara documentation repository (722 Markdown & architecture documents in ../repository)
Built Word Documents (.docx): Spensara Overview (.docx) Capability Assessment (.docx) Brink POS Ingestion Analysis (.docx) The Borg Ingestion Architecture (.docx)

Implementation Specs (157)

Detailed engineering and feature implementation specifications.
implementation-specs/specs/CustomerCredentialCustomHeaders/TASK1.1.md 3,057 bytes · Updated Oct 23, 2026 10:44 AM EDT
Raw File

TASK 1.1: Define customHeaders payload contract and validation rules

Summary

Define the admin API and stored payload contract for per-credential custom HTTP headers before changing persistence and transport code.

This task exists to prevent later ambiguity about whether the field is optional, how duplicates are handled, and what minimum validation should happen before a credential is stored.

Dependencies

  • none

Files to Modify

This task is primarily a design and implementation-alignment task.

Expected implementation touch points for later phases include:

  • backend/Kds.Ai.ApiService/Endpoints/AdminCustomerEndpoints.cs
  • backend/Kds.Ai.ApiService/Services/CustomerManagementService.cs
  • backend/Kds.Ai.Data/Credentials/BrinkPosCredentialPayload.cs
  • backend/tests/Kds.Ai.ApiService.Tests/Kds.Ai.ApiService.Tests/Endpoints/AdminCustomerEndpointsTests.cs

Required Behavior

Document and lock:

  • the JSON property name: customHeaders,
  • the shape: dictionary object of string -> string,
  • whether the field is optional for requests and responses,
  • whether null should be treated as missing/empty,
  • whether header names are case-sensitive for storage, validation, and duplicate detection,
  • minimum validation for blank names and invalid values,
  • whether header insertion order matters.

Recommended contract for this slice:

  • request shape:
json
{
  "payload": {
    "serviceUrl": "https://qa50oalphaapi.brinkpos.net/",
    "accessToken": "...",
    "locationToken": "...",
    "locationKey": "store-002",
    "enabled": true,
    "customHeaders": {
      "X-Partner-Key": "partner-secret",
      "X-Location-Code": "002"
    }
  }
}
  • customHeaders may be omitted or empty,
  • blank header names are rejected,
  • duplicate names after case-insensitive comparison are rejected,
  • values may be empty only if there is a concrete downstream need; otherwise reject whitespace-only values for cleaner operator behavior,
  • persistence may preserve the original header-name casing for readability,
  • runtime transport should emit the stored names exactly as stored.

Implemented decision for this task:

  • field name: customHeaders,
  • field type: IReadOnlyDictionary<string, string> in response/detail models and a nullable dictionary-like input model in requests,
  • missing or null input is treated as no custom headers,
  • header names are validated case-insensitively for uniqueness,
  • blank or whitespace-only names are invalid,
  • blank or whitespace-only values are invalid for this slice.

Acceptance Criteria

  • [ ] The payload field name and JSON shape are defined
  • [ ] Optionality and null semantics are defined
  • [ ] Duplicate-header behavior is defined
  • [ ] Minimum validation rules for names and values are defined
  • [ ] The contract is compatible with future non-Brink source integrations without redesigning the field

Notes

  • Prefer one simple JSON object over a list of name/value records.
  • Avoid over-designing around advanced HTTP header scenarios that are not needed yet.