Skip to main content

max / makenotwork

Add SyncKit tier management, fix dashboard key UX, tag taxonomy fixes SyncKit: add app tiers endpoint (POST /api/v1/sync/app/tiers), tier change endpoint (POST /api/v1/sync/subscription/change) with Stripe proration, update_app_sync_sub_tier DB function, synckit-client SDK methods (get_available_tiers, change_subscription_tier, TierInfo type). Dashboard: fix broken API key copy button (keys are hashed, can't be recovered), show key on create/regenerate with copy button and warning, reload page after feature toggle so tabs update immediately. Tag taxonomy: fixes for discover filters, bulk tag operations, import pipeline, validation. Test updates for new tag hierarchy. v0.5.15
Co-Authored-By
Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-05-11 16:30 UTC
Commit: ea0e960abb685f4f149a47fcb27fcff07525fea0
Parent: d661899
26 files changed, +741 insertions, -245 deletions
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "makenotwork"
3 - version = "0.5.14"
3 + version = "0.5.15"
4 4 edition = "2024"
5 5 license-file = "LICENSE"
6 6
@@ -1,7 +1,7 @@
1 1 # Makenotwork TODO
2 2
3 3 ## Status
4 - v0.5.12 deployed 2026-05-10. Audit grade A (Run 24). ~88K LOC, 1,933 tests, 0 warnings. Migration 110. Sprints 1-9 complete (see `todo_done.md`). Content seeded: AF 0.4.0 + GO 0.3.1 on discover page.
4 + v0.5.14 deployed 2026-05-11. Audit grade A (Run 24). ~88K LOC, 1,935 tests, 0 warnings. Migration 111. Sprints 1-9 complete (see `todo_done.md`). Content seeded: AF 0.4.0 + GO 0.3.1 on discover page.
5 5
6 6 Human tasks in `human_todo.md`. Completed items in `todo_done.md`.
7 7
@@ -11,7 +11,7 @@
11 11
12 12 Priority order. See `human_todo.md` for the full manual testing feature map.
13 13
14 - 1. ~~**Deploy**~~ — Done (v0.5.11, 2026-05-10). Run 24 fixes + scheduler SQL fixes + robots.txt + Prometheus auth + ALERT_EMAIL.
14 + 1. ~~**Deploy**~~ — Done (v0.5.14, 2026-05-11). Run 24 fixes + scheduler SQL fixes + robots.txt + Prometheus auth + ALERT_EMAIL + tag taxonomy overhaul (migration 111).
15 15 2. **Manual testing** — walk through `human_todo.md` sign-off table on live server (Stripe checkout, license keys, promo codes, cart, SyncKit sync)
16 16 3. **Content seeding** — at least one real creator with published content on discover page
17 17 4. **Invite testers** — generate invite codes, send hand-written emails per `docs/internal/outreach/tiers.md`
@@ -195,7 +195,7 @@
195 195 import/ (CSV converter, pipeline, intermediate format)
196 196 MNW/server/tests/
197 197 integration.rs, harness/, workflows/*.rs
198 - MNW/server/migrations/ (001-107)
198 + MNW/server/migrations/ (001-111)
199 199 MNW/server/templates/
200 200 MNW/server/deploy/
201 201 MNW/server/site-docs/public/, MNW/server/site-docs/unpublished/
@@ -166,6 +166,31 @@
166 166 Ok(())
167 167 }
168 168
169 + /// Update the tier and storage limit of an app sync subscription.
170 + #[tracing::instrument(skip_all)]
171 + pub async fn update_app_sync_sub_tier<'e>(
172 + executor: impl sqlx::PgExecutor<'e>,
173 + stripe_subscription_id: &str,
174 + tier: AppSyncTier,
175 + storage_limit_bytes: Option<i64>,
176 + ) -> Result<Option<DbAppSyncSubscription>> {
177 + let sub = sqlx::query_as::<_, DbAppSyncSubscription>(
178 + r#"
179 + UPDATE app_sync_subscriptions
180 + SET tier = $2, storage_limit_bytes = $3
181 + WHERE stripe_subscription_id = $1
182 + RETURNING *
183 + "#,
184 + )
185 + .bind(stripe_subscription_id)
186 + .bind(tier)
187 + .bind(storage_limit_bytes)
188 + .fetch_optional(executor)
189 + .await?;
190 +
191 + Ok(sub)
192 + }
193 +
169 194 /// Cancel an app sync subscription (set status + canceled_at).
170 195 #[tracing::instrument(skip_all)]
171 196 pub async fn cancel_app_sync_sub(
@@ -103,12 +103,13 @@
103 103 query.push_str(" AND i.price_cents <= $4");
104 104 }
105 105 if filters.tag.is_some() {
106 + // Match exact slug or any descendant (e.g. "audio.genre" matches "audio.genre.electronic")
106 107 query.push_str(
107 108 r#" AND EXISTS (
108 109 SELECT 1 FROM item_tags it2
109 110 JOIN tags t2 ON t2.id = it2.tag_id
110 111 WHERE it2.item_id = i.id
111 - AND (t2.slug = $5 OR t2.parent_id = (SELECT id FROM tags WHERE slug = $5))
112 + AND (t2.slug = $5 OR t2.path LIKE $5 || '.%')
112 113 )"#,
113 114 );
114 115 }