Skip to content

Latest commit

 

History

History
195 lines (153 loc) · 5.52 KB

File metadata and controls

195 lines (153 loc) · 5.52 KB

TheyOne PM — Development Guide

Architecture

┌─────────────────────────────────────────────┐
│  index.html                                 │
│  ┌──────────┐  ┌──────────┐  ┌───────────┐ │
│  │ <style>  │  │ HTML     │  │ <script>  │ │
│  │ CSS vars │  │ Structure│  │ Store     │ │
│  │ Layout   │  │ Modal    │  │ UI        │ │
│  │ Themes   │  │ Views    │  │ Events    │ │
│  └──────────┘  └──────────┘  └───────────┘ │
└─────────────────────────────────────────────┘

Pre-Commit Checklist

  • python3 validate.py — no structural px issues
  • python3 -c "compile(open('index.html').read())" — syntax passes
  • Open in browser — no console errors
  • Create/edit/delete task — data persists on reload
  • Switch all views — no crashes
  • Dark/light toggle works
  • Import/export works
  • Keyboard shortcuts all work

Fibonacci Rule

Only apply CSS variables --g1 through --g8 and --r-xs through --r-xl to spacing properties: padding, margin, gap, border-radius.

Never replace these with Fibonacci values:

  • max-width, min-width, width of containers/modals/inputs
  • height, min-height, max-height of layout elements
  • Canvas dimensions (width, height attributes on <canvas>)
  • z-index values
  • flex-basis or grid-template-columns structural values
  • line-height values (keep unitless or 1.5)
/* ✅ Correct */
padding: var(--g3) var(--g5);
gap: var(--g4);
border-radius: var(--r-md);

/* ❌ Wrong */
max-width: 34px;         /* was 700px, wrongly converted */
width: 34px;             /* was 200px, wrongly converted */
padding: 34px;            /* was 34px? no such thing */

Before running any automated conversion:

  1. Read this rule
  2. Add a comment in the conversion prompt: "DO NOT convert structural layout values (max-width, width, height, canvas dims)"
  3. After conversion, run python3 validate.py
  4. Manually review all 34px values

Code Conventions

Store Class (Data Layer)

  • All data mutations go through Store methods
  • Store.save() persists to IndexedDB + localStorage fallback
  • Store.audit(action, taskId, detail) logs every change
  • Never modify Store.state directly from UI code
// ✅ Correct
Store.updateTask(id, { status: 'done' });

// ❌ Wrong — bypasses audit/save
Store.state.tasks.find(t => t.id === id).status = 'done';
Store.save();

UI Class (View Layer)

  • All rendering goes through UI.render() → calls view-specific renderer
  • Renderers return HTML strings, set el.innerHTML
  • Event handlers are inline onclick attributes or setupEvents() delegation
  • UI.esc(s) escapes HTML to prevent XSS
// ✅ Correct — renderer returns HTML
renderBoard(tasks) {
    const el = document.getElementById('v-board');
    el.innerHTML = '<div class="board">...</div>';
},

// ❌ Wrong — direct DOM manipulation in render
renderBoard(tasks) {
    document.getElementById('v-board').appendChild(...);
}

Naming Conventions

  • Task IDs: PKGD-{100+length} (auto-increment)
  • Epic IDs: EPIC-{n}
  • Feature IDs: FEAT-{n}
  • Story IDs: STORY-{n}
  • Sprint IDs: SP-{n}
  • Methods: camelCase
  • CSS classes: kebab-case
  • CSS variables: --kebab-case
  • Constants: UPPER_SNAKE_CASE

Adding a New Feature

1. Add Data Field

// In Store.addTask or Store.updateTask
const task = {
    ...d,
    id: 'PKGD-' + (this.state.tasks.length + 100),
    createdAt: new Date().toISOString(),
    // ...existing fields
};

2. Add to Task Modal (HTML)

<div class="form-group">
    <label>New Field</label>
    <input class="input" id="f-newfield" placeholder="...">
</div>

3. Add to saveTask()

const d = {
    newfield: document.getElementById('f-newfield').value,
    // ...existing fields
};

4. Add to openTask()

document.getElementById('f-newfield').value = t ? (t.newfield || '') : '';

5. Add to Task Card (optional)

In UI._cardHTML(), add to the relevant section (card-tags, card-foot, etc.)

Common Patterns

Adding a New View

  1. Add nav item in HTML sidebar
  2. Add view div: <div id="v-myview" class="view"></div>
  3. Add renderer reference in UI.render(): myview: () => this.renderMyView()
  4. Add keyboard shortcut in UI.setupKeys()
  5. Add nav highlight in UI.go()

Adding a New Store Method

myNewMethod(arg) {
    if (!arg) return;
    this.state.tasks.push({...});
    this.audit('MY_ACTION', taskId, detail);
    this.save();
}

Adding Keyboard Shortcut

// In UI.setupKeys()
if (e.key === 'x') this.go('myview');
// With modifier:
if ((e.metaKey || e.ctrlKey) && e.key === 'x') { e.preventDefault(); this.doThing(); }

Git Conventions

  • Commit messages: type: description
  • Types: feat, fix, docs, refactor, test
  • One feature per commit
  • Never commit broken syntax

Validation Script

python3 validate.py

Checks for:

  • max-width: 34px in modal/container contexts (should be 400/500/700)
  • width: 34px in filter input contexts (should be 200)
  • Any other suspicious structural px values

Run before every commit.