# StudyFlow Auth and App Shell Implementation Plan

Last updated: 2026-03-19

This file defines the concrete implementation plan for:

- public landing page
- sign-up and sign-in flow
- authenticated app shell
- protected routes
- document dashboard
- how authenticated actions hand off into billing checks and workflow execution

It is the missing glue between:

- the product definition
- the billing model
- the helper services
- the n8n workflows

## Goal

Make StudyFlow feel like a real product before the document pipeline starts.

That means the user experience should be:

1. discover product
2. create account or log in
3. enter protected app shell
4. if needed, choose a plan
5. upload document
6. use workspace, grounded chat, and optional study tools

The auth layer is not an add-on. It is part of the product architecture.

## Recommended Runtime Split

Use:

- `studyflow-web-app`
  - frontend
- `studyflow-auth`
  - auth + session + billing bridge
- `studyflow-db-api`
  - user-scoped document/workspace data
- `n8n`
  - workflow orchestration after authorization

## What Lives Where

### `studyflow-web-app`

Owns:

- landing page
- pricing page or pricing section
- sign-up page
- sign-in page
- private dashboard
- document list
- workspace reader
- grounded chat UI
- upgrade prompts
- billing settings UI entry points

### `studyflow-auth`

Owns:

- user creation
- password verification
- session cookie issuance
- session validation
- sign-out
- current-user endpoint
- checkout session creation
- customer portal session creation
- Stripe webhook handling
- entitlement summary exposure

### `studyflow-db-api`

Owns:

- user-linked document metadata
- workspace data
- chat history
- usage event storage if we keep it there

### `n8n`

Owns:

- async document processing
- retrieval orchestration
- grounded chat orchestration
- optional study-pack orchestration

## Recommended Frontend Route Map

### Public routes

#### `/`

Landing page.

Sections:

- hero
- value explanation
- workflow preview
- pricing preview
- CTA to sign up
- CTA to sign in

#### `/pricing`

Optional dedicated pricing page.

Can be folded into `/` for MVP.

#### `/signup`

Account creation page.

#### `/login`

Sign-in page.

### Private routes

All private routes should require a valid session.

#### `/app`

Main dashboard.

Should show:

- welcome state
- trial upload CTA when no active plan exists and the trial has not been used
- upload CTA only when an active plan exists
- plan selection / upgrade CTA when no active plan exists
- trial-used state when the no-plan transform entitlement is exhausted
- recent documents
- remaining quota summary

#### `/app/documents`

User document list.

Should show:

- uploaded document projects
- processing status
- ready workspaces
- upgrade prompts when relevant

#### `/app/documents/:documentId`

Document workspace page.

Should show:

- transformed HTML workspace
- grounded chat panel
- optional study-pack actions
- topic-level actions such as `Generate infographic` where the extracted content is a good visual candidate
- model/provider info where appropriate

Recommended infographic action behavior:

- `Generate infographic` should appear in the topic or section action area, not in a hidden settings panel
- the action should appear only for topics or sections that have already been marked infographic-eligible
- if the current user is on `Ultra` and has remaining infographic credits:
  - button is enabled
- if the current user is on `Basic` or `Plus`:
  - button remains visible but disabled
  - lock treatment should be visually paired with `Upgrade to Ultra`
- if the current user is on `Ultra` but has exhausted infographic credits:
  - button remains visible in a disabled exhausted state
  - show reset date or billing-period context nearby

Recommended topic-page behavior:

- eligible topic + Ultra + credits remaining
  - show enabled `Generate infographic`
- eligible topic + Basic/Plus
  - show disabled locked action near `Upgrade to Ultra`
- eligible topic + Ultra but no credits left
  - show disabled exhausted action
- not eligible topic
  - hide infographic action entirely

This keeps the page cleaner and makes the upgrade path feel relevant instead of forced.

Versioning behavior:

- the page should show the current ready document version by default
- if a newer upload is processing, show that a newer version is building
- old version chat/history should not silently merge into the new version
- if version history is exposed later, it should be explicit in the UI

MVP duplicate behavior:

- if a user uploads a file that already exists as a parsed project, do not create a second visible project
- show a warning that the document was already parsed
- offer a direct link to the existing project page
- if the user truly wants to parse it again, require deleting the existing project first

#### `/app/settings`

Account and billing settings.

Should show:

- current plan
- current usage
- manage billing button
- sign out

## Session Model

Recommended MVP approach:

- server-issued secure session cookie
- HTTP-only
- `SameSite=Lax` or stricter as appropriate
- `Secure=true` in production

Why this is the right MVP:

- simpler than a custom JWT-heavy client model
- easier to protect server-rendered or API-backed routes
- easier to reason about in one-product SaaS flow

## Access States In The App Shell

The private shell should distinguish between:

### 1. Authenticated with no active plan

Show:

- onboarding
- pricing summary
- upgrade CTA
- one limited-size trial upload entry point if unused
- the resulting deterministic workspace if the trial was already used
- account settings

Do not show as enabled:

- additional uploads after the one trial document
- grounded chat by default
- study-pack actions

### 2. Authenticated with active plan

Show:

- upload
- real documents
- plan-aware usage state
- workspace and chat actions allowed by entitlement

This avoids sending newly signed-up users straight into a dead-end upload screen.

Important product note:

- the no-plan shell should feel useful enough to explain the product
- but it should not accidentally become a permanent free AI tier
- the exact trial size cap remains open for decision and should be documented before implementation starts

## Usage-State UX Rule

The app shell should distinguish between:

- available usage
- in-progress reserved usage
- consumed usage

Recommended behavior:

- while an expensive action is running, show `In progress`
- do not permanently decrement visible credits until the action succeeds
- if the action fails, restore the prior available count without requiring a full refresh
- if the same idempotent action is retried, return the existing result or active state instead of implying a second credit burn

This matters most for:

- grounded chat retries
- study-pack generation
- infographic generation

## Required Auth Endpoints

### `POST /auth/signup`

Input:

```json
{
  "email": "user@example.com",
  "password": "plaintext-from-form"
}
```

Behavior:

1. validate input
2. create user
3. hash password
4. create session
5. set cookie
6. return user summary

### `POST /auth/login`

Input:

```json
{
  "email": "user@example.com",
  "password": "plaintext-from-form"
}
```

Behavior:

1. verify credentials
2. create session
3. set cookie
4. return user summary

### `POST /auth/logout`

Behavior:

1. invalidate session
2. clear cookie

### `GET /auth/me`

Behavior:

1. read cookie
2. validate session
3. return current user + billing summary stub

Example:

```json
{
  "user": {
    "id": "user_123",
    "email": "user@example.com"
  },
  "subscription": {
    "plan": "basic",
    "status": "active"
  }
}
```

## App Shell Data Fetching

### On initial private app load

The frontend should fetch:

- `/auth/me`
- `/billing/entitlements`
- `/documents` or recent documents endpoint

This gives the shell:

- identity
- plan state
- remaining quota
- recent user work

## Recommended Private Layout

Use a true app shell, not a marketing page with features bolted on.

Recommended structure:

- top bar
  - logo
  - plan badge
  - usage summary
  - account menu
- left rail
  - dashboard
  - documents
  - settings
- main stage
  - document list or active workspace

This should feel like a calm product workspace, not a one-page site.

## Landing Page Structure

The public page should be simple and conversion-oriented.

Recommended sections:

1. Hero
   - clear promise
   - `Get started`
   - `See pricing`
2. How it works
   - upload
   - transform
   - grounded chat
   - optional study tools
3. Why grounded chat matters
   - answers come only from your document
4. Pricing
   - Basic / Plus / Ultra
5. FAQ
   - privacy
   - supported files
   - billing

Do not overload the landing page with internal workflow detail.

## Protected Route Rules

### If unauthenticated user hits `/app/*`

Redirect to:

- `/login`

### If authenticated user lacks plan access

Do not redirect away from the app entirely.

Instead:

- keep them in the app
- show locked state or upgrade CTA where the premium action lives

Examples:

- Basic user can open workspace page
- Basic user cannot run study-pack generation
- Basic or Plus user can see infographic generation but cannot run it

## Document Upload Flow

This is the critical handoff from app shell into backend processing.

### Desired flow

1. authenticated user opens upload flow
2. app checks entitlement for `document_upload`
3. app validates allowed type and size client-side where possible
4. app uploads file to storage or internal upload endpoint
5. backend validates type, MIME, and parser-safe acceptance
6. backend computes file fingerprint and checks for an existing project for that user
7. if duplicate exists:
   - show warning and link to existing project
   - do not start processing
8. if validation fails:
   - show plain-language rejection state
   - do not start processing
9. if not duplicate:
   - create document/project record
   - trigger n8n document workflow
10. app shows processing state
11. app polls or subscribes for ready state
12. workspace becomes available

### Important rule

Browser should not call n8n directly.

Use:

- web app/backend route
- authenticated user context
- entitlement check first

## Grounded Chat Flow

### Desired flow

