Setup Ralph.
This commit is contained in:
147
specs/authentication.md
Normal file
147
specs/authentication.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 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:
|
||||
```typescript
|
||||
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:**
|
||||
```json
|
||||
{
|
||||
"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):**
|
||||
```json
|
||||
{
|
||||
"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
|
||||
Reference in New Issue
Block a user