Files
phaseflow/specs/authentication.md
2026-01-10 17:13:18 +00:00

3.2 KiB

Authentication Specification

Job to Be Done

When I access PhaseFlow, I want to securely log in with my email, so that my personal health data remains private.

Auth Provider

Using PocketBase for authentication and data storage.

Connection:

  • POCKETBASE_URL environment variable
  • src/lib/pocketbase.ts initializes client

Login Flow

Email/Password Authentication

  1. User enters email and password on /login
  2. App calls PocketBase authWithPassword
  3. On success, PocketBase sets auth cookie
  4. User redirected to dashboard

Session Management

  • PocketBase manages session tokens automatically
  • Auth state persisted in browser (cookie/localStorage)
  • Session expires after 14 days of inactivity

Pages

/login

Elements:

  • Email input
  • Password input
  • "Sign In" button
  • Error message display
  • Link to password reset (future)

Behavior:

  • Redirect to / on successful login
  • Show error message on failed attempt
  • Rate limit: 5 attempts per minute

Protected Routes

All routes except /login require authentication.

Middleware Check:

  1. Check for valid PocketBase auth token
  2. If invalid/missing, redirect to /login
  3. If valid, proceed to requested page

API Authentication

User Context

API routes access current user via:

const pb = new PocketBase(process.env.POCKETBASE_URL);
// Auth token from request cookies
const user = pb.authStore.model;

Protected Endpoints

All /api/* routes except:

  • /api/calendar/[userId]/[token].ics (token-based auth)
  • /api/cron/* (CRON_SECRET auth)

User API

GET /api/user

Returns current authenticated user profile.

Response:

{
  "id": "user123",
  "email": "user@example.com",
  "garminConnected": true,
  "cycleLength": 31,
  "lastPeriodDate": "2024-01-01",
  "notificationTime": "07:00",
  "timezone": "America/New_York"
}

PATCH /api/user

Updates user profile fields.

Request Body (partial update):

{
  "cycleLength": 28,
  "notificationTime": "06:30"
}

User Schema

See src/types/index.ts for full User interface.

Auth-related fields:

  • id - PocketBase record ID
  • email - Login email

Profile fields:

  • cycleLength - Personal cycle length (days)
  • notificationTime - Preferred notification hour
  • timezone - User's timezone

PocketBase Client (src/lib/pocketbase.ts)

Exports:

  • pb - Initialized PocketBase client
  • getCurrentUser() - Get authenticated user
  • isAuthenticated() - Check auth status

Settings Page (/settings)

User profile management:

  • View/edit cycle length
  • View/edit notification time
  • View/edit timezone
  • Link to Garmin settings

Success Criteria

  1. Login completes in under 2 seconds
  2. Session persists across browser refreshes
  3. Unauthorized access redirects to login
  4. User data isolated by authentication

Acceptance Tests

  • Valid credentials authenticate successfully
  • Invalid credentials show error message
  • Session persists after page refresh
  • Protected routes redirect when not authenticated
  • GET /api/user returns current user data
  • PATCH /api/user updates user record
  • Logout clears session completely
  • Auth cookie is HttpOnly and Secure