viepilot 1.9.11 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +175 -2
  2. package/README.md +3 -3
  3. package/bin/viepilot.cjs +7 -5
  4. package/bin/vp-tools.cjs +193 -0
  5. package/dev-install.sh +34 -13
  6. package/docs/user/features/architect-design-mode.md +170 -0
  7. package/docs/user/features/hooks.md +93 -0
  8. package/docs/user/features/ui-direction.md +79 -3
  9. package/lib/adapters/claude-code.cjs +42 -0
  10. package/lib/adapters/cursor.cjs +31 -0
  11. package/lib/adapters/index.cjs +26 -0
  12. package/lib/hooks/brainstorm-staleness.cjs +231 -0
  13. package/lib/viepilot-config.cjs +103 -0
  14. package/lib/viepilot-install.cjs +128 -153
  15. package/package.json +1 -1
  16. package/skills/vp-audit/SKILL.md +21 -21
  17. package/skills/vp-auto/SKILL.md +21 -7
  18. package/skills/vp-brainstorm/SKILL.md +46 -35
  19. package/skills/vp-crystallize/SKILL.md +37 -25
  20. package/skills/vp-debug/SKILL.md +2 -2
  21. package/skills/vp-docs/SKILL.md +7 -7
  22. package/skills/vp-evolve/SKILL.md +25 -12
  23. package/skills/vp-info/SKILL.md +23 -23
  24. package/skills/vp-pause/SKILL.md +5 -5
  25. package/skills/vp-request/SKILL.md +12 -12
  26. package/skills/vp-resume/SKILL.md +4 -4
  27. package/skills/vp-rollback/SKILL.md +3 -3
  28. package/skills/vp-status/SKILL.md +4 -4
  29. package/skills/vp-task/SKILL.md +3 -3
  30. package/skills/vp-ui-components/SKILL.md +12 -12
  31. package/skills/vp-update/SKILL.md +17 -17
  32. package/templates/architect/apis.html +159 -0
  33. package/templates/architect/architect-actions.js +217 -0
  34. package/templates/architect/architecture.html +160 -0
  35. package/templates/architect/data-flow.html +109 -0
  36. package/templates/architect/decisions.html +96 -0
  37. package/templates/architect/deployment.html +184 -0
  38. package/templates/architect/erd.html +154 -0
  39. package/templates/architect/feature-map.html +113 -0
  40. package/templates/architect/index.html +108 -0
  41. package/templates/architect/sequence-diagram.html +133 -0
  42. package/templates/architect/style.css +365 -0
  43. package/templates/architect/tech-notes.html +89 -0
  44. package/templates/architect/tech-stack.html +114 -0
  45. package/templates/architect/user-use-cases.html +154 -0
  46. package/templates/project/AI-GUIDE.md +53 -54
  47. package/templates/project/PROJECT-CONTEXT.md +7 -11
  48. package/templates/project/README.md +43 -0
  49. package/templates/project/ROADMAP.md +1 -27
  50. package/workflows/audit.md +3 -3
  51. package/workflows/autonomous.md +38 -5
  52. package/workflows/brainstorm.md +575 -191
  53. package/workflows/crystallize.md +168 -58
  54. package/workflows/debug.md +9 -9
  55. package/workflows/documentation.md +5 -5
  56. package/workflows/evolve.md +44 -12
  57. package/workflows/pause-work.md +2 -2
  58. package/workflows/request.md +8 -8
  59. package/workflows/resume-work.md +1 -1
  60. package/workflows/rollback.md +1 -1
