Hardened Deploy in 22 Minutes
Shipyard preflight + GitHub repo creation + Vercel deploy + live header audit + security header fixes + redeploy. From "clean local build" to "live with A/A+ security headers" in 22 minutes.
From Repo to Production with Hardened Security — 22 Minutes
Shipyard preflight + GitHub repo creation + Vercel deploy + live header audit + security header fixes + redeploy. A 26-minute Design Forge build went from "clean local build" to "live at aigraas.com with A/A+ security headers" in 22 more minutes.
Part 2 of a series. See From Research to 13-Page Website in 26 Minutes for how the site was built before this use case picks up.
What Happened
The AIGRaaS website was built and clean locally at 3:46 PM ET. But a clean build is not a shipped product — there's no GitHub repo, no Vercel project, no custom domain, no PWA manifest, no SEO artifacts, no security headers, and no audit evidence to hand a security reviewer.
In 22 minutes, the workflow closed that gap:
- SEO + PWA artifacts — SITE constants, full metadata, sitemap, robots, manifest, favicon, OG image, 4 PWA icon variants
- GitHub repo — created private
hrconsultnj/aigraasviagh repo create, pushed main - Shipyard preflight — production readiness checklist (env, health, security, performance)
- Vercel deploy — CLI
vercel link+vercel --prod, then connected GitHub for auto-deploys - Custom domain — DNS records, SSL provisioning, HTTP→HTTPS redirect
- Live audit — curl headers, fetch SEO artifacts, inspect meta tags, check SSL expiry
- Code quality fixes — React 19 lint rule (
set-state-in-effect), unused imports - Security headers — added X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy via
next.config.ts - Redeploy + re-audit — commit + push (auto-deploy) + verify new headers live
Total: 22 minutes and 14 seconds from "ready to ship" to "audit complete with A/A+ security grades."
Session Timeline
| Milestone | Time (ET) | Elapsed |
|---|---|---|
| SEO/PWA phase started | 15:49:33 | 0:00 |
| Build verification — 17 static routes | 15:56:48 | 7:15 |
| GitHub repo created + pushed | 15:59:49 | 10:16 |
/shipyard:preflight run | 16:01:05 | 11:32 |
| Vercel CLI link + production deploy | 16:01:55 | 12:22 |
| Vercel GitHub integration connected | 16:03:03 | 13:30 |
| Everything live at aigraas.com | ~16:05:00 | ~15:27 |
| Live header audit started | 16:05:55 | 16:22 |
| SEO artifacts verified (all 11) | 16:06:28 | 16:55 |
| Security headers checked | 16:06:50 | 17:17 |
| Lint errors fixed (2 files) | 16:08:50 | 19:17 |
Security headers added to next.config.ts | 16:09:18 | 19:45 |
| Audit fix commit + push | 16:09:54 | 20:21 |
| New headers verified live | 16:10:10 | 20:37 |
| Final audit output | 16:11:47 | 22:14 |
Phase 1: SEO + PWA Setup (~7 minutes)
Before a single deploy command, the site needed the production artifacts that SEO, search engines, PWA installers, social sharing, and browser UIs all depend on.
| Artifact | File | Purpose |
|---|---|---|
| SITE constants | src/lib/constants.ts | Single source of truth: name, description, URL, creator, links |
| Full metadata | src/app/layout.tsx | viewport, themeColor, metadataBase, 15 keywords, icons, appleWebApp, openGraph, twitter cards |
| Sitemap | src/app/sitemap.ts | 12 routes with lastModified, changeFrequency, priority |
| Robots | src/app/robots.ts | Allow all, disallow /api/ and /dashboard/ |
| PWA manifest | src/app/manifest.ts | standalone display, #10B981 theme, 4 icons |
| Favicon + OG | public/favicon.svg, og-image.png | Teal-mint lettermark + 1200x630 social share |
| PWA icons | public/icons/*.png | 192/512, each in any and maskable purpose |
Next.js 16 handles manifest.ts, sitemap.ts, and robots.ts as route handlers — no need for static files in public/. The routes are auto-registered and appear in the build output as static routes.
Phase 2: Repo + Deploy (~6 minutes)
# 1. Create private GitHub repo + push main in one command
gh repo create aigraas --private --source=. \
--description "AI Guardrails as a Service — constitutional guardrails..." \
--push
# 2. Shipyard preflight audit
/shipyard:preflight
# 3. Vercel project link + production deploy
vercel link --yes --project aigraas
vercel --prod
# 4. Connect Vercel to GitHub for auto-deploysShipyard preflight flagged the deploy footprint correctly (12MB) and identified context-aware skips — no API routes means no CORS/CSRF/rate limit needs, so those checks are skipped rather than marked as blockers.
Production Readiness: aigraas.com
Environment & Secrets:
[SKIP] No .env.example needed (0 process.env references)
[PASS] .env* gitignored, no env files tracked
Security:
[SKIP] CORS/CSRF/rate limiting (no API routes)
[NOTE] Run /sentinel:headers --url https://aigraas.vercel.app after deploy
Performance:
[PASS] Deploy size: 12MB (1.1M static + 11M server)
[PASS] 0 raw <img> tags (next/image throughout)
[PASS] Production build clean (17 routes, all static)Vercel deploy protection gotcha: Private projects from CLI deploys are protected by default (401 on preview URLs). Connecting the custom domain bypasses this for production; preview URLs remain protected unless explicitly disabled in Vercel dashboard → Settings → Deployment Protection.
Phase 3: Live Audit (~3 minutes)
Once the custom domain was live, the audit verified every layer with shell commands:
# Deployment layer
curl -sI https://aigraas.com
curl -sI http://aigraas.com # Verify 308 redirect to HTTPS
openssl s_client -connect aigraas.com:443 -servername aigraas.com </dev/null
# SEO artifacts (all should be 200 OK)
for path in /robots.txt /sitemap.xml /manifest.webmanifest /favicon.svg /og-image.png; do
curl -sI "https://aigraas.com$path" | head -1
done
# Security header grading
curl -sI https://aigraas.com | grep -iE 'strict-transport|x-frame|x-content|referrer|permissions|csp'Initial security header audit showed HSTS was present (Vercel adds it automatically with 2-year max-age, exceeding the 1-year recommendation), but the four standard hardening headers were missing — the gap Sentinel-style grading catches.
Phase 4: Hardening (~4 minutes)
Two classes of fix landed in a single commit:
Code quality fixes:
theme-toggle.tsx— Refactored touseSyncExternalStore(React 19set-state-in-effectlint rule)use-case-detail.tsx— Removed unusedStaggerChildren/StaggerItemimports
Security headers added to next.config.ts:
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "X-Frame-Options", value: "DENY" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=(), interest-cohort=()"
},
],
},
];
}Commit + push triggered the Vercel GitHub integration's auto-deploy. No manual redeploy command. Verification at 16:10:10 confirmed the four new headers were live — full audit complete at 16:11:47.
Final Audit Report
Deployment Status
| Check | Result |
|---|---|
| Domain | aigraas.com — HTTP/2 200 |
| SSL | Valid until Jul 3, 2026 (auto-renews) |
| HTTP → HTTPS | 308 Permanent Redirect |
| HSTS | max-age=63072000 (2 years) |
| CDN | Vercel edge (iad1, cache HIT) |
| GitHub integration | Connected, auto-deploys on push to main |
| Build | 17 routes, all static, ~12MB footprint |
SEO Artifacts (all 200 OK)
| Artifact | Status | Notes |
|---|---|---|
/ | HTML 64KB | Full metadata, OG, Twitter cards |
/robots.txt | Valid | Allow all, disallow /api/ and /dashboard/ |
/sitemap.xml | Valid | 12 URLs, lastmod, priority |
/manifest.webmanifest | Valid | PWA standalone, #10B981 theme |
/favicon.svg | 200 | Teal-mint lettermark |
/apple-touch-icon.png | 200 | 180x180 |
/og-image.png | 200 | 1200x630 |
/icons/icon-192x192.png + maskable | 200 | PWA any-purpose + maskable |
/icons/icon-512x512.png + maskable | 200 | PWA any-purpose + maskable |
Security Headers (after fix commit)
| Header | Value | Grade |
|---|---|---|
strict-transport-security | max-age=63072000 | A+ (2yr, exceeds 1yr rec) |
x-frame-options | DENY | A |
x-content-type-options | nosniff | A |
referrer-policy | strict-origin-when-cross-origin | A |
permissions-policy | camera=(), microphone=(), geolocation=(), interest-cohort=() | A |
content-security-policy | Not set | Acceptable (static marketing site, inline fonts) |
Code Quality
| Check | Result |
|---|---|
| TypeScript | Clean (0 errors) |
| ESLint | Clean (was 1 error + 2 warnings — fixed) |
| Build | Clean, 17 static routes |
Why This Is Efficient
1. Shipyard preflight caught the right things
The /shipyard:preflight skill didn't dump a generic checklist — it detected that this was a static marketing site with zero API routes and correctly skipped CORS/CSRF/rate limiting checks. It flagged the Sentinel header check as a note, not a blocker, because security headers are a post-deploy activity. Preflight that understands context is preflight that saves time.
2. Fix-in-place beats fresh redeploy
The Vercel GitHub integration meant the audit fixes were a single git push away from production. No manual vercel --prod command, no deploy tokens to juggle, no preview-vs-production URL confusion. Push to main → Vercel rebuilds → live in ~40 seconds.
3. next.config.ts headers() is the right place
Security headers in next.config.ts apply to every route automatically, including sitemap/robots/manifest/static assets. Versus alternatives:
| Approach | Pros | Cons |
|---|---|---|
next.config.ts headers() | All routes, version-controlled, works locally | None |
| Vercel dashboard headers | UI-based | Not version-controlled, easy to drift |
middleware.ts | Dynamic per-request | Runtime cost for static sites |
4. Final audit is reproducible
Every verification is a curl/openssl command. No GUI. No vendor tooling. Anyone can run the same commands against the live site and get the same grades — including the next auditor or a compliance reviewer.
Key Metrics
| Metric | Value |
|---|---|
| Total duration | 22m 14s |
| Files created/edited | 15 |
| Routes deployed | 17 (all static) |
| Deploy footprint | 12 MB (1.1M static + 11M server) |
| Git commits | 2 (initial + audit fixes) |
| Security headers added | 4 |
| HSTS max-age | 2 years (exceeds 1-year recommendation) |
| Final grades | A/A+ across all headers |
| SEO artifacts | 11, all 200 OK |
| Manual clicks in Vercel UI | 0 (only GitHub connect) |
Reproduce This Audit
Every check in the final audit is a shell command. You can run these against any Vercel/Next.js deploy:
DOMAIN="https://your-site.com"
# Deployment
curl -sI "$DOMAIN" | head -20
curl -sI "${DOMAIN/https/http}" | grep -i location
# SSL
echo | openssl s_client -connect "${DOMAIN#https://}:443" \
-servername "${DOMAIN#https://}" 2>/dev/null | openssl x509 -noout -dates
# SEO artifacts
for path in /robots.txt /sitemap.xml /manifest.webmanifest /favicon.svg /og-image.png; do
echo -n "$path: "
curl -sI "$DOMAIN$path" | head -1
done
# Security header grading
curl -sI "$DOMAIN" | grep -iE 'strict-transport|x-frame|x-content|referrer|permissions|csp'If any of these come back missing or graded below A, you have work to do. If they all come back clean, you've shipped a hardened site.