Architecture
┌─────────────┐ portal link ┌──────────────────┐
│ Parent │ ───────────────► │ /portalaccess/… │
└─────────────┘ └────────┬─────────┘
│ sets upload_access cookie
▼
┌──────────────────┐
│ Upload page / │
│ /api/upload* │
└────────┬─────────┘
│ Graph upload
▼
┌─────────────┐ admin OAuth ┌──────────────────┐
│ Admin │ ───────────────► │ /setup + Redis │
│ (/setup) │ │ config + links │
└─────────────┘ └────────┬─────────┘
│
┌────────────────────────┼────────────────────────┐
▼ ▼ ▼
Upstash Redis OneDrive (Graph) Azure Email
links + config uploaded video notificationTemporary links and Redis
| Redis key | Contents | TTL |
|---|---|---|
link:{uuid} | createdAt, childName, edc, expiresAt, optional usedAt | Set to link expiry at creation; kept until dismissed after consume |
app:config | Partial config overrides | None |
Parent-facing checks (/portalaccess/[token])
| Result | Behavior |
|---|---|
| Missing / expired / used | Redirect to /link-expired |
| Still in buffer | Redirect to pending countdown with availableAt |
| Active | Set portal cookie and redirect to / |
Important: opening the link does not consume it. Consumption happens only after a successful upload finalize.
Filename derivation
At upload time the server builds:
GMA Video {Child Name} {DD.MM.YYYY}_{ageWeeks}{extension}Age (weeks) = whole weeks from EDC → date recorded (lib/age.ts). Calculation is server-side; the parent UI does not preview age.
Authentication cookies
| Cookie | Purpose | Notes |
|---|---|---|
onedrive_pkce | PKCE code verifier | HttpOnly, short-lived (~10 min) |
onedrive_auth_flow | setup | admin | upload-access | HttpOnly, short-lived |
upload_access | Signed portal or admin session | HttpOnly; Secure in production; ~14 days |
Cookie HMAC secret resolution: UPLOAD_ACCESS_SECRET → else UPSTASH_REDIS_REST_TOKEN → else a dev-only fallback (do not rely on fallback in production).
Portal vs admin payload
- Portal:
{ type: "portal", token, exp } - Admin:
{ type: "admin", username, exp }— username must remain allowlisted
There is no Next.js middleware.ts; auth is enforced inside route handlers.
Last updated on