Skip to content

feat(shortener): Free/Pro/Enterprise tier gating via feature flags + license (B5)#66

Open
PenguinzTech wants to merge 2 commits into
feature/shortener-redirect-analyticsfrom
feature/shortener-tiering
Open

feat(shortener): Free/Pro/Enterprise tier gating via feature flags + license (B5)#66
PenguinzTech wants to merge 2 commits into
feature/shortener-redirect-analyticsfrom
feature/shortener-tiering

Conversation

@PenguinzTech

Copy link
Copy Markdown
Contributor

Feature (Track B, part 3) — tier gating

Stacked on #65 (base = feature/shortener-redirect-analytics). Targets release/v0.1.x.

Two-layer gating per the house tier matrix — a PostHog feature flag (default OFF, graceful degradation) AND license entitlement.

  • app/features.pyfeature_enabled() (cached last-known, new flags OFF, never crashes if PostHog unreachable), get_license_tier() (free/professional/enterprise; dev & bypass-domain → enterprise; production fails closed to free on error), and require_tier/require_professional/require_enterprise decorators (→ 402 when below).
  • Free 5-collection cap enforced server-side in collections.py (402 on the 6th; Pro/Enterprise unlimited).
  • Branded QR (color/logo params) gated to Professional in the QR endpoint; plain QR stays Free.
  • Advanced analytics (geo/device/browser/OS breakdowns) at /analytics/urls/<id>/advanced gated to Enterprise; basic analytics stays all-tiers.
  • Flags: current.collections, current.branded-qr, current.advanced-analytics. Config: POSTHOG_KEY/POSTHOG_HOST.

Kept in a new module (not licensing.py) to avoid conflicting with the A5a licensing hardening (#60).

Tests

649 passed, 90% coverage; features.py 100% — tier resolution, flag degradation, each gate's 402/allow paths, mocked PostHog + license clients (no network).

🤖 Generated with Claude Code

…license (B5)

Two-layer gating (PostHog flag defaulted OFF + license tier), per house tier matrix:
- app/features.py: feature_enabled() (graceful degradation, cached last-known, new
  flags OFF, never crash), get_license_tier() (free/professional/enterprise; dev &
  bypass-domain → enterprise; production fails CLOSED to free on error),
  require_tier/require_professional/require_enterprise decorators → 402 when below.
- Free 5-collection cap enforced server-side in collections.py (402 on 6th; Pro/Ent
  unlimited) — flag current.collections.
- Branded QR (color/logo params) gated to Professional in urls.py QR endpoint (plain
  QR stays Free) — flag current.branded-qr.
- Advanced analytics (geo/device/browser/OS breakdowns) at /analytics/urls/<id>/advanced
  gated to Enterprise; basic analytics stays all-tiers — flag current.advanced-analytics.
- config: POSTHOG_KEY/POSTHOG_HOST (default https://license.penguintech.io).

Tests: 649 passed, 90% coverage; features.py 100% (tier resolution, flag degradation,
each gate 402/allow, mocked posthog+license clients, no network).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@PenguinzTech PenguinzTech added this to the v0.1.x milestone Jul 14, 2026
@PenguinzTech PenguinzTech added the type:feature New feature label Jul 14, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @PenguinzTech, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

…verage >90%)

Adds comprehensive test coverage for:
- Advanced analytics endpoint with Enterprise tier gating and feature flags
- Date filtering (from/to) in advanced analytics
- Advanced breakdown fields (geo, devices, browsers, os)
- Redirect error paths: invalid destination URL validation, user-agent parsing
- Click recording error handling and database exceptions
- Edge cases: no clicks, no user-agent header, database errors with rollback

Coverage improvements:
- analytics.py: 72% → 92% (advanced endpoint now fully covered)
- redirect.py: 23% → 90% (error paths and edge cases now covered)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant