Skip to content

feat: subscriptions management + project name display fix#218

Open
NovakPAai wants to merge 1 commit into
mainfrom
feat/analytics-subscriptions
Open

feat: subscriptions management + project name display fix#218
NovakPAai wants to merge 1 commit into
mainfrom
feat/analytics-subscriptions

Conversation

@NovakPAai
Copy link
Copy Markdown
Collaborator

Summary

  • Subscriptions (Analytics → History): track paid plans and API deposits across all 7 agents. Service select grew from 5 to 9 + API (custom): Claude Code · ChatGPT/Codex · Cursor · Copilot · Kiro · OpenCode · Qwen Code · Kilo · API (custom). Pick service → Plan select populates; pick plan → monthly amount auto-fills. Prices verified 2026-05-15 against vendor pages.
  • Project name fix: Cost by Project and Most Expensive Sessions show codbash (basename) instead of ~/code/codbash or $HOME prefix. Sessions whose path equals $HOME merge into a single (home) group.

What's changed

Backend (src/data.js):

  • displayProject(session) helper — basename / (home) / unknown. Used in byProject aggregation. Exported via __test.
  • 14 unit tests in test/display-project.test.js (node:test, zero-dep).

Frontend:

  • SERVICE_PLANS extended with kind field (subscription / api / api-only).
  • renderPlanSlot(cfg) swaps a native <select> for Plan into a free-text <input> when service is API (custom).
  • Form is a <form onsubmit> — Enter submits from any field.
  • updateAddButtonState announces validation reason via aria-describedby="sub-new-hint".
  • Subgroups by kind (Subscriptions / API deposits) with <h4> headings + subtotals.
  • localStorage migration is read-time only, returns immutable copies; legacy single-entry format gets a (legacy) plan prefix.
  • aria-live #sub-aria-live updated before render() for add/remove announcements.
  • Touch target on Remove × is now 32×32 (WCAG 2.5.8 AA).
  • Responsive @media (max-width: 480px) — form collapses to single column.

Quality gates

