7.0 KiB
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-sm480px,--bp-md768px,--bp-lg1024px,--bp-xl1280px. 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 includesviewport-fit=cover. - Structure: Main app layout: page container → header + main content + fixed
BottomNav. Content max-widthmin(680px, 100%)(or--content-max720px 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
secretKeystate (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 onlyJournalEntry: 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