Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 46 additions & 11 deletions site/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,32 @@
<p class="eyebrow">Terminal-first API regression ledger</p>
<h1 id="hero-title">Regression history for APIs <em>that change.</em></h1>
<p class="hero-lede">Backline gives backend teams a durable trail from HTTP check to CI decision.</p>
<div class="setup-strip" aria-label="Start locally">
<span>Start locally</span>
<code>docker compose up --build -d</code>
<div class="setup-strip" aria-label="Install Backline">
<span>Install Backline</span>
<code>./gradlew :apps:cli:installDist</code>
</div>
<div class="hero-actions">
<a class="button button-light" href="https://github.com/ChimdumebiNebolisa/Backline/blob/main/README.md#quick-start">Open setup guide <span aria-hidden="true">-&gt;</span></a>
<a class="text-link" href="https://github.com/ChimdumebiNebolisa/Backline/tree/main/docs">Read the docs <span aria-hidden="true">+</span></a>
</div>
</div>
<figure class="demo-capture hero-capture reveal" data-reveal>
<img src="/demo/failed-run-diff.webp" width="1360" height="900" alt="Terminal capture from Backline's Docker end-to-end demo showing a failed broken-endpoint run and its diff." fetchpriority="high" />
<figcaption>Failed run and diff from the documented Docker demo.</figcaption>
</figure>
<section class="evidence-window hero-evidence reveal" aria-label="Authentic Backline CLI output" data-reveal>
<div class="evidence-window-bar"><span>Backline CLI</span><span>failed run and diff</span></div>
<pre><code><span class="dim">$</span> cd examples/sample-api
<span class="dim">$</span> backline run --timeout-seconds 120
RUN_ID: dc1aad4c-48b7-44f8-9849-6df62de09d8a
status: QUEUED
<span class="danger">status: FAILED</span>

<span class="dim">$</span> backline diff dc1aad4c-48b7-44f8-9849-6df62de09d8a
[NEWLY_FAILING]
<span class="danger">- broken-endpoint (Broken endpoint) null -&gt; FAILED</span>

[NEWLY_PASSING]
<span class="success">- get-user (Fetch user) null -&gt; PASSED</span>
<span class="success">- health (Health check) null -&gt; PASSED</span></code></pre>
<p class="evidence-note">Verbatim CLI output from the documented Docker demo.</p>
</section>
</section>

<section class="system-band" aria-label="Backline system boundary">
Expand All @@ -64,10 +77,32 @@ <h1 id="hero-title">Regression history for APIs <em>that change.</em></h1>
<h2 id="report-title">Generated Markdown reports show what failed.</h2>
<p>Backline writes a reviewable report from stored API data: run status, check counts, failures, latency, and comparison context.</p>
</div>
<figure class="demo-capture report-capture reveal" data-reveal>
<img src="/demo/markdown-report.webp" width="1360" height="900" alt="Generated Backline Markdown report for sample-api showing a failed run with two passed and one failed check." loading="lazy" />
<figcaption>Generated Markdown report from the same failed sample run.</figcaption>
</figure>
<section class="evidence-window report-output reveal" aria-label="Authentic generated Backline Markdown report" data-reveal>
<div class="evidence-window-bar"><span>backline report</span><span>sample-api</span></div>
<pre><code># Backline Run Report

## Run summary
- **Project**: sample-api (`sample-api`)
- **Environment**: local
- **Run ID**: dc1aad4c-48b7-44f8-9849-6df62de09d8a
- **Status**: <span class="danger">FAILED</span>
- **Attempt count**: 1

## Check summary
| Metric | Count |
| ------- | ----- |
| Total | 3 |
| Passed | 2 |
| Failed | 1 |
| Errored | 0 |

## Failed checks
- **Result status**: <span class="danger">FAILED</span>
- **HTTP status**: 500
- **Error code**: STATUS_MISMATCH
- **Error message**: Expected status 200 but was 500</code></pre>
<p class="evidence-note">Verbatim Markdown report excerpt from the same failed sample run.</p>
</section>
</section>

<section class="workflow-section shell section" id="workflow" aria-labelledby="workflow-title">
Expand Down
6 changes: 3 additions & 3 deletions site/public/demo/SOURCE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Demo capture source
# Demo output source

