Skip to main content

max / makenotwork

Clean up todo.md: move completed items to todo_done.md - todo.md reduced from 459 to 155 lines (open items only) - todo_done.md: added audit run 18/19, UX audit (16/16 complete), pre-beta tasks, integration test fixes, unwrap audit - Updated migrations reference to 001-088 - Consolidated post-beta sections into compact summaries Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-03 03:26 UTC
Commit: ac53b1cc772c956e77893f8ff8729cfc5e7c1b42
Parent: a4d6be1
2 files changed, +142 insertions, -303 deletions
M server/docs/todo.md +63 -303
@@ -1,139 +1,50 @@
1 1 # Makenotwork TODO
2 2
3 3 ## Status
4 - Done: All pre-beta phases. Active: Creator setup (Stripe), manual testing. Next: Soft launch.
4 + Done: All pre-beta phases, UX audit remediation. Active: Creator setup (Stripe), manual testing. Next: Soft launch.
5 5
6 6 v0.4.8. Audit grade A (Run 18, 2026-05-01). ~1,230 unit + ~684 integration = ~1,914 tests. Mutation kill rate 99.4%. Property-based testing active (proptest). `cargo test --features fast-tests` for fast runs.
7 7
8 8 Human tasks (manual testing, outreach, legal, infrastructure) moved to `human_todo.md`.
9 + Completed items moved to `todo_done.md`.
9 10
10 11 ---
11 12
12 - ## Audit Run 19 (2026-05-02)
13 + ## Remaining Audit Items
13 14
14 - ### Code
15 - - [x] **[MEDIUM]** Add timeout to `payments/connect.rs:198` raw reqwest call (Stripe resume-subscription)
16 - - [x] **[MEDIUM]** Add `ModerationActionId` newtype and `ModerationActionType` enum to `db/moderation.rs` (already existed in id_types.rs + enums.rs)
15 + ### Code (Run 19)
17 16 - [ ] **[LOW]** Add README.md to server/
18 - - [x] **[LOW]** Bump dependency pins: tokio 1.49->1.50, uuid 1.20->1.22, chrono 0.4.43->0.4.44, yara-x 1.13->1.14, anyhow 1.0.101->1.0.102
19 - - [x] Fix auth rate limit for lockout test (`constants.rs` fast-tests override, burst 5->20)
20 17
21 - ### Deferred
18 + ### Deferred Code Quality
22 19 - [ ] Extract inline SQL from route handlers to db/ (4 locations)
23 20 - [ ] Remove `async-trait` in favor of Rust 2024 native async traits
24 21 - [ ] Migrate inline `onclick` handlers to `addEventListener` for strict CSP
22 + - [ ] Monitor scheduler.rs (1249), git/mod.rs (624), license_keys.rs (684) for growth
25 23
26 - ---
27 -
28 - ## UX Audit Remediation (2026-05-02)
29 -
30 - Usability audit grade: B. Complexity C+, Completeness B+, Learnability B, Discoverability B-.
31 -
32 - ### Critical (broken or high-dropout flows)
33 -
34 - - [x] **[HIGH]** Add "Add to collection" UI — "Save to collection" dropdown on item pages + "Add to collection" in library purchase context menus. Checkbox toggle, inline create, click-outside-to-close
35 - - [x] **[HIGH]** Consolidate item creation wizard from 8 steps to 6 — merged Details+Appearance into "Basics" step, removed Distribution step (already in dashboard Pricing tab)
24 + ### UX — Remaining
36 25 - [ ] **[HIGH]** Add global search to site header — search only exists on /discover page. Add input to `site_header.html` with Cmd+K shortcut
37 26
38 - ### High (significant friction reduction)
39 -
40 - - [x] **[MEDIUM]** Restructure user dashboard tabs — 4 core tabs (Account, Projects, Payments, Support) always visible, Analytics/Creator/SyncKit/Media/SSH Keys/Forums in "More" dropdown
41 - - [x] **[MEDIUM]** Fix price input to use dollars, not cents — PWYW min, subscription tier, promo code fixed discount, and inline item edit all now accept dollars with auto-conversion to cents
42 - - [x] **[MEDIUM]** Standardize pricing terminology — item wizard now says "One-Time Purchase" to match project wizard, paywall, landing page, and docs
43 - - [x] **[MEDIUM]** Add self-service refund UI for creators — new "Sales" tab on item dashboard with per-transaction refund buttons, Stripe refund API integration
44 -
45 - ### Medium (discoverability and learnability)
46 -
47 - - [x] **[MEDIUM]** Surface embed feature — added "Edit" and "Embed" links on public item pages for creators (via `is_owner` flag)
48 - - [x] **[MEDIUM]** Link data export from dashboard — promoted "Your Data" section from collapsed `<details>` to always-visible in Account tab
49 - - [x] **[MEDIUM]** Explain creator application — pitch.html already says "Most applications are approved within a few days"
50 - - [x] **[LOW]** Add one-line descriptions to project feature checkboxes — already implemented via `ProjectFeature::description()` + `type-card-desc` in template
51 - - [x] **[LOW]** Improve empty states — library purchases has "Discover Content" CTA, project content has "Add First Item" CTA with explanatory text
52 - - [x] **[LOW]** Make promo code visible at checkout — replaced `<details>` with visible inline form
53 -
54 - ### Low (power-user improvements)
55 -
56 - - [x] **[LOW]** Add bulk operations for item management — already implemented (publish/unpublish/delete in project Content tab with multi-select)
57 - - [x] **[LOW]** Add keyboard shortcuts — `?` help overlay with shortcut list, `Esc` closes modals, `Cmd+S` saves forms (Cmd+K deferred until global search)
58 - - [x] **[LOW]** Add soft delete with 7-day recovery — items now soft-deleted (deleted_at column), auto-purged after 7 days by scheduler, restore endpoint at POST /api/items/{id}/restore
59 - - [x] **[LOW]** Add wishlist/bookmark for fans — "Wishlist" toggle on item pages, wishlists table, toggle API at POST /api/wishlists/{item_id}
60 - - [x] **[LOW]** Add changelog or "What's New" — `/changelog` page with entry history, linked from site footer
61 -
62 - ### Deferred (post-beta table stakes)
63 -
64 - - [ ] Reviews/ratings system for items (all three competitors have this)
27 + ### UX — Deferred (post-beta table stakes)
28 + - [ ] Reviews/ratings system for items
65 29 - [ ] Gift purchases at checkout
66 30 - [ ] HTML rich email for creator broadcasts (currently plain text only)
67 - - [ ] "Edit" link on public project/item pages for logged-in creators (currently must navigate to dashboard)
68 31 - [ ] RSS feed link on all project pages (currently only shown if blog posts exist)
69 32
70 33 ---
71 34
72 - ## Integration Test Fixes (completed 2026-05-02)
73 -
74 - All 34 previously-failing tests resolved (10 root causes). Additional 3 sandbox test failures fixed. Key changes:
75 -
76 - - Auth rate limiter: moved from `route_layer` to per-handler `.layer()` — GET /login no longer rate-limited (production fix)
77 - - Advisory lock deadlock: `pg_advisory_lock`/`pg_advisory_unlock` used different pool connections, leaving locks permanently held. Replaced with `check_sandbox_cap` that pins lock+count+unlock to a single connection (production fix)
78 - - Test harness: unique IP per TestClient via atomic counter, preventing cross-test rate limit interference
79 - - `fast-tests` feature: Argon2 reduced to 8MiB/1iter (~10ms vs ~600ms), sandbox rate limit relaxed. Run tests with `cargo test --features fast-tests`. Sandbox suite: 2.3s (was 40+ min)
80 - - Consolidated 4 sandbox "blocks" tests into 1, fixed UUID type in subscription test
81 -
82 - ---
83 -
84 - ## Audit Run 18 (2026-05-01)
85 -
86 - ### Testing
87 - - [x] **[LOW]** Add unit tests to `wam_client.rs` — 5 tests (URL construction, serialization, fire-and-forget error handling)
88 - - [x] **[LOW]** Add unit tests to `git_ssh.rs` for `parse_ssh_command` and `parse_repo_path` — 14 tests (all operations, quoting, traversal, edge cases)
89 -
90 - ### Performance
91 - - [x] **[LOW]** `scanning/hash_lookup.rs` creates new `reqwest::Client` per call — fixed: static `LazyLock<reqwest::Client>`
92 - - [x] **[LOW]** `routes/ota.rs` `delete_release_handler` — replaced `list_releases` (O(N)) + `list_artifacts` with `get_release_artifact_keys` (O(1) ownership check + S3 key fetch)
93 -
94 - ### Data Integrity
95 - - [x] **[LOW]** CSV import `parse_amount_cents` — removed ambiguous heuristic. Whole numbers are always cents. Decimal values (e.g. "12.50") are dollars.cents. No format option needed.
96 -
97 - ### Deferred
98 - - [x] Split `helpers.rs` (~1,268 lines) into `formatting.rs`, `crypto.rs`, `rate_limit.rs` — re-exported from helpers for backward compat
99 - - [x] Reduce `analytics.rs` query duplication — extracted `Scope` enum with `where_clause`/`table_prefix`/`bind_scope`, 623→468 lines (155 LOC removed)
100 - - [x] `discover.rs` — already deduplicated via `append_item_discover_filters` + `bind_item_discover_filters!` macro. Remaining 3 SELECT variants differ in `match_score` expression (trigram/constant/NULL) — genuinely distinct SQL
101 - - [x] `routes/admin/` performance: `admin_users` called `count_users` 3× — replaced with single `count_users_summary` using `COUNT(*) FILTER`
102 -
103 - ---
104 -
105 - ## Pre-Beta Code Tasks
35 + ## Pre-Beta — Remaining
106 36
107 37 ### SyncKit
108 - - [x] Sync log compaction — cursor-based: tracks `last_pulled_seq` per device (migration 084), deletes entries all devices have pulled (7-day safety margin). Runs in monitor maintenance loop alongside existing 90-day age-based prune.
109 - - [ ] Add key rotation mechanism (requires server-side re-encryption of all sync_log entries) — deferred post-beta
110 -
111 - ### Git Access Provisioning
112 - - [x] Dashboard page for SSH key management — promoted from collapsed `<details>` in Account tab to dedicated "SSH Keys" dashboard tab. Tab conditionally shown when `git_enabled`. Reuses existing API endpoints and HTMX partials.
113 - - [x] Per-repo collaborator access — `repo_collaborators` table (migration 087) with per-user `can_push` flag. SSH auth (`git_ssh.rs`) checks collaborator table for push and private repo read access. API: `POST/GET/DELETE /api/repos/{id}/collaborators`. Dashboard Code tab shows collaborators per linked repo with add/remove UI.
114 - - [x] Replace manual `setup-ssh-keys.sh` — added `mnw-admin setup-git` subcommand that creates `/opt/git/.ssh`, sets permissions, installs sudoers rule, and verifies syntax. Shell script superseded.
115 -
116 - ### Moderation
117 - - [x] Admin "send warning" action: `POST /api/admin/users/{id}/warn` sends policy-violation email without suspending. Records in moderation_actions.
118 - - [x] `moderation_actions` table (migration 085): id, user_id, admin_id, action_type, reason, content_ref, resolved_at, created_at. Indexed for active-actions lookup and user history.
119 - - [x] Admin handlers record actions: suspend→creates "suspension" action, terminate→creates "termination" action, remove_item→creates "content_removal" action (with item_id as content_ref).
120 - - [x] Actions resolved automatically: unsuspend→resolves suspension actions, restore_item→resolves content_removal by content_ref.
121 - - [x] User-facing "Account Status" section on Settings page: shows active moderation actions (danger-bg boxes with type, date, reason) or "Your account is in good standing." Links to appeals and support. Added to `user_details.html` after the Account section.
122 - - [x] Moderation history (collapsed `<details>`): shows resolved past actions with resolution date. Only visible when history exists.
38 + - [ ] Add key rotation mechanism (requires server-side re-encryption of all sync_log entries)
123 39
124 40 ### Incident Notification System
125 - - [ ] Let creators opt into status alerts (email or webhook) when platform status changes. Implementation: subscribe endpoint on /health, store preferences in DB, trigger email on status transition (Operational -> Degraded/Error and recovery). Reuse existing email infrastructure (Postmark).
41 + - [ ] Let creators opt into status alerts (email or webhook) when platform status changes
126 42
127 43 ### Frontend
128 44 - [ ] Git browser integration: add discover/follow integration (post-beta)
129 45
130 46 ---
131 47
132 - ## Code Review Remediation — Deferred
133 - - [ ] Monitor scheduler.rs (1249), git/mod.rs (624), license_keys.rs (684) for growth
134 -
135 - ---
136 -
137 48 ## File Scanning — Future Improvements
138 49
139 50 ### Background scan queue (next)
@@ -141,118 +52,57 @@ All 34 previously-failing tests resolved (10 root causes). Additional 3 sandbox
141 52 - [ ] Enqueue oversized files from `scan_and_classify` instead of blanket HeldForReview
142 53 - [ ] Scheduler picks up queued scans, streams from S3 to temp file, scans from disk
143 54 - [ ] Update entity scan status + notify creator on completion
144 - - [ ] ClamAV already supports chunked `INSTREAM` — use it for streaming scans
145 - - [ ] SHA-256 is naturally streaming — hash in chunks during download
146 - - [ ] YARA requires full buffer — memory-map the temp file or skip YARA for large files
147 55
148 56 ### Separate scanning service (later, when traffic justifies)
149 57 - [ ] Extract scan worker into standalone binary (same crate, different bin target)
150 - - [ ] Worker polls scan_queue, runs on dedicated machine with more RAM
151 - - [ ] Allows horizontal scaling independently of request serving
152 58
153 59 ---
154 60
155 61 ## Competitive Comparison Remediation (2026-04-29)
156 62
157 63 ### i18n — Grade C
158 - - [ ] Evaluate `fluent-rs` vs `rust-i18n` for Rust i18n (Fluent is Mozilla's, used by Firefox; rust-i18n is macro-based)
159 - - [ ] Extract all user-facing strings from templates into message catalog (server/templates/)
160 - - [ ] Add locale negotiation middleware (Accept-Language header + user preference)
161 - - [ ] i18n error messages (Liberapay's `LazyResponse` pattern — render error text in user's locale)
64 + - [ ] Evaluate `fluent-rs` vs `rust-i18n`
65 + - [ ] Extract user-facing strings into message catalog
66 + - [ ] Add locale negotiation middleware
67 + - [ ] i18n error messages
162 68
163 69 ### OpenAPI Spec — Grade A-
164 - Infrastructure done: `utoipa` integrated, spec at `/api/openapi.json`. 19 endpoints documented (6 license key, 13 SyncKit), 29 schemas.
165 -
166 - - [ ] Annotate remaining public endpoints (public projects, guest checkout, email signup)
167 - - [ ] Auto-generate API reference docs from spec (integrate with DocEngine or separate page)
70 + - [ ] Annotate remaining public endpoints
71 + - [ ] Auto-generate API reference docs from spec
168 72
169 73 ### CI/CD Formalization — Grade B+
170 74 - [ ] Add `cargo clippy` + `cargo test` as git pre-push hook or CI gate
171 - - [ ] Add migration integrity check to CI (Ghost has `check-migration-integrity.js`)
172 - - [ ] Add test timing report to CI output (flag tests >5s as slow)
173 - - [ ] Consider sourcehut builds.sr.ht manifest as lightweight hosted CI (no GitHub Actions needed)
174 -
175 - ### unwrap() Audit — Grade A
176 - - [x] Audited all `unwrap()` in production code paths (routes/, db/, auth, payments, storage, scanning, scheduler)
177 - - [x] Only 1 dangerous unwrap found: `promo_codes.rs:212` (`and_hms_opt(23,59,59).unwrap()`). Fixed with `.ok_or_else()`.
178 - - [x] All others are safe: tests, static regex in LazyLock, infallible Response::builder(), guarded by preceding None checks.
179 - - Periodic sweep sufficient — no clippy deny needed
75 + - [ ] Add migration integrity check to CI
76 + - [ ] Add test timing report to CI output
77 + - [ ] Consider sourcehut builds.sr.ht manifest
180 78
181 79 ---
182 80
183 81 ## Post-Beta
184 82
185 83 ### Earn-Back Credit Program
186 - - [ ] Schema: `earn_back_credits` table (user_id, period_start, period_end, subscription_paid_cents, revenue_earned_cents, credit_months, applied, created_at)
187 - - [ ] Annual calculation job in scheduler: on each creator's account anniversary, compare 12-month subscription fees paid vs gross sales revenue
188 - - [ ] If fees > revenue: credit = ceil((fees - revenue) / monthly_tier_price) months, capped at 12
189 - - [ ] Apply credits: skip Stripe billing for credited months (pause subscription or issue Stripe credit notes)
190 - - [ ] Dashboard display: show earn-back status (months until anniversary, current earnings vs fees paid, projected credit)
191 - - [ ] Email notification on credit issuance (congratulatory if earned back, supportive if credited)
192 - - [ ] Update economics.md and how-we-work.md to reflect implementation status (remove "Planned" qualifier)
193 - - [ ] Counter on public pricing page: "X creators have earned back their subscription fees"
84 + - [ ] Schema, annual calculation job, apply credits, dashboard display, email notification
194 85
195 86 ### Churn Monitoring and Creator Health
196 - - [ ] `creator_health` materialized view or scheduled query: monthly revenue, upload frequency, login frequency, follower count, subscription age per creator
197 - - [ ] Churn risk scoring: flag creators with declining activity (no uploads in 30 days, no logins in 14 days, revenue drop >50% month-over-month)
198 - - [ ] Admin dashboard widget: churn risk list, retention cohort chart (by signup month), tier distribution over time
199 - - [ ] Revenue concentration alert: warn if any single creator represents >10% of total subscription revenue
200 - - [ ] Monthly retention metrics email to admin: new creators, churned creators, net change, MRR, average revenue per creator
87 + - [ ] creator_health materialized view, churn risk scoring, admin dashboard widget
201 88 - [ ] Trigger: implement before reaching 100 creators
202 89
203 90 ### Phase 11B: Promotions
204 - - [ ] Affiliate/referral program (per-product opt-in, configurable commission %, 30-day cookie)
91 + - [ ] Affiliate/referral program
205 92
206 93 ### Phase 13D: Creator Platform Import System — Remaining
207 -
208 - #### Phase B
209 - - [ ] Substack ZIP importer (posts.json + subscribers.csv inside ZIP archive)
210 - - [ ] Ghost JSON importer (Ghost export format → ImportPayload)
211 -
212 - #### Phase C
213 - - [ ] Gumroad CSV/API importer (sales CSV + product API)
214 - - [ ] Bandcamp sales CSV preset (column mapping preset for Bandcamp export format)
215 - - [ ] Ko-fi members CSV preset (column mapping preset)
216 - - [ ] Lemon Squeezy REST API importer
217 - - [ ] Patreon OAuth API importer (OAuth flow + paginated member/post API)
94 + - [ ] Substack ZIP importer, Ghost JSON importer
95 + - [ ] Gumroad CSV/API, Bandcamp CSV preset, Ko-fi CSV preset, Lemon Squeezy, Patreon OAuth
218 96
219 97 ### Phase 14E: Media Transcoding Pipeline
220 -
221 - #### Phase 14E-1: Probe + Detect Infrastructure
222 - - [ ] Probe uploaded files at confirm time: extract codec, bitrate, sample rate, duration, dimensions
223 - - [ ] Classify uploads as lossless (WAV/AIFF/FLAC/ALAC/ProRes) or lossy (MP3/AAC/OGG/Opus/H.264/VP9)
224 - - [ ] Auto-populate `duration_seconds`, `video_width`, `video_height` from probe data
225 - - [ ] Store detected codec + source classification in DB (new columns or metadata JSON)
226 -
227 - #### Phase 14E-2: Audio Transcoding (SmallFiles tier)
228 - - [ ] Background job: lossless audio uploads -> Opus 128 kbps (SmallFiles) or FLAC (BigFiles+)
229 - - [ ] WAV/AIFF -> FLAC saves ~50%; WAV/AIFF -> Opus 128 saves ~90%
230 - - [ ] FLAC/ALAC -> Opus 128 saves ~83% (SmallFiles only)
231 - - [ ] Lossy uploads (MP3/AAC/OGG/Opus): store as-is, no conversion
232 - - [ ] Track `original_s3_key` + `delivery_s3_key` per file (originals kept for BigFiles+)
233 -
234 - #### Phase 14E-3: Fan Download Format Choice
235 - - [ ] Fan chooses download format at purchase time (original lossless, FLAC, MP3 320, AAC 256)
236 - - [ ] Pre-generate common formats on first request, cache in S3
237 - - [ ] SmallFiles: delivery format only (transparent Opus/AAC). BigFiles+: original + delivery formats
238 -
239 - #### Phase 14E-4: Video Transcoding
240 - - [ ] ProRes/uncompressed MOV -> H.264 CRF 18 MP4 (universal playback)
241 - - [ ] Optionally generate VP9 for web streaming (40-50% smaller than H.264)
242 - - [ ] Lossy video (H.264/VP9/H.265): store as-is, no re-encode
243 - - [ ] Remux where possible (H.264 in MOV -> H.264 in MP4, zero quality loss)
244 - - [ ] Auto-generated thumbnails (ffmpeg frame extraction at configurable timestamp)
245 -
246 - #### Phase 14E-5: Everything Tier Features
247 - - [ ] Adaptive bitrate streaming (HLS/DASH) — multiple quality levels per video
248 - - [ ] Audio: FLAC + Opus 128 + Opus 64 quality ladder
249 - - [ ] Video: original + 1080p + 720p + 480p quality ladder (VP9 or AV1)
250 - - [ ] Bandwidth metering + per-tier bandwidth caps
98 + - [ ] Probe + detect infrastructure
99 + - [ ] Audio transcoding (SmallFiles tier)
100 + - [ ] Fan download format choice
101 + - [ ] Video transcoding
102 + - [ ] Everything tier: adaptive bitrate streaming, quality ladders
251 103
252 104 ### Phase 14B: Embeddable Widgets
253 - - [ ] Embed endpoint /embed/i/{uuid} — embeddable buy button, audio player, 30-sec preview
254 - - [ ] Overlay widget (JS snippet for external sites, checkout popup)
255 - - [ ] Inline embed (iframe-based product card)
105 + - [ ] Embed endpoint, overlay widget, inline embed
256 106
257 107 ### Phase 16: Performance
258 108 - [ ] Response caching, query optimization, CDN, metrics endpoint
@@ -261,179 +111,89 @@ Infrastructure done: `utoipa` integrated, spec at `/api/openapi.json`. 19 endpoi
261 111 - [ ] Evaluate Cloudflare `/crawl` endpoint, per-creator crawl preference toggle
262 112
263 113 ### Phase 17B: Content Newsletters — Remaining
264 - - [ ] Delivery metrics (sent, delivered, opened, clicked)
265 - - [ ] Section-level email preferences (subscribers opt in/out per project)
114 + - [ ] Delivery metrics, section-level email preferences
266 115
267 116 ### Phase 17C: Comments — Remaining
268 - - [ ] Creator moderation via MT moderation tools
269 - - [ ] Restrict commenting to buyers/subscribers (MT community membership gating)
117 + - [ ] Creator moderation via MT tools, restrict commenting to buyers/subscribers
270 118
271 119 ### Phase 20: OSS Creator Tools
272 - - [ ] G7: Git-backed wikis
273 - - [ ] G7B: Compare view, tags/releases, code search, repo creation UI, activity feed
274 - - [ ] G8: Platform-wide mailing lists via platform integration I3 (needs subscription management UI + devlog subscribe button)
275 - - [ ] OSS-specific: sponsor tiers, license display, FUNDING.yml, build artifacts
276 - - [ ] CI/Build enhancements: status badges, artifact signing, log streaming
277 - - [ ] Distribution: package mirrors, reproducible builds, changelog rendering
278 - - [ ] Sustainability: fund-this-dependency widget, aggregate goals
120 + - [ ] Git-backed wikis, compare view, tags/releases, code search
121 + - [ ] Platform-wide mailing lists, sponsor tiers, CI/build enhancements
279 122
280 123 ### Phase 20B: Mobile Apps (Consumption)
281 - - [ ] iOS + Android: library view, download purchased content, offline, audio player, reader, push notifications
124 + - [ ] iOS + Android: library, downloads, offline, audio player, reader, push notifications
282 125
283 126 ### Phase 20C: Physical Product Listings
284 - - [ ] Physical product listing type (self-fulfilled, no MNW fulfillment)
285 - - [ ] Shipping address collection at checkout
286 - - [ ] Order management in creator dashboard (mark shipped, tracking number)
127 + - [ ] Physical product type, shipping address, order management
287 128
288 129 ### Ko-fi Comparison Gaps
289 - - [ ] Fundraising goals — display campaign target + progress bar on project page
290 - - [ ] Commissions — listing with portfolio, slot limits, client messaging, upfront payment
291 - - [ ] Social integrations — Discord webhook or Zapier integration post-beta
130 + - [ ] Fundraising goals, commissions, social integrations
292 131
293 132 ### Phase 20D: Automated Revenue Split Payouts
294 - - [ ] Automated Stripe Transfers for revenue splits (currently recorded as obligations; owners settle directly)
295 - - [ ] Requires switching split-enabled projects from direct charges to destination charges
296 - - [ ] Dashboard: mark splits as settled (manual confirmation while automated transfers not available)
297 - - [ ] Trigger: stable split recording for 3+ months, legal review complete
133 + - [ ] Automated Stripe Transfers, multi-processor support
298 134
299 135 ### Phase 21: Scheduled Content — Remaining
300 136 - [ ] Pre-save + pre-order, countdown display, calendar view
301 137
302 138 ### Phase 22: Live Streaming (Everything tier)
303 -
304 - Trigger: implement when first Everything tier creator subscribes (or when demand signals justify).
305 - Full spec preserved in git history (commit before this refactor). Summary:
306 -
307 - - Phase 22A: DB schema (streams, stream_sessions, stream_donations) + CRUD
308 - - Phase 22B: Internal API endpoints (auth webhook, started/ended/viewers hooks, HMAC)
309 - - Phase 22C: Public API (status, viewer-token, live page, donate, SSE events)
310 - - Phase 22D: Dashboard UI (stream setup, status, usage meter, settings, VOD archive, donations)
311 - - Phase 22E: MediaMTX deployment (see `human_todo.md`)
312 - - Phase 22F: VOD archival pipeline (ffmpeg concat, thumbnails, S3 upload, auto-publish)
313 - - Phase 22G: Stream donations (0% fee, overlay, leaderboard)
314 - - Phase 22H: Live page + HLS player (hls.js, access control, chat, live indicators)
315 - - Phase 22I: Billing + overage (usage tracking, Stripe metered billing, grace period)
316 - - Phase 22J: Testing (unit + integration + manual checklist)
317 - - Phase 22K: Documentation updates
318 -
319 - Phase ordering: 22A → 22B → 22E → 22C → 22H → 22D → 22I → 22G → 22F → 22J → 22K
320 - MVP: 22A + 22B + 22E + 22C + 22H (stream, fans watch, no donations/VOD/billing)
321 -
322 - Cost model: MediaMTX zero cost (MIT), $0.03-0.04/stream-hour marginal, 20hr included per $60/mo creator. Break-even: $0.60-0.80/mo per creator. Dedicated VPS trigger: >3 concurrent or >50% CPU.
139 + - [ ] Full spec in git history. MVP: 22A + 22B + 22E + 22C + 22H
140 + - [ ] Trigger: first Everything tier creator subscribes
323 141
324 142 ### Phase 24: Payment Independence
325 -
326 - #### Stablecoin checkout (low effort)
327 - - [ ] Add `crypto` to `payment_method_types` in checkout session creation (or enable via Stripe Dashboard)
328 - - [ ] Handle refunds (Stripe returns stablecoins to fan's original wallet automatically)
329 - - [ ] Test end-to-end: fan pays with USDC, creator sees USD in Stripe balance
330 - - [ ] Update payments.md and payouts.md
331 -
332 - #### Phase 24A: Reduce creator-side fees (trigger: creator feedback)
333 - - [ ] Evaluate Stripe's Link for lower repeat-purchase friction
334 - - [ ] Research bundling/minimum-purchase features to reduce fixed fee impact
335 - - [ ] Document which Stripe features could reduce creator processing costs
336 -
337 - #### Phase 24B: Stripe dependency mitigation (trigger: >200 creators or policy change)
338 - - [ ] Evaluate Stripe Treasury for embedded financial accounts
339 - - [ ] Document Stripe suspension recovery plan
340 - - [ ] Identify one backup processor (Adyen, Square) with Connect-like direct charges
341 - - [ ] Architecture assessment: map code paths for multi-processor support
342 -
343 - #### Phase 24C: International expansion (trigger: rejected applications from unsupported countries)
344 - - [ ] Track which countries applicants come from
345 - - [ ] Evaluate licensed payout partners (Tipalti, Hyperwallet/PayPal)
346 - - [ ] Evaluate BaaS providers (Unit, Sila Money) for ACH payouts
347 - - [ ] Research Stripe country coverage expansion
143 + - [ ] Stablecoin checkout, reduce creator-side fees, Stripe dependency mitigation, international expansion
348 144
349 145 ### License Key Self-Management
350 - - [ ] Let buyers manage activations (view devices, deactivate) without a MNW account
351 - - [ ] Configurable offline grace period per item (default 7 days, creator can set 14/30)
352 - - [ ] License transfer: let a buyer reassign a key to another user (creator toggle per item)
353 -
354 - ### SyncKit S5: SDK & Multi-Tenant
355 - - [ ] Swift SDK, multi-tenant isolation, rate limiting per tier
356 - - [ ] Developer dashboard as MNW dashboard tab
357 -
358 - ### SyncKit S8: Advanced Features
359 - - [ ] WebSocket realtime sync (shared gateway with MT real-time threads)
360 - - [ ] CRDT conflict resolution, selective sync, schema migration, pull filtering
361 -
362 - ### SyncKit S9: Productize
363 - - [ ] Add SyncKit usage dashboard tab (current weight, burst consumed, per-user breakdown)
364 - - [ ] Write developer-facing landing page
365 - - [ ] Write quickstart guide: integrate SyncKit into a Tauri app in 30 minutes
366 - - [ ] Publish example app (minimal Tauri + SyncKit template)
367 - - [ ] Health dashboard for SyncKit service
368 - - [ ] Stripe billing integration for SyncKit add-on (weight + burst metering)
369 - - [ ] Implement weight + burst quota enforcement
370 - - [ ] Per-user seat tracking
371 -
372 - ### Developer Services (Future)
373 - - [ ] DS2: Crash reporting → MT threads
374 - - [ ] DS3: Feedback collection → MT threads
375 - - [ ] Dashboard aggregate endpoint (pulls crash/feedback counts from MT internal API)
146 + - [ ] Buyer activation management, offline grace period, license transfer
147 +
148 + ### SyncKit S5/S8/S9
149 + - [ ] Swift SDK, multi-tenant, rate limiting, WebSocket realtime, CRDT, productize
150 +
151 + ### Developer Services
152 + - [ ] Crash reporting, feedback collection, dashboard aggregate endpoint
376 153
377 154 ### Fan+ Accounts
378 - - [ ] Stripe integration: create Fan+ product/price ($8/mo), webhook handlers
379 - - [ ] Monthly $5 credit: generate single-use promo code on renewal, email to subscriber
380 - - [ ] `+` badge on username display
381 - - [ ] `is_fan_plus` flag in session data for feature gating
382 - - [ ] Dev community as private MT community (Fan+ only)
383 - - [ ] Advisory polls infrastructure (simple yes/no polls, Fan+ only)
384 - - [ ] Guarantees/economics page updates for Fan+
155 + - [ ] Stripe integration, monthly credit, badge, feature gating, dev community
385 156
386 157 ### DocEngine — Remaining
387 - - [ ] Full-text search index (build at load time, JSON endpoint for client-side search)
388 - - [ ] Versioned docs (directory per version, version switcher)
158 + - [ ] Full-text search index, versioned docs
389 159
390 160 ### Notification Service
391 - - [ ] `notifications` table (user_id, type, source, title, body, link, read, created_at)
392 - - [ ] Notification creation on key events (new comment, new follower, purchase, mention, flag)
393 - - [ ] API endpoints: GET /api/notifications (paginated), POST /api/notifications/read
394 - - [ ] MT consumes MNW notifications API
395 - - [ ] Client apps (GO/BB/AF) poll notifications for sync/OTA events
396 - - [ ] Digest preferences (immediate, daily, weekly)
397 - - [ ] In-app notification center (MNW dashboard)
161 + - [ ] notifications table, event triggers, API endpoints, digest preferences
398 162
399 163 ### Search Infrastructure
400 - - [ ] MNW full-text search (tsvector on items, blog posts, projects)
401 - - [ ] Unified search API: `/api/search?q=term&scope=items,threads,posts,projects`
402 - - [ ] Cross-project search results (MNW items + MT threads in one response)
164 + - [ ] Full-text search (tsvector), unified search API, cross-project results
403 165
404 166 ### Image Upload Pipeline
405 - - [ ] Shared image processing: thumbnail generation, format validation, size limits
167 + - [ ] Thumbnail generation, format validation, size limits
406 168
407 169 ### Link Preview Extraction
408 - - [ ] Extract MT `link_preview.rs` into shared crate or copy pattern to MNW
409 - - [ ] MNW: OG metadata for item/project pages (social sharing cards)
410 - - [ ] MNW blog posts: auto-preview linked URLs
170 + - [ ] Extract to shared crate, OG metadata, blog post URL previews
411 171
412 172 ---
413 173
414 174 ## Dependencies (blocked on upstream)
415 - - [ ] Monitor yara-x for wasmtime >=42.0.2 (11 CVEs including 2 critical — RUSTSEC-2026-0095, -0096)
175 + - [ ] Monitor yara-x for wasmtime >=42.0.2 (RUSTSEC-2026-0095, -0096)
416 176 - [ ] Monitor aws-sdk-s3 for lru fix (RUSTSEC-2026-0002)
417 177 - [ ] Monitor async-stripe for instant fix (RUSTSEC-2024-0384)
418 178 - [ ] rsa (RUSTSEC-2023-0071) via sqlx-mysql + yara-x — no fix available
419 179
420 180 ## Deferred
421 181 - [ ] Team/organization accounts
422 - - [ ] Creator @makenot.work email addresses (forwarding-only, Migadu)
182 + - [ ] Creator @makenot.work email addresses (Migadu)
423 183 - [ ] Tax-year revenue summary, invoice generation, 1099 guidance
424 - - [ ] Merchant of Record (MoR) — handle VAT/GST/sales tax globally
184 + - [ ] Merchant of Record (MoR)
425 185 - [ ] Email drip workflows
426 186 - [ ] Music metadata fields (BPM, key, genre)
427 - - [ ] Podcast private RSS feeds (per-subscriber unique RSS, Spotify integration)
187 + - [ ] Podcast private RSS feeds
428 188 - [ ] OG image generation
429 189 - [ ] UTM parameter tracking
430 190 - [ ] Blog post revision history
431 191 - [ ] Series/serial ordering, reading progress
432 192 - [ ] Traffic/referrer tracking
433 - - [ ] Revisit admin system (currently config-based ADMIN_USER_ID)
193 + - [ ] Revisit admin system (currently config-based)
434 194 - [ ] S3 bucket versioning
435 - - [ ] PDF stamping (watermark with buyer email/name)
436 - - [ ] CONCURRENTLY index strategy — plan before tables grow large
195 + - [ ] PDF stamping
196 + - [ ] CONCURRENTLY index strategy
437 197
438 198 ## Key Paths
439 199 ```
@@ -445,7 +205,7 @@ MNW/server/src/
445 205 import/ (CSV converter, pipeline, intermediate format)
Lines truncated
@@ -121,3 +121,82 @@ Systematic creator-perspective audit of docs, legal, code, and competitive posit
121 121 - [x] Expanded analytics.md "We don't track" list — explicitly lists page views, referrals, UTM, geo, conversion funnels as absent
122 122 - [x] Renamed Streaming tier to Everything — enum, DB migration 079, all templates, all docs, CLAUDE.md, env vars
123 123 - [x] Removed "video coming soon" labels from how-we-work.md, items.md — video uploads are implemented
124 +
125 + ---
126 +
127 + ## Audit Run 19 (2026-05-02)
128 +
129 + - [x] Add timeout to `payments/connect.rs:198` raw reqwest call (Stripe resume-subscription)
130 + - [x] Add `ModerationActionId` newtype and `ModerationActionType` enum (already existed in id_types.rs + enums.rs)
131 + - [x] Bump dependency pins: tokio 1.50, uuid 1.22, chrono 0.4.44, yara-x 1.14, anyhow 1.0.102
132 + - [x] Fix auth rate limit for lockout test (constants.rs fast-tests override, burst 5->20)
133 +
134 + ---
135 +
136 + ## Audit Run 18 (2026-05-01)
137 +
138 + - [x] Add unit tests to `wam_client.rs` — 5 tests
139 + - [x] Add unit tests to `git_ssh.rs` — 14 tests
140 + - [x] `scanning/hash_lookup.rs` — static `LazyLock<reqwest::Client>`
141 + - [x] `routes/ota.rs` `delete_release_handler` — O(1) ownership check
142 + - [x] CSV import `parse_amount_cents` — removed ambiguous heuristic
143 + - [x] Split `helpers.rs` into `formatting.rs`, `crypto.rs`, `rate_limit.rs`
144 + - [x] Reduce `analytics.rs` query duplication — `Scope` enum, 623→468 lines
145 + - [x] `discover.rs` — already deduplicated via macro
146 + - [x] `routes/admin/` — single `count_users_summary` using `COUNT(*) FILTER`
147 +
148 + ---
149 +
150 + ## UX Audit Remediation (2026-05-02) — All Complete
151 +
152 + - [x] **[HIGH]** Add "Add to collection" UI — dropdown on item pages + library context menus
153 + - [x] **[HIGH]** Consolidate item wizard from 8 to 6 steps — merged Details+Appearance, removed Distribution
154 + - [x] **[MEDIUM]** Restructure dashboard tabs — 4 core + "More" dropdown
155 + - [x] **[MEDIUM]** Fix price input to use dollars — PWYW min, tier, promo, inline edit
156 + - [x] **[MEDIUM]** Standardize pricing terminology — "One-Time Purchase" everywhere
157 + - [x] **[MEDIUM]** Self-service refund UI — Sales tab on item dashboard + Stripe API
158 + - [x] **[MEDIUM]** Surface embed feature — Edit/Embed links on public item pages
159 + - [x] **[MEDIUM]** Link data export — promoted from collapsed details to visible
160 + - [x] **[MEDIUM]** Explain creator application — already present in pitch.html
161 + - [x] **[LOW]** Feature checkbox descriptions — already implemented via `ProjectFeature::description()`
162 + - [x] **[LOW]** Improve empty states — CTAs already present
163 + - [x] **[LOW]** Make promo code visible at checkout — inline form
164 + - [x] **[LOW]** Bulk operations — already implemented (publish/unpublish/delete)
165 + - [x] **[LOW]** Keyboard shortcuts — `?` help overlay, Esc, Cmd+S
166 + - [x] **[LOW]** Soft delete with 7-day recovery — deleted_at column, scheduler purge, restore endpoint
167 + - [x] **[LOW]** Wishlist/bookmark — toggle on item pages, wishlists table
168 + - [x] **[LOW]** Changelog — /changelog page linked from footer
169 +
170 + ---
171 +
172 + ## unwrap() Audit — Grade A
173 +
174 + - [x] Audited all `unwrap()` in production code paths
175 + - [x] Only 1 dangerous unwrap found: `promo_codes.rs:212`. Fixed with `.ok_or_else()`.
176 + - [x] All others are safe: tests, static regex in LazyLock, infallible Response::builder()
177 +
178 + ---
179 +
180 + ## Pre-Beta Code Tasks — Completed
181 +
182 + ### SyncKit
183 + - [x] Sync log compaction — cursor-based, runs in monitor maintenance loop
184 +
185 + ### Git Access Provisioning
186 + - [x] Dashboard page for SSH key management
187 + - [x] Per-repo collaborator access — migration 087
188 + - [x] Replace manual `setup-ssh-keys.sh` — `mnw-admin setup-git`
189 +
190 + ### Moderation
191 + - [x] Admin "send warning" action
192 + - [x] `moderation_actions` table (migration 085)
193 + - [x] Admin handlers record actions
194 + - [x] Actions resolved automatically
195 + - [x] User-facing "Account Status" section
196 + - [x] Moderation history
197 +
198 + ---
199 +
200 + ## Integration Test Fixes (2026-05-02)
201 +
202 + All 34 previously-failing tests resolved. Key changes: auth rate limiter per-handler, advisory lock deadlock fix, unique IP per TestClient, fast-tests feature flag, sandbox test consolidation.