max / makenotwork
6 files changed,
+89 insertions,
-11 deletions
| @@ -3385,7 +3385,7 @@ dependencies = [ | |||
| 3385 | 3385 | ||
| 3386 | 3386 | [[package]] | |
| 3387 | 3387 | name = "makenotwork" | |
| 3388 | - | version = "0.4.7" | |
| 3388 | + | version = "0.4.8" | |
| 3389 | 3389 | dependencies = [ | |
| 3390 | 3390 | "anyhow", | |
| 3391 | 3391 | "argon2", |
| @@ -20,7 +20,7 @@ utoipa = { version = "5", features = ["axum_extras", "chrono", "uuid"] } | |||
| 20 | 20 | utoipa-axum = "0.2" | |
| 21 | 21 | serde = { version = "1.0.228", features = ["derive"] } | |
| 22 | 22 | serde_json = "1.0.149" | |
| 23 | - | tokio = { version = "1.49.0", features = ["macros", "rt-multi-thread", "net", "signal"] } | |
| 23 | + | tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread", "net", "signal"] } | |
| 24 | 24 | tokio-stream = { version = "0.1", features = ["sync"] } | |
| 25 | 25 | tower = "0.5.3" | |
| 26 | 26 | tower-http = { version = "0.6.8", features = ["trace", "fs", "limit", "request-id", "propagate-header", "set-header"] } | |
| @@ -35,8 +35,8 @@ dotenvy = "0.15.7" | |||
| 35 | 35 | ||
| 36 | 36 | # Database | |
| 37 | 37 | sqlx = { version = "0.8.6", features = ["runtime-tokio", "postgres", "uuid", "chrono", "migrate"] } | |
| 38 | - | uuid = { version = "1.20.0", features = ["v4", "serde"] } | |
| 39 | - | chrono = { version = "0.4.43", features = ["serde"] } | |
| 38 | + | uuid = { version = "1.22.0", features = ["v4", "serde"] } | |
| 39 | + | chrono = { version = "0.4.44", features = ["serde"] } | |
| 40 | 40 | ||
| 41 | 41 | # Authentication | |
| 42 | 42 | argon2 = "0.5.3" | |
| @@ -75,7 +75,7 @@ base64 = "0.22.1" | |||
| 75 | 75 | infer = "0.19" | |
| 76 | 76 | goblin = "0.10" | |
| 77 | 77 | zip = "8.2" | |
| 78 | - | yara-x = "1.13" | |
| 78 | + | yara-x = "1.14" | |
| 79 | 79 | ||
| 80 | 80 | # CSV parsing (import system) | |
| 81 | 81 | csv = "1.3" | |
| @@ -88,7 +88,7 @@ log = "0.4" | |||
| 88 | 88 | ||
| 89 | 89 | # Error handling | |
| 90 | 90 | thiserror = "2.0.18" | |
| 91 | - | anyhow = "1.0.101" | |
| 91 | + | anyhow = "1.0.102" | |
| 92 | 92 | ||
| 93 | 93 | # Metrics | |
| 94 | 94 | metrics = "0.24" |
| @@ -9,6 +9,66 @@ Human tasks (manual testing, outreach, legal, infrastructure) moved to `human_to | |||
| 9 | 9 | ||
| 10 | 10 | --- | |
| 11 | 11 | ||
| 12 | + | ## Audit Run 19 (2026-05-02) | |
| 13 | + | ||
| 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) | |
| 17 | + | - [ ] **[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 | + | ||
| 21 | + | ### Deferred | |
| 22 | + | - [ ] Extract inline SQL from route handlers to db/ (4 locations) | |
| 23 | + | - [ ] Remove `async-trait` in favor of Rust 2024 native async traits | |
| 24 | + | - [ ] Migrate inline `onclick` handlers to `addEventListener` for strict CSP | |
| 25 | + | ||
| 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 | + | - [ ] **[HIGH]** Add "Add to collection" UI — fans can create collections but cannot add items to them. Add dropdown/button on library purchase rows and on item pages (`library_purchases.html`, `item.html`) | |
| 35 | + | - [ ] **[HIGH]** Consolidate item creation wizard from 8 steps to 5 — merge Details+Appearance into one step, move Distribution (license keys, promo codes) to post-creation item dashboard tabs. Current 8-step gauntlet has ~40% estimated dropout for first-time creators | |
| 36 | + | - [ ] **[HIGH]** Add global search to site header — search only exists on /discover page. Add input to `site_header.html` with Cmd+K shortcut | |
| 37 | + | ||
| 38 | + | ### High (significant friction reduction) | |
| 39 | + | ||
| 40 | + | - [ ] **[MEDIUM]** Restructure user dashboard tabs — show 4 core tabs (Account, Projects, Payments, Support) by default. Collapse SyncKit, SSH Keys, Forums, Media into "More Tools" overflow section. Current 11 tabs overwhelm new creators | |
| 41 | + | - [ ] **[MEDIUM]** Fix price input to use dollars, not cents — promo code and subscription tier forms accept cents (e.g. "500" for $5). Add live preview ("= $5.00") or switch to dollar input with auto-conversion | |
| 42 | + | - [ ] **[MEDIUM]** Standardize pricing terminology — project wizard says "One-time purchase", item wizard says "Fixed Price" for same concept. Pick one term and use it everywhere | |
| 43 | + | - [ ] **[MEDIUM]** Add self-service refund UI for creators — backend exists (`pending_refunds.rs`) but no dashboard UI. Add "Refund" button in creator transaction history | |
| 44 | + | ||
| 45 | + | ### Medium (discoverability and learnability) | |
| 46 | + | ||
| 47 | + | - [ ] **[MEDIUM]** Surface embed feature — currently buried 4 clicks deep (Dashboard > Project > Item > Embed tab). Add "Embed" link on public item pages for creators | |
| 48 | + | - [ ] **[MEDIUM]** Link data export from dashboard — `/dashboard/export` has no entry point from dashboard tabs. Add link in sidebar or 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 | + | - [ ] **[LOW]** Add bulk operations for item management — multi-select items in project Content tab for batch publish/unpublish/tag/price changes | |
| 57 | + | - [ ] **[LOW]** Add keyboard shortcuts — Cmd+K search, ? help overlay, p publish toggle, Esc close modal | |
| 58 | + | - [ ] **[LOW]** Add soft delete with 7-day recovery — items/projects currently hard-delete on confirmation. Add "Recently Deleted" archive with restore option | |
| 59 | + | - [ ] **[LOW]** Add wishlist/bookmark for fans — simple heart icon on item cards, DB table for saved items. Table-stakes vs Bandcamp/Gumroad/itch.io | |
| 60 | + | - [ ] **[LOW]** Add changelog or "What's New" — no mechanism to inform existing users about new features | |
| 61 | + | ||
| 62 | + | ### Deferred (post-beta table stakes) | |
| 63 | + | ||
| 64 | + | - [ ] Reviews/ratings system for items (all three competitors have this) | |
| 65 | + | - [ ] Gift purchases at checkout | |
| 66 | + | - [ ] 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 | + | - [ ] RSS feed link on all project pages (currently only shown if blog posts exist) | |
| 69 | + | ||
| 70 | + | --- | |
| 71 | + | ||
| 12 | 72 | ## Integration Test Fixes (completed 2026-05-02) | |
| 13 | 73 | ||
| 14 | 74 | All 34 previously-failing tests resolved (10 root causes). Additional 3 sandbox test failures fixed. Key changes: |
| @@ -200,6 +200,7 @@ impl StripeClient { | |||
| 200 | 200 | .header("Authorization", format!("Bearer {}", self.config.secret_key)) | |
| 201 | 201 | .header("Stripe-Account", connected_account_id) | |
| 202 | 202 | .form(&[("pause_collection", "")]) | |
| 203 | + | .timeout(std::time::Duration::from_secs(30)) | |
| 203 | 204 | .send() | |
| 204 | 205 | .await | |
| 205 | 206 | .map_err(|e| { |
| @@ -229,16 +229,15 @@ | |||
| 229 | 229 | Secure payment processing | |
| 230 | 230 | </div> | |
| 231 | 231 | ||
| 232 | - | <details style="margin-top: 1rem; font-size: 0.9rem;"> | |
| 233 | - | <summary style="cursor: pointer; opacity: 0.7;">Have a promo code?</summary> | |
| 232 | + | <div style="margin-top: 1rem; font-size: 0.9rem;"> | |
| 234 | 233 | <form hx-post="/api/promo-codes/claim" | |
| 235 | 234 | hx-swap="outerHTML" | |
| 236 | - | style="margin-top: 0.5rem; display: flex; gap: 0.5rem;"> | |
| 237 | - | <input type="text" name="code" placeholder="Enter code" required | |
| 235 | + | style="display: flex; gap: 0.5rem; align-items: center;"> | |
| 236 | + | <input type="text" name="code" placeholder="Promo code" required | |
| 238 | 237 | style="flex: 1; padding: 0.4rem 0.6rem; font-size: 0.85rem;"> | |
| 239 | 238 | <button class="secondary" type="submit" style="white-space: nowrap;">Redeem</button> | |
| 240 | 239 | </form> | |
| 241 | - | </details> | |
| 240 | + | </div> | |
| 242 | 241 | {% endif %} | |
| 243 | 242 | {% endif %} | |
| 244 | 243 | </div> |
| @@ -58,6 +58,24 @@ v0.3.1. Audit grade A. 340 tests. | |||
| 58 | 58 | - Integer vs float (`1` vs `1.0`) treated as different in `resolve_field_merge` — serde_json Value semantics. | |
| 59 | 59 | - Null base in `resolve_field_merge` returns KeepRemote — documented, callers should use LWW fallback. | |
| 60 | 60 | ||
| 61 | + | ## Business Sustainability (from 2026-05-02 audit) | |
| 62 | + | ||
| 63 | + | ### Pricing & Revenue | |
| 64 | + | - [ ] Reconcile pricing models — synckit-plan.md tiers, synckit_pricing.md Weight/Burst, and economics.md add-on into one coherent model. Weight/Burst as billing engine, simple tier names as customer-facing packaging. | |
| 65 | + | - [ ] Charge for sync in GO, BB, AF — $2-5/mo premium feature. Validates willingness-to-pay, generates real revenue, establishes SyncKit value proposition before B2B launch. | |
| 66 | + | - [ ] Clarify SyncKit relationship to MNW creator tiers — is it included, discounted, or full standalone pricing for creators? | |
| 67 | + | - [ ] Re-evaluate free tier — MNW has no free tier by philosophy. Consider 14-day trial instead of 100 users/1GB free, or remove entirely. | |
| 68 | + | - [ ] Fix Micro tier messaging — frame as "$5/mo for up to 1,000 Micro users" rather than "$0.005/user" with a hidden $5 floor. | |
| 69 | + | ||
| 70 | + | ### Operational Prerequisites (before first external customer) | |
| 71 | + | - [x] Automate sync_log compaction — already wired in server monitor.rs maintenance loop | |
| 72 | + | - [ ] Per-API-key rate limiting — current rate limiting is global, not per-developer. Required for multi-tenancy. | |
| 73 | + | - [ ] Separate VPS for SyncKit — $15-30/mo. Prevents resource contention between SyncKit and MNW on shared Hetzner instance. | |
| 74 | + | ||
| 75 | + | ### Documentation & Accuracy | |
| 76 | + | - [ ] Update synckit-plan.md economics — replace R2 references with Hetzner Object Storage, replace "$1.00 support" with realistic estimate, add Rust-only base-case projections. | |
| 77 | + | - [ ] Monitor Turso and PowerSync — track whether either ships E2E encryption or flat pricing (SyncKit's main differentiators). | |
| 78 | + | ||
| 61 | 79 | ## Deferred (Post-Beta) | |
| 62 | 80 | - [ ] Conflict resolution helpers — LWW, field-level merge, custom resolver callback in the SDK. Reduces client-side boilerplate. (Gap vs Ditto, Couchbase) | |
| 63 | 81 | - [ ] Key rotation mechanism (requires server-side re-encryption of all sync_log entries) |