- reset_password sets is_active=True so users with unverified accounts
can log in after using the forgot-password flow
- admin set_password also sets is_active=True for the same reason
- auth() now checks is_active before verifying the password, ensuring
inactive users always see the email-verification prompt regardless of
password correctness (avoids leaking password validity)"
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
The @router.get("/{user_id:path}") decorator was accidentally dropped from the
get_user function when the /local/... routes were inserted above it in the
previous PR. Without the decorator the function was never registered as a GET
handler, so GET /api/admin/users/<id> matched the PUT/DELETE catch-all routes
and Starlette correctly returned 405 Method Not Allowed instead of 200/403.
Adding the decorator back restores the GET endpoint and fixes the 5 tests that
were failing with 405.
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Resolve conflicts in app/auth.py and app/api/admin_users.py:
- auth.py: combine admin-aware profile creation (from main, adding
is_complimentary/highest-tier defaults for admins) with signup
notification/webhook (from our branch). Admin users skip the
signup notification since they are the ones being notified.
- admin_users.py: combine is_complimentary assignment (from main)
with tier_changed/new_tier tracking variables (from our branch)
to fire plan-change notifications when an admin updates a user.
- Add `is_complimentary` column to UserProfile model (migration 019)
- Update `_ensure_user_profile` to accept `is_admin` param; admins get
highest subscription tier, is_complimentary=True, onboarding skipped
- Call `_ensure_user_profile` from all login paths (OAuth, local user, admin creds)
- Add `is_complimentary` to UserProfileUpsert schema, response helpers,
list_users, get_user, upsert_user_profile in admin API
- Add complimentary toggle to admin users UI with gift badge in table
- Write 18 new tests covering complimentary plan and admin auto-creation
- Update SubscriptionTiers.md documentation
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Restore the get_user handler that was accidentally dropped when inserting
the local user management routes before the /{user_id:path} catch-all
- Move period inside the 'Create one' button text in admin_users.html
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Remove SMTP hard-requirement from /api/auth/signup: when SMTP is not
configured accounts are activated immediately (no email verification).
When SMTP is configured the existing email-verification flow is kept.
- Inject allow_signup into global template context via app/views/base.py
- Add data-allow-signup attribute to base.html body tag
- Update common.js _renderLoggedOutAuth to show Sign Up (→ /signup) when
signup is enabled, otherwise Get Started (→ /pricing)
- Add admin API endpoints before the /{user_id:path} catch-all:
GET /api/admin/users/local – list all local accounts
POST /api/admin/users/local – admin-create local account (active immediately)
DELETE /api/admin/users/local/{id} – delete local account + profile
- Add LocalUserCreate / LocalUserResponse Pydantic schemas
- Update admin_users.html with Local User Accounts section and modals
- Update .env.demo to document ALLOW_LOCAL_SIGNUP
- Update docs/BillingSetup.md: SMTP is optional, document both flows
- Update tests: test_signup_smtp_not_configured now asserts 201 + immediate
activation; add 7 new integration tests for admin local user endpoints
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
- Add SubscriptionPlan model and subscription_plans table (migration 015)
- Add billing cycle/period/allow_overage fields to UserProfile (migration 016)
- Add subscription_overage_percent config field (replaces overage_factor)
- Rewrite check_upload_allowed: use overage_percent, yearly carry-over, no daily cap
- Add seed_default_plans(), _plan_to_dict(), get_year_file_count(), _months_elapsed()
- Update get_tier/get_all_tiers to be DB-first with TIER_DEFAULTS fallback
- Add TIER_DEFAULTS alias (TIERS kept for backward compat)
- New /api/plans/ CRUD endpoints (admin-only except list/get)
- New /admin/plans Plan Designer page with Alpine.js UI
- Add Plan Designer link to admin navigation in base.html
- Remove 'Files per day' row from pricing comparison table
- Add billing cycle + period start to admin users edit modal
- Seed default plans on startup in lifespan handler
- Rewrite docs/SubscriptionTiers.md with full plan/overage/API docs
- Fix all tests in test_subscription.py (remove daily cap tests, add overage/carry-over tests)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- 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>
- Add UserProfile model (app/models.py) with per-user settings: display_name, daily_upload_limit, notes, is_blocked
- Add Alembic migration 013_add_user_profiles for the new table
- Add REST API at /api/admin/users/ with list, get, upsert (PUT), delete endpoints (admin-only)
- Add HTML template admin_users.html with Alpine.js: filterable user list, paginated table, edit/create modal, delete confirmation modal
- Add view handler at /admin/users (admin-only redirect guard)
- Register routers in app/api/__init__.py and app/views/__init__.py
- Add 'Users' link to admin nav dropdown in base.html (desktop + mobile)
- Add 27 tests covering auth, list, get, upsert, delete, and model constraints
- Register UserProfile in conftest.py model imports
- Document new endpoints in docs/API.md
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>