Difficulty: Hard
Type: Bug
Summary
Update local access decisions so expired memberships are denied even when the active flag is still true.
Current Behaviour
computeAccessDecision() checks membership tier, role, and membership.active, but it does not evaluate membership.expiresAt. If a session contains active: true with an expired expiresAt, the local gate can still allow access.
Expected Behaviour
A membership with an expiry timestamp in the past should be denied. The denied result should include a safe, user-facing reason that can be shown by Gated and related UI components.
Suggested Implementation
Add an expiry check inside computeAccessDecision(). Parse membership.expiresAt only when present, deny access if the timestamp is valid and in the past, and handle malformed dates conservatively. Add tests for active expired memberships, active future memberships, missing expiry, and malformed expiry values.
Files or Areas Likely Affected
lib/api/access-decision.ts
components/gated.tsx
test/access-decision.test.ts
lib/api/types.ts
Acceptance Criteria
Additional Notes
This is a frontend safety check and should not replace backend authorisation. Backend access checks should remain the source of truth when available.
Difficulty: Hard
Type: Bug
Summary
Update local access decisions so expired memberships are denied even when the
activeflag is still true.Current Behaviour
computeAccessDecision()checks membership tier, role, andmembership.active, but it does not evaluatemembership.expiresAt. If a session containsactive: truewith an expiredexpiresAt, the local gate can still allow access.Expected Behaviour
A membership with an expiry timestamp in the past should be denied. The denied result should include a safe, user-facing reason that can be shown by
Gatedand related UI components.Suggested Implementation
Add an expiry check inside
computeAccessDecision(). Parsemembership.expiresAtonly when present, deny access if the timestamp is valid and in the past, and handle malformed dates conservatively. Add tests for active expired memberships, active future memberships, missing expiry, and malformed expiry values.Files or Areas Likely Affected
lib/api/access-decision.tscomponents/gated.tsxtest/access-decision.test.tslib/api/types.tsAcceptance Criteria
expiresAtvalues are denied.expiresAtvalues can pass tier and role checks.expiresAtpreserves current behaviour.Additional Notes
This is a frontend safety check and should not replace backend authorisation. Backend access checks should remain the source of truth when available.