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.
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.
- 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.
- Verdict: Rejected — structurally incomplete.
- Verdict: Viable fallback. Fully specified below.
- Verdict: Rejected — carries unreleased code.
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.
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 > filefor files that exist on master - ❌ Never
git applya full-file diff without reviewing every hunk
This is slower but eliminates the entire class of "accidentally reverted security fix" bugs.
- The pro-plan code is functionally correct — just contaminated by ancestry.
- 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.
- Stripe products needed in both prod and test. Ahmed created prod Apr 15.
- Deferred features acceptable for launch. Confirmed by Gaurav Apr 13.
HasProPlanmiddleware is not wired to any routes — it's scaffolding for future use. Include it but don't expect it to be active.
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 |
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 |
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: isPremium → hasAnalyticsAccess (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 |
- ❌ Removal of
CheckoutRateLimittrait orrateLimitedstate - ❌ 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_durationcasts - ❌ Removal of
HasFactorytrait orLogimport - ❌ 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
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.
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.
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.
- Video tour, walking distance label, view counting (Phase 2)
- Fixing staging branch (self-corrects)
- Refactoring extracted code (follow-up issues)
- Wiring
HasProPlanmiddleware to routes (include file, wire later)
git merge-base --is-ancestor origin/master feature/pro-plan-v2→ true- For Group 1 (master-first) files: diff shows ONLY additions (exception:
ProfileController.phphas 2 expected substitutions:isPremium→hasAnalyticsAccess). For Group 2 (copy-and-audit) files: removals are expected (old 2-tier code replaced) but must pass the mandatory audit checklist. composer testpasses (including ProPlan, SmartLabel, Subscription, Webhook filters)npm run buildsucceeds- QA sign-off on full checklist
- Merged to master by Thu Apr 17
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-v2Copy 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"
done1d. 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; fi1e. 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"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:
- Add
isProPlan(string $plan): boolmethod (delegates toStripePlan::isPro()) - Add
getProPlans(): arraymethod (delegates toStripePlan::getProPlans()) - In
getPlanDisplayName(): add 3 cases forPLAN_PRO_MONTHLY,PLAN_PRO_QUARTERLY,PLAN_PRO_ANNUALLY - In
buildPlanCode(): addif ($baseType === 'pro') { return 'rr-pro-'.$duration; }BEFORE the existing return statement. Critical: without this, Pro plan codes generatepro-monthlyinstead ofrr-pro-monthly, breaking checkout. - In
getGroupedPlans(): add'pro' => $allPlans->filter(fn($plan) => self::isProPlan($plan->code))
DO NOT change ?string → string 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: isPremium → hasAnalyticsAccess (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"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 buildsucceeds - File does not reference
$page.propskeys 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
authin diff removals) - No rate limit or security logic removed
Additional audits for specific Group 2 files:
DesktopTable.vue / MobileTable.vue:
- Public
/pricingpage 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
.eduverification 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
upgradeClickemits tier parameter ('premium'or'pro') thatPayment.vue(master-first) correctly handles - If
Payment.vuedoesn'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"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=Subscriptiontests/Unit/PlanServiceTest.php— may assert Pro display names areUnknown Planand oldbuildPlanCode()outputs. Update assertions to expect Pro plan names andrr-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?)"
doneExpected:
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 -uCompare 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"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-165b. 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 → masterProduction seed:
php artisan stripe:create-pro-plans production --dry-run
php artisan stripe:create-pro-plans productionTrigger: >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:
feature/pro-plan-v2from master - Serial execution — tasks are sequential
- Deployment:
deployment/2026-04-16 - Fallback: Path B if >12 hours or >3 unresolvable issues
| 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 |
- Pro on public pricing page? Mahmoud said no, Megan flagged missing.
- Quarterly visibility: Initial selection, upgrades, or both?
- Deferred features: "Coming Soon" vs hidden?
- CLAUDE.md rule: Never create a feature branch from staging.
- Hook:
git merge-base --is-ancestor origin/master <branch>on PR creation. - Lesson: staging-based branches carry security regressions in mixed files — even hunk extraction requires per-line review.
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.