Skip to content

Instantly share code, notes, and snippets.

@gsingal
Last active April 16, 2026 00:40
Show Gist options
  • Select an option

  • Save gsingal/be434e2a8291db5e3f766125297b2dd8 to your computer and use it in GitHub Desktop.

Select an option

Save gsingal/be434e2a8291db5e3f766125297b2dd8 to your computer and use it in GitHub Desktop.
Pro Plan Clean Extraction — Remediation Plan (v2, Codex-reviewed)

Pro Plan Clean Extraction — Remediation Plan (v5)

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Review history:

  • v1: Full-file diff-and-apply. Codex R1: controllers carry security regressions. → REVISE
  • v2: Hunk-level triage with denylist. Codex R2: Room.php missing, frontend misclassified, Stripe broken. → REVISE
  • v3: 4-category system. Codex R3: "clean diff" files have removals, Payment.vue copy-then-restore unsafe. → REVISE
  • v4: Master-first principle. Codex R4: Plan broke its own rule with "Maybe" copy items. PlanService missing buildPlanCode/getGroupedPlans. Non-failing patch loop. → REVISE
  • v5: No "Maybe" — every file definitive. PlanService fully specified. Fail-fast on apply.
  • R5: Pricing page regression from shared tables, SelectPlan variant testing. R6: SelectPlan .edu banner removal. R7: Photo upload limits in HaveRoomController/Photos.vue/PhotosTab.vue.
  • v5-final (this): All findings addressed. 37 files. Photo entitlement path included. Codex R8: APPROVE — no production-incident-level findings.

Problem & Why Now

The Pro Plan feature branch (feature/pro-plan-combined) was created from staging instead of master. The diffs are contaminated — master has security improvements (ownership checks, rate limiting, fraud guards) that the staging-based branch predates. Cherry-picking into deployment/2026-04-14 produced an incomplete, broken extraction. Megan's QA found 10+ bugs.

Why now: Gaurav out next week. Pro Plan must launch this week.

Prior Art & Research

  • Codex R1-R3 (Apr 15): Three adversarial rounds established that no file from the contaminated branch can be blindly copied. Even frontend "rewrites" bundle unrelated behavior changes. The only safe approach is: start from master, add pro-specific code using the feature branch as reference.
  • Prior incident (Apr 8): Deployment merge silently reverted files. PR #4030 added prevention.

Alternatives Considered