@@ -0,0 +1,217 @@
1
+ /**
2
+ * ViePilot Architect Item Actions (ENH-033)
3
+ *
4
+ * Injects per-item Approve / Edit prompt-copy buttons into every element
5
+ * marked with [data-arch-id] in the Architect HTML workspace.
6
+ *
7
+ * ISOLATION RULE: Each action is scoped exclusively to the identified item
8
+ * on the identified page. Approving one item does NOT imply approval of any
9
+ * related item on any other page. Cross-page updates require separate prompts.
10
+ *
11
+ * Prompt formats:
12
+ * APPROVE: [ARCH:{slug}:{id}] APPROVE — "{title}" on {slug} page. No changes needed.
13
+ * EDIT: [ARCH:{slug}:{id}] EDIT — "{title}" on {slug} page. Current: "{excerpt}". What should I change?
14
+ */
15
+
16
+ (function () {
17
+ 'use strict';
18
+
19
+ // ── Prompt templates ──────────────────────────────────────────────────────
20
+
21
+ function approvePrompt(slug, id, title) {
22
+ return '[ARCH:' + slug + ':' + id + '] APPROVE — "' + title + '" on ' + slug + ' page. No changes needed.';
23
+ }
24
+
25
+ function editPrompt(slug, id, title, excerpt) {
26
+ var body = excerpt ? ' Current: "' + excerpt + '".' : '';
27
+ return '[ARCH:' + slug + ':' + id + '] EDIT — "' + title + '" on ' + slug + ' page.' + body + ' What should I change?';
28
+ }
29
+
30
+ // ── Clipboard helper ─────────────────────────────────────────────────────
31
+
32
+ function copyText(text, btn) {
33
+ var original = btn.textContent;
34
+ function onDone() {
35
+ btn.textContent = 'Copied!';
36
+ btn.classList.add('copied');
37
+ setTimeout(function () {
38
+ btn.textContent = original;
39
+ btn.classList.remove('copied');
40
+ }, 1500);
41
+ }
42
+ if (navigator.clipboard && navigator.clipboard.writeText) {
43
+ navigator.clipboard.writeText(text).then(onDone).catch(function () {
44
+ legacyCopy(text);
45
+ onDone();
46
+ });
47
+ } else {
48
+ legacyCopy(text);
49
+ onDone();
50
+ }
51
+ }
52
+
53
+ function legacyCopy(text) {
54
+ var ta = document.createElement('textarea');
55
+ ta.value = text;
56
+ ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;pointer-events:none;';
57
+ document.body.appendChild(ta);
58
+ ta.focus();
59
+ ta.select();
60
+ try { document.execCommand('copy'); } catch (e) { /* silent */ }
61
+ document.body.removeChild(ta);
62
+ }
63
+
64
+ // ── Text extraction ───────────────────────────────────────────────────────
65
+
66
+ function getTitle(el) {
67
+ if (el.dataset.archTitle) return el.dataset.archTitle.trim().slice(0, 80);
68
+ // Table row: first <td>
69
+ if (el.tagName === 'TR') {
70
+ var td = el.querySelector('td');
71
+ if (td) return td.textContent.trim().slice(0, 80);
72
+ }
73
+ // Card/div: heading
74
+ var h = el.querySelector('h2,h3,h4,h5');
75
+ if (h) return h.textContent.trim().slice(0, 80);
76
+ return el.textContent.trim().slice(0, 80);
77
+ }
78
+
79
+ function getExcerpt(el) {
80
+ if (el.dataset.archExcerpt) return el.dataset.archExcerpt.trim().slice(0, 100);
81
+ // Table row: second <td>
82
+ if (el.tagName === 'TR') {
83
+ var tds = el.querySelectorAll('td');
84
+ if (tds.length >= 2) return tds[1].textContent.trim().slice(0, 100);
85
+ }
86
+ // Card/div: first <p>
87
+ var p = el.querySelector('p');
88
+ if (p) return p.textContent.trim().slice(0, 100);
89
+ return '';
90
+ }
91
+
92
+ // ── Build actions DOM ─────────────────────────────────────────────────────
93
+
94
+ function makeActionsEl(slug, id, title, excerpt) {
95
+ var wrap = document.createElement('div');
96
+ wrap.className = 'arch-item-actions';
97
+
98
+ var badge = document.createElement('span');
99
+ badge.className = 'arch-id-badge';
100
+ badge.textContent = id;
101
+ badge.title = 'Item ID: [ARCH:' + slug + ':' + id + ']';
102
+
103
+ var btnApprove = document.createElement('button');
104
+ btnApprove.className = 'arch-btn arch-btn-approve';
105
+ btnApprove.textContent = '✅ Approve';
106
+ btnApprove.title = 'Copy APPROVE prompt — scoped to this item only';
107
+ btnApprove.type = 'button';
108
+ btnApprove.addEventListener('click', function (e) {
109
+ e.stopPropagation();
110
+ copyText(approvePrompt(slug, id, title), btnApprove);
111
+ });
112
+
113
+ var btnEdit = document.createElement('button');
114
+ btnEdit.className = 'arch-btn arch-btn-edit';
115
+ btnEdit.textContent = '✏️ Edit';
116
+ btnEdit.title = 'Copy EDIT prompt — scoped to this item only';
117
+ btnEdit.type = 'button';
118
+ btnEdit.addEventListener('click', function (e) {
119
+ e.stopPropagation();
120
+ copyText(editPrompt(slug, id, title, excerpt), btnEdit);
121
+ });
122
+
123
+ wrap.appendChild(badge);
124
+ wrap.appendChild(btnApprove);
125
+ wrap.appendChild(btnEdit);
126
+ return wrap;
127
+ }
128
+
129
+ // ── Inject into page ──────────────────────────────────────────────────────
130
+
131
+ function inject() {
132
+ var slug = (document.body.dataset.archSlug || 'unknown').trim();
133
+ var items = document.querySelectorAll('[data-arch-id]');
134
+
135
+ items.forEach(function (el) {
136
+ var id = el.dataset.archId;
137
+ if (!id) return;
138
+ var title = getTitle(el);
139
+ var excerpt = getExcerpt(el);
140
+ var actionsEl = makeActionsEl(slug, id, title, excerpt);
141
+
142
+ if (el.tagName === 'TR') {
143
+ // Ensure thead gets an empty actions header column (once per table)
144
+ var table = el.closest('table');
145
+ if (table) {
146
+ var theadRow = table.querySelector('thead tr');
147
+ if (theadRow && !theadRow.querySelector('.arch-actions-th')) {
148
+ var th = document.createElement('th');
149
+ th.className = 'arch-actions-th';
150
+ theadRow.appendChild(th);
151
+ }
152
+ }
153
+ var td = document.createElement('td');
154
+ td.className = 'arch-actions-cell';
155
+ td.appendChild(actionsEl);
156
+ el.appendChild(td);
157
+ } else {
158
+ // Card / div: insert after first child (heading area)
159
+ var first = el.firstElementChild;
160
+ if (first && first.nextSibling) {
161
+ el.insertBefore(actionsEl, first.nextSibling);
162
+ } else if (first) {
163
+ el.appendChild(actionsEl);
164
+ } else {
165
+ el.prepend(actionsEl);
166
+ }
167
+ }
168
+ });
169
+ }
170
+
171
+ // ── Stale / gap badge injection (ENH-034) ────────────────────────────────
172
+ // Items with data-arch-stale="true" get an amber "⚠ gap" badge.
173
+ // Stale means: brainstorm detected a gap here; HTML not yet synced.
174
+
175
+ function injectStaleBadges() {
176
+ document.querySelectorAll('[data-arch-stale="true"]').forEach(function (el) {
177
+ var reason = el.getAttribute('data-arch-stale-note') || 'gap detected in brainstorm';
178
+ var badge = document.createElement('span');
179
+ badge.className = 'arch-gap-badge';
180
+ badge.textContent = '⚠ gap';
181
+ badge.title = reason;
182
+
183
+ if (el.tagName === 'TR') {
184
+ var firstTd = el.querySelector('td');
185
+ if (firstTd && !firstTd.querySelector('.arch-gap-badge')) {
186
+ firstTd.appendChild(badge);
187
+ }
188
+ } else {
189
+ var h = el.querySelector('h2,h3,h4');
190
+ if (h && !h.querySelector('.arch-gap-badge')) {
191
+ h.appendChild(badge);
192
+ }
193
+ }
194
+ });
195
+ }
196
+
197
+ function markStale(id, reason) {
198
+ var el = document.querySelector('[data-arch-id="' + id + '"]');
199
+ if (!el) return;
200
+ el.setAttribute('data-arch-stale', 'true');
201
+ if (reason) el.setAttribute('data-arch-stale-note', reason);
202
+ injectStaleBadges();
203
+ }
204
+
205
+ // Expose for browser console use during architect review sessions
206
+ window.vpMarkStale = markStale;
207
+
208
+ if (document.readyState === 'loading') {
209
+ document.addEventListener('DOMContentLoaded', function () {
210
+ inject();
211
+ injectStaleBadges();
212
+ });
213
+ } else {
214
+ inject();
215
+ injectStaleBadges();
216
+ }
217
+ })();
@@ -0,0 +1,160 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Architecture — {project}</title>
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body data-arch-slug="architecture">
10
+ <nav class="nav-sidebar">
11
+ <div class="logo">
12
+ <span>ViePilot Architect Mode</span>
13
+ <strong>{project}</strong>
14
+ </div>
15
+ <ul>
16
+ <li><a href="index.html">🏠 Hub</a></li>
17
+ <li><a href="architecture.html" class="active">🏗️ Architecture</a></li>
18
+ <li><a href="sequence-diagram.html">🎬 Sequence</a></li>
19
+ <li><a href="data-flow.html">🔄 Data Flow</a></li>
20
+ <li><a href="decisions.html">📋 Decisions (ADR)</a></li>
21
+ <li><a href="tech-stack.html">🛠️ Tech Stack</a></li>
22
+ <li><a href="tech-notes.html">📝 Tech Notes</a></li>
23
+ <li><a href="feature-map.html">🗺️ Feature Map</a></li>
24
+ <li><a href="erd.html">🗄️ ERD</a></li>
25
+ <li><a href="user-use-cases.html">👤 Use Cases</a></li>
26
+ <li><a href="deployment.html">🚀 Deployment</a></li>
27
+ <li><a href="apis.html">🔌 APIs</a></li>
28
+ </ul>
29
+ </nav>
30
+
31
+ <main class="main-content">
32
+ <div class="page-header">
33
+ <div>
34
+ <h1>🏗️ System Architecture</h1>
35
+ <p>Component boundaries and system structure</p>
36
+ </div>
37
+ <button id="theme-toggle" onclick="toggleTheme()">☀️ Light</button>
38
+ </div>
39
+
40
+ <div class="card" data-arch-id="ARCH-DIAG1" data-arch-title="C4 Context Diagram">
41
+ <h2>C4 Context Diagram</h2>
42
+ <div class="mermaid-wrap">
43
+ <div class="mermaid">
44
+ C4Context
45
+ title System Context for {project}
46
+ Person(user, "User", "A user of the system")
47
+ System(sys, "{project}", "The main system")
48
+ System_Ext(ext1, "{External System 1}", "{Description}")
49
+ System_Ext(ext2, "{External System 2}", "{Description}")
50
+
51
+ Rel(user, sys, "Uses")
52
+ Rel(sys, ext1, "Calls")
53
+ Rel(sys, ext2, "Integrates with")
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="card" data-arch-id="ARCH-DIAG2" data-arch-title="System Diagram">
59
+ <h2>System Diagram</h2>
60
+ <div class="mermaid-wrap">
61
+ <div class="mermaid">
62
+ graph TD
63
+ Client["🖥️ Client (Browser/Mobile)"]
64
+ API["⚙️ API Gateway"]
65
+ Service1["📦 {Service 1}"]
66
+ Service2["📦 {Service 2}"]
67
+ DB["🗄️ Database"]
68
+ Cache["⚡ Cache"]
69
+
70
+ Client --> API
71
+ API --> Service1
72
+ API --> Service2
73
+ Service1 --> DB
74
+ Service1 --> Cache
75
+ Service2 --> DB
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="card">
81
+ <h2>Components</h2>
82
+ <table>
83
+ <thead>
84
+ <tr>
85
+ <th>Component</th>
86
+ <th>Responsibility</th>
87
+ <th>Technology</th>
88
+ <th>Notes</th>
89
+ </tr>
90
+ </thead>
91
+ <tbody>
92
+ <tr data-arch-id="C1">
93
+ <td>{Component 1}</td>
94
+ <td>{Responsibility}</td>
95
+ <td>{Technology}</td>
96
+ <td>{Notes}</td>
97
+ </tr>
98
+ <tr data-arch-id="C2">
99
+ <td>{Component 2}</td>
100
+ <td>{Responsibility}</td>
101
+ <td>{Technology}</td>
102
+ <td>{Notes}</td>
103
+ </tr>
104
+ </tbody>
105
+ </table>
106
+ </div>
107
+
108
+ <div class="card">
109
+ <h2>Service Boundaries</h2>
110
+ <p style="color:var(--text-muted);font-size:13px;">{Describe service boundaries, communication protocols, data ownership}</p>
111
+ </div>
112
+
113
+ <div class="card">
114
+ <h2>External Systems</h2>
115
+ <table>
116
+ <thead>
117
+ <tr>
118
+ <th>System</th>
119
+ <th>Type</th>
120
+ <th>Description</th>
121
+ <th>Integration method</th>
122
+ <th>Owned by</th>
123
+ <th>Notes</th>
124
+ </tr>
125
+ </thead>
126
+ <tbody>
127
+ <tr data-arch-id="C3">
128
+ <td>{External System 1}</td>
129
+ <td>{SaaS / Internal / 3rd party}</td>
130
+ <td>{What it does}</td>
131
+ <td>{REST / Webhook / SDK}</td>
132
+ <td>{Team / Vendor}</td>
133
+ <td>{Notes}</td>
134
+ </tr>
135
+ <tr data-arch-id="C4">
136
+ <td>{External System 2}</td>
137
+ <td>{SaaS / Internal / 3rd party}</td>
138
+ <td>{What it does}</td>
139
+ <td>{REST / Webhook / SDK}</td>
140
+ <td>{Team / Vendor}</td>
141
+ <td>{Notes}</td>
142
+ </tr>
143
+ </tbody>
144
+ </table>
145
+ </div>
146
+ </main>
147
+
148
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
149
+ <script>
150
+ mermaid.initialize({ startOnLoad: true, theme: 'dark' });
151
+ function toggleTheme() {
152
+ const html = document.documentElement;
153
+ const isLight = html.classList.toggle('light');
154
+ document.getElementById('theme-toggle').textContent = isLight ? '🌙 Dark' : '☀️ Light';
155
+ mermaid.initialize({ startOnLoad: false, theme: isLight ? 'default' : 'dark' });
156
+ }
157
+ </script>
158
+ <script src="architect-actions.js"></script>
159
+ </body>
160
+ </html>
@@ -0,0 +1,109 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Data Flow — {project}</title>
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body data-arch-slug="data-flow">
10
+ <nav class="nav-sidebar">
11
+ <div class="logo">
12
+ <span>ViePilot Architect Mode</span>
13
+ <strong>{project}</strong>
14
+ </div>
15
+ <ul>
16
+ <li><a href="index.html">🏠 Hub</a></li>
17
+ <li><a href="architecture.html">🏗️ Architecture</a></li>
18
+ <li><a href="sequence-diagram.html">🎬 Sequence</a></li>
19
+ <li><a href="data-flow.html" class="active">🔄 Data Flow</a></li>
20
+ <li><a href="decisions.html">📋 Decisions (ADR)</a></li>
21
+ <li><a href="tech-stack.html">🛠️ Tech Stack</a></li>
22
+ <li><a href="tech-notes.html">📝 Tech Notes</a></li>
23
+ <li><a href="feature-map.html">🗺️ Feature Map</a></li>
24
+ <li><a href="erd.html">🗄️ ERD</a></li>
25
+ <li><a href="user-use-cases.html">👤 Use Cases</a></li>
26
+ <li><a href="deployment.html">🚀 Deployment</a></li>
27
+ <li><a href="apis.html">🔌 APIs</a></li>
28
+ </ul>
29
+ </nav>
30
+
31
+ <main class="main-content">
32
+ <div class="page-header">
33
+ <div>
34
+ <h1>🔄 Data Flow</h1>
35
+ <p>Request/event flows and sequence diagrams</p>
36
+ </div>
37
+ <button id="theme-toggle" onclick="toggleTheme()">☀️ Light</button>
38
+ </div>
39
+
40
+ <div class="card" data-arch-id="DF-DIAG1" data-arch-title="Primary Request Flow">
41
+ <h2>Primary Request Flow</h2>
42
+ <div class="mermaid-wrap">
43
+ <div class="mermaid">
44
+ sequenceDiagram
45
+ participant C as Client
46
+ participant A as API Gateway
47
+ participant S as {Service}
48
+ participant D as Database
49
+
50
+ C->>A: Request {action}
51
+ A->>A: Auth / Rate limit
52
+ A->>S: Forward request
53
+ S->>D: Query/write
54
+ D-->>S: Result
55
+ S-->>A: Response
56
+ A-->>C: Final response
57
+ </div>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="card" data-arch-id="DF-DIAG2" data-arch-title="Event Flow (Async)">
62
+ <h2>Event Flow (Async)</h2>
63
+ <div class="mermaid-wrap">
64
+ <div class="mermaid">
65
+ flowchart LR
66
+ Producer["{Producer}"] -->|event| Queue["{Queue/Topic}"]
67
+ Queue --> Consumer1["{Consumer 1}"]
68
+ Queue --> Consumer2["{Consumer 2}"]
69
+ Consumer1 --> Store["{Data Store}"]
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <div class="card">
75
+ <h2>Flow Notes</h2>
76
+ <table>
77
+ <thead>
78
+ <tr>
79
+ <th>Flow</th>
80
+ <th>Trigger</th>
81
+ <th>Steps</th>
82
+ <th>SLA / Notes</th>
83
+ </tr>
84
+ </thead>
85
+ <tbody>
86
+ <tr data-arch-id="DF1">
87
+ <td>{Flow name}</td>
88
+ <td>{Trigger}</td>
89
+ <td>{Steps}</td>
90
+ <td>{SLA}</td>
91
+ </tr>
92
+ </tbody>
93
+ </table>
94
+ </div>
95
+ </main>
96
+
97
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
98
+ <script>
99
+ mermaid.initialize({ startOnLoad: true, theme: 'dark' });
100
+ function toggleTheme() {
101
+ const html = document.documentElement;
102
+ const isLight = html.classList.toggle('light');
103
+ document.getElementById('theme-toggle').textContent = isLight ? '🌙 Dark' : '☀️ Light';
104
+ mermaid.initialize({ startOnLoad: false, theme: isLight ? 'default' : 'dark' });
105
+ }
106
+ </script>
107
+ <script src="architect-actions.js"></script>
108
+ </body>
109
+ </html>
@@ -0,0 +1,96 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Architecture Decisions — {project}</title>
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body data-arch-slug="decisions">
10
+ <nav class="nav-sidebar">
11
+ <div class="logo">
12
+ <span>ViePilot Architect Mode</span>
13
+ <strong>{project}</strong>
14
+ </div>
15
+ <ul>
16
+ <li><a href="index.html">🏠 Hub</a></li>
17
+ <li><a href="architecture.html">🏗️ Architecture</a></li>
18
+ <li><a href="sequence-diagram.html">🎬 Sequence</a></li>
19
+ <li><a href="data-flow.html">🔄 Data Flow</a></li>
20
+ <li><a href="decisions.html" class="active">📋 Decisions (ADR)</a></li>
21
+ <li><a href="tech-stack.html">🛠️ Tech Stack</a></li>
22
+ <li><a href="tech-notes.html">📝 Tech Notes</a></li>
23
+ <li><a href="feature-map.html">🗺️ Feature Map</a></li>
24
+ <li><a href="erd.html">🗄️ ERD</a></li>
25
+ <li><a href="user-use-cases.html">👤 Use Cases</a></li>
26
+ <li><a href="deployment.html">🚀 Deployment</a></li>
27
+ <li><a href="apis.html">🔌 APIs</a></li>
28
+ </ul>
29
+ </nav>
30
+
31
+ <main class="main-content">
32
+ <div class="page-header">
33
+ <div>
34
+ <h1>📋 Architecture Decisions (ADR)</h1>
35
+ <p>Decision log — context, options considered, chosen path, rationale</p>
36
+ </div>
37
+ <button id="theme-toggle" onclick="toggleTheme()">☀️ Light</button>
38
+ </div>
39
+
40
+ <div class="card">
41
+ <h2>Decision Log</h2>
42
+ <table>
43
+ <thead>
44
+ <tr>
45
+ <th>ID</th>
46
+ <th>Date</th>
47
+ <th>Decision</th>
48
+ <th>Options Considered</th>
49
+ <th>Chosen</th>
50
+ <th>Rationale</th>
51
+ <th>Status</th>
52
+ </tr>
53
+ </thead>
54
+ <tbody>
55
+ <tr data-updated="true" class="updated" data-arch-id="D1">
56
+ <td>D001</td>
57
+ <td>{date}</td>
58
+ <td>{Topic, e.g. "Database choice"}</td>
59
+ <td>{option A, option B, option C}</td>
60
+ <td><strong>{Chosen option}</strong></td>
61
+ <td>{Rationale}</td>
62
+ <td><span class="badge badge-decided">Decided</span></td>
63
+ </tr>
64
+ <tr data-arch-id="D2">
65
+ <td>D002</td>
66
+ <td>{date}</td>
67
+ <td>{Topic}</td>
68
+ <td>{options}</td>
69
+ <td><strong>{Chosen}</strong></td>
70
+ <td>{Rationale}</td>
71
+ <td><span class="badge badge-open">Open</span></td>
72
+ </tr>
73
+ </tbody>
74
+ </table>
75
+ </div>
76
+
77
+ <div class="card">
78
+ <h2>Legend</h2>
79
+ <p style="font-size:13px;color:var(--text-muted);">
80
+ <span class="badge badge-decided">Decided</span> — decision finalized &nbsp;
81
+ <span class="badge badge-open">Open</span> — needs resolution &nbsp;
82
+ <span class="badge badge-deferred">Deferred</span> — intentionally postponed
83
+ </p>
84
+ </div>
85
+ </main>
86
+
87
+ <script>
88
+ function toggleTheme() {
89
+ const html = document.documentElement;
90
+ const isLight = html.classList.toggle('light');
91
+ document.getElementById('theme-toggle').textContent = isLight ? '🌙 Dark' : '☀️ Light';
92
+ }
93
+ </script>
94
+ <script src="architect-actions.js"></script>
95
+ </body>
96
+ </html>