mirror of
https://github.com/Sea-Haven-Industries/procurement-ingest.git
synced 2026-09-30 15:23:13 +00:00
Some checks are pending
Deploy / deploy (push) Waiting to run
* feat(api): Add @redocly/cli as a dev dependency
Signed-off-by: Adam Moussa <adam@seahavenind.com>
* feat(api): Add Redocly configuration file with custom rules
Signed-off-by: Adam Moussa <adam@seahavenind.com>
* chore(api): Redocly lint config + bring openapi.json into compliance
redocly.yaml from the Redocly guidelines builder, with three generated
rules corrected: response-contains-property had the status codes as the
required body fields (intent was the Error schema's top-level 'error';
403 exempt since API Gateway emits AWS's {message} shape, 501 not 503);
operation-4xx-problem-details-rfc7807 off (adopting RFC 7807 would be a
runtime + SHOC-contract change, decided against); the two inert casing
rules (parameter names, schema properties) removed because both name
sets are contract-pinned (gateway resource paths, DynamoDB items).
Spec changes, no runtime impact: operationIds renamed to method-prefixed
kebab-case (get-work-orders, post-work-order-comment, ...); tags added to
all 15 operations + root tags object (groups the Redoc sidebar); examples
on all six parameters; license field; server description punctuation; two
descriptions reworded to start capitalized. Real linter catches fixed:
the two x-planned ops were missing their {workOrderId} path parameter
and any 4xx response (403 added - true today, gateway rejects unsigned).
.redocly.lint-ignore.yaml pins the six deliberate exceptions: webhook
keys are the shipped SHOC contract event names (not renameable), and the
x-planned ops answer only 501 (no 2xx to document).
package.json: npm run lint:api. Verified: lint 0 errors, 675 pytest,
headless-Chrome render of the tagged docs page.
* feat(api): SHOC design-system theme for /docs (vendored fonts)
Themes the Redoc page with the canonical SHOC token set: Montserrat 600
headings / DM Sans body / JetBrains Mono code, primary #1c75bc, navy
#262262 sidebar text + right panel, #f9fafb background, 244px sidebar.
sortRequiredPropsFirst on; 200 responses pre-expanded.
Fonts ship as lambdas/api/fonts.css (latin woff2 subsets from
@fontsource 5.3.0, embedded as data URIs, ~90KB) and inline via a new
__FONTS_CSS__ placeholder with the same </style breakout guard --
the offline single-response invariant holds, nothing fetches Google
Fonts (test-pinned). Bundling cp + bundle-consistency pin + spec-drift
asset checks extended.
Verified: headless-Chrome render (theme + fonts applied), ruff, 675
pytest, cdk synth + staged-asset check.
* feat(api): SHOC gradient topbar on /docs
64px fixed header with the SHOC shell gradient token (#1b1f52 ->
#1c4f8f -> #1c75bc), Sea Haven wordmark in Montserrat 600, page name
right-aligned in DM Sans. Redoc's scrollYOffset: 64 keeps the sticky
sidebar and anchor scrolling clear of the fixed bar. Verified via
headless-Chrome render.
* style(api): normalize /docs header and right-panel blues
The right panel's #262262 is a purple-leaning navy that clashed with
the cyan-leaning gradient, and the bar's brightest point sat directly
over the dark panel. Right panel now uses #1b1f52 (the gradient's own
dark endpoint) and the gradient runs bright-to-dark so its dark end
lands flush on the panel -- no seam, one blue family. Verified via
headless-Chrome render.
* style(api): right-panel gradient on /docs via bundle-pinned override
Redoc's theme only takes solid colors (it derives shades from
rightPanel.backgroundColor), so the gradient (#1b3d79 -> #1b3068 ->
#1b1f52, continuing the topbar blend) rides as a CSS override on the
styled-components classes of the per-section right-panel divs
(.sc-iGgWBj.sc-gsFSXq + the .sc-dExYaf stub). Those names are
deterministic for the vendored 2.5.3 bundle (verified across loads) but
change on any Redoc bump: re-derive via headless probe (find elements
whose computed background equals the rightPanel color). If they stop
matching, the panel falls back to the solid #1b1f52 theme color --
cosmetic only. Verified via headless-Chrome render.
* feat(api): collapsible samples column on /docs
Redoc CE has no built-in panel toggle, so the topbar gains a Hide/Show
samples button that flips .samples-collapsed on <html>: the right-panel
divs hide (same bundle-pinned styled-components classes as the gradient
override) and each section's content half takes the full width. Choice
persists in localStorage; aria-pressed tracks state. If the pinned
classes stop matching after a Redoc bump the toggle goes inert --
cosmetic only. Both states verified via headless-Chrome render.
* ci(api): spec-lint CI gate + npm Dependabot coverage
New spec-lint job mirrors the local npm run lint:api so openapi.json
cannot drift from redocly.yaml with green CI. Dependabot gains the npm
ecosystem (package.json is new; nothing watched @redocly/cli).
* feat(api): docs finishing touches - x-tagGroups, favicon, docs:preview
x-tagGroups sections the Redoc sidebar (Read API / Meta / SHOC Feed);
inline data-URI SVG favicon (SHOC blue) stops the browser's follow-up
/favicon.ico request 403ing at the gateway; npm run docs:preview wraps
the real-handler local render (scripts/preview_docs.py); README gains a
docs-page architecture section covering the inline pattern, theme,
pinned-selector caveat, and tooling. Lint 0 errors, 675 pytest,
headless render verified.
---------
Signed-off-by: Adam Moussa <adam@seahavenind.com>
162 lines
6.5 KiB
HTML
162 lines
6.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Procurement Ingest API</title>
|
|
<link rel="icon" href="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%3E%3Crect%20width='16'%20height='16'%20rx='3'%20fill='%231c75bc'/%3E%3Ctext%20x='8'%20y='12'%20font-size='10'%20font-family='sans-serif'%20font-weight='700'%20text-anchor='middle'%20fill='white'%3ES%3C/text%3E%3C/svg%3E">
|
|
<!--
|
|
Redoc (redoc.standalone.js, MIT), vendored offline and inlined server-side
|
|
so /docs is a single token-gated request with no CDN or follow-up asset
|
|
fetch. The bundle, the SHOC design-system fonts (fonts.css, data-URI
|
|
@font-face), and the OpenAPI spec are substituted for the placeholders
|
|
below by lambdas/api/handler.py::_docs_shell / _render_docs_html. Redoc is
|
|
read-only by design -- there is no try-it-out to disable; live calls go
|
|
through Postman (Authorization type "AWS Signature") since data routes
|
|
require SigV4.
|
|
Theme = the SHOC design-system token set (the Sea Haven visual standard):
|
|
Montserrat headings / DM Sans body / JetBrains Mono code, primary #1c75bc,
|
|
navy #262262, page background #f9fafb, 244px sidebar. Fonts are vendored --
|
|
nothing here may fetch from Google Fonts.
|
|
-->
|
|
<style>__FONTS_CSS__</style>
|
|
<style>
|
|
html, body { margin: 0; padding: 0; background: #f9fafb; }
|
|
/* SHOC shell topbar: 64px, gradient header token. Redoc has no topbar of
|
|
its own; scrollYOffset below keeps its sticky sidebar/scroll accounting
|
|
clear of this fixed bar. Gradient runs bright-to-dark (reversed from the
|
|
SHOC shell) so its dark end (#1b1f52) sits flush over the right panel,
|
|
which uses the same color -- one continuous blue family, no seam. */
|
|
#topbar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 64px;
|
|
z-index: 10;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 24px;
|
|
box-sizing: border-box;
|
|
background: linear-gradient(90deg, #1c75bc 0%, #1c4f8f 45%, #1b1f52 100%);
|
|
color: #ffffff;
|
|
font-family: "Montserrat", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
}
|
|
#topbar .brand {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.02em;
|
|
}
|
|
#topbar .page {
|
|
margin-left: 16px;
|
|
font-family: "DM Sans", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
font-size: 13px;
|
|
font-weight: 400;
|
|
opacity: 0.85;
|
|
}
|
|
#samples-toggle {
|
|
margin-left: auto;
|
|
padding: 5px 14px;
|
|
background: transparent;
|
|
color: #ffffff;
|
|
border: 1px solid rgba(255, 255, 255, 0.45);
|
|
border-radius: 6px;
|
|
font-family: "DM Sans", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
}
|
|
#samples-toggle:hover { border-color: #ffffff; background: rgba(255, 255, 255, 0.1); }
|
|
#redoc { padding-top: 64px; }
|
|
/* Collapsible samples column: Redoc CE has no built-in panel toggle, so
|
|
the topbar button flips .samples-collapsed on <html>, hiding the
|
|
right-panel divs (same bundle-pinned classes as the gradient below)
|
|
and letting each section's content half take the full width. If the
|
|
pinned classes stop matching after a Redoc bump the toggle goes inert
|
|
-- cosmetic only. Choice persists in localStorage. */
|
|
html.samples-collapsed .sc-iGgWBj.sc-gsFSXq,
|
|
html.samples-collapsed div.sc-dExYaf { display: none; }
|
|
html.samples-collapsed [data-section-id] > div:first-child { width: 100%; }
|
|
/* Right-panel gradient (#1b3d79 -> #1b1f52, continuing the topbar blend).
|
|
Redoc's theme only accepts solid colors (it derives shades from
|
|
rightPanel.backgroundColor), so the solid #1b1f52 stays in the theme as
|
|
the fallback and this override layers the gradient on top.
|
|
BUNDLE-PINNED SELECTORS: .sc-iGgWBj.sc-gsFSXq are the styled-components
|
|
classes of the per-section right-panel divs (plus .sc-dExYaf, the
|
|
full-height background stub) generated by the vendored
|
|
redoc.standalone.js 2.5.3. They are deterministic for this exact bundle
|
|
but WILL change on any Redoc bump -- re-derive them then (headless probe:
|
|
find elements whose computed background is the rightPanel color). If
|
|
they stop matching, the panel silently falls back to solid #1b1f52 --
|
|
cosmetic only, nothing breaks. Every stripe shares the same horizontal
|
|
geometry, so the per-section gradients read as one continuous column. */
|
|
.sc-iGgWBj.sc-gsFSXq,
|
|
div.sc-dExYaf {
|
|
background-image: linear-gradient(90deg, #1b3d79 0%, #1b3068 45%, #1b1f52 100%);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="topbar">
|
|
<span class="brand">Sea Haven Industries</span>
|
|
<button id="samples-toggle" type="button" aria-pressed="false">Hide samples</button>
|
|
<span class="page">Procurement Ingest API</span>
|
|
</div>
|
|
<div id="redoc"></div>
|
|
<script>__REDOC_JS__</script>
|
|
<script>
|
|
Redoc.init(
|
|
__OPENAPI_SPEC_JSON__,
|
|
{
|
|
sortRequiredPropsFirst: true,
|
|
expandResponses: "200",
|
|
scrollYOffset: 64,
|
|
theme: {
|
|
colors: {
|
|
primary: { main: "#1c75bc" }
|
|
},
|
|
typography: {
|
|
fontFamily: '"DM Sans", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif',
|
|
fontWeightBold: "600",
|
|
headings: {
|
|
fontFamily: '"Montserrat", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif',
|
|
fontWeight: "600"
|
|
},
|
|
code: {
|
|
fontFamily: '"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace'
|
|
}
|
|
},
|
|
sidebar: {
|
|
width: "244px",
|
|
backgroundColor: "#f9fafb",
|
|
textColor: "#262262"
|
|
},
|
|
rightPanel: {
|
|
backgroundColor: "#1b1f52"
|
|
},
|
|
fab: {
|
|
backgroundColor: "#1c75bc"
|
|
}
|
|
}
|
|
},
|
|
document.getElementById("redoc")
|
|
);
|
|
(function () {
|
|
var KEY = "procurement-docs-samples-collapsed";
|
|
var btn = document.getElementById("samples-toggle");
|
|
function apply(collapsed) {
|
|
document.documentElement.classList.toggle("samples-collapsed", collapsed);
|
|
btn.textContent = collapsed ? "Show samples" : "Hide samples";
|
|
btn.setAttribute("aria-pressed", String(collapsed));
|
|
}
|
|
var initial = false;
|
|
try { initial = localStorage.getItem(KEY) === "1"; } catch (e) {}
|
|
apply(initial);
|
|
btn.addEventListener("click", function () {
|
|
var collapsed = !document.documentElement.classList.contains("samples-collapsed");
|
|
try { localStorage.setItem(KEY, collapsed ? "1" : "0"); } catch (e) {}
|
|
apply(collapsed);
|
|
});
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|