A: Continue patching deployment branch (Ahmed's Path 1)

  • Verdict: Rejected — structurally incomplete.

B: Scoped re-implementation on master (Ahmed's Path 2)

  • Verdict: Viable fallback. Fully specified below.

C: Polish on staging, then deploy (Ahmed's Path 3)

  • Verdict: Rejected — carries unreleased code.

D: Master-based extraction with "master-first" principle (Recommended)

For every file: start from master's version, then add ONLY the pro-specific changes using the feature branch as a reference. Never overwrite master with a feature-branch file unless the file is brand new.

  • Pro: Mathematically cannot introduce regressions — master's code is never removed.
  • Con: More manual work than copy-and-pray. ~6-10 hours.
  • Verdict: Chosen. Switch to Path B if >12 hours or >3 unresolvable issues.

Key Principle: Master-First Extraction

Every extraction step starts from master's current file and adds to it. The feature branch is a REFERENCE, not a SOURCE. This means:

  • ✅ Read the feature branch diff to understand what pro-plan code looks like
  • ✅ Manually add those changes to master's file
  • ✅ Copy files that are genuinely new (don't exist on master at all)
  • ❌ Never git show feature-branch:file > file for files that exist on master
  • ❌ Never git apply a full-file diff without reviewing every hunk

This is slower but eliminates the entire class of "accidentally reverted security fix" bugs.

Assumptions

  1. The pro-plan code is functionally correct — just contaminated by ancestry.
  2. Master's code is authoritative — any difference between master and the feature branch that isn't clearly pro-plan-related is a regression in the feature branch.
  3. Stripe products needed in both prod and test. Ahmed created prod Apr 15.
  4. Deferred features acceptable for launch. Confirmed by Gaurav Apr 13.
  5. HasProPlan middleware is not wired to any routes — it's scaffolding for future use. Include it but don't expect it to be active.

File Classification (3 categories, 37 files)

Category A: NEW — Copy from feature branch (7 files)

Files that do NOT exist on master. Zero regression risk.

File Purpose Verified new?
app/Console/Commands/CreateProPlans.php Stripe seeder (stripe:create-pro-plans {env}) ✅ not on master
app/Http/Middleware/HasProPlan.php Route middleware (not yet wired) ✅ not on master
app/Services/SmartLabelService.php Smart label computation ✅ not on master
tests/Feature/ProPlanTest.php Pro plan tests ✅ not on master
tests/Feature/SmartLabelServiceTest.php Smart label feature tests ✅ not on master
tests/Unit/SmartLabelServiceTest.php Smart label unit tests ✅ not on master
tests/Unit/RoomRecommendationServiceTest.php Recommendation unit tests ✅ not on master

Category B: ADDITIVE ONLY — Apply diff (verified no regressions) (3 files)

Files where the diff contains ONLY additions and the additions are all pro-plan code. Verified: zero removals of existing functionality.

File Removals Additions Safe?
app/Models/StripePlan.php 1 (getPaidPlans line replaced) ~40 ✅ replacement is pro-aware merge
app/Services/RoomRecommendationService.php 0 ~15 ✅ purely additive
app/helpers.php 0 ~5 ✅ purely additive

Category C: MASTER-FIRST — Start from master, manually add pro hunks (24 files)

Files where the diff has removals, rewrites, or mixed changes. Start from master's version. Read the feature branch diff to identify the pro-specific additions. Apply only those additions manually.

Backend (7 files):

File What to add from feature branch What to NOT change
app/Services/PlanService.php isProPlan(), getProPlans() methods. Keep ?string nullable types if master has them. Nullable type hints, null safety
app/Http/Controllers/ProfileController.php Analytics: isPremiumhasAnalyticsAccess (isPremium || isPro), prop rename Everything else (ownership, rate limit, guards)
app/Http/Controllers/SearchController.php use SmartLabelService, two computeLabelsForRooms() calls Everything else (validation, strip, security)
app/Models/Room.php Add 'smart_labels' to FRONTEND_VISIBLES array Everything else (casts, fraud guard, HasFactory)
app/Http/Controllers/Admin/SubscriptionsCrudController.php Pro plan codes in filter dropdowns, stripe_price_id resolution Everything else
app/Console/Commands/SuggestSimilarSublets.php Pro-aware suggestion logic (review 4 removals first) Anything unrelated to pro
database/seeders/TestDatabaseSeeder.php Add 3 Pro plan rows to seedStripePlans(). Do NOT copy the file — feature branch collapses 60 rooms to 1. Room/city data, all other seeder logic
app/Http/Controllers/HaveRoomController.php Update image limit logic: Pro plans get unlimited (or higher) photo limit. Currently hard-coded to 30 for non-standard. Existing upload validation, ClamAV scanning
resources/js/components/Room/Photos.vue Update photo limit display: Pro plan gets unlimited indicator instead of 8 : 30 Existing upload/preview logic
resources/js/Pages/HaveRoom/components/PhotosTab.vue Update upgrade messaging: include Pro alongside Premium Existing layout

Frontend (17 files):

File Removals in diff Approach
resources/js/Pages/PostRoom/Payment.vue Removes rateLimited, 429 handling Start from master. Add: pro plan detection, pro checkout branch, upgradeClick tier param
resources/js/Pages/PostRoom/Payment/UpgradeToPremium.vue Restructures component Start from master. Add: highlightedTier prop, pro upgrade button, tier-aware emit
resources/js/Pages/PostRoom/SelectPlan.vue Restructures for variants Start from master. Add: pro plan option, variant routing
resources/js/Pages/PostRoom/SelectPlan/Plans.vue Swaps analytics events Start from master. Add: pro coupon display, pro plan type in events
resources/js/Pages/PostRoom/SelectPlan/PlansVariantC.vue Exists on master, modified Start from master. Add: pro-specific changes
resources/js/Pages/PostRoom/SelectPlan/DesktopTable.vue -97 lines (rewrite) Start from master. Add: pro column, pro row data, pro styling
resources/js/Pages/PostRoom/SelectPlan/MobileTable.vue -61 lines (rewrite) Start from master. Add: pro section, pro data
resources/js/Pages/Account/ListingCard.vue -66 lines Start from master. Add: pro badge, pro plan detection
resources/js/Pages/Account/Listings/Upgrade.vue Full rewrite Start from master. Add: pro ceiling check, pro tier in selection, pro upgrade path
resources/js/Pages/Account/Listings/Analytics.vue Modified Start from master. Add: hasAnalyticsAccess prop (match ProfileController)
resources/js/Pages/NeedRoom/components/GoogleMap.vue Full pin rewrite Start from master. Add: pro pin tier, pro z-index level, pro crown marker
resources/js/Pages/NeedRoom/components/MarkerModal.vue Badge rewrite Start from master. Add: pro badge alongside existing premium badge
resources/js/Pages/NeedRoom/components/GroupMarkerModal.vue Group pin rewrite Start from master. Add: pro badge in group modal
resources/js/Pages/NeedRoom/components/MapView.vue Minor Start from master. Add: pro map layer
resources/js/Pages/NeedRoom/components/ResultsCard.vue -37 lines Start from master. Add: pro flag, smart label display
resources/js/composables/usePlan.js -12 lines Start from master. Add: pro plan awareness functions
resources/js/utils/planUtils.js -12 lines Start from master. Add: pro utility functions

DENYLIST — changes that MUST NOT be ported

  • ❌ Removal of CheckoutRateLimit trait or rateLimited state
  • ❌ Removal of ownership checks (Room::whereUserId(Auth::user()->id))
  • ❌ Removal of idempotency keys or prebook duplicate guard
  • ❌ Removal of isValidRoomId(), stripForPublicDisplay(), location validation
  • ❌ Removal of defense-in-depth fraud guard in Room::boot()
  • ❌ Removal of prebook_pause_until/prebook_pause_duration casts
  • ❌ Removal of HasFactory trait or Log import
  • ❌ Removal of 429 rate limit handling in Payment.vue
  • ❌ Collapsing test seeder data (60 rooms → 1)
  • ❌ Removal of auth guards before discount fetching
  • ❌ Removal of availability chips or analytics instrumentation

Risks & Rollback

Risk 1: Manual extraction misses a pro-plan hunk

Probability: Medium. Impact: Medium (missing feature, caught in QA). Mitigation: After each file, compare rendered UI against feature branch behavior. QA checklist covers all features. Rollback: Add missing hunks.

Risk 2: Large frontend files are hard to manually extract

Probability: High for GoogleMap.vue, DesktopTable.vue (complex rewrites). Impact: Medium — may need to copy-then-audit instead of master-first for these. Mitigation: For files where the rewrite IS the pro feature (map pins, plan tables), copy from feature branch and audit for non-pro regressions. Use master-first for mixed files. Escalation: If >3 frontend files can't be cleanly extracted, switch to Path B.

Risk 3: Stripe seeding with placeholder IDs

Probability: Medium. CreateProPlans.php has REPLACE_WITH_* placeholders. Mitigation: Task 1 replaces all placeholders before committing. --dry-run preview before seeding. Non-production placeholder for quarterly must also be replaced. Rollback: Update IDs, re-seed.

Non-Goals

  • Video tour, walking distance label, view counting (Phase 2)
  • Fixing staging branch (self-corrects)
  • Refactoring extracted code (follow-up issues)
  • Wiring HasProPlan middleware to routes (include file, wire later)

Success Criteria

  1. git merge-base --is-ancestor origin/master feature/pro-plan-v2 → true
  2. For Group 1 (master-first) files: diff shows ONLY additions (exception: ProfileController.php has 2 expected substitutions: isPremiumhasAnalyticsAccess). For Group 2 (copy-and-audit) files: removals are expected (old 2-tier code replaced) but must pass the mandatory audit checklist.
  3. composer test passes (including ProPlan, SmartLabel, Subscription, Webhook filters)
  4. npm run build succeeds
  5. QA sign-off on full checklist
  6. Merged to master by Thu Apr 17

Tasks

Task 1: Setup — Stripe IDs, branch, new files

1a. Collect Stripe price IDs from Ahmed

6 IDs needed (3 products × 2 environments):

Product Prod price ID Test price ID
Pro Monthly ($49/mo) price_??? price_???
Pro Quarterly ($117/3mo) price_??? price_???
Pro Annual ($348/yr) price_??? price_???

1b. Create branch and seed command

git checkout master && git pull origin master
git checkout -b feature/pro-plan-v2

Copy CreateProPlans.php from feature branch. Replace ALL placeholder IDs (including the non-production quarterly placeholder). Verify command signature is stripe:create-pro-plans {env}.

1c. Copy Category A (new) files

for file in \
  app/Http/Middleware/HasProPlan.php \
  app/Services/SmartLabelService.php \
  tests/Feature/ProPlanTest.php \
  tests/Feature/SmartLabelServiceTest.php \
  tests/Unit/SmartLabelServiceTest.php \
  tests/Unit/RoomRecommendationServiceTest.php; do
  git show origin/feature/pro-plan-combined:"$file" > "$file"
done

1d. Apply Category B (additive-only) diffs

FAILED=0
for file in app/Models/StripePlan.php app/Services/RoomRecommendationService.php app/helpers.php; do
  git diff origin/master origin/feature/pro-plan-combined -- "$file" > /tmp/pro.patch
  if git apply /tmp/pro.patch; then
    echo "OK: $file"
  else
    echo "FAILED: $file — resolve manually before continuing"
    FAILED=$((FAILED+1))
  fi
done
if [ $FAILED -gt 0 ]; then echo "$FAILED files failed — fix before committing"; exit 1; fi

1e. Commit

git add \
  app/Console/Commands/CreateProPlans.php \
  app/Http/Middleware/HasProPlan.php \
  app/Services/SmartLabelService.php \
  app/Models/StripePlan.php \
  app/Services/RoomRecommendationService.php \
  app/helpers.php \
  tests/Feature/ProPlanTest.php \
  tests/Feature/SmartLabelServiceTest.php \
  tests/Unit/SmartLabelServiceTest.php \
  tests/Unit/RoomRecommendationServiceTest.php
git commit -m "feat: Pro Plan extraction — new files and clean diffs"

Task 2: Backend Category C — manual pro hunk additions

For each file: open master's version, read the feature branch diff as reference, add ONLY pro-specific code.

2a. PlanService.php — 5 changes, all additive. Keep all existing ?string nullable type hints and null checks unchanged:

  1. Add isProPlan(string $plan): bool method (delegates to StripePlan::isPro())
  2. Add getProPlans(): array method (delegates to StripePlan::getProPlans())
  3. In getPlanDisplayName(): add 3 cases for PLAN_PRO_MONTHLY, PLAN_PRO_QUARTERLY, PLAN_PRO_ANNUALLY
  4. In buildPlanCode(): add if ($baseType === 'pro') { return 'rr-pro-'.$duration; } BEFORE the existing return statement. Critical: without this, Pro plan codes generate pro-monthly instead of rr-pro-monthly, breaking checkout.
  5. In getGroupedPlans(): add 'pro' => $allPlans->filter(fn($plan) => self::isProPlan($plan->code))

DO NOT change ?stringstring type hints or remove null checks. The feature branch removes null safety — master's callers may pass null.

2b. ProfileController.php — Change analytics method only: isPremiumhasAnalyticsAccess (2 locations). Add StripePlan import if missing.

2c. SearchController.php — Add use SmartLabelService import. Add computeLabelsForRooms() call after room processing (before sort). Add same for partial rooms. Touch nothing else.

2d. Room.php — Add 'smart_labels' to FRONTEND_VISIBLES array. Touch nothing else.

2e. SubscriptionsCrudController.php — Add Pro plan codes to admin filter dropdown. Add stripe_price_id resolution for Pro.

2f. SuggestSimilarSublets.php — Add pro-aware suggestion logic. Review the 4 removals — if they're refactors (not pro-related), skip them.

2g. TestDatabaseSeeder.php — Add 3 Pro plan rows to seedStripePlans(). Do NOT touch room/city/user data.

2h. HaveRoomController.php — Update image limit logic. Currently $maxImages = 30 for non-standard plans. Add Pro tier check: Pro plans get unlimited photos (or a higher cap like 100). Update the plan name in the error message to include Pro.

2i. Photos.vue — Update the hard-coded 8 : 30 photo limit display to include Pro tier (unlimited or higher).

2j. PhotosTab.vue — Update the "upgrade to Premium" messaging to also mention Pro, or show contextually correct messaging based on current plan tier.

composer test --filter=ProPlan
composer test --filter=SmartLabel
git add app/Services/PlanService.php app/Http/Controllers/ProfileController.php \
  app/Http/Controllers/SearchController.php app/Models/Room.php \
  app/Http/Controllers/Admin/SubscriptionsCrudController.php \
  app/Console/Commands/SuggestSimilarSublets.php \
  database/seeders/TestDatabaseSeeder.php
git commit -m "feat: Pro Plan backend — manual hunk extraction from master

ProfileController: analytics access includes Pro
SearchController: smart labels via SmartLabelService
Room: smart_labels in FRONTEND_VISIBLES
PlanService: isProPlan(), getProPlans()
Admin: Pro plan filtering
TestDatabaseSeeder: Pro plan rows"

Task 3: Frontend Category C — manual pro additions

Every file below has a definitive decision. No "Maybe."

Group 1: MASTER-FIRST (add pro hunks to master's file) — 9 files

These files have mixed changes, security regressions, or suspicious removals. Start from master, add only pro code.

File What to add Why master-first
Payment.vue Pro plan detection, pro checkout branch, upgradeClick tier param Removes rateLimited, 429 handling
Plans.vue Pro coupon display, pro plan type in analytics events Swaps analytics events
Analytics.vue hasAnalyticsAccess prop (match backend change) Small change, master-first is trivial
ListingCard.vue Pro badge, pro plan detection -66 lines = suspicious removals
ResultsCard.vue Pro flag, smart label display Removes availability chip
usePlan.js Pro plan awareness functions -12 lines need review
planUtils.js Pro utility functions -12 lines need review
PlansVariantC.vue Pro-specific changes (exists on master) Modified file, not new
SelectPlan.vue Pro option, variant routing changes Feature branch removes .edu banner (regression)
MapView.vue Pro map layer support Minor changes, master-first is easy

Group 2: COPY-AND-AUDIT (copy from feature branch, run audit) — 8 files

These files are intentional full rewrites where the rewrite IS the pro feature. The old code is being replaced by a multi-tier system — you can't "add pro hunks" because the entire architecture changes. Copy from feature branch, then run the mandatory audit checklist.

File Why copy is OK Audit focus
GoogleMap.vue 4-tier pin system replaces 2-tier — this IS the feature Verify Standard/Premium pins still render correctly
MarkerModal.vue Multi-tier badge replaces premium-only SVG Verify Premium badge still works
GroupMarkerModal.vue Multi-tier group pin Verify existing group behavior
DesktopTable.vue Pro column requires table restructure Verify Standard/Premium columns intact
MobileTable.vue Same Same
Upgrade.vue Pro ceiling + tier selection = new component structure Verify Standard→Premium upgrade still works
UpgradeToPremium.vue Tier-aware split IS the pro feature Verify Premium-only upgrade still works

NOTE: SelectPlan.vue was previously in Group 2 but moved to Group 1 (master-first) because the feature branch removes the .edu verification error banner that exists on master. This is NOT a pro-plan change — it's a staging regression.

Mandatory audit for EVERY Group 2 file after copy:

  • npm run build succeeds
  • File does not reference $page.props keys that don't exist on master
  • Standard plan path exercised (visual check or test)
  • Premium plan path exercised
  • Free plan display works
  • No auth guards removed (search for auth in diff removals)
  • No rate limit or security logic removed

Additional audits for specific Group 2 files:

DesktopTable.vue / MobileTable.vue:

  • Public /pricing page still renders correctly (these are shared with the Pricing page, not just PostRoom)
  • Column count matches expected plans (Free, Standard, Premium, Pro)
  • Guest access to pricing page works (no auth errors)

SelectPlan.vue (now Group 1 — master-first):

  • Add pro plan option to each variant branch without removing .edu verification banner
  • All variant branches still work: control, no-quarterly-pro, new-design
  • Free plan submission still works in each variant
  • Analytics events include pro plan type

UpgradeToPremium.vue:

  • Event contract: verify upgradeClick emits tier parameter ('premium' or 'pro') that Payment.vue (master-first) correctly handles
  • If Payment.vue doesn't have a handler for the tier param yet, add it in Task 3 Group 1 work
  • Standard→Premium proration still correct
npm run build  # Must succeed
git add resources/js/
git commit -m "feat: Pro Plan frontend — plan selection, upgrade, map pins, badges, analytics"

Task 4: Verification

4a. Full test suite

composer test
npm run build
php artisan route:list | grep -i pro
composer test --filter=ProPlan
composer test --filter=SmartLabel
composer test --filter=Subscription

⚠️ Expected test updates: Existing tests may fail because they assert pre-Pro behavior:

  • tests/Unit/PlanServiceTest.php — may assert Pro display names are Unknown Plan and old buildPlanCode() outputs. Update assertions to expect Pro plan names and rr-pro-* codes.
  • tests/Unit/StripePlanTest.php — may expect only 2 plan types. Update to include Pro.

These are expected failures caused by the extraction, not regressions. Fix the assertions in the same commit.

4b. Security check — ALL modified files (not just backend)

For every file modified on the branch, count removals and verify they're expected:

echo "=== Backend (expect 0 removals except ProfileController 2-4) ==="
for file in app/Http/Controllers/ProfileController.php \
  app/Http/Controllers/SearchController.php \
  app/Models/Room.php \
  app/Http/Controllers/Admin/SubscriptionsCrudController.php \
  app/Services/PlanService.php \
  app/Console/Commands/SuggestSimilarSublets.php \
  database/seeders/TestDatabaseSeeder.php; do
  removals=$(git diff origin/master -- "$file" | grep "^-" | grep -v "^---" | wc -l)
  echo "  $file: $removals removals"
done

echo "=== Frontend Group 1 master-first (expect 0 removals) ==="
for file in resources/js/Pages/PostRoom/Payment.vue \
  resources/js/Pages/PostRoom/SelectPlan/Plans.vue \
  resources/js/Pages/Account/Listings/Analytics.vue \
  resources/js/Pages/Account/ListingCard.vue \
  resources/js/Pages/NeedRoom/components/ResultsCard.vue; do
  removals=$(git diff origin/master -- "$file" | grep "^-" | grep -v "^---" | wc -l)
  echo "  $file: $removals removals"
done

echo "=== Frontend Group 1 remaining (expect 0 removals) ==="
for file in resources/js/composables/usePlan.js \
  resources/js/utils/planUtils.js \
  resources/js/Pages/PostRoom/SelectPlan/PlansVariantC.vue \
  resources/js/Pages/PostRoom/SelectPlan.vue \
  resources/js/Pages/NeedRoom/components/MapView.vue; do
  removals=$(git diff origin/master -- "$file" | grep "^-" | grep -v "^---" | wc -l)
  echo "  $file: $removals removals"
done

echo "=== Frontend Group 2 copy-and-audit (ALL files — removals OK if intentional rewrites) ==="
for file in resources/js/Pages/NeedRoom/components/GoogleMap.vue \
  resources/js/Pages/NeedRoom/components/MarkerModal.vue \
  resources/js/Pages/NeedRoom/components/GroupMarkerModal.vue \
  resources/js/Pages/Account/Listings/Upgrade.vue \
  resources/js/Pages/PostRoom/Payment/UpgradeToPremium.vue \
  resources/js/Pages/PostRoom/SelectPlan/DesktopTable.vue \
  resources/js/Pages/PostRoom/SelectPlan/MobileTable.vue; do
  removals=$(git diff origin/master -- "$file" | grep "^-" | grep -v "^---" | wc -l)
  echo "  $file: $removals removals (audit: are these the old 2-tier code being replaced?)"
done

Expected:

  • ProfileController.php: 2-4 (isPremium → hasAnalyticsAccess substitution)
  • All other backend + Group 1 frontend: 0
  • Group 2 frontend: removals are OK IF they're the old implementation being replaced by multi-tier

Any unexpected removals → investigate before committing.

4c. Completeness check

# Search for ALL pro-related tokens — includes tests/ and bootstrap/
rg "isPro|PLAN_PRO|pro-plan|ProPlan|pro_plan|smart_label|SmartLabel|hasAnalyticsAccess|getProPlans|rr-pro-|HasProPlan|showPro|proUpgradePrice|pro-pin|stripe:create-pro-plans|isProPlan|getGroupedPlans.*pro" \
  app/ resources/js/ config/ routes/ database/ tests/ bootstrap/ \
  --type-add 'web:*.{php,vue,js}' -t web -l 2>/dev/null | sort -u

Compare against our 34-file list. Investigate any unlisted files.

4d. Branch ancestry + content integrity

# Ancestry check
git merge-base --is-ancestor origin/master feature/pro-plan-v2 && echo "ANCESTRY: CLEAN" || echo "ANCESTRY: CONTAMINATED"

# Content integrity: verify no file was wholesale replaced with feature-branch version
# (except Category A new files and Group 2 intentional rewrites)
git diff origin/master feature/pro-plan-v2 --stat | grep "Bin" && echo "⚠️ Binary changes detected" || echo "No binary changes"

Task 5: Deploy, QA, Launch

5a. Deployment branch

git checkout master && git pull origin master
git checkout -b deployment/2026-04-16
git merge feature/pro-plan-v2
git push origin deployment/2026-04-16

5b. QA server seed

php artisan stripe:create-pro-plans non-production --dry-run   # Preview
php artisan stripe:create-pro-plans non-production              # Execute
# Verify: SELECT code, name, stripe_price_id, monthly_charge FROM stripe_plans WHERE code LIKE 'rr-pro%';
# Expected: 3 rows with correct prices and real Stripe price IDs (not placeholders)

5c. Smoke test

Run /qa-smoke against QA.

5d. Full QA checklist (Megan)

Pro Plan core:

  • Pro on Select a Plan (monthly, quarterly, annual)
  • Pro on Upgrade page
  • New listing → Pro checkout works
  • Standard → Pro upgrade (correct proration)
  • Premium → Pro upgrade (correct proration)
  • Pro Monthly → Pro Quarterly upgrade
  • Pro Monthly → Pro Annual upgrade
  • Pro ceiling message ("highest tier")
  • 31+ photo upload works on Pro
  • Map pins: Pro crown badge
  • Listing cards: Pro flag
  • Smart labels on Pro listings
  • Admin: Pro subscriptions visible/filterable

Non-Pro regression checks:

  • Standard checkout still works
  • Premium checkout still works
  • Free plan display correct
  • Standard → Premium upgrade works (proration: $10 not $25)
  • Guest pricing page loads (no auth error)
  • Map pins: Standard/Premium badges unchanged
  • Existing listing edit flow works
  • No visual regressions on search results

Known issues to verify:

  • Guest discount fetch doesn't error (#2973)
  • Deferred features not confusingly absent

5e. Fix → re-QA → merge

# Forward-integrate master before merging (Apr 8 lesson)
git checkout deployment/2026-04-16
git merge master
git push origin deployment/2026-04-16
# PR: deployment/2026-04-16 → master

Production seed:

php artisan stripe:create-pro-plans production --dry-run
php artisan stripe:create-pro-plans production

Fallback Plan: Path B (Scoped Re-implementation)

Trigger: >12 hours on Path D, or >3 unresolvable frontend conflicts.

What it is: Build minimum viable Pro Plan on master from scratch. Use feature branch as reference only (never merge/copy).

Minimum viable slice:

Priority Files What to build
P0 — billing StripePlan.php, PlanService.php, CreateProPlans.php Pro constants, methods, seeder
P0 — checkout SelectPlan.vue, PlansVariantC.vue, Plans.vue, DesktopTable.vue, MobileTable.vue Pro option in plan selection
P0 — payment Payment.vue, UpgradeToPremium.vue Pro checkout and upgrade flow
P0 — upgrade Upgrade.vue Pro upgrade path, tier ceiling
P1 — display ListingCard.vue, ResultsCard.vue, Analytics.vue Pro badges, analytics access
P1 — map GoogleMap.vue, MarkerModal.vue, GroupMarkerModal.vue, MapView.vue Pro pin tier
P1 — backend ProfileController.php, SearchController.php, Room.php Analytics gate, smart labels
P2 — admin SubscriptionsCrudController.php Admin filtering
P2 — features SmartLabelService.php, SuggestSimilarSublets.php, RoomRecommendationService.php Smart labels, suggestions

P0 is launch-blocking. P1 ships same day if possible. P2 can follow.

Estimated time: 1.5-2 days for P0+P1. Most infrastructure exists on master.


Branch Strategy

  • Branch: feature/pro-plan-v2 from master
  • Serial execution — tasks are sequential
  • Deployment: deployment/2026-04-16
  • Fallback: Path B if >12 hours or >3 unresolvable issues

Timeline

Day Action Owner
Tue Apr 15 (evening) Tasks 1-2: Setup, backend extraction Claude + Ahmed
Wed Apr 16 (morning) Task 3: Frontend extraction Claude + Ahmed
Wed Apr 16 (midday) Task 4: Verification Claude
Wed Apr 16 (afternoon) Task 5: Deploy QA, full QA Ahmed + Megan
Thu Apr 17 (morning) Fix QA findings Ahmed/Mahmoud/Claude
Thu Apr 17 (1pm ET) Merge to master, deploy Ahmed

Open Questions

  1. Pro on public pricing page? Mahmoud said no, Megan flagged missing.
  2. Quarterly visibility: Initial selection, upgrades, or both?
  3. Deferred features: "Coming Soon" vs hidden?

Process Lessons (post-ship)

  1. CLAUDE.md rule: Never create a feature branch from staging.
  2. Hook: git merge-base --is-ancestor origin/master <branch> on PR creation.
  3. Lesson: staging-based branches carry security regressions in mixed files — even hunk extraction requires per-line review.
@majones919

Copy link
Copy Markdown

My concern here is it sounds like we need to rebuild things, and it's already Wednesday at 6:15pm. The slack convo flags QA wednesday, production Thursday. Ideally it goes smooth and goes out Thursday still... but if it doesn't go as expected, I would recommend NOT pushing this on Friday and instead waiting until Monday if needed.

@mahmoudessam7

Copy link
Copy Markdown

Thorough plan, I like it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment