feat: integrate design tokens from www.makepostsell.com styleguide #94
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "explore/design-tokens"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
loading, status notices, cart buttons, checkout layout, toggle
Exploration branch — tokens.css provides new variables alongside
existing common.css variables. No visual regressions expected as
common.css values take precedence for shared property names.
Summary by CodeRabbit
New Features
Improvements
Documentation
mentioned in commit
df8f4993c6📝 Walkthrough
Walkthrough
This PR introduces a comprehensive gift card system (purchase, redemption, management), shop environment classification (production/staging/development), a 21-day trial feature, and Bring Your Own Bucket (BYOB) S3 support. Includes new models, migrations, request helpers, templates, routes, and extensive documentation updates across design system, architecture, and ticket specifications.
Changes
make_post_sell/models/gift_card.py,gift_card_transaction.py,cart_gift_card.pymake_post_sell/models/cart.pyjson_gift_cardscolumn, gift card association proxy, purchase tracking, discount deductions per gift card, and validation methods.make_post_sell/routes.py,templates/gift_card.j2,static/js/gift_card.jstemplates/gift_card_manage.j2,gift_card_detail.j2make_post_sell/models/shop.pymake_post_sell/request_methods.py,lib/karaoke.py,lib/s3_mirror.pyshop_uploads_clientandshop_bucket_namerequest methods. Defers S3 client creation to post-shop-load in backfill operations. Adds domain check for 127.0.0.1.docs/design-system.md,CLAUDE.mddocs/architecture.md,docs/tickets/mps-10.mdthroughmps-16.mdmake_post_sell/scripts/alembic/versions/f8201a9ba045_...,9884324a48e3_...mps_gift_card,mps_gift_card_transaction,mps_cart_gift_card), cartjson_gift_cardscolumn, shop settings, and environment/trial/primary S3 columns with idempotent guards.templates/base.j2,cart.j2,content.j2,home.j2,product_edit.j2,shop.j2,shop_about.j2request.app["bucket.secure_uploads.get_endpoint"]withrequest.shop_cdn_endpointfor all media/thumbnail URLs. Adds environment and trial banners to base template.make_post_sell/lib/mail.py,lib/digest_sender.pysend_gift_card_email()function with amount, code, message, and redemption instructions. Digest sender filters to production shops only (Shop.environment == 0).make_post_sell/static/js/watch.jsmake_post_sell/models/__init__.py,meta.py,product.pytemplates/actions_view.j2request.shop.gift_card_enabled.Sequence Diagram
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~50 minutes
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings: use the
@coderabbitai generate docstringscommand.Comment
@coderabbitai helpto get the list of available commands and usage tips.changed the description
Actionable comments posted: 14
🟡 Minor comments (9)
🧹 Nitpick comments (7)
🤖 Prompt for all review comments with AI agents
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID:
ffa4c162-a0ca-4566-b877-4c0c156a88e9📥 Commits
Reviewing files that changed from the base of the PR and between
32a19a339candcca3172c9b.📒 Files selected for processing (62)
CLAUDE.mdGIT_HASHdocs/architecture.mddocs/design-system.mddocs/tickets/mps-10.mddocs/tickets/mps-11.mddocs/tickets/mps-12.mddocs/tickets/mps-13.mddocs/tickets/mps-14.mddocs/tickets/mps-15.mddocs/tickets/mps-16.mdmake_post_sell/GIT_HASHmake_post_sell/lib/digest_sender.pymake_post_sell/lib/karaoke.pymake_post_sell/lib/mail.pymake_post_sell/lib/s3_mirror.pymake_post_sell/models/__init__.pymake_post_sell/models/cart.pymake_post_sell/models/cart_gift_card.pymake_post_sell/models/gift_card.pymake_post_sell/models/gift_card_transaction.pymake_post_sell/models/meta.pymake_post_sell/models/product.pymake_post_sell/models/shop.pymake_post_sell/request_methods.pymake_post_sell/routes.pymake_post_sell/scripts/alembic/versions/9884324a48e3_add_environment_trial_and_primary_s3_.pymake_post_sell/scripts/alembic/versions/f8201a9ba045_add_gift_card_tables_and_shop_settings.pymake_post_sell/static/css/common.cssmake_post_sell/static/css/tokens.cssmake_post_sell/static/js/watch.jsmake_post_sell/templates/actions_view.j2make_post_sell/templates/base.j2make_post_sell/templates/cart.j2make_post_sell/templates/content.j2make_post_sell/templates/gift_card.j2make_post_sell/templates/gift_card_detail.j2make_post_sell/templates/gift_card_manage.j2make_post_sell/templates/home.j2make_post_sell/templates/join-or-log-in.j2make_post_sell/templates/product.j2make_post_sell/templates/product_edit.j2make_post_sell/templates/shop.j2make_post_sell/templates/shop_about.j2make_post_sell/templates/shop_new.j2make_post_sell/templates/shop_settings.j2make_post_sell/templates/snippets/footer.j2make_post_sell/templates/snippets/related_content.j2make_post_sell/templates/styleguide.j2make_post_sell/templates/user_purchases.j2make_post_sell/tests/test_functional.pymake_post_sell/tests/test_integration.pymake_post_sell/tests/test_models.pymake_post_sell/views/__init__.pymake_post_sell/views/cart.pymake_post_sell/views/content.pymake_post_sell/views/feeds.pymake_post_sell/views/gift_card.pymake_post_sell/views/player.pymake_post_sell/views/product.pymake_post_sell/views/shop.pymake_post_sell/views/watch.py⚠️ Potential issue | 🟠 Major
Grandfathered shops stay inactive with this
is_activeexample.Lines 27-30 define
NULLtrial_started_timestampas “pre-trial era, treated as paid,” but Line 69 only returnsplan_active or is_trial_active. For those legacy shops both branches are false, so the example would lock out existing stores unless some separate backfill setsplan_active=True.💡 Proposed fix
Also applies to: 66-69
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Reject duplicate gift cards before applying deductions.
The same card can be attached more than once (
make_post_sell/models/cart_gift_card.py:8-33has no(cart_id, gift_card_id)uniqueness guard), anddiscounted_shop_totals_in_cents()will apply its balance once per attachment. Add a duplicate-id/code check here, and ideally back it with a DB constraint later.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Reject non-positive redemption amounts.
This constructor accepts
0or negative cents, which would either create meaningless rows or add balance back once downstream code subtracts the “deduction.” Enforceamount_in_cents > 0here and ideally at the schema level too.💡 Proposed fix
Also applies to: 18-24, 33-38
🤖 Prompt for AI Agents
⚠️ Potential issue | 🔴 Critical
Make redemption atomic and reject non-positive amounts.
min(amount_in_cents, self.balance_in_cents)turns negative inputs into balance increases, and this read/modify/write update can double-spend the same card under concurrent checkouts. This needs a positive-amount guard plus DB-level locking or an atomicUPDATE ... WHERE balance_in_cents >= ...in the redemption path.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
trial_endednever changes the shop’s effective access state.The new flag is stored, but
is_trial_active,is_trial_expired, andis_activeignore it. An early-ended trial will still look active until the timestamp expires.Also applies to: 303-335
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 140
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 140
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 140
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 140
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1544
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1910
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 147
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 542
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1019
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 2302
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1861
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1349
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 151
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 299
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1281
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1526
Include
primary_s3_regionin thehas_primary_s3validation.add_shop_uploads_client()always passesshop.primary_s3_regionto the boto3 S3 client, buthas_primary_s3doesn't require that field. This allows a shop to pass the BYOB readiness check whileprimary_s3_regionisNoneor empty, resulting in a misconfigured client.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
The non-production discovery guard is bypassed by async rebuilds.
reforge_discovery_ring()now empties the ring for staging/development shops, butreforge_discovery_ring_async()still callscompute_discovery_ring()directly. Any background rebuild will repopulate discovery for shops that were supposed to stay hidden.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Don't silently fall back to the platform bucket when BYOB is enabled.
If
primary_s3_enabledis true but one field is missing, all three helpers quietly return the MPS client/bucket/CDN instead of surfacing a misconfiguration. That breaks the BYOB contract and can send shop media back to the shared bucket.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Avoid storing raw BYOB credentials in
mps_shop.Adding
primary_s3_access_keyandprimary_s3_secret_keyas plain text columns means a DB leak exposes every connected bucket. This should be an encrypted secret reference or envelope-encrypted payload, not directly readable key material.🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Mirror the existence checks in
downgrade().upgrade()is intentionally tolerant of already-present columns, butdowngrade()drops everything unconditionally. On a partially applied or hand-repaired schema, rollback will fail or remove columns this revision never created.💡 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Missing the required pre-migration backup step.
This script starts applying DDL immediately, but the repo rule for Alembic migrations requires taking a SQLite backup first. Please wire that into the migration path before this ships.
As per coding guidelines, "Always create a backup of the database before any database operations (migrations, schema changes, etc.)".
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Downgrade does not restore the pre-migration schema.
upgrade()addsmps_cart.json_gift_cards, butdowngrade()never removes it. The unguarded drops will also fail on partially-applied or partially-rolled-back databases.Suggested rollback fix
🤖 Prompt for AI Agents
⚠️ Potential issue | 🟠 Major
Guard the initial ring seed against stale async responses.
This callback writes
ringProductIdsusing the mutablecurrentProductId. If the user navigates before the fetch resolves, the old response can overwrite the new ring state and persist the wrong ring in localStorage.Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents
⚠️ Potential issue | 🔴 Critical
🧩 Analysis chain
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 261
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 414
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 1636
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 505
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 3793
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 206
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 118
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 442
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 3800
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 425
🏁 Script executed:
Repository: engineering/make-post-sell/make_post_sell
Length of output: 630
Update watch.py to return CDN endpoint URLs for media, matching the template pattern.
The template now uses
request.shop_cdn_endpointfor the video URL, but watch.py returns presigned S3 URLs viagenerate_presigned_url()formedia_url,instrumentals_url, andvocals_url. This creates a scheme mismatch: the initial page load uses persistent CDN URLs, but navigation in watch mode switches to temporary presigned URLs (ExpiresIn=900), which will expire after 15 minutes and break playback.watch.py already uses
request.shop_cdn_endpointforfile_urlandthumbnail_url. Updatemedia_url,instrumentals_url, andvocals_urlto follow the same pattern for consistency across watch mode lifecycle.🤖 Prompt for AI Agents