V8 Central — Product & Technical Spec
  1. Docs
  2. Frontend spec (from backend doc)
  3. FE: Plans & subscription (Phase 7)

#FE: Plans & subscription screens (from backend Phase 7)

Frontend spec for backend Phase 7: Plans (Subscription) — requirements complete 2026-10-03, not built. V8 requirement This phase finally settles how plans are sold, so it answers three questions the frontend had been blocked on: who owns the subscription (D-3), whether the credit wallet stays (D-4) and whether plan limits still apply (D-6).

i18n namespaces: plans.*, plans.admin.*, plans.change.*, plans.limits.*, plans.expiry.*, plans.coupon.*, plans.redeem.*.

#Two kinds of plan — system and custom (new 2026-10-06)

Default / system plansCustom plans
Created bySeeders — there from the startThe admin, in the admin panel
WhichFree, Newbie, Pro, Master, Business · Managed, Self Managed (V7 restructured users only, 7.14) · Legacy per-server · LifetimeAnything new — a promo or partner plan
IdentityA fixed key (free, pro…) used by the backend and the V7 migration. The key never changesNo migration role
Admin mayEdit name, prices, limits, features, add-ons, visibilityEverything, plus trial on/off and "no downgrade"
Admin may notDelete them — archive or hide only. Free cannot even be archived (free and free-forever users need it)Delete only if no user has ever been on it; otherwise archive (7.19)

Re-running the seeder only adds missing plans — it never overwrites the admin's changes.

Three things the frontend takes from this:

  • The admin plan list needs to show which kind a plan is. A system plan's Delete is permanently off with the reason, and on Free so is Archive. A custom plan's Delete is off as soon as anyone has ever been on it — "archive instead". Those are three different disabled states, each with its own sentence.
  • A fixed key exists, but it is not an invitation to branch on it. This spec has said all along that a plan name is data and never an identifier; that still holds. The key is the backend's identity for migration, so the frontend keeps rendering from data and does not special-case free or pro. The one honest use is showing the key in the admin list, so an admin can tell a system plan from a look-alike custom one.
  • The seeded list explains things this spec already describes. Managed and Self Managed being seeded plans is why 7.14 can show them only to migrated users; Legacy and Lifetime being seeded is why those existing-user states have somewhere to live. Nothing changes in those screens — it just confirms them.

#A. Admin: managing plans

#FeatureScreen / controlRules from the backend docFrontend notes
7.1PlansAdmin plans list + create/edit pageCreate, edit, hide / show, archive a plan: name, prices, limits, allowed features, trial on / offFull page, not a modal — there are many fields. Status is three-state (visible / hidden / archived), so show it as a badge and never silently drop archived plans that users still hold
7.2Feature listChecklist inside the plan editorOne list of all plan features (servers, apps, team members, share server, API rate limit per minute, and features from later phases). Each plan turns them on / off or sets a limit. Added 2026-10-05: V7's API limits are the starting values (Free 60 … Business 180)The list comes from the API and will grow with every later phase, so render it generically: group → feature → on/off → optional number. Never a hand-written list of features — the API rate limit arriving as just another row is proof the generic rendering was the right call. On the user side it is one more line in the compare table; the frontend does not enforce it, it only reports the 429 the API returns
7.24Plan overviewAdmin dashboard pageNew 2026-10-05: users per plan, upcoming renewals, and accounts close to being lockedThree lists on one page, each a link into the matching user. "Close to being locked" is the useful one — it is the day −7 to day −15 window from 7.12, so it needs the date and days left per account, not just a count
7.13CouponsAdmin coupons screenCodes with percent off, which plans, first payment or recurring, expiryOn the user side: one coupon field at pay time, with the discount shown before confirming
7.14Plan visibilityA user list on the plan (migration only)Rewritten 2026-10-05: all plans are shown to all users — new users all see the same common plans. A plan may carry a list of users who can see it for one purpose only: V7 → V8 migration. V7 "restructured" users get two plans of their own, "Managed" and "Self Managed", each with its own name, price and features, and they see only those, as in V7. The old "Master / Business only for allowed users" rule and the per-plan display name are both goneTwo corrections to earlier assumptions here. First, the plans page is the same for everyone by default, so visibility is no longer a general feature to design around — but the catalogue still must not be cached across accounts, because a migrated user legitimately sees a different list. Second, there is no display name any more: "Managed" and "Self Managed" are real plans with real names, not labels over Newbie and Business, so the frontend shows name and nothing else. Anything that was going to prefer a display name over the name should just use the name
7.18Feature / limit changeConfirm dialog on SaveNew 2026-10-05: when the admin turns a feature off or lowers a limit, users on that plan are warned by email first and the change applies from their next renewalThe Save confirm must list what will change for existing users and say "from each user's next renewal", not "now". On the user side the plan page needs a pending-change note (see 7.18 in §B). D-34: nothing in the doc stops the admin lowering a limit below what a user is already using, which the user-initiated downgrade check (7.8) would refuse — so the editor should at least show how many users would be over the new limit
7.19Archive planStatus on the planNew 2026-10-05: users already on an archived plan keep it until they change plan; new users can't pick itAdded 2026-10-06: Free can never be archived (free and free-forever users need it), a system plan can never be deleted at all, and a custom plan can be deleted only if nobody has ever been on it. Confirms the 7.1 rule: archived plans must still render as somebody's current plan even though they are missing from the catalogue. Make the one-way door clear in the admin list ("N users on it, they keep it until they move") and on the user side (changing away from an archived plan cannot be undone)
7.20One user's planAdmin → user → "Custom plan" pageNew 2026-10-05: the admin can give one user their own plan: custom price, server / app limits, cycle and expiry days (as in V7)A per-user form, reached from the user's admin record, not from the plans list. The big frontend consequence is on the user side: the current plan may be a plan that appears in no card and no compare table, so the plan page must render the current plan from its own data and never by looking it up in the catalogue
7.21Free foreverToggle on the admin's user recordNew 2026-10-05: the admin can mark a user free forever (as in V7)On the user side this behaves like lifetime for the screens: no renewal date, no renew price, no expiry or credit banners — but it is a different label, so don't reuse the lifetime badge. Keep the plans list visible so they can still upgrade
7.23Redeem-code batchesAdmin codes pageNew 2026-10-05: create a batch of codes giving a plan or credit: quantity, expiry, on / off, download the list, and see who used each codeA batch is the record, not the code: list batches, open one to see its codes with used / unused and by whom. Download is a file the backend produces. Switching a batch off must stop redemption without deleting history, so it is a status, not a delete
7.10–7.12Expiry timingAdmin settings pageAdded 2026-10-05: the admin sets the reminder start (default 7 days before), the warning day (default −7), the lock day (default −15), and the reminder weekdays (default Monday + Thursday)Four settings on one page. The important consequence is on the user side: none of those numbers may be written into a screen or a translation string, because an admin can change them. Every user-facing message carries a date from the API, which also means the strings need a date placeholder, not a hard-coded "15 days"
7.26Add-ons in a planAdd-ons picker in the plan editorNew 2026-10-06: the admin can select and assign any available add-on to a plan (examples renamed 2026-10-06: Log Monitoring (V7 InsightHub / Monitoring Panel) — which now has its own phase too, Phase 13 (2026-10-07), and is the opposite of White label: 13.1 makes it tied to the plan, so a downgrade switches it off and removes it from every server — White label — which now has its own phase, Phase 12, and from **2026-10-06 is the one lifetime exception: when the user takes and pays a plan that carries it, White label is added to the account as purchased and stays there for life, even if they change plan later — and 12.11's latest wording (11:37) says there is no on / off switch at all, as in V7 (12.7, 12.11) — Reseller panel (V7 self-hosted panel) — now backend Phase 15 (2026-10-07), and a lifetime licence like White label (FE: Reseller panel) — and add-ons from later phases); users on that plan get them included. Not assignable: WP Toolkit — which now explicitly includes Object Cache Pro — and Premium Hosting Care, both handled separately — and Phase 14 (2026-10-07) explains the second one: Premium Hosting Care is bought per account with its own cycle and expiry date, so a plan has nothing to grant. The downgrade check (7.8) also covers add-ons in use — except White label, which a downgrade can never take awayThe picker must be built from the API's add-on list, like the feature list (7.2), because later phases add add-ons. Two consequences elsewhere: the add-ons page needs an "Included with your plan" card state distinct from "Buy", and the downgrade block must list an add-on in use as a reason, not just servers and apps. Note this confirms the frontend's existing rule rather than breaking it — Premium Hosting Care is shown to every user precisely because it is never plan-assigned. It also draws a useful line for the add-ons page: a plan can include an add-on (Reseller panel, Log Monitoring → card reads Included; White label is different — its card reads Purchased, because the plan grants it once and for ever) or merely gate who sees it (WP Toolkit → always bought, never included). Object Cache Pro is not a card at all — it rides inside WP Toolkit
7.1aPlan namesName field in the plan editorAdded 2026-10-05: the starting plans use the V7 names for now — not final — and the admin can rename any plan. Renaming only changes the name users see; users on a renamed plan keep the same planReinforces the dynamic-plans rule: a plan name is data, never an identifier. Nothing may key off a name — not a card layout, not a feature check, not a test fixture, not an i18n key. A rename must never look to the user like a plan change

#B. User: the plan screens

#FeatureScreen / controlRulesFrontend notes
7.3Plan ownerShown on the plan pageOne plan per owner, and the limits count across all their organizationsSay this plainly on the page ("this plan covers all your organizations"), because a member of someone else's organization will see no plan of their own. Members see the owner's limits, not a buy button
7.4View planPlan page headerCurrent plan, cycle, days left, renew price, servers / apps used vs allowedTwo usage bars (servers, apps) with the exact numbers, plus days left as a relative line and the exact date on hover
7.5Pay from creditConfirm-and-pay dialogPlans are paid from the user's credit balance, tax added, and every payment is saved as a chargeThe dialog shows price, tax, credit used and the remaining balance before the button. No card form here — paying means having credit
7.6TrialBanner on the plan page, then a blocking choose-plan stateNew users get a trial; the admin sets the number of days. New 2026-10-05: when the trial ends, the user must pick a paid plan to continueShow days left, never a fixed number. The end of a trial is now a gate, not a banner: the app stops at the plans page until a paid plan is bought. It needs its own state — different from expired (which follows a paid plan) and from locked (day −15) — with plain copy about what still works. D-33: the catalogue contains a Free plan, yet 7.6 says the user must pick a paid one, so it is unclear whether Free may be chosen at the end of a trial
7.7Choose / change planPlans page → confirm-and-payMonthly or yearly. Unused days of the old plan come back as credit, and the new plan starts a fresh 30 / 365 days. Not enough credit → "Add $X credit first". Added 2026-10-05: before paying the user sees a preview — credit back, amount to pay, new end dateThe dialog must show the credit coming back and the amount due, so a change never looks like a double charge. The backend now requires the new end date in that preview too, which settles what the dialog contains: credit back · amount to pay · new end date. "Add $X credit first" links straight to adding credit and returns to this dialog. The preview is a backend quote — the frontend never works out the end date itself
7.8Downgrade checksBlocking state on the plan cardBlocked if servers / apps are over the new plan's limits, or a feature in use (team members, shared servers…) is off in the new plan. Added 2026-10-06 (7.26): an add-on in use that the new plan does not include also blocks it — with one exception, White label, which is lifetime and survives any plan change (12.11). Log Monitoring is the clearest case of the rule (13.1, 2026-10-07): a downgrade removes it from every server — and 13.7, answered the same day, adds that every collected report is deleted with it. So the block, or at least the warning, must name those servers and say the reports go, because there is no export and reinstalling starts from zero. The admin can also mark a plan "no downgrade"Check before the final button and list exactly what is in the way ("3 servers over the limit", "shared servers are not in this plan", "Log Monitoring is not included in that plan — 3 servers would stop being monitored"), each with a link to fix it. A "no downgrade" plan shows the reason instead of a dead button
7.9Cancel / ResumeCancel dialog · Resume actionCancel stops auto-renew; resume turns it back onMake clear that cancelling does not end the plan today: it runs to the end of the period. The plan page then shows "ends on " with Resume
7.10Auto-renewBanner / plan page lineOn the expiry day, renewed from credit if there is enough. Changed 2026-10-05: if there isn't, Central tries again every day until the lock day (default −15), so the plan renews as soon as credit is added (as in V7)Show "renews on for " and warn early when the credit is below the renew price. The retry changes the copy on every expired screen: adding credit is enough — there is no "Renew" button to press afterwards, and the banner must say so instead of leaving people wondering. The price is the one that will apply at renewal, which may have changed (7.17)
7.11RemindersAdmin settings + the matching in-app bannerEmails before expiry if credit is short, and after expiry. Added 2026-10-05: the admin picks which weekdays reminders go out on (default Monday + Thursday) and how many days before expiry they start (default 7)The frontend shows the matching in-app banner so the screen and the email agree. New admin screen work: a weekday picker with those two ticked, plus the reminder-start number. The user-facing banner must not copy the email's schedule — it is shown whenever the plan is in that state, not on Mondays and Thursdays
7.12After expiryBanners, then a locked accountReminders → warning day (default −7): managed servers are powered off at the provider → lock day (default −15): managed servers are deleted at the provider, self-managed servers are only removed from Central (not touched at the provider), and the account is locked. The owner's team members are locked too, and while expired every server action is blocked with "Plan has expired. Please renew it" — though the user can still view their data, delete a server, and add credit / renew. All three day numbers are set by the admin (reminder start, warning day, lock day)This is the harshest rule in the product, so the warning must be unmissable: a persistent banner with the exact date, what will happen, and "Add credit". Rewritten 2026-10-05 — the outcome now depends on the server type, which answers D-31: a managed server is powered off, then destroyed at the provider; a self-managed server only loses its Central link and keeps running. Those are completely different losses, so the banner must name the servers and say which happens to which — the same pattern the managed-server overdue warning already uses (6.12). Two dates matter now, not one: the power-off date and the lock date. Because the days are admin settings, every screen and translation string must take the date from the API — never "15 days" or "7 days" written into the UI, and never a day count worked out in the browser. The locked state needs its own screen — billing reachable, everything else closed — and it must say servers still exist at the provider. Members need their own version of that screen: they cannot pay, so it names the owner and says "ask them to add credit", with no pay button and no billing tab. Members should also see the day −7 warning before it happens, or being locked out will arrive with no notice. The expired window is now specified, so it is a real UI state, not a guess: every screen stays readable, action buttons are disabled with that one message, and exactly two things stay live — Delete server and Add credit. That is the opposite of the usual pattern, so don't grey out whole pages: keep the data visible and disable the controls
7.25Expiry date & statusEverywhere a plan date or state is shownNew 2026-10-05: a plan stores a real expiry date (not V7's day counter); days left are worked out from it. Plan status: active / expired / locked. Central checks the expiry date on every action, so a missed nightly job cannot keep an expired plan workingSettles two things the frontend had to guess. First, status is now a field — the screens read active / expired / locked instead of deciding from a day count, which closes the old gap on Subscriptions. Second, days left are derived from a date, so always show the exact date and treat "N days left" as a label on top of it — and never count days in the browser, because a plan can expire mid-session and the next action will be refused
7.18Pending plan changeNote on the current-plan cardNew 2026-10-05: a feature turned off or a limit lowered by the admin applies from the user's next renewal (warned by email first)A pending-change note next to the plan, with the date and exactly what changes ("from 12 Nov: 25 servers instead of 50"). Nothing changes on screen before that date, so the usage bars keep today's limit. If the user is already over the coming limit, say so and link to what to remove — the backend states no check for this case (D-34)
7.22UnlockButton on the locked screenNew 2026-10-05: a locked account unlocks automatically once the user adds credit and pays the plan. Servers removed at day −15 stay removedSo the locked screen is not a dead end: it shows exactly two steps — add credit, then pay the plan — and unlocking needs no support ticket. It must be honest that nothing comes back on its own, and — after the 7.12 rewrite — honest per server type: a self-managed server is still at the provider and has to be connected again from Add server → Connect a panel, but a managed server was deleted at the provider and is simply gone. So the page must never show one blanket "your servers are safe" line. The backend doc does not spell out the reconnect path, so don't promise more than "they are still at your provider" for the self-managed ones
7.15EnterpriseContact formContact form for custom plansA short form, not a mailto link, with a clear "we'll get back to you" state
7.23Redeem a codeRedeem code dialogNew 2026-10-05: the admin creates batches of codes that give a plan or credit (AppSumo-style deals). Users redeem a code from their account, and each code works onceOne short dialog: paste the code → it says what it gives before the user confirms, because a plan code and a credit code have very different results. Then the right success state: a plan code lands on the plan page, a credit code on the wallet. The failure cases all need their own plain message — unknown, already used, expired, switched off, and not valid for this account — never one "invalid code". Where the entry point sits is a product choice: this spec puts it on the plan page and in Billing → Wallet, since those are the two things a code can give; if Bhavik would rather have it in the user menu it is a one-line move
7.16Activity logNothing to build hereEvery plan change, renew, cancel and resume is in the activity logRendered on the Audit log page
7.17Price changeLine on the plan page + renewal bannerNew 2026-10-05: when the admin changes a plan's price, users already on that plan are warned by email first, and the new price starts at their next renewalThe plan page must show the price that will actually be charged next, not the price that was paid: "renews on <date> for <new price>", with the old price struck through while a change is pending. Never show a changed price as if it applied today. Because the renew amount can move, the "not enough credit to renew" warning (7.10) must be recalculated against the new price

#C. Plan limits everywhere else

Phase 7 says Central checks the plan before an action, and a feature that is not in the plan shows "Upgrade your plan to use this". For the frontend that means one shared pattern rather than per-screen guesses:

  • One place asks "may I do this?" and returns either yes, or a reason: not in your plan, limit reached, or no permission (that one comes from the organization role, Phase 4).
  • The three reasons look different on purpose: upgrade → plan page, limit → usage, permission → ask an admin.
  • Buttons stay visible but disabled with the reason, so people can see what a bigger plan adds.
  • The exact feature names come from the API's feature list (7.2) — the frontend never hard-codes which plan has what.

#Existing users

CaseRule from the backend docWhat the screens must handle
Normal usersKeep their current plan, cycle and days left — and V7's days-left counter becomes an expiry date at migration (added 2026-10-05)Nothing special beyond showing the imported values. Because the counter becomes a date, a migrated plan shows the same exact date as a new one, so no screen needs a special case
"Restructured" V7 usersAdded 2026-10-05 (7.14): they get two plans of their own — "Managed" and "Self Managed", each with its own name, price and features — and see only those, as in V7The one case where the plans page is not the common catalogue. Nothing special to build: the page renders whatever plans the API returns for that account, which is why the catalogue is never cached or shared between accounts. These are ordinary plans, so no "migrated plan" badge and no second code path
Lifetime ownersKeep their lifetime plan and extra servers, including those still paying in installments (V7 allowed 1 or 3 payments). Whether new users can buy lifetime, and how installments work in V8, is decided later (added 2026-10-05)A plan page with no renewal date and no renew price, and no "lifetime" entry in the plans list unless the API offers one. A migrated owner can be part-way through installments, so the lifetime state needs a "paid 1 of 3" line and must not show a plan as fully paid when it isn't. No installment screens are built until the backend decides
Legacy per-server plansKeep working, with an option to convert to a normal planA clearly-labelled legacy state plus a convert flow showing what changes. Don't force it
Add-onsWP Toolkit and managed hosting come in their own phases. Premium Hosting Care now has one — backend Phase 14 (2026-10-07), which confirms why 7.26 calls it not assignable: it is bought per account with its own expiry, never included in a plan (FE: Premium Hosting Care)No add-on screens in this phase

#What this phase answers

Was openNow
D-3 Subscription per user or per organization?Per owner (7.3), with limits pooled across all their organizations — the V7 model, not the per-organization one the earlier product request implied. See the conflict note on Subscriptions
D-4 Keep the credit wallet? Auto-renew from credit? Lifetime? Legacy plans?Yes to all: plans are paid from credit, auto-renew takes credit on the last day, lifetime owners keep theirs (new sales undecided), legacy per-server plans keep working with a convert option
D-6 Do application limits still apply?Yes — plans carry server and app limits, the plan page shows used vs allowed, and downgrades are blocked when usage is over the limit

#Still open after this phase

  • Which payment gateway tops up the credit balance (D-5) — answered by backend Phase 6 on 2026-10-05: Stripe, PayPal and Instamojo, with the admin enabling each one. See FE: Billing screens.
  • Currency and tax rules (D-22): the doc says "tax added" but not how it is calculated or shown. Phase 6 adds "tax as V7 (Instamojo, or Stripe for India)" — a trigger, still not a rule.
  • D-32 (new, from Phase 6): every successful credit payment adds +3 to the server limit (6.4), so the usage bar in 7.4 cannot simply show the plan's allowed_servers — the API has to return the real allowance.
  • D-33 (new): the trial ends and the user "must pick a paid plan" (7.6), but the catalogue has a Free plan — may they choose it, or is Free only for accounts that never had a trial?
  • D-34 (new): the admin can lower a limit on a plan (7.18) with no stated check, while a user's own downgrade is blocked when usage is over the limit (7.8). What happens at renewal to a user who is now over the new limit is undefined.
  • Lifetime plans for new users — the backend parked this decision, and on 2026-10-05 parked lifetime installments (V7: 1 or 3 payments) with it. Migrated owners can be mid-installment, so the screens must show that without a payment flow existing.
  • How app and server usage is counted across organizations (the old counting worry in D-6) is not described; the frontend just shows the numbers the API returns.
ServerAvatar V8 Central · prepared by central-app-2 (Pair 2 frontend) for Bhavik Jethwa · nothing in this spec is implemented yet · Built 2026-10-07 12:51 UTC