Custom domain and the documentation site
Serve the web apps on readable hostnames instead of *.cloudfront.net, and publish these docs as a website with screenshots of the live apps.
| Site | URL |
|---|---|
| SaaS app | https://saas.haibui.click |
| Admin console | https://saas-admin.haibui.click |
| Documentation | https://saas-docs.haibui.click |
Custom domain
Section titled “Custom domain”DOMAIN_NAME names a Route 53 hosted zone in the same account. When it’s set, the client stack:
- finds the zone with
HostedZone.fromLookup, - creates one DNS-validated ACM certificate for
saas.,saas-admin.andsaas-docs.<zone>(inus-east-1, as CloudFront requires), - gives each CloudFront distribution its hostname and the certificate,
- adds A and AAAA alias records pointing at the distributions.
Without DOMAIN_NAME nothing changes. No backend change is needed: the control plane’s CORS allows any https:// origin, the tenant APIs allow *, and the apps sign in with SRP, so Cognito has no callback URLs.
Documentation site
Section titled “Documentation site”client/docs is an Astro site using the Starlight docs theme, with hand-written pages for concepts, app guides, operations and reference. The walkthroughs in docs/ stay the single source: scripts/sync-steps.mjs copies them into the site on every build, turns each # NN — Title into the page title, links between steps into site links and links to code into GitHub links.
It’s hosted by the same StaticSite construct as the apps, with a new singlePageApp: false mode:
- A CloudFront Function rewrites
/guide/and/guideto/guide/index.html, because an S3 origin behind Origin Access Control has no directory indexes. - Missing pages return
/404.htmlwith status404, instead of the SPA fallback to/index.htmlwith200. - No
config.jsonis written.
Diagrams with D2
Section titled “Diagrams with D2”The architecture and flow diagrams are written in D2 and rendered to SVG at build time by astro-d2, with official AWS service icons. They replace the ASCII art the step docs used to have.
- Concept pages hold the source as
```d2blocks; the big overview is inclient/docs/diagrams/architecture.d2. - The rendered SVGs in
client/docs/public/d2/are committed. The step docs and the README embed them as plain images, so they also render on GitHub, andsync-steps.mjspoints those images at the site’s copy. astro.config.mjsskips generation when thed2binary isn’t installed (brew install d2), so the site still builds from the committed SVGs.
Clicking any screenshot or diagram opens it full size, using starlight-image-zoom.
Screenshots with the Playwright CLI
Section titled “Screenshots with the Playwright CLI”The screenshots are captured from the deployed apps by client/docs/screenshots/capture.sh with npx playwright screenshot at 2× pixel density. Amplify keeps the Cognito session in localStorage, so login.mjs signs in to each app once and saves the browser storage, and each capture loads it with --load-storage. A short viewport plus --full-page crops each image to the page’s content.
- client/cdk/lib/client-stack.ts: hosted zone lookup, certificate, docs site,
DocsSiteUrl. - client/cdk/lib/static-site.ts: optional
domain, optionalconfig,singlePageApp. - client/cdk/bin/client.ts: reads
DOMAIN_NAME. - scripts/deploy-client.sh: also builds
client/docs. - client/docs: the site.
src/content/docs/holds the pages,diagrams/andpublic/d2/the D2 diagrams,scripts/sync-steps.mjsthe step sync andscreenshots/the capture scripts.
Deploy
Section titled “Deploy”DOMAIN_NAME=haibui.click ./scripts/deploy-client.shThe first deploy with a domain waits a few minutes for certificate validation. Outputs:
serverless-saas-client.AdminSiteUrl = https://saas-admin.haibui.clickserverless-saas-client.AppSiteUrl = https://saas.haibui.clickserverless-saas-client.DocsSiteUrl = https://saas-docs.haibui.clickVerify
Section titled “Verify”| Check | Result |
|---|---|
GET https://saas.haibui.click/config.json |
200, the control plane URL |
GET https://saas-admin.haibui.click/tenants/new (SPA deep link) |
200 |
GET https://saas-docs.haibui.click/concepts/architecture/ and without the trailing slash |
200 |
GET https://saas-docs.haibui.click/nope/ |
404, the docs’ not-found page |
| Signed in to both apps on the new hostnames (Playwright) | dashboard, products, orders and users load data from the APIs |
| Every internal link and image in the built site | resolves |
| Clicking a screenshot or diagram | opens it full size in a dialog |
Regenerate the screenshots
Section titled “Regenerate the screenshots”cd client/docs && npx playwright install chromiumADMIN_USER=… ADMIN_PASSWORD=… TENANT=acme TENANT_USER=… TENANT_PASSWORD=… npm run screenshotsUse dedicated accounts for this, for example a tenant user made with scripts/dev-create-tenant-user.sh.