feat(subscriptions): add SaaS subscription tiers, pricing page, and enforced upload quotas
- Add Free / Starter / Professional / Business tiers with lifetime, daily, and monthly file limits (app/utils/subscription.py) - Add subscription_tier column to UserProfile model + migration 014 - Enforce quotas at upload time (HTTP 402 on violation) in /api/ui-upload - New REST API: GET /api/subscriptions/tiers, /my, /platform (admin) - New pages: /pricing (marketing, public) and /subscription (per-user status) - Enhanced dashboard: SaaS stats (files today/month, OCR count, active users) in multi-user mode; original single-user layout preserved - Admin users page: show Plan badge, allow tier editing via dropdown - Navigation: add Pricing link + subscription icon in user header - Tests: 23 unit tests for subscription tier logic - Docs: docs/SubscriptionTiers.md Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -141,25 +141,35 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', fun
|
||||
if (authSection) {
|
||||
authSection.textContent = ''; // Clear existing content
|
||||
const container = document.createElement('div');
|
||||
container.className = 'flex items-center';
|
||||
container.className = 'flex items-center gap-2';
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.src = data.picture;
|
||||
img.alt = 'Avatar';
|
||||
img.className = 'w-8 h-8 rounded-full mr-2';
|
||||
img.className = 'w-8 h-8 rounded-full';
|
||||
|
||||
const span = document.createElement('span');
|
||||
span.textContent = displayName;
|
||||
|
||||
// Subscription link
|
||||
const planLink = document.createElement('a');
|
||||
planLink.href = '/subscription';
|
||||
planLink.className = 'text-xs text-indigo-600 hover:text-indigo-800 font-medium hidden md:inline';
|
||||
planLink.title = 'My subscription';
|
||||
const planIcon = document.createElement('i');
|
||||
planIcon.className = 'fas fa-layer-group';
|
||||
planLink.appendChild(planIcon);
|
||||
|
||||
const logoutLink = document.createElement('a');
|
||||
logoutLink.href = '/logout';
|
||||
logoutLink.className = 'ml-3 text-red-600 hover:text-red-800';
|
||||
logoutLink.className = 'text-red-600 hover:text-red-800';
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'fas fa-sign-out-alt';
|
||||
logoutLink.appendChild(icon);
|
||||
|
||||
container.appendChild(img);
|
||||
container.appendChild(span);
|
||||
container.appendChild(planLink);
|
||||
container.appendChild(logoutLink);
|
||||
authSection.appendChild(container);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user