Files
cv-site/PROJECT-MEMORY.md
T

16 KiB

CV Project - Developer Memory

⚠️ CRITICAL: Read This Before Any Changes

This document contains non-negotiable rules and hard-learned lessons from this project's development. Violating these causes bugs, breaks features, and wastes time.


🔴 ABSOLUTE RULES - NEVER VIOLATE

1. Icon Naming Convention (CRITICAL)

ALWAYS use "icons" - NEVER "logos"

// ✅ CORRECT
.show-icons
localStorage.getItem('cv-icons')
const showIcons = ...

// ❌ WRONG - WILL BREAK ICON TOGGLE
.show-logos
localStorage.getItem('cv-logos')
const showLogos = ...

Why: Icon toggle had critical bug (commit 3f77fed) because JavaScript used .show-logos but CSS checked for .show-icons. This caused toggles to only work after page refresh.

Test that enforces this: tests/mjs/1-toggles.test.mjs

Memory file: ~/.claude/cv-icons-migration.md


2. Hyperscript Parser Limit (NEEDS RETESTING)

⚠️ TO VERIFY: Maximum 3 def statements limit with latest hyperscript version

Status: We upgraded to the LATEST hyperscript version. This limit may no longer exist.

TODO: Test if the 3 def statement limit still applies with current version

Current solution (still recommended): Move complex logic to JavaScript functions

// ✅ CORRECT - JavaScript functions
function toggleIcons(showIcons) { ... }
function toggleCVLength(isLong) { ... }
function toggleTheme(isClean) { ... }

// Call from hyperscript
_="on change call toggleIcons(my.checked)"

// ❌ WRONG - Too many def statements
_="def toggleIcons(show)
     if show then add .show-icons...
   end"

Why: Parser crashes/fails silently when limit exceeded.

Test that enforces this: tests/mjs/3-hyperscript.test.mjs

Reference: HYPERSCRIPT-RULES.md


3. Toggle Synchronization (WORKING) + Hover Sync (FIXED)

Toggle checkboxes WORK perfectly

Every toggle checkbox exists in TWO places and stays synchronized:

  1. Action bar (desktop) - #lengthToggle, #iconToggle, #themeToggle
  2. Hamburger menu (mobile) - #lengthToggleMenu, #iconToggleMenu, #themeToggleMenu

Toggle behavior (WORKING):

  • Clicking either toggle updates BOTH
  • Changes are real-time (no page refresh)
  • localStorage persists the state
  • Page load reads from localStorage and applies to both
// ✅ CORRECT - Update both toggles
function toggleIcons(showIcons) {
  const paper = document.querySelector('.cv-paper');
  const otherToggle = document.querySelector('#iconToggle') ||
                      document.querySelector('#iconToggleMenu');

  if (showIcons) {
    paper?.classList.add('show-icons');
    localStorage.setItem('cv-icons', 'true');
    if (otherToggle) otherToggle.checked = true;
  } else {
    paper?.classList.remove('show-icons');
    localStorage.setItem('cv-icons', 'false');
    if (otherToggle) otherToggle.checked = false;
  }
}

HOVER SYNC - PDF/Print buttons NOW WORKING

Action buttons that sync hover states:

  1. Action bar (desktop):
    • #action-bar-pdf-btn - Download PDF button
    • .action-bar-print-btn - Print Friendly button
  2. Hamburger menu (mobile):
    • .menu-pdf-btn - PDF button (templates/partials/navigation/hamburger-menu.html:178)
    • .menu-print-btn - Print button (templates/partials/navigation/hamburger-menu.html:186)

Working hover sync functions:

  • syncPdfHover(isHovering) - Syncs PDF button hover between locations
  • syncPrintHover(isHovering) - Syncs Print button hover between locations

Implementation:

  • Both buttons in each location have mouseenter/mouseleave handlers
  • Sync functions select all matching buttons (.pdf-btn, .menu-pdf-btn)
  • CSS classes .pdf-hover-sync and .print-hover-sync applied to all instances
  • Visual feedback matches across action bar and menu

