The current license validation endpoint returns only a boolean (valid). The silkpanel‑cms hard‑lock feature needs more granular information to decide whether to show a permanent lockout (paid license expired) or simply restrict updates (trial expired). The API must be extended to return:
status: string enum with values active_paid, expired_paid, trial, expired_trial, never_paid (or similar).
has_ever_paid: boolean – indicates if the user has at least one completed Stripe payment or a Stripe customer ID exists.
plan_tier: optional string (e.g., basic, pro) – for future feature flag usage.
expires_at: ISO 8601 date/time string – when the current paid period ends (null if never paid).
grace_period_days: integer – remaining days until hard lock if license expired (optional, could be calculated on CMS side).
Acceptance criteria for devso.me:
- The license check endpoint returns the new fields alongside
valid.
- The logic to determine
has_ever_paid is based on the existence of a Stripe customer ID linked to the user account and/or a successful payment history (at least one paid invoice).
- A user who only ever used a trial returns
has_ever_paid: false and status: trial or expired_trial.
- A user whose paid subscription has expired returns
has_ever_paid: true, status: expired_paid.
- An active paid user returns
status: active_paid.
- The new response is backward‑compatible – existing CMS versions ignoring the extra fields must continue to work (the
valid field remains the primary signal).
- The implementation does not break any existing client relying on the old response format (additive change only).
Out of scope for devso.me sub‑ticket:
- Changes to the purchasing flow or Stripe integration itself.
- Returning full payment history – only the derived status flags are needed.
- Any rate‑limiting changes (should be handled separately if required).
Acceptance criteria (main CMS ticket)
- A paid license that expires causes the entire Filament admin panel to become inaccessible behind a permanent, non‑dismissable modal.
- The lock takes effect on the next admin page load after the license is detected as expired.
- Trial license expiration does not trigger this lock; trial behavior remains unchanged.
- No admin route can bypass the modal – the middleware covers all registered admin paths.
- The enforcement mechanism is delivered as the separate
silkpanel/license-enforcement package.
- Documentation is updated to reflect the new locking behavior and the difference between trial and paid license expiration.
- A grace period for unreachable license servers prevents false lockouts (configurable).
- There is no built‑in “super admin bypass” – support intervention requires direct server access.
Out of scope
- Renewal or payment UI inside the CMS (all handled on
devso.me).
- Locking the public frontend – only the admin panel is affected.
- Feature‑specific partial locks (e.g., keeping some pages accessible) – the entire panel is blocked.
- Detailed design of the modal beyond the basic permanent overlay and message.
The current license validation endpoint returns only a boolean (
valid). The silkpanel‑cms hard‑lock feature needs more granular information to decide whether to show a permanent lockout (paid license expired) or simply restrict updates (trial expired). The API must be extended to return:status: string enum with valuesactive_paid,expired_paid,trial,expired_trial,never_paid(or similar).has_ever_paid: boolean – indicates if the user has at least one completed Stripe payment or a Stripe customer ID exists.plan_tier: optional string (e.g.,basic,pro) – for future feature flag usage.expires_at: ISO 8601 date/time string – when the current paid period ends (null if never paid).grace_period_days: integer – remaining days until hard lock if license expired (optional, could be calculated on CMS side).Acceptance criteria for devso.me:
valid.has_ever_paidis based on the existence of a Stripe customer ID linked to the user account and/or a successful payment history (at least one paid invoice).has_ever_paid: falseandstatus: trialorexpired_trial.has_ever_paid: true,status: expired_paid.status: active_paid.validfield remains the primary signal).Out of scope for devso.me sub‑ticket:
Acceptance criteria (main CMS ticket)
silkpanel/license-enforcementpackage.Out of scope
devso.me).