feat: landing guide, a third seeded role, a staff order list — and the docs to match - #64
Merged
Merged
Conversation
Adds deploy-api.yml and deploy-web.yml, each triggered by an allowlist of paths rather than paths-ignore, so scope is explicit: src/tests/solution files deploy the API, web/** deploys the SPA, and a docs or markdown change matches neither and deploys nothing. Both call a new reusable test-suite.yml and declare needs: tests, so nothing reaches Azure unless backend units, frontend units and the end-to-end smoke test all pass for that exact commit. The suite lives in one file so the two deploys cannot drift on what 'tests passed' means. The web deploy is gated on the smoke test too — a SPA is useless against a broken API. The API job publishes Release to a directory outside the workspace and audits it before deploying: any .cs, .csproj, .sln, .env, compose file, or .git/node_modules/src/web/tests/docs directory fails the run, and the app dll and appsettings.json must be present. It then polls /health and stops the web app on a 503, because a crash-looping F1 app silently consumes the 60 CPU-minutes/day allowance. Azure auth is OIDC — id-token: write and no stored credential. Every action is pinned to a full commit SHA, each verified to exist against the GitHub API; one I had written from memory was wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Everyone now lands on a guide at / and the store moves to /store. A working storefront is confusing without knowing it is a demo, that nothing can charge you, and which account to use, so the guide answers those first and links into the store from several places. The guide leads with the payments question because it is the one that decides whether a visitor trusts the site: checkout runs a mock gateway, no card details are collected, no processor is contacted, and a Stripe configuration is restricted to test mode. Three roles existed but only two were seeded, so nothing demonstrated what ManageCatalog actually buys you. DbSeeder now creates a Manager as well, and the guide spells out for each role what it can and cannot do — the interesting line being that a Manager may restock and hide a widget but not retire one. Staff could not find an order at all: admin had only lookup-by-GUID, and nobody has a GUID to hand. Adds GET /admin/orders with a recent-orders list, and rebuilds the admin page around selecting from it. The item rows are loaded rather than skipped — OrderSummary derives its item count from them, and an initial optimisation reported every order as empty. Receipts work on the free tier without a mail server: the hosted demo writes email to the log, so the order detail page carries the same line items, totals, payment and tracking, and now prints as a receipt. The print stylesheet drops the chrome and collapses the columns. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The tax chapter said what the calculator did but never showed the arithmetic, the coverage, or who bears the charge — the three things a reader actually asks. It now carries the formula (taxable = subtotal; shipping is not taxed), a worked example across CA / OR / an unknown state, the rounding mode and why it differs from .NET's default, the full 51-entry rate table generated from the source, and the quote and tax-info endpoints that expose it without placing an order. Shipping tiers are written down alongside it, since they are the other half of the total. The bugs chapter gains rows 12-32: the refresh-token race, the broken HTML email part, the compose keys that never reached the container, the startup crash loop that burns free-tier quota, the SPA fallback and CSP, the order list nobody could reach, and the provisioning failures — a Windows batch shim, MSYS path rewriting, a PowerShell automatic variable, a non-existent action SHA, an OIDC subject that doesn't match its documentation, and a required check that could never pass. Everything else was drifting from the code: the Manager account was seeded but undocumented, the landing page had replaced the catalog at /, Mailpit was running in compose while the runbook still told you to start your own, and the deploy gate was undescribed. The README's LICENSE link pointed at a file that does not exist, which on a public repo reads as a license that isn't granted; it now says so plainly. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two commits: the app change, then the documentation that had drifted behind it.
The app
A landing page at
/. Everyone arrives at a plain-language guide instead of beingdropped into a catalog with no explanation. It states up front that no payment is ever
taken — the mock gateway never asks for a card, and the Stripe path is test-mode only —
hands out the three demo accounts with copy buttons and a can/cannot list for each role,
points at
/ordersfor the receipt (emails go to the log on the hosted demo, so there isnothing to miss), and links into the store. The catalog moved to
/store.A Manager account, seeded. The
ManageCatalogpolicy has existed since the catalogwork but no seeded account could exercise it, so a reviewer could only ever see Customer
and Administrator.
manager@widgetworks.democloses that: catalog and order fulfilment,but not delete and not user management.
A staff order list (
GET /admin/orders). The admin screen could only look an order upby GUID, and nobody has a GUID to hand — so orders were effectively invisible to the
people whose job is fulfilling them. The list is now the entry point; selecting a row opens
the detail and status controls.
The docs
The tax chapter described the calculator but never showed the arithmetic, the coverage, or
who bears the charge. It now carries the formula (taxable = subtotal — shipping is not
taxed), a worked example across CA / OR / an unknown state, the away-from-zero rounding
and why it differs from .NET's default, the full 51-entry rate table generated from
StaticStateTaxRateProvider, and thequote/tax-infoendpoints. Shipping tiers arewritten down beside it, since they are the other half of the total.
The bugs chapter gains rows 12–32 — the refresh-token race, the broken HTML email part, the
compose keys that never reached the container, the startup crash loop that burns free-tier
quota, the SPA fallback and CSP, the order list nobody could reach, and the provisioning
failures (a Windows batch shim, MSYS path rewriting, a PowerShell automatic variable, an
action SHA that didn't exist, an OIDC subject that doesn't match its documentation, and a
required check that could never pass).
Everything else was drift: the Manager account undocumented,
/no longer the catalog,Mailpit running in compose while the runbook told you to start your own, the deploy gate
undescribed, and a README
LICENSElink pointing at a file that does not exist — which on apublic repo reads as a license that was never granted. It now says so plainly.
Deployment
This touches
src/**andweb/**, so merging fires both deploys — each gated on thefull test suite (backend units, frontend units, API smoke test) before anything uploads.
🤖 Generated with Claude Code