mirror of
https://github.com/Afilmory/afilmory
synced 2026-02-01 22:48:17 +00:00
- Added support for virtualized rendering in ListView using @tanstack/react-virtual for improved performance with large photo sets. - Integrated new hooks for mobile responsiveness and context management in ListView and PhotoCard components. - Updated PageHeader and ViewModeSegment for better layout consistency and user experience. - Increased upload limits in backend configuration to accommodate larger files and requests. Signed-off-by: Innei <tukon479@gmail.com>
3.5 KiB
3.5 KiB
Billing Plans & Quota Strategy
This document tracks the current subscription plans, quota knobs, and the design approach that backs the enforcement code in be/apps/core.
Goals
- Offer predictable resource guarantees (library size, upload size, sync object size, monthly processing) per plan.
- Decouple plan defaults from tenant-specific overrides so superadmins can hotfix limits without redeploys.
- Keep room for future self-serve subscriptions while allowing manual override flows during private beta.
Plan Catalog (2025-11-30)
| Plan ID | Label | Availability | Monthly Process Limit | Library Items | Upload Size (MB) | Sync Object (MB) | Notes |
|---|---|---|---|---|---|---|---|
free |
Free | Default for new orgs | 300 | 500 | 20 | 50 | Soft cap for testing & hobby users. |
pro |
Pro | Upcoming public tier | 1,000 | 5,000 | 200 | 500 | Placeholder numbers; tune before launch. |
friend |
Friend (Internal) | Manual via superadmin | Unlimited (null) | Unlimited | Unlimited | Unlimited | Private plan for friends/internal testers; never exposed in product UI. |
Unlimited==nullin the DB schema, meaning enforcement is skipped for that quota dimension.
Global Hard Caps (system guardrails)
These apply to every plan (including friend) to protect the service from pathological requests. Plan-specific limits are enforced first, then clipped by these ceilings:
- Max file size: 1 GB (
ABSOLUTE_MAX_FILE_SIZE_BYTES) - Max request payload: 5 GB (
ABSOLUTE_MAX_REQUEST_SIZE_BYTES) - Max files per batch: 128 (
MAX_UPLOAD_FILES_PER_BATCH) - Max text fields per request: 256 (
MAX_TEXT_FIELDS_PER_REQUEST)
Effectively:
resolvedFileLimit = min(plan.uploadLimit, 1 GB)andresolvedBatchLimit = min(resolvedFileLimit * 128, 5 GB).
Design Notes
- Plan definitions live in
billing-plan.constants.ts. Each entry carries human-friendly metadata for the super-admin dashboard plus aquotasobject. - Overrides are stored under
system.billing.planOverrides. This is a JSON blob keyed by plan id. It is parsed through zod (SystemSettingService.getBillingPlanOverrides) and merged in the billing plan service. - Payment product mapping lives in
system.billing.planProducts. Each plan id can map to provider specific identifiers (e.g.creemProductId). Plans that require checkout (likepro) stay hidden until a product id is configured, which prevents exposing upgrade buttons in environments that are not ready. - Tenant assignment is tracked via
tenant.plan_idand can only be changed by superadmins (see/super-admin/tenantsbackend+dashboard). The Friend plan is intentionally absent from any public selector. - Quota enforcement is performed in:
PhotoAssetService(manual upload size + library limit + monthly process allowance)DataSyncService(sync object size, library headroom, monthly process allowance)
- Usage accounting leverages
billing_usage_eventrows, so adding new quota dimensions is mostly a matter of emitting/aggregating the corresponding events.
Future ideas: surface plan metadata in the dashboard, wire plans to Stripe/Billing provider, and allow per-tenant overrides directly in the admin UI.