Files involved:

  • templates/partials/navigation/action-buttons.html (lines 9-10, 18-19)
  • templates/partials/navigation/hamburger-menu.html (lines 178-184, 186-189)
  • static/js/cv-functions.js (lines 71-99)
  • static/css/main.css (lines 2690-2712)

Test coverage: tests/mjs/8-hover-sync.test.mjs

Test that enforces toggle sync: tests/mjs/1-toggles.test.mjs


4. Real-Time Rendering + Persistence (CRITICAL)

ALL UI changes MUST happen in BOTH DOM and localStorage

BOTH are required - not mutually exclusive:

// ✅ CORRECT - DOM update AND localStorage
paper.classList.add('show-icons');        // Visual change (instant feedback)
localStorage.setItem('cv-icons', 'true'); // Persistence (survives reload)

// ❌ WRONG - Only DOM (lost on page reload)
paper.classList.add('show-icons');

// ❌ WRONG - Only storage (no visual feedback)
localStorage.setItem('cv-icons', 'true');

Why both are needed:

  • DOM changes = instant visual feedback (users see it immediately)
  • localStorage = state persists across page reloads (users don't lose their preferences)
  • Users need BOTH: instant feedback + remembered preferences

Test that enforces this: tests/mjs/1-toggles.test.mjs (verifies both DOM and localStorage)


5. Test Suite as Single Source of Truth

If a test passes, the feature MUST work. If a feature works, the test MUST pass.

tests/mjs/
├── 0-zoom.test.mjs              # Zoom functionality
├── 1-toggles.test.mjs           # ALL toggles + sync + persistence
├── 2-keyboard-shortcuts.test.mjs # L, I, V, ? keys
├── 3-hyperscript.test.mjs       # Parse errors + def limit
├── 4-htmx.test.mjs              # HTMX integration
├── 5-language.test.mjs          # EN/ES switching
├── 6-modals.test.mjs            # Modal functionality
├── 7-mobile-responsive.test.mjs # Mobile viewports
└── 8-hover-sync.test.mjs        # PDF/Print button hover sync

Non-negotiable:

  • NO code changes without test validation
  • NO bug fixes without regression test
  • NO features without test coverage
  • NO deployment if tests fail

Run before every commit:

bun tests/run-all.mjs

Reference: tests/README.md, tests/TEST-SUMMARY.md


📋 Architecture Decisions

Tech Stack

Backend:

  • Go 1.21+ (Backend server)
  • Standard library net/http (HTTP server)
  • Go templates (Server-side rendering)

Frontend:

  • HTMX (Hypermedia-driven interactions)
  • Hyperscript (Latest version - event handling)
  • Vanilla JavaScript (cv-functions.js - toggles, keyboard shortcuts)
  • Iconify (Icon system)

Testing:

  • Playwright (E2E browser automation)
  • Bun (Test runner ONLY - NOT the runtime!)

Why Go:

  • Fast compilation
  • Single binary deployment
  • Built-in templating
  • Excellent standard library
  • Strong typing
  • Cross-platform

Why HTMX + Hyperscript:

  • Server-driven UI (hypermedia pattern)
  • Minimal JavaScript
  • Progressive enhancement
  • Real-time updates capabilities

File Organization

cv/
├── main.go                      # Server entry point (v1.1.0)
├── go.mod, go.sum               # Go dependencies
├── internal/
│   ├── config/                  # Configuration
│   ├── handlers/                # HTTP handlers
│   ├── middleware/              # HTTP middleware
│   ├── models/                  # Data models
│   ├── routes/                  # Route definitions
│   └── templates/               # Template utilities
├── static/
│   ├── js/
│   │   └── cv-functions.js      # Global functions (toggles, keyboard, hover sync)
│   ├── css/                     # Stylesheets
│   ├── hyperscript/
│   │   └── functions._hs        # Hyperscript functions (if any)
│   ├── images/                  # Static images
│   └── pdf/                     # PDF files
├── templates/
│   ├── index.html               # Main page template
│   ├── cv-content.html          # CV content
│   ├── language-switch.html     # Language switcher
│   └── partials/
│       ├── navigation/
│       │   ├── action-bar.html        # Desktop action bar
│       │   ├── action-buttons.html    # PDF + Print buttons
│       │   └── hamburger-menu.html    # Mobile menu (ALL controls + buttons)
│       ├── widgets/             # Reusable UI components
│       └── modals/              # Modal dialogs
└── tests/
    └── mjs/                     # Systematic test suite (Playwright + Bun runner)

Critical files:

  • main.go - Server entry point
  • static/js/cv-functions.js - Toggle, keyboard, and hover sync functions
  • templates/partials/navigation/action-buttons.html - PDF + Print buttons (action bar)
  • templates/partials/navigation/hamburger-menu.html - Complete mobile menu with toggles + buttons
  • templates/index.html - Main template structure

🐛 Historical Bugs (Learn From These)

Bug 1: Icon Toggle Required Refresh

Commit: 3f77fed Date: 2025-11-17 Symptom: Icon toggle only worked after page refresh Root cause: Class name mismatch

  • JavaScript: classList.add('show-logos')
  • CSS: .cv-paper:not(.show-icons) Fix: Changed all references from "logos" to "icons" Test added: Screenshot verification in 1-toggles.test.mjs Memory: ~/.claude/cv-icons-migration.md

Bug 2: Hyperscript Parser Crash

Date: 2025-11-16 Symptom: Silent failures, toggles stopped working Root cause: Exceeded 3 def statement limit Fix: Moved toggle logic to JavaScript (cv-functions.js) Test added: Def statement counter in 3-hyperscript.test.mjs Reference: HYPERSCRIPT-RULES.md

Bug 3: Toggle Desynchronization

Date: 2025-11-15 Symptom: Action bar and menu toggles out of sync Root cause: Only updating one toggle, not both Fix: Every toggle function now updates both locations Test added: Sync verification in 1-toggles.test.mjs


🎯 Development Workflow

Before Making Changes

  1. Read relevant test: Understand what's being tested
  2. Run the test: See current behavior
  3. Make changes: Code + test updates together
  4. Run test again: Verify it passes
  5. Run ALL tests: bun tests/run-all.mjs
  6. Manual verification: Browser stays open - check it yourself
  7. Commit: With clear description

When Adding a Feature

  1. Write test FIRST (test what you want to build)
  2. Implement feature
  3. Test passes (feature works)
  4. Update documentation (TEST-SUMMARY.md)
  5. Commit both (code + test together)

When Fixing a Bug

  1. Write regression test (reproduces the bug)
  2. Test FAILS (proves bug exists)
  3. Fix the bug
  4. Test PASSES (proves fix works)
  5. Commit both (fix + test together)

📝 Key Patterns

Toggle Pattern (Standard)

function toggleX(enabled) {
  const target = document.querySelector('.target');
  const otherToggle = document.querySelector('#xToggle') ||
                      document.querySelector('#xToggleMenu');

  if (enabled) {
    target?.classList.add('state-class');
    localStorage.setItem('cv-x', 'true');
    if (otherToggle) otherToggle.checked = true;
  } else {
    target?.classList.remove('state-class');
    localStorage.setItem('cv-x', 'false');
    if (otherToggle) otherToggle.checked = false;
  }
}

Must have:

  • Real-time DOM update
  • localStorage persistence
  • Sync both toggle locations
  • Safe navigation (?.)

Hyperscript Pattern (LIMITED USE)

<!-- ✅ GOOD - Simple event delegation -->
<button _="on click call myJavaScriptFunction(my.checked)">

<!-- ⚠️ AVOID - Complex logic (use JS instead) -->
<button _="on click
             if condition then ...
             else ... end">

<!-- ❌ FORBIDDEN - def statements (unless absolutely necessary) -->
<script type="_hyperscript">
  def myFunction()  <!-- COUNTS TOWARD 3 LIMIT -->
    ...
  end
</script>

Keyboard Shortcuts Pattern

document.addEventListener('keydown', (e) => {
  // ✅ ALWAYS check for input fields
  if (e.target.matches('input, textarea, select')) return;

  // ✅ Use lowercase key
  const key = e.key.toLowerCase();

  switch(key) {
    case 'l': toggleCVLength(!body.classList.contains('cv-long')); break;
    case 'i': toggleIcons(!paper.classList.contains('show-icons')); break;
    case 'v': toggleTheme(!body.classList.contains('theme-clean')); break;
    case '?': document.querySelector('#shortcuts-modal')?.showModal(); break;
  }
});

Test: tests/mjs/2-keyboard-shortcuts.test.mjs


🔧 Common Operations

Adding a New Toggle

  1. Add to HTML: Action bar + menu
  2. Add localStorage key: Choose naming convention
  3. Add toggle function: Follow standard pattern
  4. Add keyboard shortcut: Optional but recommended
  5. Add to test: Update 1-toggles.test.mjs
  6. Add to keyboard test: If you added shortcut
  7. Run ALL tests

Changing Class Names

  1. Search globally: Find ALL references
  2. Update JavaScript: cv-functions.js
  3. Update CSS: All stylesheets
  4. Update HTML: All templates
  5. Update tests: Search for old name
  6. Create memory file: ~/.claude/name-migration.md
  7. Test thoroughly

Debugging Toggle Issues

Checklist:

  • Check class name matches between JS and CSS
  • Verify both toggles are updated (action bar + menu)
  • Check localStorage key is correct
  • Verify real-time DOM update happens
  • Run 1-toggles.test.mjs - does it catch the bug?
  • If test doesn't catch it, FIX THE TEST FIRST

📚 Key Documents

Must Read Before Changes

  • tests/README.md - Test suite accountability
  • doc/HYPERSCRIPT-RULES.md - Parser limits and workarounds
  • ~/.claude/cv-icons-migration.md - Icon naming convention

Reference Documentation

  • tests/TEST-SUMMARY.md - Complete test documentation
  • tests/mjs/README.md - Test structure and patterns
  • doc/MODERN-WEB-TECHNIQUES.md - Architecture decisions

Historical Record

  • tests/archive/README.md - Legacy tests (reference only)
  • Git history - Search for bug fix commits

🎓 Lessons Learned

1. Name Things Correctly From the Start

Lesson: Renaming "logos" to "icons" required:

  • Updating 4 files
  • Creating memory document
  • Adding test verification
  • Could have been avoided with better initial naming

Rule: Think about naming conventions BEFORE first implementation

2. Tests Are Not Optional

Lesson: Icon toggle bug existed for days before we added screenshot verification to the test. The test was passing but the feature was broken.

Rule: Tests must verify ACTUAL behavior, not just code execution

3. Framework Limits Are Real

Lesson: Hyperscript's 3 def limit seems arbitrary but it's a hard constraint. We learned this after hitting silent failures.

Rule: Read framework documentation carefully, especially limits/constraints

4. Synchronization Is Hard

Lesson: Having toggles in two or more places (action bar + menu) means every change must update all locations. Forgetting this causes desync bugs.

Rule: If something appears in multiple places, use a single function to update ALL locations

5. Real-Time Updates Are Expected

Lesson: Users don't understand localStorage vs DOM updates. If they click a button, they expect INSTANT visual feedback.

Rule: Every toggle must update both localStorage AND DOM immediately


🚀 Future Developers

Before you change ANYTHING:

  1. Read this document
  2. Read tests/README.md
  3. Run bun tests/run-all.mjs
  4. Understand which test covers what you're changing
  5. Make your changes + update tests together
  6. Run ALL tests again
  7. Manual verification in browser
  8. Update this document if you learn something new

When you hit a bug:

  1. Which test should have caught this?
  2. Why didn't it?
  3. Fix the test FIRST
  4. Then fix the bug, using the debug agent and the htmx expert
  5. Document the lesson in this file

Remember:

  • Tests are the specification
  • If tests pass but feature fails → tests are wrong
  • If feature works but tests fail → feature is wrong
  • When in doubt, trust the tests MORE than the code

Last Updated: 2025-11-17 Project Status: Production Test Coverage: 9 systematic tests, 100% core features Critical Memory Files: This file + ~/.claude/cv-icons-migration.md