Document spec gaps: auth, phase scaling, observability, testing
Address 21 previously undefined behaviors across specs: - Authentication: Replace email/password with OIDC (Pocket-ID) - Cycle tracking: Add fixed-luteal phase scaling formula with examples - Calendar: Document period logging behavior (preserve predictions) - Garmin: Clarify connection is required (no phase-only mode) - Dashboard: Add UI states, dark mode, onboarding, accessibility - Notifications: Document timezone batching approach - New specs: observability.md (health, metrics, logging) - New specs: testing.md (unit + integration strategy) - Main spec: Add backup/recovery, known limitations, API updates Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
68
spec.md
68
spec.md
@@ -425,14 +425,18 @@ interface PeriodLog {
|
||||
}
|
||||
```
|
||||
|
||||
### Data Retention
|
||||
|
||||
All logs (DailyLog, PeriodLog) are retained indefinitely. No automatic deletion or archival. SQLite handles large datasets efficiently for single-user scenarios.
|
||||
|
||||
---
|
||||
|
||||
## API Routes
|
||||
|
||||
```
|
||||
# Auth (PocketBase handles user auth)
|
||||
POST /api/auth/login
|
||||
POST /api/auth/register
|
||||
# Auth (PocketBase handles via OIDC)
|
||||
GET /api/auth/login - Initiate OIDC flow
|
||||
GET /api/auth/callback - OIDC callback handler
|
||||
POST /api/auth/logout
|
||||
|
||||
# Garmin Token Management
|
||||
@@ -450,7 +454,8 @@ GET /api/cycle/current - Current phase info
|
||||
|
||||
# Daily
|
||||
GET /api/today - Today's decision + all data
|
||||
GET /api/history - Historical logs
|
||||
GET /api/history - Historical logs (cursor-based pagination)
|
||||
Query params: ?cursor=<lastId>&limit=20
|
||||
|
||||
# Calendar
|
||||
GET /api/calendar/:userId/:token.ics - ICS feed (public, token-protected)
|
||||
@@ -460,6 +465,10 @@ POST /api/calendar/regenerate-token - Generate new calendar token
|
||||
POST /api/overrides - Set active overrides
|
||||
DELETE /api/overrides/:type - Remove override
|
||||
|
||||
# Observability
|
||||
GET /api/health - Health check for monitoring
|
||||
GET /metrics - Prometheus metrics endpoint
|
||||
|
||||
# Cron (internal, protected)
|
||||
POST /api/cron/garmin-sync - Fetch Garmin data (6 AM)
|
||||
POST /api/cron/notifications - Send emails (7 AM)
|
||||
@@ -773,7 +782,7 @@ EOF
|
||||
|----------|----------|
|
||||
| Garmin API unavailable | Use last known values, note in email |
|
||||
| Garmin tokens expired | Email user with re-auth instructions |
|
||||
| No Garmin data yet | Use phase-only decision |
|
||||
| Garmin not connected | Block app usage, show onboarding prompt |
|
||||
| User hasn't set period date | Prompt in dashboard, block email until set |
|
||||
| Email delivery failure | Log, retry once |
|
||||
| Invalid ICS request | Return 404 |
|
||||
@@ -785,11 +794,51 @@ EOF
|
||||
- Garmin tokens encrypted at rest (AES-256)
|
||||
- ICS feed URL contains random token (not guessable)
|
||||
- Cron endpoints protected by secret header
|
||||
- PocketBase handles user auth
|
||||
- PocketBase handles user auth via OIDC
|
||||
- HTTPS enforced via Traefik
|
||||
|
||||
---
|
||||
|
||||
## Backup & Recovery
|
||||
|
||||
PocketBase stores all data in a single SQLite database file.
|
||||
|
||||
**Backup Procedure:**
|
||||
```bash
|
||||
# Stop PocketBase or use SQLite backup API
|
||||
cp /path/to/pb_data/data.db /path/to/backups/data-$(date +%Y%m%d).db
|
||||
```
|
||||
|
||||
**What to backup:**
|
||||
- `pb_data/data.db` - Main database (users, logs, settings)
|
||||
- `pb_data/storage/` - Any uploaded files (if applicable)
|
||||
|
||||
**Recovery:**
|
||||
```bash
|
||||
# Stop PocketBase
|
||||
cp /path/to/backups/data-YYYYMMDD.db /path/to/pb_data/data.db
|
||||
# Restart PocketBase
|
||||
```
|
||||
|
||||
Backups are manual. Set up your own cron job or backup solution as needed.
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
The following are **out of scope** for MVP:
|
||||
|
||||
| Limitation | Notes |
|
||||
|------------|-------|
|
||||
| Phase-only mode | Garmin connection required; no fallback without biometrics |
|
||||
| Pregnancy/menopause | Cycle tracking assumes regular menstrual cycles |
|
||||
| Hormonal birth control | May disrupt natural cycle phases |
|
||||
| API versioning | Single version; breaking changes via deprecation |
|
||||
| Formal API documentation | Endpoints documented in spec only |
|
||||
| E2E tests | Unit + integration tests only (authorized skip) |
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
@@ -821,9 +870,12 @@ phaseflow/
|
||||
│ │ │ ├── [userId]/[token].ics/route.ts
|
||||
│ │ │ └── regenerate-token/route.ts
|
||||
│ │ ├── overrides/route.ts
|
||||
│ │ ├── health/route.ts
|
||||
│ │ └── cron/
|
||||
│ │ ├── garmin-sync/route.ts
|
||||
│ │ └── notifications/route.ts
|
||||
│ │ └── metrics/
|
||||
│ │ └── route.ts # Prometheus metrics
|
||||
│ ├── components/
|
||||
│ │ ├── dashboard/
|
||||
│ │ │ ├── decision-card.tsx
|
||||
@@ -843,7 +895,9 @@ phaseflow/
|
||||
│ │ ├── nutrition.ts
|
||||
│ │ ├── email.ts
|
||||
│ │ ├── ics.ts # ICS feed generation
|
||||
│ │ └── encryption.ts
|
||||
│ │ ├── encryption.ts
|
||||
│ │ ├── logger.ts # Structured JSON logging
|
||||
│ │ └── metrics.ts # Prometheus metrics
|
||||
│ └── types/
|
||||
│ └── index.ts
|
||||
├── flake.nix
|
||||
|
||||
Reference in New Issue
Block a user