Skip to main content

max / makenotwork

Usability audit remediation and creator self-service (v0.5.1) Error handling: field-specific validation errors, slug conflict suggestions, custom HTML5 validation messages, Stripe setup feedback, export error handling. Dashboard: item details declutter (AI/release date to Advanced), UUID->Item ID, Promotions->Promo Codes rename, empty state improvements (blog, team, promos), membership tiers tab always visible, content tab column sorting, toast dismiss button, chart tooltips, Export All button, CSV exports across all data views. Item page: promo code field moved above buy buttons with "Have a code?" label, improved bundle-only item messaging, cart removal confirmation. Library: visible Open button on purchase rows, receipt link in context menu. Promo codes: editable after creation (max_uses, expires_at, starts_at via PUT), scheduled start dates (migration 099), bulk delete expired codes, starts_at validation at all checkout paths. Purchase receipts: GET /receipt/{transaction_id} with print support, buyer and seller access, linked from library purchases. Cart checkout: partial failure now redirects to /cart?checkout=partial with warning banner instead of misleading success redirect.
Co-Authored-By
Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-07 19:38 UTC
Commit: a79dbba2d9266329ad21489474646c2a670a241e
Parent: cbf083b
53 files changed, +1275 insertions, -422 deletions
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makenotwork"
3 - version = "0.5.0"
3 + version = "0.5.1"
4 4 edition = "2024"
5 5 license-file = "LICENSE"
6 6
M server/docs/todo.md +178 -227
@@ -1,270 +1,221 @@
1 1 # Makenotwork TODO
2 2
3 3 ## Status
4 - Done: All pre-beta phases, UX audit remediation, creator trust audit remediation, shopping cart + wishlist checkout. Active: Final pre-launch testing. Next: Soft launch (target 2026-05-09).
4 + v0.5.0 deployed 2026-05-06. Soft launch target 2026-05-09. Audit grade A. ~85K LOC, 1,912 tests, 0 warnings. Migration 096.
5 5
6 - v0.5.0 deployed 2026-05-06. Audit grade A (Run 20, 2026-05-04). ~85K LOC, 1,912 tests (1220 unit + 664 integration + 28 load), 0 cargo warnings, 2 flaky sandbox tests. CI on astra operational. Mutation kill rate 99.4%. Property-based testing active (proptest). UX audit (2026-05-06): Learnability A-, Complexity B+, Discoverability B+, Feature Completeness B. Shopping cart implemented: multi-item Stripe checkout sessions, wishlist-to-cart flow, per-seller grouping, savings nudges. Migration 096.
7 -
8 - Human tasks (manual testing, outreach, legal, infrastructure) moved to `human_todo.md`.
9 - Completed items moved to `todo_done.md`.
6 + Human tasks in `human_todo.md`. Completed items in `todo_done.md`.
10 7
11 8 ---
12 9
13 - ## Remaining Audit Items
10 + ## Sprint 1: Creator Self-Service (table stakes)
14 11
15 - ### Run 20 (2026-05-04) — Medium priority — DONE
12 + Creators expect these from any platform. Without them, sellers hit walls during normal operation.
16 13
17 - ### Run 20 — Low priority — DONE
18 - Split checkout.rs (792 -> 434 + 308 helpers). yara-x bumped 1.14->1.15 (intaglio fix). aws-sdk-s3 bumped 1.119->1.131. rustls-webpki 0.101.7/0.103.10 remain upstream-blocked.
14 + - [x] Add refund initiation from item sales tab (already implemented — refund button + Stripe refund + webhook handler)
15 + - [x] Allow editing promo codes after creation (PUT endpoint, inline edit form for max_uses, starts_at, expires_at)
16 + - [x] Add bulk delete for expired promo codes (DELETE /api/promo-codes/expired + "Delete all expired" button)
17 + - [x] Add scheduled start/end dates for promo codes (migration 099: starts_at column, validation at all checkout paths)
18 + - [x] Add purchase receipt/invoice download for completed purchases (GET /receipt/{transaction_id}, linked from library)
19 + - [x] Handle mid-queue cart checkout failure gracefully (redirect to /cart?checkout=partial with banner)
19 20
20 - ### Deferred Code Quality
21 - - [ ] Remove `async-trait` in favor of Rust 2024 native async traits (chronic)
22 - - [ ] Add README.md to server/
23 - - [x] Delete stale `database_schema.md` (50 migrations) — superseded by `schema.md` (57 migrations)
24 - - [x] Fix MT README prerequisites: removed Redis/Valkey (sessions are PostgreSQL-backed)
25 - - [ ] Split oversized route files: exports.rs (737), license_keys.rs (741), health.rs (844), tabs/user.rs (707)
26 - - [ ] Monitor scheduler.rs (1249), git/mod.rs (624) for growth
27 - - [x] [rust-fuzz] Replace `.unwrap()` with `.expect("tier passed is_none guard")` in db/creator_tiers.rs:607
28 - - [x] [rust-fuzz] Change `Config.host_url` from `String` to `Arc<str>` — eliminates 30+ String clones across codebase
21 + ## Sprint 2: Catalog Power Tools
29 22
30 - ### Dashboard Usability — Remaining (2026-05-05)
23 + Creators with 20+ items need these. One-at-a-time editing doesn't scale.
31 24
32 - Dashboard restructure complete (Phases 1-6 in todo_done.md). Tab layout: Projects, Payments, Analytics, Profile, Account, Plan + overflow. Fan/creator progressive disclosure implemented. Labels removed. Jargon renamed. Discoverability items complete.
25 + - [ ] Always show bulk action bar (disabled/grayed until items selected)
26 + - [ ] Add bulk rename operation
27 + - [ ] Add bulk tag operation
28 + - [ ] Add bulk price change operation
29 + - [ ] Implement soft delete with 30-day recovery — "Recently Deleted" section
30 + - [ ] Show undo toast after bulk delete
31 + - [ ] Add global search across all projects and items from dashboard
33 32
34 - #### Performance
35 - - [x] Add performance philosophy doc (`docs/performance_philosophy.md`) — Tufte/McMaster-Carr principles applied to MNW
36 - - [x] Add frontend performance rules to CONTRIBUTING.md — image dimensions, reload avoidance, loading states, density
37 - - [x] Fix layout shift: add aspect-ratio to all images missing dimensions (item page, audio player, buy page, wizards)
38 - - [x] Replace `window.location.reload()` with HTMX tab re-fetch on item settings (4x), item details (1x), user profile (2x)
39 - - [x] Remove "Loading..." placeholder text from 2FA and passkey sections (empty until revealed)
40 - - [x] Add static JS convention to CONTRIBUTING.md — data-attribute bridges, IIFE pattern, htmx:afterSwap re-init, CLAUDE.md updated
41 - - [x] Extract item-details.js (~350 lines) — bundle, section, tag management from item_details.html. Uses htmx:afterSwap for re-init on tab swap
42 - - [x] Extract item-upload.js (~220 lines) — audio + version upload from partials. htmx:afterSwap re-init
43 - - [x] Extract blog-editor.js (~100 lines) — from dashboard-blog-editor.html. Data attributes for project/post IDs
44 - - [ ] (Deferred) Extract audio-player.js (~450 lines) — will happen as part of unified media player below
33 + ## Sprint 3: Onboarding Overhaul
45 34
46 - ### Unified Media Player
35 + The join wizard conflates buyer and creator journeys. This sprint simplifies it so fans don't bounce through creator steps and creators don't skip things they need.
47 36
48 - Unify audio and video playback into one shared component. Video gets custom controls, insertions, chapters, speed, volume, progress persistence — matching the audio experience. Plan at `~/.claude/plans/eager-ancient-salmon.md`.
37 + - [ ] Branch signup by intent — ask "browse or sell?" after account creation
38 + - [ ] Collapse from 5 steps to 3 (account, profile, welcome)
39 + - [ ] Move creator pitch to dashboard (not a signup step)
40 + - [ ] Move Stripe setup to just-in-time (prompt at first publish)
41 + - [ ] Rename "Apply as Creator" to "Tell us about your work"
42 + - [ ] Rename "Pitch" — term is never defined for users
49 43
50 - - [x] **Phase 1:** Extract media-player.js + media-player.css from audio_player.html — CSS renamed to media-* classes, JS reads config from `<script type="application/json">` bridge, keyboard shortcuts (Space/arrows/M/F/S) included. Template: 1035 → 206 lines
51 - - [x] **Phase 2:** Make state machine media-type aware — video uses single element (no dual gapless), all mediaB references guarded with null checks
52 - - [x] **Phase 3:** VideoPlayerTemplate + video_player.html template + video item handler in item.rs. Video items get dedicated player page (like audio). build_segments_json handles Video content type
53 - - [x] **Phase 4:** Video items now route to dedicated player page (early return in item handler, matching audio pattern) — item.html video section is dead code
54 - - [x] **Phase 5:** Keyboard shortcuts included in Phase 1 (Space, arrows, M, F, S)
55 - - [x] **Code fuzz fixes:** null standbyEl crashes in chapter nav + position restore, play-before-seek race in single-element advance, integer cast overflow guards in build_segments_json
44 + ## Sprint 4: Dashboard Polish
56 45
57 - #### Remaining (from code fuzz 2026-05-05)
58 - - [ ] **Video URL fallback on S3 presign failure** — audio handler falls back to `audio_url` (CDN URL stored in DB), but video handler falls back to `None` because `ContentData::Video` has no `video_url` field. Add `video_url` column to items table (migration), populate from CDN base + S3 key on upload, fall back to it in video handler when presign fails. Matches audio pattern.
59 - - [ ] **Arrow key seek should use virtual timeline** — arrow keys currently set `el.currentTime` directly, bypassing segment boundaries. In segment mode this can seek into content from adjacent segments or past boundaries. Fix: route arrow seek through the progress bar seek logic (find target segment from virtual time, load correct segment, seek to offset). Affects both audio and video.
46 + Terminology fixes, layout improvements, and removing noise from the creator dashboard.
60 47
61 - #### Discoverability — DONE
62 - - [x] Add Media Library access from content editors — "Insert Image" button in blog/item editors, section editors. Shared `media-picker.js` modal fetches `/api/media`, inserts markdown ref at cursor
63 - - [x] Add content search/filter to project Content tab — client-side search by title, filter by status + type dropdowns
64 - - [x] Add "Embed & Share" quick action on Item Overview — button navigates to Embed tab
65 - - [x] Add bulk operations hint on Content tab — form-hint explaining checkbox selection
66 - - [x] Add contextual next-step suggestions after key actions — empty state flow hint, draft/published guidance on item overview
48 + - [ ] Rename "creator tiers" to "Creator Plans" everywhere
49 + - [ ] Show current tier limits inline on Creator Plan tab
50 + - [ ] Make onboarding checklist harder to dismiss
51 + - [ ] Add banner if creator tier not subscribed
52 + - [ ] Promote "Export" to top-level dashboard navigation
53 + - [ ] Add section headers to "More" dropdown
54 + - [ ] Don't show "Your account is in good standing" when no issues
55 + - [ ] Add feature description cards on first visit to project dashboard
56 + - [ ] Add "Project Features" discovery card in overview
67 57
68 - #### Feature Completeness
58 + ## Sprint 5: Account Settings Cleanup
59 +
60 + The account tab is dense and unsorted. Security setup has no guidance.
61 +
62 + - [ ] Reorder: Account Status (top), Security, Account Info, Preferences
63 + - [ ] Add security checklist
64 + - [ ] Split dense content into clearer sub-sections
65 + - [ ] Add "Setup Status" badges (e.g., "2FA: Not Set Up")
66 + - [ ] Promote Stripe Tax toggle to visible position in Payments tab
67 + - [ ] Differentiate pause/deactivate/delete with comparison table
68 + - [ ] Link SSH Keys from Project Code tab
69 +
70 + ## Sprint 6: Item Editor Refinements
71 +
72 + Small improvements to the item editing experience.
73 +
74 + - [ ] Move Sections management to its own collapsible area
75 + - [ ] Add tip/callout about Sections feature
76 + - [ ] Suggest default sections on first item creation based on type
77 + - [ ] Add section at top of pricing tab explaining strategies with examples
78 + - [ ] Clarify whether PWYW + license keys can combine
79 + - [ ] Add real-time validation to pricing fields with format examples
80 + - [ ] Ensure item type descriptions always render in wizard
81 + - [ ] Show allowed file types before upload attempt
82 + - [ ] Show tier-specific file size limit with upgrade link
83 +
84 + ## Sprint 7: Collections Everywhere
85 +
86 + Collections exist but are hard to find and use. This makes them a first-class feature.
87 +
88 + - [ ] Improve "Add to Collection" affordance on item page
89 + - [ ] Add "Add to Collection" action on discover result cards
90 + - [ ] Add "Add to Collection" from library items
91 +
92 + ## Sprint 8: Discovery Improvements
93 +
94 + Help fans find content and help creators understand their audience.
95 +
96 + - [ ] Expose AI Tier filter in discover UI
97 + - [ ] Add search suggestions/autocomplete
98 + - [ ] Add "Has source code" filter for projects with linked Git repos
69 99 - [ ] Add download count analytics per item
100 + - [ ] Add distinction between "already downloaded" and "available for download" in library
101 +
102 + ## Sprint 9: Documentation
103 +
104 + Fill gaps so creators can self-serve instead of contacting support.
105 +
106 + - [ ] Add docs for Collections feature
107 + - [ ] Add docs for Promo Codes & Discounts
108 + - [ ] Add docs for Git integration / source browser
109 + - [ ] Add docs for License Keys
110 + - [ ] Add docs for SyncKit integration
111 + - [ ] Add FAQ / Troubleshooting page by user role
112 +
113 + ---
114 +
115 + ## Backlog (no sprint assigned)
116 +
117 + ### Promo Codes — Nice to Have
118 + - [ ] Add preset trial duration options ("14 days", "30 days")
119 + - [ ] Add share tracking — show which users redeemed a code
120 +
121 + ### Uploads
122 + - [ ] Support resumable uploads for large files (S3 multipart API)
123 + - [ ] Surface content scanning failures to users
124 + - [ ] Add batch file download (ZIP) for item versions
125 +
126 + ### Media Player
127 + - [ ] Video URL fallback on S3 presign failure (migration: `video_url` column)
128 + - [ ] Arrow key seek should use virtual timeline (segment-aware)
129 +
130 + ### Code Quality
131 + - [ ] Remove `async-trait` in favor of Rust 2024 native async traits
132 + - [ ] Add README.md to server/
133 + - [ ] Split oversized route files: exports.rs, license_keys.rs, health.rs, tabs/user.rs
134 + - [ ] Monitor scheduler.rs, git/mod.rs for growth
135 +
136 + ### Feature Completeness
70 137 - [ ] Add cross-project item view
71 - - [ ] Add refund initiation from dashboard
72 - - [ ] Add "Export as CSV" button on item sales tables
138 + - [ ] Git browser: add discover/follow integration
73 139
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 -
89 - ### UX Audit Remediation (2026-05-06) — DONE (4 rounds)
90 -
91 - **Learnability (B+ → A-):** Join preamble, TOTP/passkey labels, SyncKit jargon fix, empty state CTAs (subscriptions, collections), project onboarding checklist, tab hover hints (all dashboards), passkey login label.
92 -
93 - **Complexity (B- → B+):** Pitch step simplified (removed trial/tier fields), item wizard sections step removed (6→5 steps), item Settings merged into Details, item Embed folded into Overview (7→5 tabs), item tab hints.
94 -
95 - **Upload flow:** Client-side file size pre-validation with tier limit from presign response, tier-aware error messages (HTTP 413), retry preserves file selection, upload speed + ETA display.
96 -
97 - **Discoverability (B- → B+):** Wishlists tab in Library (new endpoint + template), data export link in dashboard header, changelog link de-muted, RSS/copy-link moved to profile header, library purchases search filter, quick-edit links confirmed present.
98 -
99 - **Shopping cart + wishlist checkout (Feature Completeness B → B+):** Migration 096 (cart_items table), cart DB module, cart API (toggle/remove/count), multi-line-item Stripe Checkout Sessions per seller (Direct Charges), cart checkout route, cart webhook handler (batch transaction completion), cart page grouped by seller with savings nudge, wishlist-to-cart flow, "Add to Cart" on item pages + wishlists + purchase page, cart link in nav, scheduler cleanup.
100 -
101 - ### UX — Deferred (post-launch)
102 - - [ ] Storefront customization (creator themes/colors — 24 TOML themes exist in shared/themes/)
103 - - [ ] Reviews/ratings system for items
104 - - [ ] Wishlist price-drop alerts
105 - - [ ] Gift purchases at checkout
106 - - [ ] HTML rich email for creator broadcasts (currently plain text only)
107 - - [ ] In-app notification center (beyond email-only notifications)
108 - - [ ] Cross-seller cart checkout (currently one Stripe session per seller)
109 - - [ ] Promo codes in cart checkout (currently single-item only)
110 - - [ ] PWYW custom amounts in cart (currently uses minimum price)
140 + ### Global UX
141 + - [ ] Add toast stacking for multiple notifications
142 + - [ ] Add "New" badge/dot indicator on recently launched features
143 + - [ ] Auto-show "What's New" modal on major version bumps
144 + - [ ] Link changelog from landing page
145 + - [ ] Add aria-describedby linking hint text to form inputs
146 + - [ ] Add aria-invalid and aria-errormessage for validation errors
111 147
112 148 ---
113 149
114 - ## Pre-Beta — Remaining
150 + ## Post-Launch
115 151
116 - ### Creator Trust Audit Remediation (2026-05-03) — DONE
117 - All items complete. AI disclosure updated. Buyer notification wired into email-link deletion path. Compare page, fee examples, storage docs, backup test procedure all added.
152 + ### Competitive Comparison
153 + - [ ] i18n (fluent-rs vs rust-i18n, message catalog, locale middleware)
154 + - [ ] OpenAPI spec (annotate remaining endpoints, auto-generate docs)
155 + - [ ] CI/CD formalization (clippy gate, migration check, timing report)
118 156
119 - ### Incident Notification System — DONE
120 - Creators can opt into email alerts when platform status changes. Migration 091 adds `notify_status` column. Monitor sends emails on status transitions to opted-in users with proper unsubscribe links. Dashboard checkbox in settings tab.
157 + ### File Scanning
158 + - [ ] Background scan queue (scan_queue table, scheduler, S3 streaming)
159 + - [ ] Separate scanning service (standalone binary, when traffic justifies)
121 160
122 - ### Frontend
123 - - [ ] Git browser integration: add discover/follow integration (post-beta)
161 + ### Revenue & Business
162 + - [ ] Earn-back credit program (schema, annual calc, dashboard, email)
163 + - [ ] Churn monitoring and creator health (materialized view, risk scoring)
164 + - [ ] Chargeback protection fund (dispute webhooks, pool ledger, caps)
165 + - [ ] Automated revenue split payouts (Stripe Transfers)
124 166
125 - ---
126 -
127 - ## File Scanning — Future Improvements
128 -
129 - ### Background scan queue (next)
130 - - [ ] Add `scan_queue` table (s3_key, file_type, user_id, status, created_at)
131 - - [ ] Enqueue oversized files from `scan_and_classify` instead of blanket HeldForReview
132 - - [ ] Scheduler picks up queued scans, streams from S3 to temp file, scans from disk
133 - - [ ] Update entity scan status + notify creator on completion
134 -
135 - ### Separate scanning service (later, when traffic justifies)
136 - - [ ] Extract scan worker into standalone binary (same crate, different bin target)
137 -
138 - ---
139 -
140 - ## Competitive Comparison Remediation (2026-04-29)
141 -
142 - ### i18n — Grade C
143 - - [ ] Evaluate `fluent-rs` vs `rust-i18n`
144 - - [ ] Extract user-facing strings into message catalog
145 - - [ ] Add locale negotiation middleware
146 - - [ ] i18n error messages
147 -
148 - ### OpenAPI Spec — Grade A-
149 - - [ ] Annotate remaining public endpoints
150 - - [ ] Auto-generate API reference docs from spec
151 -
152 - ### CI/CD Formalization — Grade B+
153 - - [ ] Add `cargo clippy` + `cargo test` as git pre-push hook or CI gate
154 - - [ ] Add migration integrity check to CI
155 - - [ ] Add test timing report to CI output
156 - - [ ] Consider sourcehut builds.sr.ht manifest
157 -
158 - ---
159 -
160 - ## Post-Beta
161 -
162 - ### Earn-Back Credit Program
163 - - [ ] Schema, annual calculation job, apply credits, dashboard display, email notification
164 -
165 - ### Churn Monitoring and Creator Health
166 - - [ ] creator_health materialized view, churn risk scoring, admin dashboard widget
167 - - [ ] Trigger: implement before reaching 100 creators
168 -
169 - ### Phase 11B: Promotions
167 + ### Platform Growth
170 168 - [ ] Affiliate/referral program
169 + - [ ] Creator platform import (Substack, Ghost, Gumroad, Bandcamp, Ko-fi, Patreon)
170 + - [ ] Fan+ accounts (Stripe, credits, badge, gating)
171 + - [ ] Comments (MT moderation, buyer/subscriber restriction)
172 + - [ ] Content newsletters (delivery metrics, section-level prefs)
171 173
172 - ### Phase 13D: Creator Platform Import System — Remaining
173 - - [ ] Substack ZIP importer, Ghost JSON importer
174 - - [ ] Gumroad CSV/API, Bandcamp CSV preset, Ko-fi CSV preset, Lemon Squeezy, Patreon OAuth
174 + ### Infrastructure
175 + - [ ] Media transcoding pipeline (probe, audio, video, adaptive bitrate)
176 + - [ ] Embeddable widgets (endpoint, overlay, inline)
177 + - [ ] Performance (caching, query optimization, CDN, metrics)
178 + - [ ] Search infrastructure (tsvector, unified API, cross-project)
179 + - [ ] Notification service (table, triggers, API, digest prefs)
180 + - [ ] Image upload pipeline (thumbnails, format validation)
181 + - [ ] Link preview extraction (shared crate, OG metadata)
182 + - [ ] SEO & bot access (Cloudflare crawl endpoint, per-creator toggle)
175 183
176 - ### Phase 14E: Media Transcoding Pipeline
177 - - [ ] Probe + detect infrastructure
178 - - [ ] Audio transcoding (SmallFiles tier)
179 - - [ ] Fan download format choice
180 - - [ ] Video transcoding
181 - - [ ] Everything tier: adaptive bitrate streaming, quality ladders
184 + ### Major Features
185 + - [ ] Mobile apps (iOS + Android: library, downloads, offline, player, push)
186 + - [ ] Physical product listings (type, shipping, order management)
187 + - [ ] Live streaming (Everything tier, trigger: first subscriber)
188 + - [ ] Payment independence (stablecoin, fee reduction, international)
189 + - [ ] Scheduled content (pre-save, pre-order, countdown, calendar)
190 + - [ ] OSS creator tools (git wikis, compare, tags, code search, mailing lists)
191 + - [ ] License key self-management (activation, offline grace, transfer)
192 + - [ ] SyncKit S5/S8/S9 (Swift SDK, multi-tenant, WebSocket, CRDT)
193 + - [ ] Developer services (crash reporting, feedback, dashboard)
194 + - [ ] DocEngine (full-text search, versioned docs)
182 195
183 - ### Phase 14B: Embeddable Widgets
184 - - [ ] Embed endpoint, overlay widget, inline embed
185 -
186 - ### Phase 16: Performance
187 - - [ ] Response caching, query optimization, CDN, metrics endpoint
188 -
189 - ### SEO & Bot Access
190 - - [ ] Evaluate Cloudflare `/crawl` endpoint, per-creator crawl preference toggle
191 -
192 - ### Phase 17B: Content Newsletters — Remaining
193 - - [ ] Delivery metrics, section-level email preferences
194 -
195 - ### Phase 17C: Comments — Remaining
196 - - [ ] Creator moderation via MT tools, restrict commenting to buyers/subscribers
197 -
198 - ### Phase 20: OSS Creator Tools
199 - - [ ] Git-backed wikis, compare view, tags/releases, code search
200 - - [ ] Platform-wide mailing lists, sponsor tiers, CI/build enhancements
201 -
202 - ### Phase 20B: Mobile Apps (Consumption)
203 - - [ ] iOS + Android: library, downloads, offline, audio player, reader, push notifications
204 -
205 - ### Phase 20C: Physical Product Listings
206 - - [ ] Physical product type, shipping address, order management
207 -
208 - ### Ko-fi Comparison Gaps
209 - - [ ] Fundraising goals, commissions, social integrations
210 -
211 - ### Phase 20D: Automated Revenue Split Payouts
212 - - [ ] Automated Stripe Transfers, multi-processor support
213 -
214 - ### Phase 21: Scheduled Content — Remaining
215 - - [ ] Pre-save + pre-order, countdown display, calendar view
216 -
217 - ### Phase 22: Live Streaming (Everything tier)
218 - - [ ] Full spec in git history. MVP: 22A + 22B + 22E + 22C + 22H
219 - - [ ] Trigger: first Everything tier creator subscribes
220 -
221 - ### Chargeback Protection Fund
222 - - [ ] Mutual pool: creators contribute ~0.75% of sales, pool reimburses chargeback losses (all types, not just fraud)
223 - - [ ] Requires: dispute webhooks on connected accounts, pool ledger, per-creator caps, experience rating
224 - - [ ] Full plan: `docs/internal/business/chargeback_protection_fund.md`
225 - - [ ] Prerequisite: 50+ participating creators, 3-month reserve buildup before payouts activate
226 -
227 - ### Phase 24: Payment Independence
228 - - [ ] Stablecoin checkout, reduce creator-side fees, Stripe dependency mitigation, international expansion
229 -
230 - ### License Key Self-Management
231 - - [ ] Buyer activation management, offline grace period, license transfer
232 -
233 - ### SyncKit S5/S8/S9
234 - - [ ] Swift SDK, multi-tenant, rate limiting, WebSocket realtime, CRDT, productize
235 -
236 - ### Developer Services
237 - - [ ] Crash reporting, feedback collection, dashboard aggregate endpoint
238 -
239 - ### Fan+ Accounts
240 - - [ ] Stripe integration, monthly credit, badge, feature gating, dev community
241 -
242 - ### DocEngine — Remaining
243 - - [ ] Full-text search index, versioned docs
244 -
245 - ### Notification Service
246 - - [ ] notifications table, event triggers, API endpoints, digest preferences
247 -
248 - ### Search Infrastructure
249 - - [ ] Full-text search (tsvector), unified search API, cross-project results
250 -
251 - ### Image Upload Pipeline
252 - - [ ] Thumbnail generation, format validation, size limits
253 -
254 - ### Link Preview Extraction
255 - - [ ] Extract to shared crate, OG metadata, blog post URL previews
196 + ### UX Deferred
197 + - [ ] Storefront customization (creator themes/colors)
198 + - [ ] Reviews/ratings system
199 + - [ ] Wishlist price-drop alerts
200 + - [ ] Gift purchases
201 + - [ ] HTML rich email for broadcasts
202 + - [ ] In-app notification center
203 + - [ ] Cross-seller cart checkout
204 + - [ ] Promo codes in cart checkout
205 + - [ ] PWYW custom amounts in cart
206 + - [ ] Keyboard shortcuts
256 207
257 208 ---
258 209
259 210 ## Dependencies (blocked on upstream)
260 - - [ ] Monitor yara-x for wasmtime >=42.0.2 (RUSTSEC-2026-0095, -0096)
261 - - [ ] Monitor aws-sdk-s3 for lru fix (RUSTSEC-2026-0002)
262 - - [ ] Monitor async-stripe for instant fix (RUSTSEC-2024-0384)
211 + - [ ] yara-x: wasmtime >=42.0.2 (RUSTSEC-2026-0095, -0096)
212 + - [ ] aws-sdk-s3: lru fix (RUSTSEC-2026-0002)
213 + - [ ] async-stripe: instant fix (RUSTSEC-2024-0384)
263 214 - [ ] rsa (RUSTSEC-2023-0071) via sqlx-mysql + yara-x — no fix available
264 215
265 - ## Deferred
216 + ## Deferred (no timeline)
266 217 - [ ] Team/organization accounts
267 - - [ ] Creator @makenot.work email addresses (Migadu)
218 + - [ ] Creator @makenot.work email (Migadu)
268 219 - [ ] Tax-year revenue summary, invoice generation, 1099 guidance
269 220 - [ ] Merchant of Record (MoR)
270 221 - [ ] Email drip workflows
@@ -110,6 +110,12 @@
110 110 if (elt) htmx.trigger(elt, htmx.closest(elt, '[hx-trigger]') ? 'htmx:trigger' : 'click');
111 111 };
112 112 toast.appendChild(retryBtn);
113 + var closeBtn = document.createElement('button');
114 + closeBtn.className = 'toast-dismiss';
115 + closeBtn.textContent = '\u00d7';
116 + closeBtn.setAttribute('aria-label', 'Dismiss');
117 + closeBtn.onclick = function() { toast.remove(); };
118 + toast.appendChild(closeBtn);
113 119 container.appendChild(toast);
114 120 setTimeout(function() {
115 121 toast.classList.add('fade-out');
@@ -1356,6 +1356,24 @@
1356 1356 align-items: center;
1357 1357 min-width: 0;
1358 1358 cursor: default;
1359 + position: relative;
1360 + }
1361 +
1362 + .chart-bar-col[data-tooltip]:hover::before {
1363 + content: attr(data-tooltip);
1364 + position: absolute;
1365 + bottom: 100%;
1366 + left: 50%;
1367 + transform: translateX(-50%);
1368 + background: var(--primary-dark);
1369 + color: var(--primary-light);
1370 + font-size: 0.75rem;
1371 + font-family: var(--font-mono);
1372 + padding: 0.25rem 0.5rem;
1373 + white-space: nowrap;
1374 + z-index: 10;
1375 + pointer-events: none;
1376 + margin-bottom: 0.25rem;
1359 1377 }
1360 1378
1361 1379 .chart-bar {
@@ -1616,6 +1634,25 @@
1616 1634 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1617 1635 animation: toast-in 0.3s ease-out;
1618 1636 max-width: 300px;
1637 + display: flex;
1638 + align-items: center;
1639 + gap: 0.75rem;
1640 + }
1641 +
1642 + .toast-dismiss {
1643 + background: none;
1644 + border: none;
1645 + color: inherit;
1646 + font-size: 1.1rem;
1647 + cursor: pointer;
1648 + opacity: 0.7;
1649 + padding: 0;
1650 + line-height: 1;
1651 + flex-shrink: 0;
1652 + }
1653 +
1654 + .toast-dismiss:hover {
1655 + opacity: 1;
1619 1656 }
1620 1657
1621 1658 .toast-success {
@@ -33,4 +33,47 @@
33 33 sidebar.appendChild(inlineNav);
34 34 }
35 35 });
36 + // Custom HTML5 validation messages for wizard forms.
37 + // Replaces browser defaults ("Please fill out this field") with
38 + // field-specific messages using data-* attributes or fallback rules.
39 + function applyCustomValidation(root) {
40 + var inputs = root.querySelectorAll('input[required], input[minlength], input[pattern], textarea[minlength]');
41 + inputs.forEach(function(input) {
42 + input.addEventListener('invalid', function(e) {
43 + var v = e.target.validity;
44 + var label = (e.target.closest('.form-group')?.querySelector('label')?.textContent || '').trim();
45 + var custom = e.target.dataset.validationMessage;
46 +
47 + if (custom) {
48 + e.target.setCustomValidity(custom);
49 + } else if (v.valueMissing) {
50 + e.target.setCustomValidity(label ? label + ' is required' : 'This field is required');
51 + } else if (v.tooShort) {
52 + var min = e.target.getAttribute('minlength');
53 + e.target.setCustomValidity('Must be at least ' + min + ' characters');
54 + } else if (v.tooLong) {
55 + var max = e.target.getAttribute('maxlength');
56 + e.target.setCustomValidity('Must be ' + max + ' characters or fewer');
57 + } else if (v.patternMismatch) {
58 + e.target.setCustomValidity(e.target.title || 'Please use the expected format');
59 + } else if (v.typeMismatch) {
60 + e.target.setCustomValidity('Please enter a valid ' + (e.target.type || 'value'));
61 + } else {
62 + e.target.setCustomValidity('');
63 + }
64 + });
65 + // Clear custom message on input so re-validation works
66 + input.addEventListener('input', function() {
67 + this.setCustomValidity('');
68 + });
69 + });
70 + }
71 +
72 + // Apply to initial page content
73 + applyCustomValidation(document.body);
74 +
75 + // Re-apply after HTMX swaps new wizard steps in
76 + document.addEventListener('htmx:afterSwap', function(event) {
77 + applyCustomValidation(event.detail.target);
78 + });
36 79 })();