# Grateful Journal — Project Instructions for Copilot

## Project Overview

**Grateful Journal** — A minimal, private-first gratitude journaling web app. Three main pages (Write, History/calendar, Settings/profile) plus Google auth. No feeds or algorithms; privacy by design with client-side encryption; daily use, even one sentence.

**User:** Jeet

---

## Technology Stack & Versions

| Layer    | Technology           | Notes                                                 |
| -------- | -------------------- | ----------------------------------------------------- |
| Frontend | React 19, TypeScript | Vite 7 build; port 8000                               |
| Routing  | react-router-dom 7   | Routes: `/`, `/history`, `/settings`, `/login`        |
| Auth     | Firebase 12          | Google sign-in only (no database)                     |
| Styling  | Plain CSS            | `src/index.css` (globals), `src/App.css` (components) |
| Backend  | FastAPI 0.104        | Python; port 8001; modular routes                     |
| Database | MongoDB 6.x          | Local instance; collections: users, entries, settings |

---

## Critical Implementation Rules

### Frontend

- **Colour palette (Coolors):** Use CSS variables from `src/index.css`. Primary green `#1be62c`, background soft `#f1eee1`, surface `#ffffff`, accent light `#cff2dc`, accent bright `#c3fd2f`. Do not introduce new palette colours without reason.
- **Layout:** Responsive for all screens. Breakpoints: `--bp-sm` 480px, `--bp-md` 768px, `--bp-lg` 1024px, `--bp-xl` 1280px. On laptop (1024px+), page is single-screen 100vh — no vertical scroll; fonts and spacing scaled so content fits one viewport.
- **Touch targets:** Minimum 44px (`--touch-min`) on interactive elements for small screens.
- **Safe areas:** Use `env(safe-area-inset-*)` for padding where the app can sit under notches or system UI. Viewport meta includes `viewport-fit=cover`.
- **Structure:** Main app layout: page container → header + main content + fixed `BottomNav`. Content max-width `min(680px, 100%)` (or `--content-max` 720px where appropriate).

### Backend

- **Framework:** FastAPI. APIs in Python only.
- **Modularity:** Separate file per route. Each feature (users, entries) has its own router module.
- **Database:** MongoDB. Setup instructions in `docs/MONGODB_SETUP.md`.
- **Port:** 8001 (backend); 8000 (frontend). CORS configured between them.
- **Authentication:** Relies on Firebase Google Auth token from frontend (passed in Authorization header).

### Conventions

- **Fonts:** Inter for UI, Playfair Display for headings/editorial, Lora for body/entry text. Loaded via Google Fonts in `index.html`.
- **Naming:** CSS uses BEM-like class names (e.g. `.journal-card`, `.journal-prompt`). Keep the same pattern for new components.
- **Build:** Fixing the current TypeScript/ESLint build errors is deferred to a later step; do not assume a clean build when adding features.

---

## File Layout (Reference)

```
src/                          # Frontend
  App.tsx, App.css            # Root layout, routes, global page styles
  index.css                   # Resets, :root vars, base typography
  main.tsx
  pages/                      # HomePage, HistoryPage, SettingsPage, LoginPage
  components/                 # BottomNav, LoginCard, GoogleSignInButton, ProtectedRoute
  contexts/                   # AuthContext (Firebase Google Auth)
  lib/
    firebase.ts               # Firebase auth config (Google sign-in only)
    api.ts                    # API client for backend calls

backend/                      # FastAPI backend (Port 8001)
  main.py                     # FastAPI app, CORS, routes, lifespan
  config.py                   # Settings, environment variables
  db.py                       # MongoDB connection manager
  models.py                   # Pydantic models (User, JournalEntry, Settings)
  requirements.txt            # Python dependencies
  .env.example                # Environment variables template
  routers/
    users.py                  # User registration, update, delete endpoints
    entries.py                # Entry CRUD, date filtering endpoints
```

---

## Recent Changes & Status

### Port Configuration (Updated)

✅ Frontend port changed to **8000** (was 5173)  
✅ Backend port remains **8001**  
✅ CORS configuration updated in FastAPI  
✅ Vite config updated with server port 8000

### Backend Setup (Completed)

✅ FastAPI backend initialized (port 8001)  
✅ MongoDB connection configured (local instance)  
✅ Pydantic models for User, JournalEntry, UserSettings  
✅ Route structure: `/api/users/*` and `/api/entries/*`  
✅ CORS enabled for frontend (localhost:8000)  
✅ Firebase Google Auth kept (Firestore completely removed)
✅ MongoDB as single source of truth

### API Ready

- User registration, profile updates, deletion
- Entry CRUD (create, read, update, delete)
- Entry filtering by date
- Pagination support

### Zero-Knowledge Encryption Implementation (Completed)

✅ **Crypto Module** (`src/lib/crypto.ts`) — Complete zero-knowledge privacy

- Libsodium.js (sodium-native compatible) for cryptography (XSalsa20-Poly1305)
- KDF: `deriveSecretKey(firebaseUID, firebaseIDToken, salt)` using Argon2i
- Device key: random 256-bit, persisted in localStorage
- Master key: encrypted with device key → stored in IndexedDB
- Session: Master key in memory only, cleared on logout

✅ **AuthContext Enhanced** — Encryption initialization

- `secretKey` state (Uint8Array, in-memory) added to AuthContext
- Key derivation on login with Firebase credentials
- Device key auto-generation and caching
- IndexedDB encryption key recovery on returning visits
- Graceful handling of key mismatch on cross-device login

✅ **HomePage** — Encrypted entry creation

- Combines title + entry: `{title}\n\n{entry}`
- Encrypts with `encryptEntry(content, secretKey)`
- Transmits only ciphertext + nonce to backend
- Backend never receives plaintext

✅ **HistoryPage** — Client-side decryption

- Fetches encrypted entries with ciphertext + nonce
- Decrypts with `decryptEntry(ciphertext, nonce, secretKey)`
- Extracts title from first line of decrypted content
- Graceful error display on decrypt failure

✅ **Backend Models** — Zero-knowledge storage

- `EncryptionMetadata`: stores ciphertext, nonce, algorithm only
- `JournalEntry`: title/content optional (null if encrypted)
- All encrypted entries use XSalsa20-Poly1305 algorithm
- Server processes metadata only, never accesses plaintext

✅ **API Routes** — Encrypted entry flow

- POST `/api/entries/{userId}`: validates ciphertext + nonce required
- GET `/api/entries/{userId}`: returns full encryption metadata
- Entries automatically return decryption data to authorized clients
- No decryption performed server-side

### Next Steps (Implementation)

🔄 Entry detail view with full plaintext display  
🔄 Edit encrypted entries (re-encrypt on update)  
🔄 Search encrypted entries (client-side decryption)  
🔄 Export/backup entries with device key encryption  
🔄 Multi-device key sync (optional: manual backup codes)

---

_Last updated: 2026-03-05_
