Skip to main content

max / makenotwork

Add usability audit remediations, page view tracking, buyer contacts, cross-project analytics UX easy wins: Docs/Fan+/Changelog links in header nav, contextual Edit links on public pages, project/item wizard hints, Members→Team rename, Copy ID tooltip, upload error messages now surface server-side detail. Terminology: subscription tiers→membership tiers across dashboard, wizards, public pages, and 7 docs files. Fan-facing "Subscribe" verbs kept. Page view tracking (M095): daily aggregate table with fire-and-forget UPSERT from item/project/user handlers, bot filtering, 2-year pruning. Buyer contacts: HTMX lazy-loaded section in Payments tab showing buyers who opted to share email, with CSV export. Uses existing get_seller_contacts(). Analytics: Views + Conversion stat cards on user and project analytics tabs. Cross-project comparison table with revenue bars, sales, views, conversion. New get_revenue_by_user_projects_in_range() for time-scoped comparison. Bump to 0.4.11.
Co-Authored-By
Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-06 19:55 UTC
Commit: e0c1aec160cc26cc00d98e462ce3e9b5b10493fb
Parent: aa07511
45 files changed, +814 insertions, -83 deletions
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makenotwork"
3 - version = "0.4.10"
3 + version = "0.4.11"
4 4 edition = "2024"
5 5 license-file = "LICENSE"
6 6
@@ -3,7 +3,7 @@
3 3 ## Status
4 4 Done: All pre-beta phases, UX audit remediation, creator trust audit remediation. Active: Creator setup (Stripe), manual testing. Next: Soft launch.
5 5
6 - v0.4.10 deployed 2026-05-04. Audit grade A (Run 20, 2026-05-04). ~83K LOC, 1,214+ test annotations, 0 cargo warnings, 2 cold spots. CI on astra operational. Mutation kill rate 99.4%. Property-based testing active (proptest). `cargo test --features fast-tests` for fast runs. Doc fuzz (2026-05-06): deleted stale database_schema.md, fixed MT README, updated SyncKit version in docs.
6 + v0.4.10 deployed 2026-05-04. Audit grade A (Run 20, 2026-05-04). ~83K LOC, 1,214+ test annotations, 0 cargo warnings, 2 cold spots. CI on astra operational. Mutation kill rate 99.4%. Property-based testing active (proptest). `cargo test --features fast-tests` for fast runs. Doc fuzz (2026-05-06): deleted stale database_schema.md, fixed MT README, updated SyncKit version in docs. Usability audit (2026-05-06): grade B-, 18 easy wins + 9 medium items + 3 deferred added.
7 7
8 8 Human tasks (manual testing, outreach, legal, infrastructure) moved to `human_todo.md`.
9 9 Completed items moved to `todo_done.md`.
@@ -71,11 +71,27 @@
71 71 - [ ] Add refund initiation from dashboard
72 72 - [ ] Add "Export as CSV" button on item sales tables
73 73
74 + ### Usability Audit (2026-05-06) — Easy Wins (batch) — DONE
75 + Completed: header nav (Docs, Fan+, Changelog links), contextual Edit links on project/user/item public pages, View Profile link on dashboard-user, Members→Team rename, project/item wizard hints, Copy ID tooltip. Pre-existing: empty states (Projects tab, Content tab), onboarding descriptions, insertion→clip rename, RSS link, View Live link, Tools checkboxes.
76 +
77 + All easy wins complete. Upload error fix: client-side JS now parses server JSON error responses instead of showing generic "Failed to get upload URL" / "Failed to confirm upload". Server already returns tier-specific messages ("File exceeds maximum size of X MB", "Basic tier is text-only", "You've used X of Y storage"). Fixed in: item-upload.js (audio + version), item/content.html (video + batch).
78 +
79 + ### Usability Audit (2026-05-06) — Medium — DONE
80 + Pre-existing (audit false negatives — HTMX tab content not visible to probes): promo code management (Promotions tab), custom links editor (Profile tab), collections management (Library tab), bulk item operations (Content tab checkboxes + publish/unpublish/delete), custom domain config (Profile tab), scheduled releases (Settings tab — datetime picker + cancel).
81 +
82 + Completed (2026-05-06):
83 + - Buyer Contacts: HTMX lazy-loaded in Payments tab, CSV export at `/api/export/contacts`. Uses existing `get_seller_contacts()` — no migration needed. Respects contact_revocations.
84 + - Page View Tracking: Migration 095 (`page_view_daily` table), fire-and-forget UPSERT from item/project/user page handlers, bot filtering, 2-year pruning in scheduler.
85 + - Cross-project analytics: Project Comparison table on user Analytics tab (revenue with inline bars, sales, views, conversion). Time-range aware.
86 + - Conversion analytics: Views + Conversion stat cards on both user and project Analytics tabs. Period-over-period % for views.
87 + - Subscription → Membership terminology: project dashboard tab, wizard, project page, 7 docs files.
88 +
74 89 ### UX — Deferred (post-beta table stakes)
75 90 - [ ] Reviews/ratings system for items
76 91 - [ ] Gift purchases at checkout
77 92 - [ ] HTML rich email for creator broadcasts (currently plain text only)
78 - - [ ] RSS feed link on all project pages (currently only shown if blog posts exist)
93 + - [ ] Creator-to-fan broadcast email composer (full system, not just contact export)
94 + - [ ] In-app notification center (beyond email-only notifications)
79 95
80 96 ---
81 97
@@ -75,7 +75,9 @@
75 75 })
76 76 })
77 77 .then(function(res) {
78 - if (!res.ok) throw new Error('Failed to get upload URL');
78 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
79 + throw new Error(d.error || 'Failed to get upload URL');
80 + });
79 81 return res.json();
80 82 })
81 83 .then(function(data) {
@@ -93,7 +95,9 @@
93 95 });
94 96 })
95 97 .then(function(res) {
96 - if (!res.ok) throw new Error('Failed to confirm upload');
98 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
99 + throw new Error(d.error || 'Failed to confirm upload');
100 + });
97 101 document.getElementById('upload-progress').classList.add('hidden');
98 102 document.getElementById('upload-success').classList.remove('hidden');
99 103 setTimeout(function() { window.location.href = '/dashboard/item/' + itemId; }, 1500);
@@ -156,7 +160,9 @@
156 160 })
157 161 })
158 162 .then(function(res) {
159 - if (!res.ok) throw new Error('Failed to create version');
163 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
164 + throw new Error(d.error || 'Failed to create version');
165 + });
160 166 return res.json();
161 167 })
162 168 .then(function(data) { uploadVersionFile(data.id, selectedFile); })
@@ -211,7 +217,9 @@
211 217 })
212 218 })
213 219 .then(function(res) {
214 - if (!res.ok) throw new Error('Failed to get upload URL');
220 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
221 + throw new Error(d.error || 'Failed to get upload URL');
222 + });
215 223 return res.json();
216 224 })
217 225 .then(function(data) {
@@ -225,7 +233,9 @@
225 233 });
226 234 })
227 235 .then(function(res) {
228 - if (!res.ok) throw new Error('Failed to confirm upload');
236 + if (!res.ok) return res.json().catch(function() { return {}; }).then(function(d) {
237 + throw new Error(d.error || 'Failed to confirm upload');
238 + });
229 239 document.getElementById('version-upload-progress').classList.add('hidden');
230 240 document.getElementById('version-upload-success').classList.remove('hidden');
231 241 setTimeout(function() { window.location.href = '/dashboard/item/' + itemId; }, 1500);