From 4c140575ce054fa95ea28b00b958b8199fa10379 Mon Sep 17 00:00:00 2001 From: Jay Singh <54427246+gsinghjay@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:10:46 -0500 Subject: [PATCH 1/4] docs: clarify Netlify hosting and serverless function architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace all GitHub Pages references with Netlify - Document why Netlify is required (serverless functions for form processing) - Clarify we use Netlify Functions, NOT Netlify Forms - Update form submission flow to show Sanity image upload - Update directory structure (add styles-index.njk, remove admin.njk) - Fix references to Make webhook → Netlify Function - Add notes on blocking vs non-blocking integrations --- docs/architecture.md | 116 +++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 178e558..433adfa 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -57,9 +57,9 @@ _This document builds collaboratively through step-by-step discovery. Sections a **Target Integrations:** - Sanity CMS for content management AND instructor workflow (MVP) -- GitHub Pages for static hosting +- Netlify for static hosting + serverless functions (form processing) - Discord for community notifications -- HubSpot/Airtable/Notion for CRM +- Airtable for CRM - Google Analytics 4 with consent mode **Compliance Requirements:** @@ -73,7 +73,7 @@ _This document builds collaboratively through step-by-step discovery. Sections a 2. **Error Handling**: Integration failures (Discord, CRM) must not block core user flows 3. **Performance Budget**: Static-first architecture with aggressive optimization targets 4. **Accessibility**: Built into every component from the start -5. **Build Pipeline**: Sanity webhook → GitHub Actions → Eleventy → GitHub Pages +5. **Build Pipeline**: Sanity webhook → Netlify Build Hook → Eleventy → Netlify CDN ### MVP Scope Decisions @@ -116,12 +116,23 @@ Sanity CMS → @11ty/eleventy-fetch (cached) → _data/*.js → Templates → St - Instructor workflow via Sanity Studio native interface (MVP) **Build Trigger:** -- Sanity webhook → GitHub Actions → Eleventy rebuild → GitHub Pages deploy +- Sanity webhook → Netlify Build Hook → Eleventy rebuild → Netlify deploy **Form Submissions:** -- Serverless function receives form POST -- Mutates Sanity dataset with `pending` status -- Triggers Discord webhook notification +- Netlify Function (`/.netlify/functions/submit-form`) receives form POST +- Uploads screenshot to Sanity CDN (if provided) +- Creates gallerySubmission document in Sanity with `pending` status +- Sends Discord webhook notification (non-blocking) +- Syncs to Airtable CRM (non-blocking) + +**Why Netlify (not GitHub Pages):** +GitHub Pages is static-only and cannot execute server-side code. The submission flow requires: +- Processing form data with validation +- Uploading images to Sanity CDN +- Creating documents in Sanity CMS via mutations API +- Sending notifications to Discord + +Netlify provides serverless functions that run on form submission, eliminating the need for a separate backend service. ## Core Architectural Decisions @@ -129,13 +140,13 @@ Sanity CMS → @11ty/eleventy-fetch (cached) → _data/*.js → Templates → St **Critical Decisions (Block Implementation):** - CMS Integration: Sanity with @11ty/eleventy-fetch -- Form Handling: Make webhook endpoint -- Build Pipeline: GitHub Actions with Sanity webhook trigger +- Form Handling: Netlify Function with Sanity mutations +- Build Pipeline: Netlify with Sanity webhook trigger **Important Decisions (Shape Architecture):** - Image Optimization: Sanity Image URL (CDN) -- CRM: Airtable free tier -- Notifications: Make/Zapier automation +- CRM: Airtable (via Netlify Function) +- Notifications: Discord webhook (via Netlify Function) **Deferred Decisions (Post-MVP):** - Custom instructor dashboard (using Sanity Studio for MVP) @@ -216,14 +227,14 @@ Eleventy rebuild → Netlify deploy 1. Sanity Studio setup with schemas 2. Data fetching layer (eleventy-fetch + Sanity client) 3. Template updates to use Sanity data -4. Make scenarios (form → Sanity → Discord → Airtable) -5. GitHub Actions webhook trigger +4. Netlify Function for form submission (→ Sanity → Discord → Airtable) +5. Sanity webhook → Netlify Build Hook trigger 6. Data migration from mock data to Sanity **Cross-Component Dependencies:** -- Make webhook URL needed before form can work +- Sanity API token (write access) needed for form submissions - Sanity project ID/dataset needed for all data fetching -- GitHub Actions workflow needs Sanity webhook secret +- Netlify Build Hook URL needed for Sanity webhook ## Implementation Patterns & Consistency Rules @@ -311,16 +322,19 @@ export default async function() { ### Communication Patterns -**Make Webhook Payload (Form → Make):** +**Form Submission Payload (Form → Netlify Function):** ```json { "name": "Alex Chen", "email": "alex@njit.edu", - "style": "swiss", + "style": "swiss-international-style", "demoUrl": "https://example.com/demo", - "explanation": "Grid-based layout with Helvetica...", + "authenticity": "Grid-based layout with Helvetica...", "consent": true, "marketing": false, + "screenshot": "data:image/png;base64,...", + "screenshotFilename": "screenshot.png", + "screenshotMimeType": "image/png", "timestamp": "2025-01-15T14:30:00Z" } ``` @@ -341,7 +355,7 @@ Demo: {demoUrl} | Form submission fails | Show error message, retain form data | | Missing image | Display style emoji/color block as fallback | | Empty gallery state | Show "No submissions yet" with CTA | -| Make webhook fails | Make handles retries; form shows success | +| Discord/Airtable fails | Non-blocking; logged but form shows success | **Template Consistency:** @@ -431,7 +445,8 @@ MyWebClass/ │ ├── .github/ │ └── workflows/ -│ └── ci.yml # CI checks (lint, test) - deploy handled by Netlify +│ ├── ci.yml # CI/CD Pipeline (lint, build, test, Lighthouse) +│ └── semantic-release.yml # Automated versioning and releases │ ├── docs/ # Project documentation │ ├── index.md # Documentation index @@ -461,17 +476,17 @@ MyWebClass/ │ │ └── badge.njk # Status badges │ │ │ ├── pages/ -│ │ ├── index.njk # Homepage +│ │ ├── index.njk # Homepage (featured + community galleries) │ │ ├── about.njk # About page -│ │ ├── submit.njk # Submission form → Make webhook -│ │ ├── admin.njk # Dashboard (links to Sanity Studio) +│ │ ├── submit.njk # Submission form → Netlify Function │ │ ├── 404.njk # Not found │ │ ├── legal/ │ │ │ ├── privacy.njk │ │ │ ├── terms.njk │ │ │ └── cookies.njk +│ │ ├── styles-index.njk # Design Style Gallery listing (/styles/) │ │ └── styles/ -│ │ └── style-detail.njk # Paginated design style pages +│ │ └── style-detail.njk # Individual design style pages │ │ │ ├── scripts/ │ │ ├── cookie-consent.js # Cookie banner logic @@ -510,18 +525,20 @@ src/pages/*.njk (Templates) ↓ Build public/ (Static HTML) ↓ Deploy -GitHub Pages (CDN) +Netlify CDN ``` **Form Submission Boundary:** ``` src/pages/submit.njk (Form) - ↓ POST -Make Webhook (External) - ↓ Scenario -├── Sanity API (Create document) -├── Airtable API (Create record) -└── Discord API (Send notification) + ↓ POST (JSON payload with base64 screenshot) +/.netlify/functions/submit-form (Serverless Function) + ↓ +├── Sanity API (Upload image + Create document) [blocking] +├── Discord Webhook (Notification) [non-blocking] +└── Airtable API (CRM record) [non-blocking] + ↓ +Return success/error to client ``` **Admin Boundary:** @@ -532,7 +549,7 @@ Instructors → studio.sanity.io/{project} ↓ Direct document editing ↓ - Webhook → GitHub Actions → Rebuild + Webhook → Netlify Build Hook → Rebuild & Deploy ``` ### Requirements to Structure Mapping @@ -540,24 +557,26 @@ Instructors → studio.sanity.io/{project} | PRD Requirement | Location | |-----------------|----------| | FR1-7: Design Gallery | `src/pages/index.njk`, `src/pages/styles/`, `src/_data/designStyles.js` | -| FR8-16: Submission | `src/pages/submit.njk` → Make webhook | +| FR8-16: Submission | `src/pages/submit.njk` → `netlify/functions/submit-form.js` | | FR17-24: Instructor Dashboard | Sanity Studio (`studio/`) | | FR25-28: Content Curation | Sanity Studio + `isFeatured` field | | FR29-35: Privacy/Consent | `src/scripts/cookie-consent.js`, `src/pages/legal/` | -| FR36-40: Integrations | Make scenarios (external) | +| FR36-40: Integrations | `netlify/functions/submit-form.js` (Discord, Airtable) | | FR41-45: CMS | `studio/schemas/`, `src/_data/` | | FR46-50: Accessibility | All templates, `src/styles/main.css` | ### Integration Points -| Integration | Trigger | Endpoint | -|-------------|---------|----------| -| Sanity → Eleventy | Build time | `https://{project}.api.sanity.io/...` | -| Form → Netlify Function | User submit | `/.netlify/functions/submit-form` | -| Netlify Function → Sanity | Form received | Sanity Mutations API | -| Netlify Function → Airtable | Form received | Airtable API (non-blocking) | -| Netlify Function → Discord | Form received | Discord Webhook URL (non-blocking) | -| Sanity → Netlify | Content change | Netlify Build Hook URL | +| Integration | Trigger | Endpoint | Notes | +|-------------|---------|----------|-------| +| Sanity → Eleventy | Build time | `https://{project}.api.sanity.io/...` | GROQ queries via @11ty/eleventy-fetch | +| Form → Netlify Function | User submit | `/.netlify/functions/submit-form` | JSON POST with base64 screenshot | +| Netlify Function → Sanity | Form received | Sanity Assets + Mutations API | Blocking - must succeed | +| Netlify Function → Discord | Form received | Discord Webhook URL | Non-blocking - failure logged only | +| Netlify Function → Airtable | Form received | Airtable API | Non-blocking - failure logged only | +| Sanity → Netlify | Content change | Netlify Build Hook URL | Triggers rebuild on content publish | + +**Note:** We use Netlify Functions (serverless), NOT Netlify Forms. The `data-netlify="true"` attribute on the form is a fallback only. ### Environment Variables @@ -645,7 +664,7 @@ AIRTABLE_TABLE_NAME=Submissions **Key Strengths:** - Leverages existing brownfield codebase -- No-code integrations reduce complexity (Make, Airtable) +- Single platform (Netlify) for hosting + functions - Sanity Studio eliminates custom auth for MVP - Clear separation of concerns @@ -694,8 +713,8 @@ This architecture document is your complete guide for implementing is373-final. 1. Initialize Sanity Studio in `/studio` directory 2. Create Sanity schemas (designStyle, gallerySubmission, article, author) 3. Set up data fetching layer (`src/_data/sanity.js`, `designStyles.js`) -4. Configure Make webhook scenario -5. Update form to POST to Make webhook +4. Create Netlify Function for form submission +5. Configure Sanity webhook to trigger Netlify Build Hook **Development Sequence:** 1. Initialize Sanity project and deploy schemas @@ -703,9 +722,10 @@ This architecture document is your complete guide for implementing is373-final. 3. Create data fetching layer with eleventy-fetch 4. Update templates to use Sanity data 5. Connect GitHub repo to Netlify (auto-deploy enabled) -6. Configure Sanity webhook to trigger Netlify Build Hook -7. Migrate mock data to Sanity -8. Test form submission via Netlify Function +6. Create Netlify Function (`netlify/functions/submit-form.js`) +7. Configure Sanity webhook to trigger Netlify Build Hook +8. Migrate mock data to Sanity +9. Test form submission end-to-end ### Quality Assurance Checklist From 8df9d2fce0a1e90b0213fefeeb1da755a76ac7ed Mon Sep 17 00:00:00 2001 From: Jay Singh <54427246+gsinghjay@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:12:25 -0500 Subject: [PATCH 2/4] docs: update development guide and project context for Netlify - development-guide.md: Clarify Netlify is required (not optional) - development-guide.md: Add form submission flow diagram - development-guide.md: Remove Vercel/GitHub Pages as alternatives - project_context.md: Update deployment from GitHub Pages to Netlify - project_context.md: Update form handling from Make to Netlify Function - project_context.md: Add netlify/functions to directory structure - project_context.md: Update environment variables section --- docs/development-guide.md | 48 +++++++++++++++++++++++++++++---------- docs/project_context.md | 36 ++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/docs/development-guide.md b/docs/development-guide.md index a538af0..27e55f6 100644 --- a/docs/development-guide.md +++ b/docs/development-guide.md @@ -273,26 +273,50 @@ Output is in `public/` directory. ## Deployment -### Netlify +### Netlify (Required) + +This project **requires Netlify** for hosting because the submission form uses a Netlify Function to: +- Upload screenshots to Sanity CDN +- Create submission documents in Sanity CMS +- Send Discord notifications +- Sync to Airtable CRM + +GitHub Pages and Vercel cannot be used because they don't support our serverless function architecture. + +**Setup:** 1. Connect repository to Netlify 2. Configure build settings: - Build command: `npm run build` - Publish directory: `public` -3. Set environment variables -4. Deploy - -### Vercel - -1. Import project from GitHub -2. Framework preset: Other -3. Build command: `npm run build` -4. Output directory: `public` + - Functions directory: `netlify/functions` +3. Set environment variables in Netlify Dashboard: + - `SANITY_PROJECT_ID` + - `SANITY_DATASET` + - `SANITY_API_TOKEN` (write access) + - `DISCORD_WEBHOOK_URL` (optional) + - `AIRTABLE_API_KEY` (optional) + - `AIRTABLE_BASE_ID` (optional) +4. Configure Sanity webhook to trigger Netlify Build Hook 5. Deploy -### GitHub Pages +### Form Submission Flow + +``` +User submits form + ↓ +POST to /.netlify/functions/submit-form + ↓ +Netlify Function: + 1. Upload screenshot to Sanity CDN [blocking] + 2. Create gallerySubmission document [blocking] + 3. Send Discord notification [non-blocking] + 4. Sync to Airtable [non-blocking] + ↓ +Return success/error to client +``` -The project includes `.github/workflows/ci.yml` for CI/CD. +**Note:** We use Netlify Functions, NOT Netlify Forms. The `data-netlify="true"` attribute is a fallback only. ## Common Tasks diff --git a/docs/project_context.md b/docs/project_context.md index 9e963f2..d215b8e 100644 --- a/docs/project_context.md +++ b/docs/project_context.md @@ -6,7 +6,7 @@ **Type:** Static Web Application with Headless CMS (JAMstack) **Stack:** Eleventy 3.1.2 + Sanity CMS + Tailwind CSS 3.4.18 -**Deployment:** GitHub Pages +**Deployment:** Netlify (static + serverless functions) **Status:** Brownfield (existing codebase) ## Critical Rules @@ -25,7 +25,7 @@ ### DON'T - Don't create custom authentication — use Sanity Studio native auth -- Don't build serverless functions — use Make webhook for form handling +- Don't use Netlify Forms — use Netlify Function for form handling - Don't hardcode Sanity credentials — use environment variables - Don't let Sanity fetch failures crash the build — graceful degradation - Don't use truthy checks on arrays in Nunjucks (arrays are always truthy) @@ -38,9 +38,9 @@ | Templating | Nunjucks | — | | Styling | Tailwind CSS | 3.4.18 | | CMS | Sanity | v3 | -| Forms | Make webhook | — | +| Forms | Netlify Function | — | | CRM | Airtable | Free tier | -| Hosting | GitHub Pages | — | +| Hosting | Netlify | — | ## Directory Structure @@ -52,6 +52,10 @@ src/ ├── scripts/ # Client-side JS (minimal) └── styles/ # Tailwind CSS entry +netlify/ +└── functions/ + └── submit-form.js # Form submission handler + studio/ # Sanity Studio (separate) └── schemas/ # Document type definitions ``` @@ -115,21 +119,31 @@ export default async function() { ``` User submits form (src/pages/submit.njk) ↓ -POST to Make webhook (MAKE_WEBHOOK_URL env var) +POST to /.netlify/functions/submit-form + ↓ +Netlify Function: + 1. Upload screenshot to Sanity CDN [blocking] + 2. Create gallerySubmission document (status: pending) [blocking] + 3. Send Discord notification [non-blocking] + 4. Sync to Airtable CRM [non-blocking] ↓ -Make scenario: - 1. Create Sanity document (status: pending) - 2. Create Airtable record - 3. Fire Discord webhook +Return success/error to client ``` +**Note:** We use Netlify Functions, NOT Netlify Forms. The function handles image upload, Sanity mutations, and integrations. + ## Environment Variables ```bash +# Required SANITY_PROJECT_ID=xxx # Sanity project ID SANITY_DATASET=production # Dataset name -SANITY_API_TOKEN=sk-xxx # Read token (build only) -MAKE_WEBHOOK_URL=https://... # Form submission endpoint +SANITY_API_TOKEN=sk-xxx # Write token (for form submission) + +# Optional +DISCORD_WEBHOOK_URL=https://... # Discord notifications +AIRTABLE_API_KEY=pat... # Airtable CRM sync +AIRTABLE_BASE_ID=app... # Airtable base ``` ## Accessibility Requirements From 03ae5decff7431a52e0fffef4103e9afab1f5d9f Mon Sep 17 00:00:00 2001 From: Jay Singh <54427246+gsinghjay@users.noreply.github.com> Date: Thu, 18 Dec 2025 13:46:24 -0500 Subject: [PATCH 3/4] ci: update workflows for staging/main branching strategy - CI workflow: Run on both staging and main branches - CI workflow: Remove GitHub Pages deploy (Netlify handles deployment) - Release workflow: Run on staging (prereleases) and main (releases) - pyproject.toml: Add staging branch config for rc prereleases Branching strategy: - staging: Development branch, creates rc prereleases (e.g., v1.5.0-rc.1) - main: Production branch, creates stable releases (e.g., v1.5.0) --- .github/workflows/ci.yml | 50 +++------------------------------ .github/workflows/release.yml | 52 +++-------------------------------- pyproject.toml | 5 ++++ 3 files changed, 13 insertions(+), 94 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f41d5a..c129888 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI/CD Pipeline on: push: - branches: [main] + branches: [main, staging] pull_request: - branches: [main] + branches: [main, staging] # Skip CI for release commits (handled by release workflow) env: @@ -180,47 +180,5 @@ jobs: path: .lighthouseci/ retention-days: 30 - deploy: - name: Deploy to GitHub Pages - runs-on: ubuntu-latest - needs: [build, test, lighthouse] - if: github.ref == 'refs/heads/main' && github.event_name == 'push' - permissions: - contents: read - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build site - run: npm run build - env: - SANITY_PROJECT_ID: ${{ secrets.SANITY_PROJECT_ID }} - SANITY_DATASET: ${{ secrets.SANITY_DATASET }} - SANITY_API_VERSION: ${{ secrets.SANITY_API_VERSION }} - SANITY_TOKEN: ${{ secrets.SANITY_TOKEN }} - DEPLOY_PATH_PREFIX: /MyWebClass/ - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: 'public' - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + # Note: Deployment is handled by Netlify (auto-deploys from main branch) + # CI only validates the build - Netlify deploys on successful push to main diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 13876ed..686d6a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,7 @@ name: Semantic Release on: push: - branches: [main] + branches: [main, staging] workflow_dispatch: inputs: force_release: @@ -83,50 +83,6 @@ jobs: version: ${{ steps.release.outputs.version }} tag: ${{ steps.release.outputs.tag }} - # Optional: Trigger deployment after release - deploy-after-release: - name: Deploy Released Version - needs: release - if: needs.release.outputs.released == 'true' - runs-on: ubuntu-latest - permissions: - contents: read - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - - steps: - - uses: actions/checkout@v4 - with: - ref: ${{ needs.release.outputs.tag }} - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build site - run: npm run build - env: - SANITY_PROJECT_ID: ${{ secrets.SANITY_PROJECT_ID }} - SANITY_DATASET: ${{ secrets.SANITY_DATASET }} - SANITY_API_VERSION: ${{ secrets.SANITY_API_VERSION }} - SANITY_TOKEN: ${{ secrets.SANITY_TOKEN }} - - - name: Setup Pages - uses: actions/configure-pages@v4 - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: 'public' - - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + # Note: Deployment is handled by Netlify + # Netlify auto-deploys when the release commit is pushed to main + # The release tag triggers a production deploy via Netlify's branch settings diff --git a/pyproject.toml b/pyproject.toml index ba316ce..cfc809f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,6 +28,11 @@ patch_tags = ["fix", "perf"] match = "main" prerelease = false +[tool.semantic_release.branches.staging] +match = "staging" +prerelease = true +prerelease_token = "rc" + [tool.semantic_release.remote] name = "origin" type = "github" From a4a27dcf787da8afcfbaf65b6da0df2f77ce75d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 18 Dec 2025 18:48:09 +0000 Subject: [PATCH 4/4] 1.5.0-rc.1 Automatically generated by python-semantic-release --- CHANGELOG.md | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2a4435..d7bdcbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,156 @@ # CHANGELOG -## v1.5.0 (2025-12-08) +## v1.5.0-rc.1 (2025-12-18) ### Bug Fixes +- Add url filter to articleCard links for proper pathPrefix + ([`021fd62`](https://github.com/gsinghjay/MyWebClass/commit/021fd6263d3f08ab792076e68e850408b37fc954)) + +- Await Discord notification to prevent Lambda termination + ([`9147751`](https://github.com/gsinghjay/MyWebClass/commit/9147751a198b1ce1da5ebdb10240c39e0bdeef7f)) + +- Improve gallery card consistency and community submissions display + ([`05d4407`](https://github.com/gsinghjay/MyWebClass/commit/05d44078d669ab37aa54704e680c2d467f75e975)) + +- Update E2E tests for gallery move to /styles/ page + ([`fdf1562`](https://github.com/gsinghjay/MyWebClass/commit/fdf15622c50cfa83b3cbc3f88f82896f5d5e9a60)) + +- Update hero CTA to link to community gallery section + ([`4269595`](https://github.com/gsinghjay/MyWebClass/commit/426959504469835a430559e975cc21c567693d35)) + +- **ci**: Ensure Sanity env vars available for Playwright tests + ([`2daf242`](https://github.com/gsinghjay/MyWebClass/commit/2daf242cc908a95937c9cb5a245ff54a749cb81b)) + +- **ci**: Run full build before E2E tests + ([`0e8e578`](https://github.com/gsinghjay/MyWebClass/commit/0e8e578ef5bc28b7c46dce7560bb5474ec8c92ba)) + +- **ci**: Use DEPLOY_PATH_PREFIX instead of GITHUB_ACTIONS for pathPrefix + ([`2c5d611`](https://github.com/gsinghjay/MyWebClass/commit/2c5d611a5939685b520b6977d4987c35fe705d86)) + +- **ci**: Use http-server for Playwright in CI + ([`83ea14c`](https://github.com/gsinghjay/MyWebClass/commit/83ea14c8dfdd356ee6426989d69b6a6e0023533a)) + - **images**: Resolve Sanity CDN URLs not rendering in Nunjucks macros ([`84d3543`](https://github.com/gsinghjay/MyWebClass/commit/84d35439a1f604e45c4affda9d1af5726d4ad482)) +- **netlify**: Add npm ci to build command + ([`a22830f`](https://github.com/gsinghjay/MyWebClass/commit/a22830f40098e92f474ac750261df67ca65c5bc0)) + +- **netlify**: Add SECRETS_SCAN_OMIT_PATHS for _bmad and docs folders + ([`94b2ed3`](https://github.com/gsinghjay/MyWebClass/commit/94b2ed354108e1c47b8554e9427579b5d473386c)) + +- **netlify**: Disable secret scanning (false positives) + ([`ff1c48a`](https://github.com/gsinghjay/MyWebClass/commit/ff1c48a8e850a4b9dd548adb392dff574970d39d)) + +- **netlify**: Disable secret scanning entirely (public Sanity values cause false positives) + ([`2c1efe6`](https://github.com/gsinghjay/MyWebClass/commit/2c1efe6751e8998211c69fe86b44c1714b040147)) + +- **netlify**: Remove 'production' string to avoid false positive secret detection + ([`5c70d3e`](https://github.com/gsinghjay/MyWebClass/commit/5c70d3e4c57f785f85fe78579cd4906700c6633b)) + +- **netlify**: Run build commands directly, remove NODE_ENV from env + ([`86a75aa`](https://github.com/gsinghjay/MyWebClass/commit/86a75aa90cc8c03227bc31709172423b52090397)) + +- **netlify**: Run build steps directly and include devDependencies + ([`8f22250`](https://github.com/gsinghjay/MyWebClass/commit/8f22250eaad325686e91c2899af14fbe1029aa1d)) + +- **tests**: Add networkidle waits for CI test stability + ([`a453328`](https://github.com/gsinghjay/MyWebClass/commit/a4533284687a4174cd7cca2f1ad751c0526ed5c1)) + +- **tests**: Inline viewport setup in each test for CI reliability + ([`4e462e2`](https://github.com/gsinghjay/MyWebClass/commit/4e462e2dc0cb2b2e915c10aba2246c4191395e7e)) + +- **tests**: Use beforeEach for viewport setup in CI + ([`ab5c595`](https://github.com/gsinghjay/MyWebClass/commit/ab5c5951192ac5a239adefeb8d9b74d941c77b78)) + +### Chores + +- Add Story 4.5 file and validation report + ([`9019744`](https://github.com/gsinghjay/MyWebClass/commit/9019744e360a915a3d302791f9d5fac8abbb367f)) + +- Bmad update + ([`bc198df`](https://github.com/gsinghjay/MyWebClass/commit/bc198df5e3be708c7893619742428eba84fd4ffb)) + +- BMAD update + ([`1a1adce`](https://github.com/gsinghjay/MyWebClass/commit/1a1adce4045d0eecfa4f32670fe34e05e03cde72)) + +- Mark story 2.6 as done + ([`f3b3818`](https://github.com/gsinghjay/MyWebClass/commit/f3b381830bca90a0b39ae678038f07e5c22aa725)) + +- Mark Story 4.6 as done + ([`315984f`](https://github.com/gsinghjay/MyWebClass/commit/315984f16725e1409c57a7cf9842cbb445b9c4f4)) + +- Story file + ([`4abcba0`](https://github.com/gsinghjay/MyWebClass/commit/4abcba0011723cf141319c6cc3b2def9bbcc7f8e)) + +- Story files + ([`7c4af50`](https://github.com/gsinghjay/MyWebClass/commit/7c4af50ec204f5a76dc6a39e1b0e515e1a875a6d)) + +- Switch from GitHub Pages to Netlify hosting + ([`e65fb76`](https://github.com/gsinghjay/MyWebClass/commit/e65fb76311997e0f38740d4a998920846292c44e)) + +- Update sprint status with completed stories and site improvements + ([`4b5aa42`](https://github.com/gsinghjay/MyWebClass/commit/4b5aa425a8377527e212c9b645bd95b61cdee78d)) + +- Update to project artifacts + ([`bbce29e`](https://github.com/gsinghjay/MyWebClass/commit/bbce29ec1836c5a0c2f58368c1c89752b1b8f101)) + +### Documentation + +- Clarify Netlify hosting and serverless function architecture + ([`4c14057`](https://github.com/gsinghjay/MyWebClass/commit/4c140575ce054fa95ea28b00b958b8199fa10379)) + +- Update development guide and project context for Netlify + ([`8df9d2f`](https://github.com/gsinghjay/MyWebClass/commit/8df9d2fce0a1e90b0213fefeeb1da755a76ac7ed)) + +- Update README with Netlify badge, live URL, and deployment info + ([`ead63f8`](https://github.com/gsinghjay/MyWebClass/commit/ead63f844245971a96e262a57b78ebf4a409f3e0)) + ### Features +- Make style badge clickable on submission cards + ([`a3133b1`](https://github.com/gsinghjay/MyWebClass/commit/a3133b146091cae082e1ef5b439c5f3cb9711465)) + +- Move Design Style Gallery to dedicated /styles/ page + ([`9e50de4`](https://github.com/gsinghjay/MyWebClass/commit/9e50de4e7d8adf494fdf34de851e35c3a47d2360)) + +- **articles**: Implement educational articles display (Story 2.7) + ([`1053916`](https://github.com/gsinghjay/MyWebClass/commit/105391624a0e25dde27aa27c15494f4e1660b3e2)) + +- **discord**: Story 4.6 - Discord webhook shows human-readable style name + ([`b3611f1`](https://github.com/gsinghjay/MyWebClass/commit/b3611f18bac1b37b34f6dfb766ea8329e6983b37)) + - **gallery**: Add Community Gallery section for approved submissions ([`792e405`](https://github.com/gsinghjay/MyWebClass/commit/792e40559aef318f029190601ad5c155afdfb0b8)) +- **privacy**: Story 3.1 - Cookie Consent Banner with GA4 Consent Mode + ([`3f58972`](https://github.com/gsinghjay/MyWebClass/commit/3f589728411c045defa3c3c9674ba7470f61a83b)) + +- **privacy**: Story 3.2 - Cookie Preferences Management + ([`45515f8`](https://github.com/gsinghjay/MyWebClass/commit/45515f8012c1d929be2d4e8b564a8dd3be197226)) + +- **responsive**: Implement mobile-first responsive experience + ([`88684f8`](https://github.com/gsinghjay/MyWebClass/commit/88684f86f61167da3e91b21462876ecdba6901b7)) + +- **submission**: Story 4.1 - Submission Form Page with validation + ([`209eb93`](https://github.com/gsinghjay/MyWebClass/commit/209eb932bd6f55fa36e9fb304ace8461f7e7986f)) + +- **submission**: Story 4.2 - Consent Checkboxes with GDPR compliance + ([`4b7448e`](https://github.com/gsinghjay/MyWebClass/commit/4b7448e1cf41b99e4a4c40ada510d60982da6dcf)) + +- **submission**: Story 4.3 - Screenshot Upload with Preview + ([`9c7e50d`](https://github.com/gsinghjay/MyWebClass/commit/9c7e50da67bc115c646d709b2f7708692bb4424b)) + +- **submission**: Story 4.4 - Form Submission Handler + ([`5116f65`](https://github.com/gsinghjay/MyWebClass/commit/5116f653f3f717ddb573f1bb1674a5d804cfe1a3)) + +### Refactoring + +- Remove redundant admin page and simplify navigation + ([`886543f`](https://github.com/gsinghjay/MyWebClass/commit/886543fdbac9f82c47132821276631b921614c9c)) + ## v1.4.0 (2025-12-08)