1. authenticated user types message in workspace
2. app checks entitlement for `grounded_chat_message`
3. backend verifies ownership of `documentId` and the active `documentVersionId`
4. backend forwards authorized request into chat workflow or chat service
5. answer returns for that specific version
6. usage recorded
7. UI updates remaining quota

Again:

- the browser should not directly call the internal workflow endpoint

### Grounded-chat UX rule

When the assistant answers:

- show citations when available
- show a softer trust state when the answer is only partial or extraction-limited
- show a clear unsupported state when the document does not answer the question

Do not present all answers with the same confidence treatment.

## Study-Pack Generation Flow

### Desired flow

1. authenticated user clicks `Generate study pack`
2. app checks entitlements
3. if Basic:
   - show upgrade lock
4. if Plus:
   - allow standard study-pack generation
5. if Ultra:
   - allow standard or deep mode depending on remaining credits
6. backend triggers authorized study-pack workflow/service
7. usage recorded on success

## Infographic Generation Flow

### Desired flow

1. authenticated user opens a document topic or section page
2. app determines whether the topic is infographic-eligible
3. app renders `Generate infographic` in the local action area
4. app checks entitlement for `infographic_generation`
5. if `Basic` or `Plus`:
   - show locked state and upgrade CTA to `Ultra`
6. if `Ultra` with available credits:
   - allow infographic generation
7. backend triggers authorized infographic generation service/workflow
8. usage recorded on success
9. generated visual appears in the workspace and document assets/history

## Recommended Backend Routes For App Shell

### Auth

- `POST /auth/signup`
- `POST /auth/login`
- `POST /auth/logout`
- `GET /auth/me`

### Billing

- `GET /billing/me`
- `GET /billing/entitlements`
- `POST /billing/checkout-session`
- `POST /billing/portal-session`
- `POST /billing/webhooks/stripe`

### Documents

- `GET /documents`
- `POST /documents`
- `GET /documents/:documentId`
- `POST /documents/:documentId/process`

### Workspace

- `GET /documents/:documentId/workspace`

### Chat

- `POST /documents/:documentId/chat`

### Study tools

- `POST /documents/:documentId/study-pack`
- `POST /documents/:documentId/infographic`

## Minimal Additional Tables

In addition to the auth and billing tables, add:

### `documents`

- `id`
- `document_id`
- `user_id`
- `subject`
- `status`
- `file_name`
- `mime_type`
- `created_at`
- `updated_at`

### `document_access_log` (optional later)

- `id`
- `user_id`
- `document_id`
- `action`
- `created_at`

Not required for MVP, but useful later.

## Recommended UI States

### Dashboard empty state

Show:

- first upload CTA
- supported file types
- short explanation of grounded chat

### Dashboard/project list state

Each project row or card should show:

- title or file-derived subject
- current status
- last updated time
- quick action to open when ready
- retry/delete actions when failed

Recommended statuses:

- `Processing`
- `Ready`
- `Failed`
- `Duplicate blocked`

### Processing state

Show:

- upload accepted
- extracting
- building workspace
- indexing
- ready

Also include:

- current file name
- project title if known
- status text that updates without page refresh when possible
- no fake percentages unless they are real

### Rejected-upload state

Show:

- unsupported file type
- file too large
- unreadable or corrupt file
- password-protected document

And always include:

- what the user can try next
- a clean path back to upload again

### Duplicate-blocked state

Show:

- warning that the file was already parsed
- direct link to the existing project
- note that the existing project must be deleted before parsing the same file again

Do not:

- create a second visible project
- imply that the user can overwrite the old one in place

### Locked premium state

Show:

- why it is locked
- what plan unlocks it
- upgrade CTA

For infographic generation specifically:

- place the disabled `Generate infographic` button directly where the user would expect to use it
- pair it with:
  - `Ultra feature`
  - or `Upgrade to Ultra`
- do not hide the feature completely, because visibility helps explain the product ceiling and upgrade path

### Limit reached state

Show:

- which limit is exhausted
- reset date
- upgrade/manage billing CTA

## MVP Build Order

1. landing page
2. sign-up page
3. sign-in page
4. session handling
5. protected app shell
6. dashboard + document list
7. upload flow
8. workspace page
9. grounded chat UI
10. billing and upgrade states

This gives us the real app shell before we over-focus on backend cleverness.

## Final Recommendation

The most important correction is:

- StudyFlow is not just a workflow-backed utility
- it is an authenticated SaaS product with workflows behind it

So the right implementation order is:

1. public marketing surface
2. auth + session shell
3. billing + entitlements
4. document workspace flow
5. grounded chat
6. premium study tools

That order will keep the product coherent from the first real version.
