Technical Site Rules
Public reference for site-wide technical behavior that is not game mechanics or visual style. This page documents auth, permissions, ownership, admin gating, and billing policy.
Authentication + Session Model
Sign-in is handled through NextAuth with Google provider and JWT sessions. The app treats invalid or stale JWT cookies as signed out and continues safely.
- Protected write actions use authenticated helpers (`requireCurrentUser` or `requireAdminUser`).
- Many create/edit pages redirect signed-out users to the sign-in route with callback URLs.
- Read routes can be public depending on visibility and ownership rules described below.
User Role + Plan Rules
Users are created from active sessions and assigned role/plan values used throughout permissions and billing logic.
| Rule | Current Behavior |
|---|
| Role assignment | `admin` if email is in configured admin list, otherwise `user`. |
| Plan assignment | `admin` users are `paid`; non-admin users default to `free`. |
| User record lifecycle | Created or updated during authenticated access with profile and credit fields. |
Visibility + Ownership Rules
Visibility is normalized to `public` unless explicitly set to `private`. Private creation is restricted by plan/role.
- `resolveRequestedVisibility` forces visibility to public when a user is not eligible for private content.
- `canViewResource` allows public reads for everyone; private reads are owner/admin only.
- `canEditResource` allows edits for owner/admin only.
| Action | Signed Out | Signed-in User | Owner | Admin |
|---|
| View public resource | Allowed | Allowed | Allowed | Allowed |
| View private resource | Denied | Denied unless owner | Allowed | Allowed |
| Edit resource | Denied | Denied unless owner | Allowed | Allowed |
| Create private resource | Denied | Allowed only for paid plan | Allowed only for paid plan | Allowed |
Admin-Gated Functionality
Admin-only flows are explicitly guarded. Non-admin users are denied access even when signed in.
- The admin page requires admin status and redirects non-admin users.
- Admin API routes (credits and admin image operations) require `requireAdminUser`.
- The Admin navigation link is shown only when the current user is admin.
Billing Policy Behavior
Credits are tracked in milli-cents. Daily refill uses credit profiles (`base`, `friends`, `family`) with Pacific midnight refresh, and ledger entries record all charge/refund/grant/top-up/promo events.
- Profile refill runs once per Pacific date and only adds credits when balance is below that profile's cap.
- Balances above cap are preserved; refill resumes only after spending below cap.
- Charges require sufficient balance; insufficient credits return payment-required behavior.
- Refunds, admin grants, promo redemption, and purchase top-ups update both user balance and ledger.
| Ledger Reason | Meaning |
|---|
image_generate | Credits spent for image generation requests. |
image_edit | Credits spent for image edit or adjust requests. |
daily_refresh | Pacific-time daily refill added when user balance is below the profile cap. |
image_refund | Credits returned when image operation fails after charging. |
admin_grant | Admin manually adds credits to a user account. |
purchase_topup | Credits added from a successful Stripe top-up purchase. |
promo_bonus | Credits added from promo code redemption. |
profile_override | Admin changed a user credit profile. |
promo_profile_grant | Promo code granted or changed a user credit profile. |
Do / Don't
Do
- Use shared helpers (`canViewResource`, `canEditResource`, `resolveRequestedVisibility`) for access checks.
- Gate admin-only operations with `requireAdminUser`.
- Keep write endpoints authenticated with `requireCurrentUser` where appropriate.
- Record billing-impacting actions through the credit ledger workflow.
Don't
- Do not bypass shared permission helpers with ad-hoc ownership checks.
- Do not assume signed-in users can create private content.
- Do not expose admin actions in UI flows that lack server-side admin enforcement.
- Do not change billing behavior without updating this public technical reference.