Gate Result
node --check on all touched files
node --test test/display-project.test.js ✅ 14/14
node --test test/*.test.js 94/95 (1 pre-existing wsl-windows fail on macOS, unrelated)
Three-agent review (code / security / UX with vercel-web-design-guidelines + ux-designer skills) ✅ all CRITICAL/HIGH/MEDIUM addressed
Smoke (tasks/2026-05-15-analytics-subscriptions/smoke-report.md) 🟢 GREEN

Deferred (with explicit reasons)

  • #sub-aria-live as body-level singleton — currently announced before render() and works in Chrome/Safari. Promoting the live region to a <body>-level singleton that survives render() is an app-wide refactor — follow-up PR.
  • s.id / s.date unescaped in analytics.js (Most Expensive Sessions row) — pre-existing code on lines 338, 341 outside this diff. Tech debt, separate task.
  • required on selects — manual validation in updateAddButtonState already gates submission; native required would override the custom logic.
  • Minor UX polish nits (separator pronunciation, tooltip vs keyboard, sort order when from='', role=list/role=listitem on rows) — none break the BDD acceptance scenarios; queued for next a11y polish pass.
  • 4× pre-existing var(--text) references in styles.css (lines 1850, 1878, 3053, 3155) — outside this diff. Should be replaced with var(--text-primary) in a CSS cleanup PR.

Test plan

  • git checkout feat/analytics-subscriptions && node bin/cli.js run --port 8765 --no-open
  • Open http://localhost:8765, switch to Analytics → History.
  • Subscription form: select Claude Code → Plan options appear → pick Max 5× → Paid auto-fills 100.
  • Select API (custom) → Plan field becomes free-text input with placeholder Provider / balance label; Paid placeholder changes to $ deposit.
  • Select Qwen Code → hint reads Free / API-only — use "API (custom)" to track deposits; Add disabled.
  • Add 1 subscription + 1 API deposit → two subgroups visible with subtotals.
  • Tab through form → focus ring visible on every control.
  • Press Enter from any field with valid values → entry added.
  • Cost by Project chart: row labels are short (codbash, flow-tasks, (home), etc.) — no ~/, no $HOME.
  • Most Expensive Sessions: project column likewise shows basenames.
  • Old localStorage format {plan, paid} migrates to (legacy) <plan> without errors.

Artifacts

  • SDD: docs/design/analytics-subscriptions.md
  • BDD: specs/analytics-subscriptions.feature (6 categories: happy / empty / loading / error / keyboard / edge-data)
  • Plan: tasks/2026-05-15-analytics-subscriptions/plan.md
  • Smoke report: tasks/2026-05-15-analytics-subscriptions/smoke-report.md

@vakovalskii
Copy link
Copy Markdown
Owner

⚠️ Don't merge until rebased — same pattern as #216: the branch was forked from main before #217 landed, so merging now would silently undo it.

git diff main pr218 --stat shows:

The new subscriptions + display-project work in this PR looks great (displayProject helper, (home) merge, 9-service select + plan auto-fill, docs/design/analytics-subscriptions.md + specs/ artifacts). Just needs a rebase so it lands additively rather than rewinding #217.

git fetch origin
git rebase origin/main
# expect conflicts in: ci.yml (just delete your '-2' hunk), src/repo-refresh.js (keep main's timer-tracking)
git push --force-with-lease

Will re-review immediately after. Should be quick. 🙏

@NovakPAai NovakPAai force-pushed the feat/analytics-subscriptions branch from d831a2a to 1af6aa9 Compare May 18, 2026 07:43
@NovakPAai
Copy link
Copy Markdown
Collaborator Author

Rebased onto current main (now at 56a8da8). git diff main..HEAD --stat is clean — only the subscriptions + display-project work (9 files, +1221/-77), no negative deltas against #213/#214/#215/#217. Local node --test test/display-project.test.js test/repo-refresh.test.js → 30/30 ✅. CI on the rebased head is green (6/6). Ready for re-review 🙏

@vakovalskii
Copy link
Copy Markdown
Owner

Sorry @NovakPAai — same issue again, second order this time. Just merged #216 and the diff for this PR against current main now shows -132 specs/sidebar-customization.feature, -183 src/frontend/sidebar-config.js, -353 test/sidebar-config.test.js, -111 + -64 tasks/2026-05-15-sidebar-customization/*, plus a 600-line net regression on src/frontend/app.js. Merging now would wipe #216.

Both PRs were rebased onto the same base (pre-#216), so the second one always carries an inverse of the first. One more rebase will fix it:

git fetch origin
git rebase origin/main
# expect conflicts in: src/frontend/app.js, index.html, styles.css (#216 touched the same files for sidebar groups; keep both changes)
git push --force-with-lease

The subscriptions code itself looks ready — displayProject helper is well-defended (tilde paths, (home) collapse, Windows separators, case-insensitive HOME compare, exported via __test), 14 unit tests green. Just needs the base to be current.

…splay

Analytics → History tab now lets you track paid subscriptions and API
deposits across all supported services. Service select expanded from
5 to 9 entries (+ API custom): Claude Code, ChatGPT/Codex, Cursor,
Copilot, Kiro, OpenCode, Qwen Code, Kilo, API (custom). Picking a
service populates the Plan select with current pricing (verified
2026-05-15 against vendor pages); picking a plan auto-fills the
monthly amount. API (custom) replaces the Plan select with a free-text
provider/balance input.

Cost by Project and Most Expensive Sessions now show clean project
basenames ("codbash" instead of "~/code/codbash"). Sessions whose path
equals \$HOME group into a single "(home)" row.

Implementation
- Backend helper displayProject() in src/data.js — basename / (home) /
  unknown — used in byProject aggregation. 14 unit tests via node:test.
- SERVICE_PLANS extended; kind field discriminates subscription / api /
  api-only (Qwen, Kilo).
- Native <select> for Service and Plan (replaces datalist); free-text
  input swapped in for API (custom).
- localStorage migration is read-time only, immutable copy; legacy
  single-entry format gets a "(legacy) " plan prefix.
- Form is a <form onsubmit> so Enter submits from any field;
  updateAddButtonState announces validation reason via aria-describedby.
- Subgroups (Subscriptions / API deposits) use <h4> headings.
- Touch target on Remove × bumped to 32×32 (WCAG 2.5.8 AA).
- Responsive @media flips form to single column under 480px.
- Three-agent review (code / security / UX-with-skills): all CRITICAL,
  HIGH, MEDIUM addressed; selected LOW deferred with reasons in PR body.
@NovakPAai NovakPAai force-pushed the feat/analytics-subscriptions branch from 1af6aa9 to 2cc0ff2 Compare May 19, 2026 07:23
@NovakPAai
Copy link
Copy Markdown
Collaborator Author

Rebased on current main (now at 654530c, includes #216). git diff main..HEAD --stat clean: 9 files, +1221/-77, no negative deltas against #216 files (sidebar-customization.feature, sidebar-config.js, sidebar-config.test.js, tasks/2026-05-15-sidebar-customization/*, app.js). Auto-merged without conflicts — #216 changes to app.js/index.html/styles.css didn't overlap line-wise with the analytics work. Local node --test test/display-project.test.js test/repo-refresh.test.js → 30/30 ✅. CI re-running. Ready for re-review 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants