# Project Context for AI Agents _This file contains critical rules and patterns that AI agents must follow when implementing code in this project. Focus on unobvious details that agents might otherwise miss._ --- ## 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 (when implemented) - **Framework:** FastAPI. APIs in Python only. - **Modularity:** Separate file per route. Each feature (users, entries) has its own router module. - **Database:** MongoDB. Setup instructions below. - **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 ``` --- _Last updated: 2026-03-04_ ## 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** — Created `src/lib/crypto.ts` with complete zero-knowledge privacy - Libsodium.js integrated for cryptography (XSalsa20-Poly1305) - Key derivation from Firebase credentials using Argon2i KDF - Device key generation and localStorage persistence - Encrypted secret key storage in IndexedDB - Entry encryption/decryption utilities ✅ **Key Management Flow** - **Login:** KDF derives master key from `firebaseUID + firebaseIDToken + salt` - **Device Setup:** Random device key generated, stored in localStorage - **Key Cache:** Master key encrypted with device key → IndexedDB - **Memory:** Master key kept in memory during session only - **Subsequent Login:** Cached encrypted key recovered via device key - **New Device:** Full KDF derivation, new device key generated - **Logout:** Master key cleared from memory; device key persists for next session ✅ **AuthContext Enhanced** - Added `secretKey` state (in-memory only) - Integrated encryption initialization on login - Device key and IndexedDB cache management - Automatic recovery of cached keys on same device ✅ **Backend Models Updated** — Zero-knowledge storage - `JournalEntryCreate`: title/content optional (null if encrypted) - `EncryptionMetadata`: stores ciphertext, nonce, algorithm - Server stores **encryption metadata only**, never plaintext - All entries encrypted with XSalsa20-Poly1305 (libsodium) ✅ **API Routes** — Encrypted entry flow - POST `/api/entries/{userId}` accepts encrypted entries - Validation ensures ciphertext and nonce present - Entry retrieval returns full encryption metadata - Update routes support re-encryption - Server processes only encrypted data ✅ **HomePage** — Encrypted entry creation - Entry and title combined: `title\n\n{entry}` - Encrypted with master key before transmission - Sends ciphertext, nonce, algorithm metadata to backend - Success feedback confirms secure storage ✅ **HistoryPage** — Entry decryption & display - Fetches encrypted entries from server - Client-side decryption with master key - Splits decrypted content: first line = title - Graceful handling of decryption failures - Displays original title or `[Encrypted]` on error ### Next Steps (Implementation) 🔄 Entry detail view with full decryption 🔄 Edit encrypted entries (re-encrypt on changes) 🔄 Search/filter encrypted entries (client-side only) 🔄 Export/backup encrypted entries with device key