Last Updated: 2026-03-17 Project: The Parlor (www.aledlie.com) Purpose: Comprehensive architectural patterns and data flow documentation
- Architecture Overview
- Repository Structure
- Data Flow Patterns
- Component Relationships
- Schema.org Architecture
- Testing Architecture
- Build and Deployment Pipeline
- Configuration Cascade
┌─────────────────────────────────────────────────────────────────┐
│ CONTENT LAYER │
│ _posts/ _projects/ _reports/ _work/ pages/ │
│ (Markdown files with YAML front matter) │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ JEKYLL BUILD LAYER │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ _config.yml │ │ Collections │ │ Plugins │ │
│ │ Settings │ │ Processing │ │ (paginate, │ │
│ │ │ │ │ │ sitemap) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ TEMPLATE LAYER │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ _layouts/ │ │ _includes/ │ │ _sass/ │ │
│ │ (Render │ │ (Schema, │ │ (Styles) │ │
│ │ Structure) │ │ Partials) │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ OUTPUT LAYER │
│ _site/ (Static HTML + Assets) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ HTML Pages │ │ CSS/JS/Img │ │ Schema.org │ │
│ │ │ │ (assets/) │ │ (JSON-LD) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ DEPLOYMENT LAYER │
│ GitHub Pages (via GitHub Actions) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Security │ │ Cache │ │ Analytics │ │
│ │ Headers │ │ Strategy │ │ (GA4) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
graph TD
Root["personal-site<br/>Jekyll + npm"]
Root --> Config["Configuration"]
Root --> Content["Content Collections"]
Root --> Templates["Template System"]
Root --> Styling["Styling & Assets"]
Root --> Docs["Documentation"]
Root --> Testing["Testing"]
Root --> Utils["Utilities"]
Content --> Posts["_posts/<br/>8 blog posts"]
Content --> Reports["_reports/<br/>115+ reports"]
Content --> Proj["_projects/<br/>1 project"]
Content --> Work["_work/<br/>8 files"]
Templates --> Layouts["_layouts/<br/>10 layouts"]
Templates --> Includes["_includes/<br/>46 components<br/>13 schema files"]
Templates --> Data["_data/<br/>3 YAML files"]
Styling --> CSS["assets/css/<br/>main.scss"]
Styling --> JS["assets/js/<br/>scripts + vendor"]
Styling --> IMG["assets/images/"]
Styling --> SASS["_sass/<br/>theme overrides"]
Docs --> Main["README.md<br/>CHANGELOG.md<br/>ARCHITECTURE"]
Docs --> Schema["schema/<br/>implementation guides"]
Docs --> Setup["setup/<br/>3 troubleshooting guides"]
Testing --> Unit["tests/unit/<br/>6 Jest suites"]
Testing --> E2E["tests/e2e/<br/>4 Playwright suites"]
Testing --> Perf["tests/performance/<br/>Lighthouse"]
Utils --> Analysis["analysis/<br/>git commit scripts"]
Utils --> Plotting["plotting/<br/>Python visualization"]
Utils --> Scripts["scripts/<br/>build utilities"]
Config --> ConfigYML["_config.yml"]
Config --> ConfigDir["config/<br/>playwright, lighthouse<br/>stylelint, prettier"]
Config --> Claude[".claude/<br/>settings, hooks"]
| Category | Count | Notes |
|---|---|---|
| Layouts | 10 | home, single, archive, post-index, collection, etc. |
| Includes | 46 | 13 schema-related, 33 UI components |
| Posts | 8 | 2017-2026 |
| Reports | 115+ | Technical case studies, session logs |
| Unit Tests | 6 | Jest with jsdom |
| E2E Tests | 4 | Playwright (Chrome, Firefox, Safari, Mobile) |
| Directory | Purpose |
|---|---|
_posts/ |
Blog posts (permanent content) |
_reports/ |
Technical reports and analysis (completed work) |
_projects/ |
Portfolio items (permanent) |
_work/ |
Work-in-progress, activity summaries |
_layouts/ |
Page structure templates |
_includes/ |
Reusable components (schema, analytics, UI) |
_sass/ |
Theme style overrides |
assets/ |
Static files (CSS, JS, images, fonts) |
docs/ |
Project documentation |
tests/ |
Test suites (unit, e2e, performance, analytics, baseline, visual, links) |
config/ |
Tool configurations |
utils/ |
Utility scripts (analysis/, plotting/, scripts/) |
Path: Markdown → Jekyll → Liquid Templates → HTML
graph LR
A[Markdown File] --> B[YAML Front Matter]
A --> C[Content Body]
B --> D[Jekyll Parser]
C --> D
D --> E[Layout Selection]
E --> F[Liquid Template Engine]
F --> G[Include Processing]
F --> H[Variable Substitution]
G --> I[Final HTML]
H --> I
I --> J[_site/ Directory]
Detailed Steps:
-
Content Creation
- File:
_posts/YYYY-MM-DD-title.md - Front matter defines metadata (layout, title, date, schema_type, etc.)
- Content body in Markdown format
- File:
-
Jekyll Processing
- Reads front matter YAML
- Applies defaults from
_config.yml - Converts Markdown to HTML via kramdown
- Processes Liquid tags and variables
-
Layout Application
- Selects layout based on
layout:front matter - Layouts inherit (e.g., home → archive → default → compress)
- Each layout wraps content with structure
- Selects layout based on
-
Include Insertion
- Processes
{% include %}tags - Inserts partials (navigation, footer, schema, etc.)
- Passes variables to includes
- Processes
-
Final Output
- Complete HTML page with all assets
- Schema.org JSON-LD embedded in
<head> - CSS/JS references injected
- Output to
_site/directory
Example Flow for Blog Post:
_posts/2025-11-17-example.md
↓ (Front matter: layout: single, schema_type: TechArticle)
_layouts/single.html
↓ (Layout inheritance: single → default)
_layouts/default.html
↓ (Includes head, masthead, content, footer)
_includes/_head.html
↓ (Includes seo.html for schema)
_includes/seo.html
↓ (Conditional schema based on schema_type)
_includes/tech-article-schema.html
↓ (Final HTML with embedded Schema.org)
_site/posts/example/index.html
Path: Front Matter → Schema Includes → Unified Knowledge Graph → HTML Output
graph TD
A[Page Front Matter] --> B{Schema Type?}
B -->|TechArticle| C[tech-article-schema.html]
B -->|AnalysisNewsArticle| D[analysis-article-schema.html]
B -->|HowTo| E[how-to-schema.html]
B -->|Default BlogPosting| F[post-schema.html]
B -->|About Page| G[about-page-schema.html]
H[unified-knowledge-graph-schema.html] --> I[Unified Entities]
I --> J[Person Entity @id]
I --> K[WebSite Entity @id]
I --> L[Blog Entity @id]
I --> M[Organization Entities @id]
C --> N[Page-Specific Schema]
D --> N
E --> N
F --> N
G --> N
N --> O{References Unified Entities}
J --> O
K --> O
L --> O
M --> O
O --> P[Complete JSON-LD]
P --> Q[Embedded in HTML head]
Q --> R[Search Engine Indexing]
Schema Selection Logic (in seo.html):
{% include unified-knowledge-graph-schema.html %}
{% if page.schema_type == 'TechArticle' %}
{% include tech-article-schema.html %}
{% elsif page.schema_type == 'AnalysisNewsArticle' %}
{% include analysis-article-schema.html %}
{% elsif page.schema_type == 'HowTo' %}
{% include how-to-schema.html %}
{% elsif page.layout == "single" and page.date %}
{% include post-schema.html %}
{% endif %}
{% include about-page-schema.html %}
{% include breadcrumb-schema.html %}
{% include webpage-schema.html %}Entity Reference Pattern:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://www.aledlie.com#person",
"name": "Alyshia Ledlie"
},
{
"@type": "BlogPosting",
"@id": "https://www.aledlie.com/posts/example#blogposting",
"author": {
"@id": "https://www.aledlie.com#person"
},
"publisher": {
"@id": "https://www.aledlie.com#person"
}
}
]
}Key Benefits:
- Unified Entities: Person, WebSite, Blog, Organizations defined once in
unified-knowledge-graph-schema.html - @id References: Page-specific schemas reference unified entities via
@id(no duplication) - Scalability: Add new pages without redefining core entities
- SEO: Search engines understand entity relationships across site
Path: Page Interaction → GTM → GA4 → Analytics Dashboard
graph LR
A[User Page View] --> B[GTM Container Loads]
B --> C[GTM Tag Manager]
C --> D{Event Type?}
D -->|Page View| E[GA4 Pageview Event]
D -->|Link Click| F[GA4 Click Event]
D -->|Scroll| G[GA4 Engagement Event]
E --> H[Google Analytics 4]
F --> H
G --> H
H --> I[Analytics Dashboard]
I --> J[Reports & Insights]
Implementation Details:
-
GTM Initialization (in default.html):
<body> {% include _google_tag_manager.html %} <!-- Rest of page --> </body>
-
GTM Configuration:
- Container ID:
GTM-TK5J8L38 - Tracking ID:
G-J7TL7PQH7S - Anonymous IP: Enabled for privacy
- Container ID:
-
Event Tracking:
- Automatic pageviews
- Custom events (defined in GTM)
- E-commerce tracking (if applicable)
- User interactions
-
Data Privacy:
- Do Not Track respect
- Anonymous IP collection
- GDPR compliance ready
Testing:
- Unit tests:
/tests/analytics/ - E2E tests:
/tests/e2e/analytics.spec.js - Validates GTM loading, tracking code presence, event firing
Path: Source Files → Jekyll Build → _site Output → GitHub Pages Deployment
graph TD
A[Source Files] --> B[Jekyll Build Process]
B --> C[Read _config.yml]
B --> D[Process Collections]
B --> E[Compile SCSS]
B --> F[Apply Layouts]
B --> G[Generate Sitemap]
C --> H[Site Variables]
D --> I[Posts, Projects, Reports]
E --> J[main.css]
F --> K[HTML Pages]
G --> L[sitemap.xml]
H --> M[_site/ Directory]
I --> M
J --> M
K --> M
L --> M
M --> N[GitHub Actions Build]
N --> O{Environment}
O -->|Production| P[Set JEKYLL_ENV=production]
P --> Q[Build Command]
Q --> R[bundle exec jekyll build]
R --> S[Upload Pages Artifact]
S --> T[Deploy to GitHub Pages]
T --> U[Live Site]
Build Configuration (.github/workflows/jekyll.yml):
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4.1'
bundler-cache: true
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build with Jekyll
run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
env:
JEKYLL_ENV: production
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
deploy:
environment:
name: github-pages
needs: build
steps:
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4Build Phases:
-
Dependency Installation
bundle install --deployment- Installs Ruby gems from Gemfile.lock
- Required gems: Jekyll 4.3, theme, plugins
-
SCSS Compilation
- Source:
assets/css/main.scss - Imports:
_sass/variables.scss,_sass/minimal-mistakes.scss - Output:
_site/assets/css/main.css(compressed)
- Source:
-
Content Processing
- Posts from
_posts/ - Collections from
_projects/,_reports/,_work/ - Pages from root and subdirectories
- Posts from
-
Asset Copying
- Images from
assets/images/ - JavaScript from
assets/js/ - Fonts and other static assets
- Images from
-
Output Generation
- All files written to
_site/ - Clean URLs enabled
- Trailing slashes added
- All files written to
Path: SCSS/JS Sources → Compilation → Optimized Assets → GitHub Pages
graph LR
A[assets/css/main.scss] --> B[Jekyll SCSS Compiler]
B --> C[Import _sass Partials]
C --> D[Compile to CSS]
D --> E[Compress]
E --> F[_site/assets/css/main.css]
G[assets/js/*.js] --> H[Copy to _site]
H --> I[_site/assets/js/]
F --> J[GitHub Pages CDN]
I --> J
J --> K{Cache Headers}
K -->|GitHub Default| L[Static Assets]
K -->|Dynamic| M[HTML Pages]
SCSS Architecture:
assets/css/main.scss
├── @import "variables"
│ └── _sass/variables.scss (Color definitions, font stacks, spacing)
├── @import "minimal-mistakes"
│ └── _sass/minimal-mistakes.scss (Theme base + local overrides)
│ └── _sass/minimal-mistakes/*.scss (footer, navigation, search, sidebar, syntax, tables)
└── Custom overrides (inline in main.scss)
├── Global typography (16px base, 1.7 line-height)
├── Header (compact 100px cover images)
├── Navigation (centered, uppercase PT Sans Narrow)
├── Sidebar (academic profile layout)
├── Content (1200px max-width)
└── Post lists (clean, minimal styling)
JavaScript Assets:
assets/js/
├── scripts.min.js # Main bundled scripts (fitvids, magnificPopup)
├── email-obfuscation.js # Security script for email protection
├── csrf-protection.js # CSRF token handling
└── vendor/
├── jquery-3.7.1.min.js # jQuery fallback
└── glightbox.min.js # Lightbox library
Optimization Strategy:
-
SCSS Compression
style: compressedin_config.yml- Minifies output CSS
-
Cache Strategy (GitHub Pages)
- Static assets cached via GitHub's CDN
- HTML: Dynamic (no long-term cache)
- Automatic cache invalidation on deploy
-
CDN Distribution
- GitHub Pages CDN
- Global distribution
- Automatic HTTPS via custom domain
compress.html (Base - HTML compression)
↓
default.html (Core structure - head, body, footer)
↓
┌───────────────┴──────────────┐
│ │
archive.html single.html
↓ │
┌───┴───┐ │
│ │ │
home post-index └─→ Individual posts and pages
Layout Responsibilities:
-
compress.html
- HTML minification
- Whitespace removal
- Base HTML5 structure
-
default.html
<head>with SEO, schema, analytics<body>structure- Masthead (navigation)
- Footer
- Script includes
-
archive.html
- Base archive layout
- Sidebar inclusion
- Archive container
-
home.html (extends archive)
- Recent posts display
- Pagination
- Recent posts with pagination
-
post-index.html (extends archive)
- Posts grouped by year
- Archive subtitle
-
single.html (extends default)
- Page hero (header image)
- Article structure
- Author profile
- Table of contents (if enabled)
- Post pagination
- Comments (if enabled)
- Related posts
-
collection.html
- For projects, reports, work collections
- Grid or list display
Layout Selection (Front Matter):
---
layout: single # Triggers _layouts/single.html
---Default Layouts (_config.yml):
defaults:
- scope:
path: ""
type: posts
values:
layout: single
show_date: true
author_profile: true
- scope:
path: ""
type: pages
values:
layout: single
show_date: false_includes/
├── Core Partials
│ ├── _head.html → SEO, meta tags, CSS
│ ├── masthead.html → Navigation bar
│ ├── sidebar.html → Author profile, TOC
│ ├── footer/ → Site footer (custom.html)
│ └── _scripts.html → JavaScript loading
│
├── Schema.org (Structured Data)
│ ├── unified-knowledge-graph-schema.html (Core entities)
│ ├── post-schema.html (BlogPosting)
│ ├── tech-article-schema.html (TechArticle)
│ ├── analysis-article-schema.html (AnalysisNewsArticle)
│ ├── how-to-schema.html (HowTo)
│ ├── about-page-schema.html (Person/ProfilePage)
│ ├── breadcrumb-schema.html (BreadcrumbList)
│ └── webpage-schema.html (WebPage)
│
├── Analytics
│ ├── _google_tag_manager.html (GTM container)
│ └── _facebook_pixel.html (Facebook tracking)
│
├── SEO & Metadata
│ ├── seo.html (Meta tags, OG, Twitter cards, schema orchestration)
│ └── breadcrumbs.html (Breadcrumb navigation - disabled by default)
│
└── Content Components
├── author-profile.html (Sidebar author info)
├── page__hero.html (Header image)
├── paginator.html (Pagination controls)
├── page__meta.html (Post metadata)
└── post_pagination.html (Previous/Next links)
Include Execution Flow:
default.html loads:
├── _head.html
│ └── seo.html
│ ├── unified-knowledge-graph-schema.html
│ └── [Conditional page-specific schema]
├── masthead.html
│ └── _navigation.html (renders _data/navigation.yml)
├── [Layout content (single, archive, etc.)]
├── footer/custom.html
└── _scripts.html
single.html loads (in addition to default):
├── page__hero.html (if header image)
├── sidebar.html
│ └── author-profile.html
├── page__meta.html (date, reading time)
├── page__taxonomy.html (categories, tags)
└── post_pagination.html (prev/next)
Path: _data/navigation.yml → masthead.html → Rendered Nav
graph LR
A[_data/navigation.yml] --> B[masthead.html Include]
B --> C{Render Nav Items}
C --> D[Main Navigation Links]
C --> E[External Links]
D --> F[Internal URLs]
E --> F
F --> G[<nav> HTML Element]
G --> H[CSS Styling]
H --> I[Centered Uppercase Menu]
Navigation Configuration:
# _data/navigation.yml
main:
- title: "About"
url: /about/
- title: "Blog"
url: /posts
- title: "Sumedh's Site"
url: https://www.sumedhmjoshi.com # External linkRendering Logic:
{% for link in site.data.navigation.main %}
<a href="{{ link.url | relative_url }}">
{{ link.title }}
</a>
{% endfor %}Styling (main.scss):
.greedy-nav {
font-family: $heading-font;
text-transform: uppercase;
text-align: center;
a {
color: $white;
&:hover {
color: $gray-medium;
}
}
}Philosophy: Define core entities once, reference everywhere via @id.
┌────────────────────────────────────────────────────────┐
│ unified-knowledge-graph-schema.html │
│ (Loaded on EVERY page via seo.html) │
├────────────────────────────────────────────────────────┤
│ Core Entities (with @id): │
│ • Person (@id: https://www.aledlie.com#person) │
│ • WebSite (@id: https://www.aledlie.com#website) │
│ • Blog (@id: https://www.aledlie.com#blog) │
│ • Organization - Integrity Studios │
│ • Organization - InventoryAI │
└────────────────────────────────────────────────────────┘
▲
│ References via @id
│
┌────────────────────────┴───────────────────────────────┐
│ Page-Specific Schemas │
├─────────────────────────────────────────────────────────┤
│ • BlogPosting (references Person, Blog) │
│ • TechArticle (references Person) │
│ • AnalysisNewsArticle (references Person) │
│ • HowTo (references Person) │
│ • ProfilePage (references Person) │
│ • BreadcrumbList (references WebPage) │
└─────────────────────────────────────────────────────────┘
Entity Reference Example:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://www.aledlie.com#person",
"name": "Alyshia Ledlie",
"worksFor": [
{ "@id": "https://www.aledlie.com/organizations/integrity-studios#organization" },
{ "@id": "https://www.aledlie.com/organizations/inventoryai#organization" }
]
},
{
"@type": "Organization",
"@id": "https://www.aledlie.com/organizations/integrity-studios#organization",
"name": "Integrity Studios",
"founder": { "@id": "https://www.aledlie.com#person" }
}
]
}Benefits:
- No Duplication: Person entity defined once, not repeated on every page
- Bidirectional Relationships: Person → worksFor → Organization → founder → Person
- Knowledge Graph: Search engines understand entity relationships
- Scalability: Add new entities without modifying existing schemas
- SEO: Enhanced rich results, knowledge panel eligibility
Page Render
↓
seo.html Include
↓
┌─────────────────────────────────────────┐
│ ALWAYS: unified-knowledge-graph-schema │
│ (Person, WebSite, Blog, Organizations) │
└─────────────────────────────────────────┘
↓
Check page.schema_type
↓
├─→ "TechArticle" → tech-article-schema.html
├─→ "AnalysisNewsArticle" → analysis-article-schema.html
├─→ "HowTo" → how-to-schema.html
└─→ Default + page.date → post-schema.html
↓
Check page.url
↓
├─→ Contains "/about" → about-page-schema.html
└─→ Other pages → webpage-schema.html
↓
Check breadcrumbs_enabled
↓
└─→ True → breadcrumb-schema.html
↓
Final JSON-LD embedded in <head>
Implementation (seo.html):
<!-- Unified entities (ALWAYS included) -->
{% include unified-knowledge-graph-schema.html %}
<!-- Conditional page-specific schemas -->
{% if page.schema_type == 'TechArticle' %}
{% include tech-article-schema.html %}
{% elsif page.schema_type == 'AnalysisNewsArticle' %}
{% include analysis-article-schema.html %}
{% elsif page.schema_type == 'HowTo' %}
{% include how-to-schema.html %}
{% elsif page.layout == "single" and page.date %}
{% include post-schema.html %}
{% endif %}
<!-- Conditional supplementary schemas -->
{% include about-page-schema.html %}
{% include breadcrumb-schema.html %}
{% include webpage-schema.html %}Standard Blog Post:
---
layout: single
title: "Post Title"
date: 2025-11-17
categories: [Technology]
tags: [jekyll, blogging]
# No schema_type = BlogPosting (default)
---Technical Article:
---
layout: single
title: "How to Deploy Jekyll to Vercel"
date: 2025-11-17
schema_type: TechArticle
schema_dependencies: "Ruby 3.x, Bundler, Git"
schema_proficiency: "Intermediate"
schema_section: "Jekyll"
---Analysis Article:
---
layout: single
title: "Performance Analysis: Wix vs Custom"
date: 2025-11-17
schema_type: AnalysisNewsArticle
schema_about: "Web Performance Optimization"
schema_dateline: "Web Development, November 2025"
schema_backstory: "Based on 3 months of production data"
---How-To Guide:
---
layout: single
title: "How to Set Up Jekyll Analytics"
date: 2025-11-17
schema_type: HowTo
schema_total_time: "PT30M"
schema_estimated_cost: "0"
schema_cost_currency: "USD"
schema_tools:
- "Google Analytics account"
- "GTM container"
schema_steps:
- name: "Step 1: Create GTM container"
text: "Set up Google Tag Manager container..."
- name: "Step 2: Configure Jekyll"
text: "Add GTM ID to _config.yml..."
---Documentation: See docs/schema/IMPLEMENTATION-GUIDE.md for complete guide.
┌─────────────────────────────────────────────────────────┐
│ UNIT TESTS (Jest) │
│ Purpose: Test JavaScript functions in isolation │
│ Location: tests/unit/ │
│ Coverage: assets/js/**/*.js │
│ Environment: jsdom │
└─────────────────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ E2E TESTS (Playwright) │
│ Purpose: Test full user workflows across browsers │
│ Location: tests/e2e/ │
│ Browsers: Chrome, Firefox, Safari, Mobile │
│ Features: Accessibility, Navigation, Analytics │
└─────────────────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ PERFORMANCE TESTS (Lighthouse) │
│ Purpose: Validate Core Web Vitals and SEO │
│ Location: tests/performance/ │
│ Thresholds: Performance ≥85%, A11y ≥95%, SEO ≥95% │
│ Metrics: LCP, FID, CLS, FCP, TTI │
└─────────────────────────────────────────────────────────┘
graph TD
A[npm run test:all] --> B[Jekyll Build]
B --> C[Unit Tests - Jest]
C --> D{Tests Pass?}
D -->|No| E[Fail Build]
D -->|Yes| F[E2E Tests - Playwright]
F --> G[Start Jekyll Server]
G --> H[Run E2E Specs]
H --> I{E2E Pass?}
I -->|No| E
I -->|Yes| J[Performance Tests - Lighthouse]
J --> K[Run Lighthouse Audits]
K --> L{Meet Thresholds?}
L -->|No| E
L -->|Yes| M[All Tests Pass]
Configuration (package.json):
{
"jest": {
"testEnvironment": "jsdom",
"setupFilesAfterEnv": ["<rootDir>/tests/setup.js"],
"testMatch": ["<rootDir>/tests/**/*.test.js"],
"collectCoverageFrom": [
"assets/js/**/*.js",
"!assets/js/vendor/**",
"!node_modules/**"
]
}
}Test Structure:
// tests/unit/site-functionality.test.js
describe('Site Functionality', () => {
test('Email obfuscation works', () => {
// Test email-obfuscation.js
});
test('CSRF protection initializes', () => {
// Test csrf-protection.js
});
});Commands:
npm run test # Run tests once
npm run test:watch # Watch mode for development
npm run test:ci # CI mode with coverageConfiguration (config/playwright.config.js):
module.exports = defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
use: {
baseURL: 'http://localhost:4000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'chromium', use: devices['Desktop Chrome'] },
{ name: 'firefox', use: devices['Desktop Firefox'] },
{ name: 'webkit', use: devices['Desktop Safari'] },
{ name: 'Mobile Chrome', use: devices['Pixel 5'] },
{ name: 'Mobile Safari', use: devices['iPhone 12'] },
],
webServer: {
command: 'npm run serve',
url: 'http://localhost:4000',
reuseExistingServer: !process.env.CI,
},
});Test Suites:
-
Accessibility (accessibility.spec.js)
- Axe-core integration
- WCAG 2.1 compliance
- Color contrast checks
- Keyboard navigation
-
Navigation (site-navigation.spec.js)
- Menu rendering
- Link functionality
- Mobile responsive nav
-
Analytics (analytics.spec.js)
- GTM container loading
- Tracking code presence
- Event firing verification
- Data layer validation
Example Test:
// tests/e2e/accessibility.spec.js
test('Homepage is accessible', async ({ page }) => {
await page.goto('/');
const results = await new AxeBuilder({ page }).analyze();
expect(results.violations).toEqual([]);
});Commands:
npm run test:e2e # Run all E2E tests
npx playwright test --ui # Run with UI (debugging)
npx playwright test --project=chromium # Specific browserConfiguration (config/lighthouserc.js):
module.exports = {
ci: {
collect: {
url: [
'http://localhost:4000/',
'http://localhost:4000/about/',
'http://localhost:4000/posts/',
'http://localhost:4000/projects/',
],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.85 }],
'categories:accessibility': ['error', { minScore: 0.95 }],
'categories:seo': ['error', { minScore: 0.95 }],
'categories:best-practices': ['error', { minScore: 0.90 }],
},
},
},
};Core Web Vitals Monitored:
- LCP (Largest Contentful Paint): < 2.5s
- FID (First Input Delay): < 100ms
- CLS (Cumulative Layout Shift): < 0.1
- FCP (First Contentful Paint): < 1.8s
- TTI (Time to Interactive): < 3.8s
Commands:
npm run test:performance # Run Lighthouse auditsOutput: Results saved to tests/performance/results/
Purpose: Ensure pixel-perfect consistency during refactoring.
Workflow:
# 1. Capture baseline screenshots
npm run test:visual-baseline
# 2. Make CSS/HTML changes
# 3. Run comparison
npm run test:visual
# 4. Review diffs in tests/visual/diffs/Zero-Tolerance Policy: ANY visual difference during refactoring is a bug.
Documentation: See docs/refactoring/VISUAL-REGRESSION-TESTING-QUICK-GUIDE.md
graph LR
A[Source Files] --> B[bundle install]
B --> C[bundle exec jekyll serve]
C --> D[Watch for Changes]
D --> E[Incremental Rebuild]
E --> F[http://localhost:4000]
F --> G[Browser LiveReload]
Commands:
# Install dependencies
bundle install
# Serve locally with live reload
RUBYOPT="-W0" bundle exec jekyll serve
# Build for production (local testing)
JEKYLL_ENV=production bundle exec jekyll buildDevelopment Features:
- Incremental Builds: Only rebuilds changed files
- LiveReload: Browser auto-refreshes on changes
- Draft Posts:
_drafts/directory for unpublished content - Future Posts: Posts dated in future not built (unless
--future)
graph TD
A[Git Push to master] --> B[GitHub Actions Trigger]
B --> C[Checkout Repository]
C --> D[Setup Ruby 3.4.1]
D --> E[bundle install - cached]
E --> F[Configure Pages]
F --> G[JEKYLL_ENV=production]
G --> H[bundle exec jekyll build]
H --> I[_site/ Output]
I --> J{Build Success?}
J -->|No| K[Build Failed - Check Logs]
J -->|Yes| L[Upload Pages Artifact]
L --> M[Deploy to GitHub Pages]
M --> N[Live at www.aledlie.com]
Deployment Configuration (.github/workflows/jekyll.yml):
name: Deploy Jekyll site to Pages
on:
push:
branches: ["master"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4.1'
bundler-cache: true
- uses: actions/configure-pages@v5
- run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}"
env:
JEKYLL_ENV: production
- uses: actions/upload-pages-artifact@v3
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/deploy-pages@v4Deployment Features:
- Automatic Triggers: Deploys on push to
masterbranch - Concurrency Control: Single deployment at a time, no cancellation
- Caching: Ruby gems cached for faster builds
- Custom Domain: Configured via CNAME file for www.aledlie.com
GitHub Pages Defaults:
- HTTPS: Automatic via custom domain
- CDN: GitHub's global CDN distribution
- Cache: Managed automatically by GitHub Pages
GitHub Actions (.github/workflows/jekyll.yml)
↓ (Environment variables, build commands)
Jekyll Configuration (_config.yml)
↓ (Site settings, defaults, plugins)
Minimal Mistakes Theme Defaults
↓ (Base styles, layouts, includes)
Custom Overrides (assets/css/main.scss)
↓ (Site-specific styling)
Page Front Matter
↓ (Page-level settings)
Final Rendered Page
- Theme Defaults - Minimal Mistakes base configuration
- _config.yml - Site-wide Jekyll settings
- Front Matter Defaults - Scoped defaults in
_config.yml - Page Front Matter - Individual page settings
- GitHub Actions Environment - Deployment-specific overrides
Example: Layout Selection
# _config.yml (Default for all posts)
defaults:
- scope:
path: ""
type: posts
values:
layout: single # Default layout
# _posts/example.md (Override for specific post)
---
layout: archive # Overrides default
---1. _config.yml (Jekyll Site Configuration)
# Core Settings
title: ℵ₀
url: https://www.aledlie.com
locale: en_US
encoding: utf-8
# Theme
theme: minimal-mistakes-jekyll
minimal_mistakes_skin: "contrast"
# Collections
collections:
projects:
output: true
permalink: /:collection/:path/
reports:
output: true
permalink: /:collection/:path/
work:
output: true
permalink: /work/:path/
# Pagination
paginate: 8
paginate_path: /page:num/
# Plugins
plugins:
- jekyll-feed
- jekyll-paginate
- jekyll-sitemap
- jekyll-seo-tag
# Analytics
analytics:
provider: "google-gtag"
google:
tracking_id: "G-J7TL7PQH7S"
anonymize_ip: true2. .github/workflows/jekyll.yml (Deployment Configuration)
# Build and deploy Jekyll site to GitHub Pages
on:
push:
branches: ["master"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4.1'
bundler-cache: true
- run: bundle exec jekyll build
env:
JEKYLL_ENV: production3. Gemfile (Ruby Dependencies)
source "https://rubygems.org"
gem "jekyll", "~> 4.3"
gem "minimal-mistakes-jekyll"
# Compatibility gems for Ruby 3.4.4
gem "csv"
gem "logger"
gem "webrick"
gem "base64"
# Jekyll plugins (52 gems total after cleanup)
gem "jekyll-feed"
gem "jekyll-paginate"
gem "jekyll-sitemap"
gem "jekyll-seo-tag"
gem "jekyll-gist"
gem "jekyll-include-cache"
gem "jekyll-sass-converter", "~> 3.0"4. package.json (Node.js Dependencies)
{
"scripts": {
"build": "bundle exec jekyll build",
"serve": "bundle exec jekyll serve",
"test": "jest",
"test:e2e": "playwright test --config config/playwright.config.js",
"test:performance": "node tests/performance/lighthouse.js",
"test:performance:clean": "find tests/performance/results -name '*.json' | sort | head -n -3 | xargs rm -f",
"test:all": "npm run build && npm run test && npm run test:e2e && npm run test:performance",
"lint:scss": "stylelint '**/*.scss' --config config/stylelintrc.json"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
"jest": "^30.2.0",
"lighthouse": "^12.8.2",
"stylelint": "^16.23.1"
}
}Collections
├── _projects/
│ Purpose: Portfolio and project showcase
│ Permalink: /:collection/:path/
│ Output: true (generates HTML pages)
│ Use Case: Permanent work, completed projects
│
├── _reports/
│ Purpose: Technical case studies and analysis
│ Permalink: /:collection/:path/
│ Output: true
│ Use Case: Completed investigations, technical reports
│
└── _work/
Purpose: Work-in-progress and activity summaries
Permalink: /work/:path/
Output: true
Use Case: Ongoing work, git activity reports, current projects
graph TD
A[Collection File] --> B[Read Front Matter]
B --> C[Apply Collection Defaults]
C --> D[Select Layout]
D --> E{Collection Type?}
E -->|_projects| F[collection.html layout]
E -->|_reports| F
E -->|_work| F
F --> G[Render with Collection Metadata]
G --> H[Generate Permalink]
H --> I[Output to _site/]
Collection Front Matter Example:
---
# _projects/my-project.md
title: "My Project"
excerpt: "Brief description"
header:
image: /assets/images/project-header.jpg
teaser: /assets/images/project-teaser.jpg
---
Project content here...Output: _site/projects/my-project/index.html
Listing Collections:
<!-- List all projects -->
{% for project in site.projects %}
<h2>{{ project.title }}</h2>
<p>{{ project.excerpt }}</p>
<a href="{{ project.url }}">View Project</a>
{% endfor %}- Layout Inheritance: Hierarchical layout system (compress → default → archive/single)
- Unified Schema: Single knowledge graph with @id references
- Modular Includes: Reusable partials for navigation, schema, analytics
- Three-Layer Testing: Unit (Jest), E2E (Playwright), Performance (Lighthouse)
- Configuration Cascade: GitHub Actions → Jekyll → Theme → Front Matter
- Asset Pipeline: SCSS compilation with custom overrides
- Collections Architecture: Projects, Reports, Work with custom permalinks
- Content Flow: Markdown → Jekyll → Layouts → Includes → HTML
- Schema Flow: Front Matter → Schema Selection → Unified Graph → JSON-LD
- Analytics Flow: Page View → GTM → GA4 → Dashboard
- Build Flow: Source → Jekyll Build → _site → GitHub Pages
- Asset Flow: SCSS/JS → Compilation → Optimization → CDN Cache
- Minimal Duplication: DRY principle for schemas, layouts, includes
- Progressive Enhancement: Core content accessible, enhancements layer on
- Performance First: Optimized assets, aggressive caching, Core Web Vitals
- SEO Optimized: Schema.org, semantic HTML, clean URLs
- Testing Rigor: Comprehensive test coverage across all layers
- Project Instructions:
/CLAUDE.md- Main development guide - Schema Guide:
docs/schema/IMPLEMENTATION-GUIDE.md - Setup Guides:
docs/setup/- Local development setup - Changelog:
docs/CHANGELOG.md- Change history
Last Updated: 2026-03-17 For: The Parlor (www.aledlie.com) Maintainer: Alyshia Ledlie