Files
cv-site/PROJECT-MEMORY.md
T
juanatsap 5d5b050029 feat: confirm no hyperscript def limit + update documentation
MAJOR FINDING: Latest hyperscript version has NO 3 def statement limit!

Test Results (tests/mjs/9-hyperscript-def-limit.test.mjs):
 1 def statement - PASS
 2 def statements - PASS
 3 def statements - PASS
 4 def statements - PASS (beyond historical limit)
 5 def statements - PASS (well beyond limit)

Changes:
1. Created comprehensive def limit test
   - tests/mjs/9-hyperscript-def-limit.test.mjs
   - Tests 1, 2, 3, 4, 5 def statements
   - Verifies both parsing and function execution
   - Provides detailed analysis and recommendations

2. Updated PROJECT-MEMORY.md
   - Section 2: Changed from "NEEDS RETESTING" to "REMOVED IN LATEST VERSION"
   - Documented test findings and historical context
   - Added migration plan for hyperscript file organization
   - Updated test count to 10 systematic tests

3. Updated doc/HYPERSCRIPT-RULES.md
   - Rule 2: Removed 3 def limit warning
   - Documented historical context (Hyperscript 0.9.12 had limit)
   - New best practice: Organize by category in separate files
   - Added recommended file structure

Impact:
- Can now use unlimited def statements in hyperscript
- Enables cleaner architecture with category-based organization
- Allows migration from cv-functions.js back to hyperscript
- Better alignment with hypermedia/server-driven pattern

Next Steps:
- Create organized hyperscript file structure
- Migrate toggle functions from JavaScript to hyperscript
- Migrate hover sync functions to hyperscript
- Test each migration thoroughly
2025-11-17 15:02:30 +00:00

17 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 (REMOVED IN LATEST VERSION )

CONFIRMED: NO 3 def statement limit with latest hyperscript version

Test Results (2025-11-17): Test 9 (tests/mjs/9-hyperscript-def-limit.test.mjs) confirmed:

  • 1 def statement works
  • 2 def statements work
  • 3 def statements work
  • 4 def statements work (beyond historical limit)
  • 5 def statements work (well beyond limit)

Historical Context:

  • Hyperscript 0.9.12 had a hard 3 def limit
  • Latest hyperscript version removed this limitation
  • Functions were moved to JavaScript as workaround
  • Now migrating back to hyperscript for cleaner architecture

Current Best Practice: Organize hyperscript functions by category in separate files

static/hyperscript/
├── toggles._hs        # Toggle functions (CV length, icons, theme)
├── hover-sync._hs     # Hover synchronization functions
└── utils._hs          # Utility functions (keyboard shortcuts, etc.)

Migration in progress: Moving functions from cv-functions.js back to hyperscript

Test that verifies no limit: tests/mjs/9-hyperscript-def-limit.test.mjs

Reference: doc/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 + integrity
├── 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
└── 9-hyperscript-def-limit.test.mjs # Def statement limit verification

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 - Migrating to hyperscript architecture Test Coverage: 10 systematic tests, 100% core features + def limit verification Critical Memory Files: This file + ~/.claude/cv-icons-migration.md