Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eecaae1
Fix NGU promo banner and invisible reCAPTCHA
michaelzick May 8, 2026
184f075
Fix NGU promo reCAPTCHA loading
michaelzick May 8, 2026
c2f730f
Polish NGU promo banner and modal
michaelzick May 8, 2026
56aafef
Fix mobile header spacing and tabs
michaelzick May 8, 2026
202b1c3
Restore mobile tabs style and fix active state boundaries
michaelzick May 8, 2026
605e669
Update commit message generation
michaelzick May 8, 2026
e711c5d
Text changes
michaelzick May 8, 2026
a029d35
Adjust NGU coupon scroll target and hero spacing
michaelzick May 8, 2026
1d9c549
Text changes
michaelzick May 8, 2026
20b04a9
Update NGU page styles and modify consent message in coupon email
michaelzick May 8, 2026
810440a
Text changes
michaelzick May 8, 2026
e5ad8fa
Replace NGU suit imagery with optimized WebP assets
michaelzick May 8, 2026
c25299c
Update contact image to new gray suit photo
michaelzick May 8, 2026
cd58ed0
Update NGU nav and banner tracking
michaelzick May 8, 2026
9f67abd
Update NGU CTA tracking and external link icons
michaelzick May 8, 2026
13480ee
Add link-out icons to booking CTAs
michaelzick May 8, 2026
42de072
Adjust padding in mobile navigation for improved layout
michaelzick May 8, 2026
48ad998
Full visual pass + fixes
michaelzick May 8, 2026
5eb28c9
Remove NGU nav links and rename booking CTAs
michaelzick May 9, 2026
eeb4b0d
Add agent briefs, sync skill, and CI security workflows
michaelzick May 9, 2026
1d8b6fb
Update workflows and dependency versions for security
michaelzick May 9, 2026
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
23 changes: 21 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,22 @@ on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

env:
NODE_ENV: test
NEXT_PUBLIC_RECAPTCHA_SITE_KEY_V2: test-site-key
RECAPTCHA_SECRET_KEY_V2: test-secret-key
OPENAI_API_KEY: test-openai-key
BREVO_SMTP_PASSWORD: test-brevo-password
BREVO_USER: test-brevo-user
BREVO_TO: test-to@example.com
BREVO_FROM: test-from@example.com
SITE_URL: https://www.michaelzick.com

jobs:
validate:
runs-on: ubuntu-latest
Expand All @@ -18,17 +30,24 @@ jobs:
uses: actions/checkout@v6

- name: Set up Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 24
node-version: 24.x
check-latest: true
cache: npm

- name: Install dependencies
run: npm ci

- name: Agent brief sync
run: npm run agent-briefs:check

- name: Lint
run: npm run lint

- name: Typecheck
run: npm run typecheck

- name: Test
run: npm test

Expand Down
91 changes: 91 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Security Checks

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
secrets:
name: Secret Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Run Gitleaks
run: docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:latest detect --source /repo --redact --verbose

dependencies:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- uses: actions/setup-node@v6
with:
node-version: 24.x
check-latest: true
cache: npm

- run: npm ci
- run: npm audit --audit-level=moderate

dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
steps:
- name: Review dependency changes
env:
GH_TOKEN: ${{ github.token }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2026-03-10" \
"/repos/${GITHUB_REPOSITORY}/dependency-graph/compare/${BASE_SHA}...${HEAD_SHA}" \
> dependency-review.json

jq -r '
[
.[]
| select(.change_type == "added" or .change_type == "changed")
| . as $dependency
| (.vulnerabilities // [])[]
| select((.severity | ascii_downcase) as $severity | ["moderate", "high", "critical"] | index($severity))
| "\($dependency.manifest): \($dependency.name)@\($dependency.version) introduces \(.severity) \(.advisory_ghsa_id): \(.advisory_summary) (\(.advisory_url))"
]
| .[]
' dependency-review.json > dependency-review-findings.txt

if [ -s dependency-review-findings.txt ]; then
cat dependency-review-findings.txt
exit 1
fi

echo "No moderate or higher vulnerable dependency changes detected."

codeql:
name: CodeQL Scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v6

- uses: github/codeql-action/init@v4
with:
languages: javascript-typescript

- uses: github/codeql-action/autobuild@v4

- uses: github/codeql-action/analyze@v4
174 changes: 174 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Michael Zick — Agent Orientation (Codex / AGENTS.md)

This document is the canonical project brief for AI coding agents. Read it at the start of every session instead of re-exploring the repo. Keep it current: see [Maintaining this file](#maintaining-this-file).

Sibling files [CLAUDE.md](CLAUDE.md) (Claude Code) and [GEMINI.md](GEMINI.md) (Gemini CLI) mirror this content for other harnesses. Update all three together when code structure changes.

---

## 1. Project overview

**michaelzick.com** is Michael Zick's coaching website and conversion platform for Nice Guy Recovery / Reality Alignment coaching. It combines static marketing pages, a blog, lead-capture forms, an AI-assisted questionnaire, analytics instrumentation, and Nice Guy University promotion flows.

Primary flows:
- Visitors learn about Michael's coaching model through the home, about, testimonials, contact, and Nice Guy University pages.
- Visitors submit a multi-step questionnaire and receive an OpenAI-generated coaching analysis.
- Contact and NGU coupon forms validate Invisible reCAPTCHA v2, rate-limit submissions, and send Brevo SMTP email notifications.
- Blog readers browse JSON-backed posts with category/tag filters and structured data for SEO.
- CTA and navigation interactions are tracked through a shared analytics wrapper for GA4 and Amplitude.

## 2. Tech stack

- **Framework:** Next.js 16 App Router with React 19 and TypeScript; the package is currently pinned to the patched 16.3 canary line until the same security fixes land in a stable release.
- **Styling:** Tailwind CSS 3, global styles in `app/globals.css`, image assets in `public/img/`.
- **Server routes:** Next route handlers under `app/api/*`, using Node runtime where email/OpenAI APIs are needed.
- **AI and email:** OpenAI Node SDK for questionnaire analysis; Nodemailer with Brevo SMTP for notifications.
- **Bot protection:** Classic Invisible reCAPTCHA v2 via `NEXT_PUBLIC_RECAPTCHA_SITE_KEY_V2` and `RECAPTCHA_SECRET_KEY_V2`.
- **Analytics:** GA4 and Amplitude scripts in `components/SiteAnalyticsScripts.tsx`; tracked events in `lib/analytics.ts`.
- **Testing:** Node's built-in test runner for compiled unit tests, TypeScript test build via `tsconfig.test.json`, and Playwright for E2E/mobile UI checks.
- **Tooling:** npm with `package-lock.json`, Node 24 LTS, ESLint flat config via `eslint-config-next/core-web-vitals`.

## 3. Repository layout

```
michaelzick.com/
├── app/ # Next App Router pages, layout, metadata, API routes, sitemap/robots
├── components/ # React UI components, navigation, sections, blog, questionnaire, hooks
├── content/blog/ # JSON-backed blog content fixtures and production posts
├── lib/ # Analytics, blog utilities, structured data, server validation/helpers
├── public/ # Favicons, manifest, generated sitemap, static image assets
├── scripts/ # Node scripts such as sitemap generation
├── skills/ # Repo-local agent skills
├── tests/ # Node unit tests and Playwright E2E tests
├── types/ # Ambient type declarations
├── .github/workflows/ # CI and security automation
├── package.json # npm scripts and dependency list
└── package-lock.json # npm lockfile; keep npm workflow
```

## 4. Application structure

### 4.1 App Router pages

- `app/layout.tsx` defines global metadata, JSON-LD, analytics scripts, nav, NGU promo, footer, and Open Sans.
- `app/page.tsx` renders the home page through `components/HomePageContent.tsx`.
- `app/about/page.tsx`, `app/testimonials/page.tsx`, and `app/contact/page.tsx` are static marketing/conversion pages.
- `app/contact/ContactContent.tsx` provides the contact page client experience.
- `app/questionnaire/page.tsx` renders the questionnaire flow.
- `app/nice-guy-university/page.tsx` renders the NGU promotional page and outbound CTAs.
- `app/blog/page.tsx` and `app/blog/[slug]/page.tsx` render blog index/detail pages with structured data.
- `app/sitemap.ts` and `app/robots.ts` expose Next-generated SEO metadata routes.

### 4.2 API routes

- `app/api/analyze/route.ts` accepts questionnaire submissions, applies honeypot/rate limiting/length checks, calls OpenAI (`gpt-5-mini` with fallback to `gpt-4o-mini`), and optionally emails the result via Brevo SMTP.
- `app/api/contact/route.ts` validates contact submissions, enforces per-IP rate limits, verifies Invisible reCAPTCHA v2, and sends contact email via Brevo.
- `app/api/ngu-coupon/route.ts` validates NGU coupon signups, verifies reCAPTCHA, sends the visitor coupon email, and sends the internal notification email.
- Shared server helpers live in `lib/server/`: contact and NGU normalization/validation/email builders, OpenAI client construction, and in-memory rate limiting.

### 4.3 Components and client behavior

- `components/navigation/` contains desktop/mobile navigation primitives used by `components/NavBar.tsx`.
- `components/sections/` contains major home-page content bands; keep visual changes consistent with the existing premium coaching brand.
- `components/questionnaire/` contains the questionnaire steps, fields, form, and analysis rendering.
- `components/blog/` contains blog filters, cards, hero, breadcrumbs, similar posts, and scroll-to-top behavior.
- `components/ContactForm.tsx` and `components/NguCouponSignupForm.tsx` load and execute Invisible reCAPTCHA v2 before posting to API routes.
- `components/TrackedLink.tsx` and `components/TrackedCtaLink.tsx` centralize CTA/link tracking.
- `components/hooks/` contains UI hooks for scroll tracking, fade-in behavior, and title visibility.

### 4.4 Content, SEO, and analytics

- Blog source content lives in `content/blog/posts.json`; `lib/blog.ts` normalizes slugs, excerpts, filters, dates, and similar posts.
- Site-wide brand/SEO constants live in `lib/site.ts`.
- Structured data helpers live in `lib/site-structured-data.ts` and `lib/blog-structured-data.ts`.
- `scripts/generate-sitemap.js` writes `public/sitemap.xml`; use `SITE_URL` to override the production base URL.
- Analytics scripts are hardcoded in `components/SiteAnalyticsScripts.tsx`; event dispatch lives in `lib/analytics.ts`.

## 5. Environment

No committed `.env.example` currently exists. Environment variables used by the app:

- `OPENAI_API_KEY` — required for questionnaire analysis.
- `BREVO_SMTP_PASSWORD`, `BREVO_USER`, `BREVO_TO`, `BREVO_FROM` — required for contact and NGU email routes; optional for questionnaire result notification.
- `NEXT_PUBLIC_RECAPTCHA_SITE_KEY_V2` — public Invisible reCAPTCHA v2 site key used by browser forms.
- `RECAPTCHA_SECRET_KEY_V2` — server-side Invisible reCAPTCHA v2 secret used with Google `siteverify`.
- `SITE_URL` — optional sitemap generation override; defaults to `https://www.michaelzick.com`.
- `PORT` — used by `npm start` and Playwright web server startup.
- `CI` and `PLAYWRIGHT_SKIP_BUILD` — influence Playwright server reuse/build behavior.

Do not commit `.env`, API keys, SMTP credentials, reCAPTCHA secrets, Vercel secrets, or production form exports.

## 6. Commands

```bash
npm run dev # Next dev server
npm run build # Production Next build
npm start # Start built Next app on $PORT
npm run lint # ESLint / Next core web vitals
npm run typecheck # tsc --noEmit
npm test # Compile test TS, run node --test, clean .test-dist
npm run test:e2e # Playwright E2E/mobile UI tests
npm run sitemap # Regenerate public/sitemap.xml
npm run agent-briefs:sync # Regenerate CLAUDE.md and GEMINI.md from AGENTS.md
npm run agent-briefs:check # Fail if CLAUDE.md or GEMINI.md drift from AGENTS.md
npm run check # Agent brief check + lint + typecheck + unit tests + build
```

CI runs the brief sync check, lint, typecheck, unit tests, production build, and Playwright Chromium E2E tests on the latest Node 24 patch. The security workflow runs Gitleaks, `npm audit --audit-level=moderate`, pull request dependency review via GitHub's Dependency Review API, and CodeQL.

## 7. Conventions and coding standards

- **Coding standards:** use `skills/coding-standards/SKILL.md` before implementation, refactors, API route work, UI state changes, security-sensitive code, analytics changes, and tests.
- **Package manager:** use npm and keep `package-lock.json`; do not introduce pnpm/yarn lockfiles.
- **Node version:** use Node 24, matching `.nvmrc`, `package.json#engines`, and GitHub Actions.
- **TypeScript:** the project is not yet strict (`strict: false`); keep new code strongly typed and avoid spreading `any` further.
- **Next boundaries:** keep browser-only code behind client components/hooks and server-only APIs in route handlers or `lib/server/*`.
- **API routes:** validate untrusted request bodies before use, enforce rate limits on public write routes, avoid logging secrets or full sensitive submissions, and return stable JSON errors.
- **Forms:** contact and NGU submissions must keep Invisible reCAPTCHA v2 verification and accessible failure states.
- **Analytics:** send events through `lib/analytics.ts` or tracked link components so GA4 and Amplitude payloads stay aligned.
- **SEO:** update metadata, structured data, sitemap generation, and canonical URLs when adding durable public pages or blog behavior.
- **Styling:** use Tailwind utility patterns already present in nearby components; keep pages responsive and verify mobile layouts when touching nav, hero, forms, CTAs, or promotional modals.
- **Testing:** unit-test pure helpers in `tests/*.test.ts`; use Playwright for routed UI behavior, mobile layout, reCAPTCHA flow mocks, and conversion-critical interactions.
- **Completion gate:** before marking meaningful work done, run `npm run lint`, `npm run typecheck`, and relevant tests. For PR-ready changes, run `npm run check`; add E2E when UI behavior changed.

## 8. Key files map

| Path | What lives here |
|---|---|
| [app/layout.tsx](app/layout.tsx) | Root metadata, scripts, global shell, nav, NGU promo, footer |
| [app/page.tsx](app/page.tsx) | Home route wrapper |
| [components/HomePageContent.tsx](components/HomePageContent.tsx) | Home page composition |
| [components/NavBar.tsx](components/NavBar.tsx) | Site navigation shell |
| [components/NguPromo.tsx](components/NguPromo.tsx) | Timed NGU promotion modal/banner behavior |
| [components/ContactForm.tsx](components/ContactForm.tsx) | Contact form client UX and reCAPTCHA execution |
| [components/NguCouponSignupForm.tsx](components/NguCouponSignupForm.tsx) | NGU coupon signup client UX |
| [components/questionnaire/QuestionnaireForm.tsx](components/questionnaire/QuestionnaireForm.tsx) | Questionnaire form state and submission |
| [components/questionnaire/steps.ts](components/questionnaire/steps.ts) | Questionnaire question definitions |
| [app/api/analyze/route.ts](app/api/analyze/route.ts) | OpenAI questionnaire analysis route |
| [app/api/contact/route.ts](app/api/contact/route.ts) | Contact email + reCAPTCHA route |
| [app/api/ngu-coupon/route.ts](app/api/ngu-coupon/route.ts) | NGU coupon email + reCAPTCHA route |
| [lib/server/contact.ts](lib/server/contact.ts) | Contact normalization, validation, config, email text |
| [lib/server/ngu-coupon.ts](lib/server/ngu-coupon.ts) | NGU coupon normalization, validation, config, email text |
| [lib/server/rate-limit.ts](lib/server/rate-limit.ts) | In-memory rate limiting helpers |
| [lib/blog.ts](lib/blog.ts) | Blog post normalization and filters |
| [lib/site.ts](lib/site.ts) | Site and brand constants |
| [lib/analytics.ts](lib/analytics.ts) | GA4/Amplitude event helpers |
| [scripts/generate-sitemap.js](scripts/generate-sitemap.js) | Static sitemap generation |
| [playwright.config.ts](playwright.config.ts) | Playwright web server and reporter configuration |
| [skills/coding-standards/SKILL.md](skills/coding-standards/SKILL.md) | Repo-local production coding standards |
| [skills/sync-agent-briefs/SKILL.md](skills/sync-agent-briefs/SKILL.md) | Workflow for syncing agent orientation files |

---

## Maintaining this file

**Whenever durable project facts change, update `AGENTS.md` in the same change.** Examples that require an update:

- Adding, removing, renaming, or re-homing a route, API route, component group, content source, test category, or script.
- Changing form submission behavior, analytics conventions, SEO/structured-data behavior, reCAPTCHA/email/OpenAI integrations, or security posture.
- Changing root `package.json` scripts, CI/security workflows, Node version, environment variables, or completion workflow.
- Changing a file listed in [Key files map](#8-key-files-map), or adding something that belongs in it.

Treat `AGENTS.md` as the canonical source for mirrored harness briefs. After updating it, run `npm run agent-briefs:sync` and `npm run agent-briefs:check` so [CLAUDE.md](CLAUDE.md) and [GEMINI.md](GEMINI.md) stay aligned.

Do **not** use this file for ephemeral notes, in-flight TODOs, debugging logs, or session state. It is a map, not a journal.
Loading
Loading