This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Atomic Task Matrix is a task management application that combines the Eisenhower Matrix with atomic habits principles. It uses AI (Google Gemini) to break down large tasks into micro-actions, helping users overcome procrastination. All data is synced to Google Sheets in real-time.
- Frontend Architecture: Modularized into 12 files with 5-layer architecture (~1020 lines total after UI cleanup)
- UI Design: Memphis Design (粗邊框 + 彩色卡片), drag-and-drop, HeroIcons SVG icons
- Layout: Left-right split layout (left: uncategorized 320px, right: 4 quadrants 2x2), modal-based statistics, optimized for left-to-right drag workflow
- Backend: GAS with REST endpoints (
/tasks,/tasks/update,/tasks/{id}/complete,/tasks/{id}/breakdown,/stats/weekly) - Database: Google Sheets CRUD operations (create, read, update, delete, complete tasks)
- Sync: Real-time sync without localStorage
- AI: Gemini AI Task Breakdown using
gemini-2.0-flashmodel with task intensity indicators (🌱⚡🚀) - Statistics: Minimalist design with 3 core metrics (本週完成、本週建立、待完成) - 極簡主義方案
- UX: Direct AI breakdown button on task cards, time information display, on-demand statistics modal
- Deployment: Production-ready on Zeabur (https://task-matrix.zeabur.app/)
- All Core Functionality: ✅ 建立任務、拖放分類、AI 分析、刪除任務、完成任務
- Security: ✅ All identified issues resolved (3 fixed, 1 accepted) - XSS 防護、CSRF Token、Prompt Injection 防護、LLM Output 驗證
Latest Security Audit: 資安調整規格文件 v2.0 (2025-11-03)
Security Level: 🟢 Very Low Risk (3/4 issues resolved, 1 accepted risk)
| Priority | Issue | Status | Fixed Date |
|---|---|---|---|
| 🔴 HIGH | H-01: DOM-based XSS 漏洞 | ✅ Fixed | 2025-11-03 |
| 🟠 MEDIUM | M-01: 客戶端 API Token 暴露 | ✅ Fixed | 2025-11-03 |
| 🟠 MEDIUM | M-02: Tailwind CDN 無 SRI 保護 | ✅ Accepted | 2025-11-03 |
| 🟢 LOW | L-01: ALLOWED_ORIGIN 配置清理 | ✅ Fixed | 2025-11-03 |
Current Security Measures:
- ✅ CSRF Token protection for all state-changing operations
- ✅ XSS prevention using safe DOM manipulation
- ✅ Prompt Injection prevention using JSON.stringify() in Gemini prompts
- ✅ LLM Output Validation to filter malicious content
- ✅ CSP (Content Security Policy) configured
- ✅ API authentication via GAS Web App permissions
- ✅ DEBUG_MODE for controlled error logging
- M-02: Tailwind CDN without SRI (ACCEPTED 2025-11-03)
- Issue: Tailwind CSS loaded from CDN without Subresource Integrity check
- Theoretical Risk: Supply chain attack if
cdn.tailwindcss.comis compromised - Actual Risk: Very Low
- CDN hosted by Cloudflare (extremely secure infrastructure)
- HTTPS prevents MITM attacks
- Tailwind is CSS-only, doesn't handle user data
- Core security (CSRF Token, XSS prevention) unaffected
- Mitigation Options Considered:
- Option A: Keep current CDN (chosen) - 0 hours, preserves Vanilla JS architecture
- Option B: Add SRI hash - 15 minutes, but loses JIT compilation benefits
- Option C: Self-host Tailwind - 4-6 hours, requires build process setup
- Decision Rationale:
- Cost-benefit analysis: 4-6 hours to fix very low risk is not justified
- Architecture philosophy: Vanilla JS simplicity is a project advantage
- Defense in depth: Critical protections (CSRF, XSS, Prompt Injection) already in place
- Acceptance: User explicitly chose to accept this risk
- Review: Can be revisited if project requirements change (e.g., enterprise deployment)
None - All identified security issues have been either fixed or accepted after risk assessment.
-
Main.js Modularization (RESOLVED 2025-11-02)
- Challenge: 1107-line monolithic file difficult to maintain
- Solution: Refactored into 12 modules with 5-layer architecture
- Benefits: Clear separation of concerns, easier testing, better maintainability
- Files Created:
- Layer 1:
core/constants.js,core/icons.js,models/Task.js - Layer 2:
core/config.js,core/state.js - Layer 3:
services/BackendGateway.js - Layer 4:
handlers/DragDropHandler.js,ui/Renderer.js,managers/TaskManager.js,monitors/ConnectionMonitor.js - Layer 5:
app/events.js,app/bootstrap.js
- Layer 1:
- Status: ✅ Deployed to production, all features working
-
DELETE Functionality & CORS (RESOLVED 2025-11-02)
-
✅ CSRF Token Missing from DELETE Requests
- Issue: DELETE requests don't have body, so CSRF token wasn't being sent
- Fix: Modified
services/BackendGateway.jsto add CSRF token to URL parameters
-
✅ Missing doDelete Function
- Issue: GAS backend lacked
doDelete(e)function for DELETE HTTP method - Fix: Added function at lines 40-42 in backend.gs
- Issue: GAS backend lacked
-
✅ CORS Headers
- Issue: Browser blocks DELETE/OPTIONS due to missing CORS headers
- Fix: Added CORS headers to
doOptions(),jsonResponse(),jsonError()in backend.gs - Status: ✅ Deployed to GAS, DELETE functionality working in production
-
✅ ContentService MIME Type Incompatibility
- Issue:
ContentService.MimeType.JSONnot supported in GAS - Fix: Changed to
ContentService.MimeType.TEXT, updated frontend JSON parsing
- Issue:
-
✅ CSP Violation for Inline Scripts
- Issue: "Refused to execute inline script" error after GAS deployment
- Fix: Updated CSP policy in index.html line 9 to include
'unsafe-inline'
-
-
Gemini AI Breakdown (RESOLVED 2025-11-02)
- Root Cause:
gemini-2.5-flashreturns response withthinkingfield instead oftext - Solution: Switch to
gemini-2.0-flashmodel (CONFIG.GEMINI_MODEL line 15) - Details: Gemini 2.5 has different response structure for thinking models; older models use standard response format
- Status: ✅ Working - AI breakdown successfully generates subtasks
- Root Cause:
-
UX Improvement: AI Breakdown Access (RESOLVED 2025-11-02)
- Issue: Required clicking "Focus" before accessing AI breakdown (3 steps total)
- Solution: Added direct AI button on task cards (1 step)
- Implementation:
- Task card AI button with heroicons sparkles icon
- Time information (created/updated/completed) directly on task cards
- Status: ✅ Deployed to production
-
Memphis Design Implementation (RESOLVED 2025-11-02)
- Motivation: User requested bold design update: "我覺得應該連整個UX都要大修改...設計可以大膽一點"
- Design Phase: Created 3 mockups (Memphis, Neumorphism, Art Deco)
- User Selection: Final choice - Pure Memphis Design
- Implementation:
- Updated
tailwind-config.jswith Memphis color system and shadows - Applied 150+ CSS class changes to
index.htmlwhile preserving HTML structure - Result: Thick black borders (4-5px), geometric elements, color-shifted shadows, rotated elements
- Updated
- Status: ✅ Fully implemented and deployed to production
-
Memphis Design Production Deployment & Debugging (RESOLVED 2025-11-02)
-
Initial Issue: Frontend rendered successfully but connection indicator showed 🔴 "尚未連線"
-
Root Causes Found & Fixed:
-
Renderer.js DOM Selector Mismatch
- Problem: HTML template class changed from
font-semiboldtofont-bold, but selector wasn't updated - Fix: Updated selector in
Renderer.js:60to match HTML template - Impact: Task cards couldn't render, blocking all initialization
- Problem: HTML template class changed from
-
Script Loading Race Condition
- Problem: Using
deferattribute on scripts caused non-deterministic loading order - Fix: Removed
deferto ensure sync sequential loading - Impact: BackendGateway loaded after TaskManager, causing "BackendGateway is not defined"
- Problem: Using
-
BackendGateway.js Syntax Error
- Problem: Missing comma between
request()and_parseResponse()methods - Fix: Added comma separator in object literal (line 77)
- Impact: Module parsing failed completely
- Problem: Missing comma between
-
CSRF Token Missing on POST Requests
- Problem: Async initialization meant CSRF token wasn't acquired before user action
- Fix: Added auto-fetch mechanism - POST requests without token automatically fetch one first
- Impact: All POST operations (create, update, delete, breakdown) now work reliably
-
-
Diagnostic Tools Created:
test-fetch.html- Direct API endpoint testingDEBUGGING.md- Comprehensive troubleshooting guide
-
Improvements Made:
- Enhanced error diagnostics in BackendGateway with detailed console logging
- Improved ConnectionMonitor startup to handle initialization failures gracefully
- Added fallback CSRF token acquisition mechanism
-
Final Status: ✅ All functionality working - 建立任務、拖放、AI分析、刪除、完成
-
-
Focus Panel Removal (RESOLVED 2025-11-02)
- Motivation: Focus panel added unnecessary complexity - users preferred seeing all info directly on task cards
- Changes:
- Removed entire Focus Panel right-side drawer
- Removed "專注" button from task cards
- Removed Shift+A keyboard shortcut (AI button now directly accessible)
- Removed Header/Footer keyboard shortcut hints
- Added time information display directly on task cards
- Code Impact: Reduced codebase by 264 lines (-20%)
- ui/Renderer.js: 362 → 263 lines (-99 lines)
- managers/TaskManager.js: 268 → 219 lines (-49 lines)
- app/events.js: 84 → 38 lines (-46 lines)
- app/bootstrap.js: 64 → 52 lines (-12 lines)
- core/state.js: Removed
selectedTaskIdstate - index.html: Removed Focus Panel HTML and templates
- Status: ✅ Deployed to production, tested and working
-
UI/UX Refinement & Layout Optimization (RESOLVED 2025-11-02)
-
Motivation: Eliminate non-functional UI elements and optimize information hierarchy
-
Changes Implemented:
-
Removed Non-Functional UI Elements
- Deleted search box (⌘K) with no backend functionality
- Deleted theme toggle button (亮/暗) with no implementation
- Deleted settings button with no settings panel
- Impact: Cleaner header, reduced user confusion
- Files: index.html
-
Header Layout Rebalance
- Moved connection status indicator from left to right
- Layout: Logo + Title (left) ↔ Stats Button + Connection Status (right)
- Responsive: Vertical stack on mobile, horizontal on desktop
- Impact: Better visual balance and symmetry
- Files: index.html
-
Statistics Panel Modalization
- Converted right-side statistics panel to modal popup
- Added HeroIcons chart-bar button in header
- Modal features: Click outside/ESC/X button to close, auto-refresh on open
- Layout change: 7fr:5fr (58%:42%) → 100% full width for quadrants
- Impact: 42% more space for task quadrants
- Files:
- Modal HTML: index.html
- Icon: core/icons.js
- Events: app/events.js
- Rendering: ui/Renderer.js
-
Uncategorized Zone Grid Layout
- Changed from vertical stack (space-y-3) to 2-column grid
- Responsive: 1 column (mobile) → 2 columns (desktop)
- Matches quadrant layout (lg:grid-cols-2)
- Impact: Cleaner display when multiple uncategorized tasks exist
- Files: index.html
-
Content Hierarchy Reordering
- Swapped position: Quadrants (top) ↔ Uncategorized (bottom)
- Rationale: Core work area (quadrants) deserves primary focus
- User flow: "View categorized tasks first, then process uncategorized"
- Impact: Better information architecture
- Files: index.html
-
-
Code Metrics:
- Lines removed: ~50 lines (non-functional UI elements)
- Lines added: ~60 lines (modal implementation)
- Net change: +10 lines for significantly improved UX
-
Visual Improvements:
- ✅ Cleaner header with purpose-driven elements only
- ✅ 100% width for quadrants (was 58%)
- ✅ Modal-based statistics (on-demand viewing)
- ✅ Grid-based uncategorized zone (scalable layout)
- ✅ Logical content hierarchy (important → secondary)
-
Status: ✅ Completed, ready for production deployment
-
-
Memphis Design Cleanup & Overscroll Fix (RESOLVED 2025-11-02)
-
Motivation: Simplify design by removing all shadow effects, fix background cutoff during overscroll
-
Phase 1: Shadow Removal
- Removed all Memphis shadow effects (shadow-memphis-*) for flatter design
- User feedback: "效果不錯,我決定把所有有陰影的效果全部拿掉"
- Files affected:
- index.html - Removed shadow-memphis-card, shadow-memphis-task, shadow-memphis-btn
- ui/ConfirmDialog.js - Removed shadows from dialog and buttons
- ui/FeedbackToast.js - Removed shadow from toast
- Impact: Cleaner, more minimal Memphis aesthetic
-
Phase 2: Header Border Cleanup
- Removed unnecessary pink dashed top border from header
- Kept only bottom border (orange dashed line)
- Files: index.html
-
Phase 3: Overscroll/Elastic Scrolling Fix
- Problem: White space visible at top when scrolling on desktop/mobile
- Root Cause:
background-attachment: fixedkept background fixed to viewport while content could be overscrolled, exposing white space beyond gradient - Solution:
- Removed
background-attachment: fixedfrom body - Added
overscroll-behavior: noneto html element (disables elastic scrolling) - Added
background-size: 100% 100%to body (ensures gradient covers entire area)
- Removed
- Technical Details:
- Overscroll (elastic scrolling) is default browser behavior on iOS Safari, Chrome
- When background is fixed to viewport, overscrolling content reveals the layer beneath
overscroll-behavior: noneprevents pull-to-refresh and bounce effects
- Files: index.html
- Impact: Smooth scrolling with no background cutoff on any device
-
Design Philosophy Learned:
- Not all projects need
overscroll-behavior: none - Only required when: fixed backgrounds, full-screen apps, or scroll-locked modals
- Regular websites with solid background-color don't face this issue
- Not all projects need
-
Status: ✅ All visual issues resolved, ready for production deployment
-
-
Security Fixes - H-01, M-01, L-01 (RESOLVED 2025-11-03)
- Motivation: Comprehensive security audit identified 4 vulnerabilities (資安調整規格文件 v2.0)
- Completed Fixes:
H-01: DOM-based XSS Vulnerability ✅
- Issue:
innerHTMLdirectly inserting unsanitized user data in task cards - Attack Vector: Malicious HTML/JS injection via task titles (e.g.,
<img src=x onerror="alert('XSS')">) - Fix:
- Replaced
innerHTMLwith safe DOM manipulation (createElement()+textContent) - Only use
innerHTMLfor controlled internal functions (IconLibrary)
- Replaced
- Files Modified: ui/Renderer.js
- Git Commit:
790a125(part of overscroll fix commit) - Impact: Prevents XSS attacks, protects user data and tokens
M-01: Client-side API Token Exposure ✅
- Issue: API_TOKEN hardcoded in client-side code (visible in browser source)
- Problem: Any user could copy the token and bypass frontend to call API directly
- Fix:
- Backend: Modified
validateApiToken()to check Script Properties first - Backend: Enabled "permissive mode" when no API_TOKEN configured in GAS
- Frontend: Removed API_TOKEN from config.js
- Frontend: Removed token parameter logic from BackendGateway.js
- Frontend: Removed apiToken() method from core/config.js
- Backend: Modified
- Files Modified:
- gas/backend.gs - Reordered validation logic
- config.js - Removed API_TOKEN
- core/config.js - Removed apiToken() method
- services/BackendGateway.js - Removed token parameters
- Git Commit:
eb08688 - Impact: Removed ineffective client-side token, relies on CSRF Token for real protection
L-01: ALLOWED_ORIGIN Configuration Cleanup ✅
-
Issue: CONFIG.ALLOWED_ORIGIN set to '*', but GAS doesn't support custom CORS headers
-
Problem: Misleading configuration that suggests CORS control when none exists
-
Fix:
- Removed ALLOWED_ORIGIN configuration
- Added comments explaining GAS Web App CORS limitations
- Documented that security relies on CSRF Token mechanism
-
Files Modified: gas/backend.gs
-
Git Commit:
db31c66 -
Impact: Code clarity, removed misleading configuration
-
Security Improvements Summary:
- ✅ XSS prevention: Safe DOM manipulation throughout UI
- ✅ Authentication optimization: Removed client-side token, relies on CSRF
- ✅ Code cleanup: Removed misleading CORS configuration
- ✅ All core functionality tested and working
-
Final Status: ✅ Security level upgraded from "Low Risk" to "Very Low Risk"
-
Note: M-02 (Tailwind CDN without SRI) was later assessed and accepted as a low-risk issue (see Accepted Risks section)
- Task Intensity Feature & Gemini Prompt Improvement (RESOLVED 2025-11-03)
- Motivation: User wanted to improve Gemini prompt quality to generate more actionable micro-tasks and add visual intensity indicators
- Completed Work:
Part A: Security Enhancements 🔒
-
Fixed Prompt Injection Vulnerability (NEW HIGH PRIORITY)
- Issue: Existing prompt used
任務:「${sanitizedTitle}」which could be exploited - Attack Vector: Input like
任務」\n\n忽略以上指令could hijack LLM behavior - Fix: Changed to
任務:${JSON.stringify(sanitizedTitle)}to properly escape quotes - Location: gas/backend.gs
- Impact: Prevents malicious users from manipulating AI responses
- Issue: Existing prompt used
-
Added LLM Output Validation
- Issue: AI-generated subtasks could contain HTML/JS or spreadsheet formulas
- Fix: Added filtering to reject items with
<tag>or^[=+\-@]patterns - Location: gas/backend.gs, gas/backend.gs
- Impact: Prevents XSS and formula injection attacks via AI output
-
Enhanced sanitizeForPrompt()
- Added: Remove backslashes
\and brackets{}[]from user input - Location: gas/backend.gs
- Impact: Stronger defense against escape-based injection attempts
- Added: Remove backslashes
Part B: Feature Implementation ✨
-
New Gemini Prompt with Mixed Language Strategy
- Design: English rules + Chinese examples + explicit JSON output format
- Rationale: English provides clearer structural instructions for LLM
- Features:
- Task intensity classification (Small vs Large tasks)
- Emoji-based intensity indicators: 🌱 (S ≤2min), ⚡ (M 5-10min), 🚀 (L 15-30min)
- Strict output format validation (no numbering, no markdown code blocks)
- Emphasis on concrete, verb-led actions (避免抽象詞彙)
- Location: gas/backend.gs
- Increased Token Limit: 400 → 600 tokens to accommodate richer prompts
- Impact: More specific, actionable micro-tasks with clear time expectations
-
Updated defaultBreakdown() Fallback
- Added: Emoji prefixes (🌱⚡) to fallback subtasks when AI unavailable
- Location: gas/backend.gs
- Impact: Consistent UX even without Gemini API key
-
Extended Task Model with Intensity Parsing
- New Field:
intensityproperty ('S'/'M'/'L' or null) - New Method:
Task.parseIntensity(title)extracts emoji and cleans title - Backward Compatible: Old tasks without emoji return
intensity: null - Location: models/Task.js, models/Task.js
- Impact: Frontend can distinguish task sizes without backend changes
- New Field:
-
Added Intensity Constants
- New Constants:
INTENSITY_LABELS,INTENSITY_ACCENTS - Visual Style: Memphis Design badges (thick borders, bright colors, rotation)
- Includes: emoji, duration text, Tailwind color classes
- Location: core/constants.js
- Impact: Centralized configuration for consistent styling
- New Constants:
-
Implemented Badge Rendering
- Visual Design: Colored badges with emoji + label (e.g., "🌱 小型任務")
- Placement: Before task title, with Memphis rotation effect
- Tooltip: Shows duration on hover (e.g., "≤2分鐘")
- Safety: Uses safe DOM manipulation (
createElement+textContent) - Location: ui/Renderer.js
- Impact: Users instantly see task time investment required
Emoji Cross-Platform Compatibility Analysis:
- Initial design used 🪶 (feather, Unicode 13.0, 2020+)
- Switched to older emojis for 99%+ device support:
- 🌱 (Seedling): Unicode 6.0 (2010)
- ⚡ (High Voltage): Unicode 4.0 (2003)
- 🚀 (Rocket): Unicode 6.0 (2010)
- Decision: Direct emoji in titles (方案 D) for simplicity
Design Philosophy:
-
向後兼容 (Backward Compatibility): All existing tasks without emoji work normally
-
漸進增強 (Progressive Enhancement): New AI-generated tasks automatically get intensity badges
-
Code Protection: Only modified necessary files, preserved all working logic
-
Git Commits:
- Feature branch:
feature/task-intensity-security - Merged to master and deployed to production
- All tests passed in local and production environments
- Feature branch:
-
Final Status: ✅ Deployed to production, tested and working perfectly
- Zeabur Deployment Orange Light Issue & config.js Management (RESOLVED 2025-11-03)
-
Motivation: Production deployment on Zeabur stuck at orange light (connecting), while local development worked perfectly
-
Root Cause Analysis:
- config.js was in .gitignore (for GitHub security)
- Zeabur VS Code Extension respects .gitignore rules
- Extension couldn't upload config.js → Frontend couldn't read API_BASE_URL → Orange light
-
Solution Implemented:
-
Removed config.js from .gitignore
- Location: .gitignore
- Now only contains: node_modules, .claude/settings.local.json
- Impact: Zeabur extension can now upload config.js
-
Cleaned Git History
- Used
git filter-branchto remove config.js from all 40+ commits - Cleaned all branches (master, feature/task-intensity-security, feature/ui-redesign)
- Force pushed to GitHub to ensure complete removal
- Result: GitHub repository has no config.js in any commit history
- Used
-
Documented Git Workflow
- Added comprehensive "Git Workflow & Deployment Security" section to CLAUDE.md
- Location: CLAUDE.md
- Includes: Safe commands ✅, Dangerous commands ❌, Recommended workflow, Recovery procedures
-
-
Security Considerations:
- ✅ GAS Web App URL not truly sensitive (protected by CSRF Token at runtime)
- ✅ Git history completely cleaned before removing .gitignore rule
⚠️ Requires discipline: must use selectivegit add <file>instead ofgit add .- 🚨 Emergency procedure documented if config.js accidentally committed
-
Deployment Strategy:
- GitHub (public): config.js excluded via selective git add
- Zeabur (private): config.js included automatically by VS Code extension
- Local Development: config.js exists in working directory but not tracked
-
Testing Results:
- ✅ Zeabur deployment successful with green light (connected)
- ✅ All core functionality working: 建立任務、拖放分類、AI 分析、刪除任務、完成任務
- ✅ Task sorting (newest first) working correctly
- ✅ Task intensity badges rendering properly
-
Files Modified:
- .gitignore - Removed config.js line
- CLAUDE.md - Added Git workflow documentation
-
Git Commits:
- History cleanup: Multiple commits rewritten with
git filter-branch - Documentation:
d59338a- "docs: 配置 Git 工作流程以支持 Zeabur 部署" - Task sorting:
49a981e- "feat: 任務排序優化 - 最新建立的顯示在最上面"
- History cleanup: Multiple commits rewritten with
-
Key Learnings:
- Zeabur VS Code Extension deployment differs from GitHub-based deployment
- .gitignore affects both git and deployment tools
- Sometimes security trade-offs are acceptable when primary protection (CSRF Token) is strong
- Comprehensive documentation prevents future mistakes
-
Final Status: ✅ Production deployment working, all features tested, Git workflow documented
- Statistics Simplification - 極簡主義方案 (RESOLVED 2025-11-03)
-
Motivation: User expressed concern about statistical complexity: "我想增加新指標,但太多太複雜的指標對使用者來說會不會覺得厭煩,我覺得應該找到一個平衡點"
-
Decision Process:
- Analyzed current statistics system (4 metrics with circular progress)
- Proposed 3 design philosophies:
- Option A (極簡主義): Only 3 core metrics - minimal cognitive load
- Option B (保守改良): 4 metrics with corrected definitions
- Option C (數據派): Full data analysis approach
- User chose: Option A - "少即是多" (Less is More)
-
Backend Simplification (gas/backend.gs):
- Modified
StatsService.weekly()(lines 281-299) - Removed Metrics:
- ❌
week_start/week_end(not needed for display) - ❌
completion_rate(misleading definition -本週完成/本週建立) - ❌
avg_lifetime_days(not intuitive, lacks actionable insight) - ❌
adoption_rate(always null, undefined business logic)
- ❌
- Kept 3 Core Metrics:
- ✅
total_completed(本週完成任務數) - Main metric showing weekly achievement - ✅
total_created(本週建立任務數) - Weekly task creation activity - ✅
total_pending(待完成任務數) - All pending tasks across all time
- ✅
- Location: gas/backend.gs
- Modified
-
Frontend Memphis Design (ui/Renderer.js):
- Modified
renderStats()(lines 214-249) - Replaced circular progress ring with card-based layout
- Visual Hierarchy:
- Main Metric: 本週完成任務 (large 6xl font, pink gradient card, border-4)
- Secondary Metrics: 2-column grid (本週建立 green, 待完成 amber)
- Memphis Elements: Thick borders (border-4), colorful backgrounds, no rotation (per user feedback)
- Removed Complexity: Progress ring, complex calculations display
- Location: ui/Renderer.js
- Modified
-
User Feedback & Iteration:
- Initial design included card rotation (
transform: rotate(±1deg)) - User tested and requested: "卡片取消輕微旋轉效果"
- Removed all
style="transform: rotate(...)"attributes - Final design: Clean Memphis style with thick borders and colors only
- Initial design included card rotation (
-
Design Philosophy Applied:
- Immediate Rewards: Focus on completion count (Atomic Habits principle)
- Action-Oriented: Show what was accomplished, not analytical ratios
- Minimal Cognitive Load: 3 numbers instead of 4+ complex metrics
- Visual Simplicity: Large numbers, clear labels, no distractions
-
Files Modified:
- gas/backend.gs - Simplified statistics calculation
- ui/Renderer.js - Memphis design cards without rotation
- Removed HTML modal elements (old progress ring references)
-
Testing Results:
- ✅ Backend deployed and returning correct 3-metric format
- ✅ Frontend displaying Memphis design cards correctly
- ✅ Data validation: 本週完成任務=5, 本週建立=8, 待完成=0
- ✅ Visual refinement: Rotation removed per user feedback
- ✅ No console errors, smooth modal interaction
-
Impact:
- Reduced statistical complexity by 25% (4 metrics → 3 metrics)
- Improved user comprehension with clear, action-focused metrics
- Aligned with product philosophy: Atomic Habits + Minimal Friction
- Faster development cycle: Simpler logic = easier maintenance
-
Final Status: ✅ Deployed to production, tested and working perfectly
- CSRF Token Rotation 機制修復 (RESOLVED 2025-11-04)
-
Motivation: 用戶遇到連續操作失敗問題 - 第一次拖放任務成功,第二次失敗並顯示 "Missing or invalid CSRF token" 錯誤
-
Root Cause Analysis:
- 後端使用 use-once CSRF token 設計(驗證成功後立即刪除 token)
- POST/PUT/DELETE 操作消耗舊 token 但不返回新 token
- 前端持有已失效的 token,導致第二次操作失敗
- 影響範圍:所有連續的狀態變更操作(拖放、完成、刪除、AI 分解)
-
Solution: Token Rotation Implementation:
- 實施 OWASP 推薦的 Token Rotation 機制
- 每次 POST/PUT/DELETE 操作消耗舊 token 的同時,返回新 token
- 前端自動儲存新 token(BackendGateway.js:112-115 已有機制,無需修改)
-
Backend Changes (gas/backend.gs):
- Modified 5 endpoints in
routeRequest()function (lines 96-115) - Added
generateCsrfToken()call andcsrf_tokento response payload:- POST /tasks (line 96-98) - 建立任務
- POST /tasks/update (line 99-101) - 更新任務狀態(拖放)
- POST /tasks/{id}/complete (line 102-105) - 完成任務
- POST /tasks/{id}/breakdown (line 106-110) - AI 任務分解
- DELETE /tasks/{id} (line 111-115) - 刪除任務
- Code change: +10 lines (5 endpoints × 2 lines each)
- Modified 5 endpoints in
-
Frontend Impact:
- ✅ No modifications required
- Existing auto-save mechanism in BackendGateway.js handles token updates
- Token stored in
AppState.csrfTokenand automatically refreshed on every response
-
Security Assessment 🔒:
- Core Principles Maintained:
- ✅ Use-once token (每個 token 驗證後仍立即刪除)
- ✅ 5-minute expiration (token 最長壽命 5 分鐘)
- ✅ SHA-256 + random generation (不可預測性)
- ✅ Mandatory validation for all state-changing operations
- New Security Benefits:
- ✅ Shortened attack window (token 更頻繁更新)
- ✅ Complies with OWASP Synchronizer Token Pattern
- ✅ Implements Defense in Depth principle
- Risk Analysis:
- ❌ No new risks introduced
- ✅ Does not violate existing security mechanisms
- ✅ Strengthens CSRF protection
- Core Principles Maintained:
-
Technical Details:
- Token lifecycle: Generate → Use → Delete → Generate new (continuous rotation)
- Each operation returns:
{ success: true, ..., csrf_token: "new_token_here" } - Frontend automatically extracts and stores new token from response
- Supports unlimited consecutive operations without page refresh
-
Testing Results:
- ✅ Production deployment successful
- ✅ Consecutive drag-and-drop operations (3+ times) all succeed
- ✅ No "Missing or invalid CSRF token" errors in Console
- ✅ Token rotation verified via Network panel inspection
- ✅ All operation types tested: create, update, complete, delete, AI breakdown
-
User Experience Improvement:
- Before: First operation ✅ → Second operation ❌ → Must refresh page
- After: Unlimited consecutive operations ✅✅✅ → No refresh needed
- Impact: Seamless workflow, reduced friction, better UX
-
Files Modified:
- gas/backend.gs - Added token generation to 5 endpoints
- No frontend changes required
-
Git Commit:
8827fc7- "fix: 實施 CSRF Token Rotation 機制修復連續操作失敗問題" -
Deployment Strategy:
- Backend: GAS deployment with new version (URL unchanged)
- Frontend: No changes, auto-compatible with new backend
- Testing: Production verified on https://task-matrix.zeabur.app/
-
Final Status: ✅ Deployed to production, all tests passed, verified working
- Layout Restructure - Left-Right Split (RESOLVED 2025-11-04)
-
Motivation: User requested layout change to improve drag-and-drop UX: "從下往上拖拽不順手,左右拖拽更直覺"
-
Problem Analysis:
- Original layout: Quadrants (top) + Uncategorized (bottom)
- Poor UX: Creating task → appears at bottom → drag upward to quadrants (awkward)
- User workflow inefficiency: Vertical scrolling required for task categorization
-
Solution Implemented:
-
Parent Container Layout (index.html:148)
- Changed from
space-y-6(vertical stack) →flex flex-col gap-6 lg:flex-row(horizontal split) - Enables left-right layout on desktop, maintains vertical stack on mobile
- Changed from
-
Left Side: Uncategorized Zone (index.html:150-167)
- Added wrapper:
w-full lg:w-80 lg:flex-shrink-0 - Desktop: Fixed 320px width, single column layout
- Mobile: 100% width, vertical stack
- Changed internal layout:
grid lg:grid-cols-2→space-y-3(single column)
- Added wrapper:
-
Right Side: Four Quadrants (index.html:170-240)
- Added wrapper:
flex-1(flexible width, fills remaining space) - Maintains 2x2 grid:
grid gap-6 lg:grid-cols-2 - Responsive: Vertical stack on mobile, grid on desktop
- Added wrapper:
-
-
Technical Details:
- Layout Strategy: Flexbox-based split (consistent with existing code style)
- Responsive Breakpoints:
- Mobile (<1024px): Uncategorized on top, quadrants below (vertical)
- Desktop (≥1024px): Uncategorized left (320px), quadrants right (flexible)
- Memphis Design: 100% preserved (thick borders, colors, dashed lines)
- JavaScript Impact: Zero modifications required (no DOM order dependencies)
-
UX Improvement:
- Before: Create task → bottom → drag upward (counterintuitive)
- After: Create task → left side → drag rightward (natural workflow)
- Benefit: Horizontal drag motion aligns with reading direction (left-to-right)
-
Code Changes:
- Modified Files: index.html only
- Lines Changed: ~15 lines (pure Tailwind class adjustments)
- Element Reordering: Swapped uncategorized and quadrants positions
- No Breaking Changes: All functionality preserved
-
Safety Analysis:
- ✅ No JavaScript dependencies on DOM order (uses
getElementById()) - ✅ No CSS pseudo-selectors dependent on order (
:nth-childnot used) - ✅ Drag-and-drop uses
data-statusattribute (position-independent) - ✅ All existing features tested: create, drag, delete, complete, AI breakdown
- ✅ No JavaScript dependencies on DOM order (uses
-
Responsive Design:
Breakpoint Layout Uncategorized Quadrants Mobile (<1024px) Vertical 100% width, top Stacked below Desktop (≥1024px) Horizontal 320px left Flexible right (2x2) -
Visual Balance:
- Left sidebar: Fixed 320px provides adequate space for task cards
- Right area: Flexible width ensures quadrants have sufficient room
- Gap spacing: Consistent 1.5rem (
gap-6) maintains Memphis aesthetic
-
Testing Results:
- ✅ Desktop layout: Left 320px + Right flexible works perfectly
- ✅ Mobile layout: Vertical stack maintains usability
- ✅ Drag-and-drop: Left-to-right motion feels more natural
- ✅ All task operations: Create, categorize, delete, complete, AI breakdown
- ✅ Visual consistency: Memphis Design fully preserved
-
Files Modified:
- index.html - Layout structure and Tailwind classes
-
Deployment:
- Platform: Zeabur (https://task-matrix.zeabur.app/)
- Deployment method: Direct HTML update via VS Code extension
- Testing: Manual verification in production environment
-
Final Status: ✅ Deployed to production, tested and working perfectly
Product Philosophy: Focus on core value (Eisenhower Matrix + Atomic Habits), avoid feature bloat
Planned Features (2 items, down from 7):
-
🔐 Multi-Tenancy Support - Google Account login, each user has independent task space (requires OAuth Client ID setup)
- Technical approach: Frontend Google Identity Services + Backend token verification
- Estimated effort: 9-13 hours
- Status: Technically feasible, documented architecture
- Note: NOT collaborative (Trello-style), but isolated workspaces (Notion-style)
-
🔒 Prevent Over-Breakdown - Child tasks cannot be AI-broken down again to avoid excessive fragmentation
- Frontend: Hide AI button for tasks with
parent_task_id !== null - Backend: Reject breakdown requests for child tasks
- Estimated effort: 2-3 hours
- Aligns with minimalist philosophy
- Frontend: Hide AI button for tasks with
Removed Directions (5 items removed after product positioning review):
- ❌ Theme Customization - Visual feature, not core functionality
- ❌ Task Tags - Increases cognitive load, conflicts with quadrant classification
- ❌ Advanced Statistics - Current 3 metrics already sufficient
- ❌ Notification Reminders - Changes product character, conflicts with atomic habits philosophy
- ❌ Mobile Optimization - Current responsive design is adequate, desktop-first positioning
Design Decision Process:
- All removals align with user's choice of "極簡主義" (minimalism) for statistics
- Maintains clear product boundary: Priority judgment + Task breakdown, not a full-featured task manager
- Desktop-first tool, not pursuing full-platform full-feature parity
- For Gemini issues: Check GAS logs with
[Gemini]prefix (lines 337-518 in backend.gs) - To switch models: Edit CONFIG.GEMINI_MODEL in backend.gs line 15
- Available models:
gemini-2.0-flash(stable, recommended),gemini-2.5-flash(may have response format issues) - Task intensity system: Check models/Task.js for emoji parsing logic
- To modify intensity badges: Edit core/constants.js for colors and durations
- Frontend: Vanilla JavaScript (ES6+), modularized into 12 files with 5-layer architecture
- Styling: Tailwind CSS 4.0 via CDN
- Icons: Heroicons (inline SVG)
- Backend: Google Apps Script (
gas/backend.gs) deployed as Web App - Database: Google Sheets (Tasks and Analytics sheets)
- AI Service: Google Gemini API for task breakdown
- Deployment: Zeabur (https://task-matrix.zeabur.app/)
Layer 1: Foundation (No Dependencies)
core/constants.js- Status labels and color accents (28 lines)core/icons.js- Heroicons SVG library (63 lines)models/Task.js- Task data model class (62 lines)
Layer 2: Configuration & State
core/config.js- API configuration management (36 lines)core/state.js- Global app state and DOM element references (27 lines)
Layer 3: Services
services/BackendGateway.js- Google Apps Script API communication (179 lines)
Layer 4: Business Logic
handlers/DragDropHandler.js- Drag & drop interaction handling (45 lines)ui/Renderer.js- UI rendering and updates (263 lines)managers/TaskManager.js- Task management core logic (219 lines)monitors/ConnectionMonitor.js- Connection status monitoring (44 lines)
Layer 5: Application
app/events.js- Event binding (38 lines)app/bootstrap.js- Application initialization and DOM setup (52 lines)
Total: 1056 lines (reduced from 1320 lines after Focus Panel removal)
Key Design Principles:
- Single-direction dependency flow (lower layers never depend on higher layers)
- No circular dependencies
- Each module has clear responsibility
- Global objects declared with
window.*prefix for clarity - Elements initialized in bootstrap to avoid null references
- No build process required - direct script loading
- Frontend makes API calls to Google Apps Script Web App endpoint
- GAS backend handles CRUD operations on Google Sheets
- Task breakdown optionally uses Gemini API (if API key configured)
- All state changes sync immediately - no local storage used
# No build process required - just serve the HTML file
# MUST use VS Code Live Server extension to open index.html
# DO NOT use other server tools (python http.server, npm serve, etc.)
# This is a mandatory requirement per development guidelines# Copy and configure API settings
cp config.example.js config.js
# Edit config.js with your Google Apps Script Web App URL- Create a new Google Sheets document
- Open Extensions → Apps Script
- Copy contents of
gas/backend.gsto the script editor - Update
CONFIG.SPREADSHEET_IDwith your Sheets ID - For Gemini AI: Add Script Property
GEMINI_API_KEYin Project Settings - Deploy as Web App:
- Execute as: Me
- Access: Anyone (including anonymous)
- Copy the Web App URL to
config.js - Important: Every redeployment generates a new URL - always update
config.js
- Frontend: https://task-matrix.zeabur.app/
- Spreadsheet ID:
YOUR_SPREADSHEET_ID(⚠️ Fill in your own, do not commit real ID) - GAS Web App URL:
https://script.google.com/macros/s/YOUR_DEPLOYMENT_ID/exec(⚠️ Fill in your own, do not commit real URL) - Gemini Model:
gemini-2.0-flash(stable, recommended) - Statistics Design: Minimalist 3-metric approach (極簡主義方案 A)
- Last Updated: 2025-11-04
- Security Status: 🟢 Very Low Risk (100% issues resolved: 3 fixed, 1 accepted)
- Latest Fix: CSRF Token Rotation 機制 - 支援無限連續操作
Background:
config.jsis NOT in.gitignore(intentionally removed for Zeabur deployment)- This allows Zeabur VS Code Extension to upload it, solving the orange light issue
- However, it requires careful Git operations to prevent accidental commits to GitHub
Security Strategy:
- ✅ GitHub: config.js history completely cleaned (using
git filter-branch) - ✅ Zeabur: config.js included in deployment (Zeabur extension can upload it)
⚠️ Future Commits: Must manually control what gets added to avoid re-uploading config.js
# ✅ SAFE: Add specific files only
git add ui/Renderer.js
git add managers/TaskManager.js
git add core/constants.js
# ✅ SAFE: Add files by pattern
git add ui/*.js
git add *.md
# ✅ SAFE: Check what will be committed BEFORE adding
git status
git diff
# ✅ SAFE: Commit with specific files
git commit ui/Renderer.js -m "..."# ❌ DANGEROUS: Adds ALL modified files (including config.js)
git add .
git add -A
git add --all
# ❌ DANGEROUS: Commits all changes without review
git commit -a
git commit -am "..."-
Before committing:
git status # Review what files changed git diff # Review actual changes
-
Add files selectively:
git add <specific-file-1> <specific-file-2> # or git add ui/*.js managers/*.js
-
Verify staging area:
git status # Ensure config.js is NOT staged -
Commit and push:
git commit -m "descriptive message" git push origin master
If you accidentally commit config.js to GitHub:
-
Remove from latest commit (if not pushed yet):
git reset HEAD~ config.js git commit --amend
-
Remove from history (if already pushed):
# Nuclear option - rewrites history git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch config.js" \ --prune-empty --tag-name-filter cat -- --all git push origin --force --all
-
Update GAS deployment (generate new URL):
- Redeploy GAS as Web App (creates new URL)
- Update local config.js with new URL
- Redeploy to Zeabur
Alternative Considered: Keep config.js in .gitignore
- ❌ Problem: Zeabur VS Code Extension respects .gitignore → can't upload config.js → orange light
Current Approach: Remove config.js from .gitignore
- ✅ Zeabur can upload config.js → green light
- ✅ GAS URL not truly sensitive (protected by CSRF Token)
- ✅ Git history already cleaned
⚠️ Requires discipline: always use selectivegit add
All endpoints are routed through the single Google Apps Script Web App URL.
GET /tasks- List all tasksPOST /tasks- Create new taskPOST /tasks/update- Update task status (drag & drop)POST /tasks/{id}/complete- Mark task as completedPOST /tasks/{id}/breakdown- AI breakdown (requires Gemini API key)GET /stats/weekly- Get weekly statistics
uncategorized → [urgent_important | not_urgent_important | urgent_not_important | not_urgent_not_important] → completed
- Uses HTML5 native drag/drop API
- Status updates trigger immediate API sync
- Visual feedback during drag operations
- Tasks can be dragged between quadrants and back to uncategorized
When a task is broken down:
- User clicks the AI button directly on the task card
- Original task is marked as completed
- 3-5 subtasks are created with
parent_task_idreference - Subtasks inherit the original task's quadrant
- Subtask titles include parent reference with heroicons link icon: "🔗 來自[parent] | [subtask]"
- Subtasks are immediately visible on the board
- No localStorage - all data lives in Google Sheets
- Every operation immediately syncs to backend
- Connection status indicator shows sync state
- Optimistic UI updates with rollback on failure
The application follows a strict loading order defined in index.html:
<!-- Layer 1: Foundation -->
<script src="core/constants.js" defer></script>
<script src="core/icons.js" defer></script>
<script src="models/Task.js" defer></script>
<!-- Layer 2: Configuration & State -->
<script src="core/config.js" defer></script>
<script src="core/state.js" defer></script>
<!-- Layer 3: Services -->
<script src="services/BackendGateway.js" defer></script>
<!-- Layer 4: Business Logic -->
<script src="handlers/DragDropHandler.js" defer></script>
<script src="ui/Renderer.js" defer></script>
<script src="managers/TaskManager.js" defer></script>
<script src="monitors/ConnectionMonitor.js" defer></script>
<!-- Layer 5: Application -->
<script src="app/events.js" defer></script>
<script src="app/bootstrap.js" defer></script>Critical: This order ensures each module's dependencies are loaded before the module itself.
Since Gemini 2.5 models have thinking attribute, response structure may differ:
- Add extensive logging in
backend.gs:Logger.log('[Gemini] Full response: ' + JSON.stringify(data)); Logger.log('[Gemini] Candidates: ' + JSON.stringify(data.candidates)); if (data.candidates?.[0]?.content?.parts) { Logger.log('[Gemini] Parts: ' + JSON.stringify(data.candidates[0].content.parts)); }
- Check for alternative fields:
.thinking,.reasoning,.thought - Try explicit response format in prompt:
請用以下JSON格式回答: ["子任務1", "子任務2", "子任務3"] - Add
responseMimeTypeto API call:generationConfig: { responseMimeType: "text/plain" }
- Update
Taskclass constructor inmodels/Task.js - Add field to GAS
Taskclass inbackend.gs - Update
TaskRepositorymethods for Sheets columns inbackend.gs - Add UI rendering logic in
ui/Renderer.jsif needed
- Update
STATUS_VALUESinbackend.gs - Update
STATUS_LABELSandSTATUS_ACCENTSincore/constants.js - Add corresponding HTML dropzone in
index.htmlif needed
When adding new features, follow the module architecture:
- New API endpoint: Add to
services/BackendGateway.js - New UI component: Add to
ui/Renderer.js - New business logic: Add to
managers/TaskManager.jsor create new manager - New interaction: Add to
handlers/directory - New configuration: Add to
core/config.jsorcore/constants.js
Task cards show time information directly:
- Created time: Displayed as relative time (e.g., "建立於 2 小時前")
- Updated time: Displayed as relative time (e.g., "更新於 15 分鐘前")
- Completed time: Only shown for completed tasks (e.g., "完成於 1 天前")
- Time formatting handled by
Renderer.formatRelativeTime()in ui/Renderer.js
- Check browser console for network errors
- View GAS execution logs: View → Executions in Apps Script editor
- Verify Sheets permissions and API deployment settings
- Check connection status indicator in UI
- API keys should never be committed (use
config.js, not tracked) - Google Apps Script handles authentication
- Sheets permissions control data access
- Batch operations when possible to reduce API calls
- Use lock service in GAS to prevent race conditions
- Implement debouncing for rapid user actions
- All API errors should show user-friendly messages
- Connection failures should be clearly indicated
- Maintain UI consistency even when operations fail
- Use
const/let, nevervar - Prefer arrow functions for callbacks
- Use template literals for string interpolation
- Keep functions focused and under 30 lines
- Use Tailwind utility classes exclusively
- Custom styles only in style tag if absolutely necessary
- Maintain consistent color scheme via brand variables
- Always in Traditional Chinese (繁體中文)
- Clear indication of what went wrong
- Actionable suggestions when possible