`failed-run-diff.webp` and `markdown-report.webp` render unmodified CLI and Markdown text from the successful `e2e-demo` job in [GitHub Actions run 29216457678](https://github.com/ChimdumebiNebolisa/Backline/actions/runs/29216457678). That job executes `scripts/ci-e2e-demo.sh`, the repository's Docker-backed end-to-end demo.
The terminal and Markdown evidence rendered as text on the landing page comes from the successful `e2e-demo` job in [GitHub Actions run 29216457678](https://github.com/ChimdumebiNebolisa/Backline/actions/runs/29216457678). That job executes `scripts/ci-e2e-demo.sh`, the repository's Docker-backed end-to-end demo.

The source job ran these commands:

Expand All @@ -13,4 +13,4 @@ backline diff "$RUN_ID"
backline report "$RUN_ID" -o "$REPORT_MD"
```

The captured run intentionally fails `broken-endpoint` with HTTP 500. The screenshots contain no secrets or personal filesystem paths. Only the CI frame, command prompts, sizing, and WebP encoding were added; CLI and report values were not fabricated. The report frame shows its title, run summary, and check summary without altering the generated Markdown.
The rendered run intentionally fails `broken-endpoint` with HTTP 500. The excerpts contain no secrets or personal filesystem paths. CLI and report values are copied from the CI artifact without fabrication.
Binary file removed site/public/demo/failed-run-diff.webp
Binary file not shown.
Binary file removed site/public/demo/markdown-report.webp
Binary file not shown.
24 changes: 15 additions & 9 deletions site/src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ body::after {

a { color: inherit; }

code, pre, .eyebrow, .site-nav, .setup-strip, .system-chain, .workflow-rows, .code-window, .architecture-chain, .resource-layout, .footer-inner { font-family: var(--mono); }
code, pre, .eyebrow, .site-nav, .setup-strip, .system-chain, .workflow-rows, .code-window, .evidence-window, .architecture-chain, .resource-layout, .footer-inner { font-family: var(--mono); }

pre { margin: 0; white-space: pre-wrap; word-break: break-word; }

Expand Down Expand Up @@ -162,13 +162,17 @@ p { color: var(--muted); line-height: 1.65; }

.text-link, .inline-link { display: inline-flex; align-items: center; gap: 0.75rem; color: var(--text); font-family: var(--mono); font-size: 0.7rem; text-decoration: none; }

.demo-capture { margin: 0; }
.evidence-window { overflow: hidden; border: 1px solid var(--line); background: #0d0d0f; box-shadow: 18px 20px 0 rgba(0, 0, 0, 0.16); }

.demo-capture img { display: block; width: 100%; height: auto; border: 1px solid var(--line); background: var(--surface); }
.evidence-window-bar { display: flex; justify-content: space-between; gap: 1rem; padding: 0.78rem 0.9rem; border-bottom: 1px solid var(--line); color: var(--faint); font-size: 0.7rem; text-transform: uppercase; }

.hero-capture { width: min(100%, 650px); justify-self: end; box-shadow: 18px 20px 0 rgba(0, 0, 0, 0.16); }
.evidence-window pre { padding: clamp(1rem, 2.3vw, 1.45rem); color: #e2dcd7; font-size: clamp(0.68rem, 1.05vw, 0.78rem); line-height: 1.68; }

.demo-capture figcaption { margin-top: 0.75rem; color: var(--faint); font-family: var(--mono); font-size: 0.7rem; }
.hero-evidence { width: min(100%, 650px); justify-self: end; }

.report-output { width: 100%; box-shadow: 22px 24px 0 rgba(0, 0, 0, 0.18); }

.evidence-note { margin: 0; padding: 0.75rem 0.9rem; border-top: 1px solid var(--line); color: var(--faint); font-family: var(--mono); font-size: 0.7rem; line-height: 1.5; }

.system-band { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: rgba(17, 17, 19, 0.66); }

Expand All @@ -184,8 +188,6 @@ p { color: var(--muted); line-height: 1.65; }

.section-intro p:not(.eyebrow) { max-width: 560px; margin-bottom: 0.25rem; font-size: 0.95rem; }

.report-capture { width: 100%; box-shadow: 22px 24px 0 rgba(0, 0, 0, 0.18); }

.section-heading { max-width: 720px; margin-bottom: 2.8rem; }

.section-heading p { max-width: 520px; margin-bottom: 0; font-size: 0.98rem; }
Expand Down Expand Up @@ -214,6 +216,10 @@ p { color: var(--muted); line-height: 1.65; }

.accent { color: var(--accent); }

.danger { color: var(--danger); }

.success { color: var(--success); }

.architecture-section { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--surface); }

.architecture-layout { display: grid; grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); gap: clamp(3.5rem, 9vw, 9rem); align-items: center; }
Expand Down Expand Up @@ -282,7 +288,7 @@ html[data-motion="enabled"] .reveal.is-visible { transform: translateY(0); }
.hero, .policy-section, .architecture-layout, .boundaries-section, .quick-start { grid-template-columns: 1fr; }
.hero { gap: 3.5rem; min-height: auto; }
.hero-copy { max-width: 720px; }
.hero-capture { justify-self: start; }
.hero-evidence { justify-self: start; }
.section-intro p:not(.eyebrow) { max-width: 560px; }
.boundaries-section { gap: 2.8rem; }
.architecture-chain { justify-content: flex-start; }
Expand All @@ -303,7 +309,7 @@ html[data-motion="enabled"] .reveal.is-visible { transform: translateY(0); }
.setup-strip { align-items: flex-start; flex-direction: column; gap: 0.5rem; }
.setup-strip code { font-size: 0.7rem; overflow-wrap: anywhere; }
.hero-actions { align-items: flex-start; flex-direction: column; gap: 1rem; }
.hero-capture { width: 100%; }
.hero-evidence { width: 100%; }
.system-chain { align-content: center; align-items: center; justify-content: flex-start; min-height: 102px; padding: 1rem 0; }
.section { padding-top: 4.5rem; padding-bottom: 4.5rem; }
.workflow-rows li { grid-template-columns: 1fr; gap: 0.9rem; padding: 1.35rem 0; }
Expand Down
Binary file modified site/tests/__screenshots__/landing-desktop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified site/tests/__screenshots__/landing-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 12 additions & 12 deletions site/tests/content.test.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import assert from 'node:assert/strict';
import { readFile, stat } from 'node:fs/promises';
import { readFile } from 'node:fs/promises';
import test from 'node:test';

const [html, css, robots, terminalCapture, reportCapture] = await Promise.all([
const [html, css, robots, sourceNote] = await Promise.all([
readFile(new URL('../index.html', import.meta.url), 'utf8'),
readFile(new URL('../src/style.css', import.meta.url), 'utf8'),
readFile(new URL('../public/robots.txt', import.meta.url), 'utf8'),
stat(new URL('../public/demo/failed-run-diff.webp', import.meta.url)),
stat(new URL('../public/demo/markdown-report.webp', import.meta.url)),
readFile(new URL('../public/demo/SOURCE.md', import.meta.url), 'utf8'),
]);

test('landing page exposes the verified product narrative', () => {
Expand Down Expand Up @@ -41,20 +40,21 @@ test('landing page includes accessible structure and repository links', () => {
assert.ok(css.includes('@fontsource-variable/geist'), 'expected self-hosted Geist font import');
});

test('landing page uses authentic demo captures and a direct setup path', () => {
assert.match(html, /\/demo\/failed-run-diff\.webp/);
assert.match(html, /\/demo\/markdown-report\.webp/);
assert.match(html, /docker compose up --build -d/);
test('landing page uses authentic demo text and an install-first setup path', () => {
assert.match(html, /\.\/gradlew :apps:cli:installDist/);
assert.match(html, /broken-endpoint \(Broken endpoint\) null -&gt; FAILED/);
assert.match(html, /Expected status 200 but was 500/);
assert.match(html, /README\.md#quick-start/);
assert.doesNotMatch(html, /Representative Backline CLI run|representative output|representative local history/);
assert.ok(terminalCapture.size > 0, 'expected terminal demo capture to be committed');
assert.ok(reportCapture.size > 0, 'expected Markdown report capture to be committed');
assert.doesNotMatch(html, /<img\b/i);
assert.doesNotMatch(html, /\.webp/);
assert.match(sourceNote, /GitHub Actions run 29216457678/);
assert.match(sourceNote, /without fabrication/);
});

test('visible copy avoids typographic dash clutter', () => {
assert.doesNotMatch(html, /[\u2014\u2013]/);
});

test('crawler policy allows the landing page to be indexed', () => {
assert.equal(robots, 'User-agent: *\nAllow: /\n');
assert.equal(robots.replace(/\r\n/g, '\n'), 'User-agent: *\nAllow: /\n');
});
16 changes: 7 additions & 9 deletions site/tests/site.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ test('renders the landing page and primary paths on desktop', async ({ page }) =

await expect(page).toHaveTitle('Backline | API regression history');
await expect(page.getByRole('heading', { name: 'Regression history for APIs that change.' })).toBeVisible();
const terminalCapture = page.getByRole('img', { name: /failed broken-endpoint run and its diff/i });
const reportCapture = page.getByRole('img', { name: /two passed and one failed check/i });

await expect(terminalCapture).toBeVisible();
await expect(terminalCapture).toHaveAttribute('src', '/demo/failed-run-diff.webp');
await expect(reportCapture).toHaveAttribute('src', '/demo/markdown-report.webp');
expect(await terminalCapture.evaluate((image: HTMLImageElement) => image.complete && image.naturalWidth > 0)).toBe(true);
expect(await reportCapture.evaluate((image: HTMLImageElement) => image.complete && image.naturalWidth > 0)).toBe(true);
await expect(page.locator('[aria-label="Start locally"]')).toContainText('docker compose up --build -d');
const terminalOutput = page.getByRole('region', { name: 'Authentic Backline CLI output' });
const reportOutput = page.getByRole('region', { name: 'Authentic generated Backline Markdown report' });

await expect(terminalOutput).toContainText('broken-endpoint (Broken endpoint) null -> FAILED');
await expect(reportOutput).toContainText('Expected status 200 but was 500');
await expect(page.locator('img')).toHaveCount(0);
await expect(page.locator('[aria-label="Install Backline"]')).toContainText('./gradlew :apps:cli:installDist');
await expect(page.getByRole('link', { name: /Open setup guide/ })).toHaveAttribute(
'href',
'https://github.com/ChimdumebiNebolisa/Backline/blob/main/README.md#quick-start',
Expand Down
Loading