AES-256-GCM API key encryption and color-based PDF redline extraction
Jeroen1991z closes the plaintext-keys-in-Supabase gap with per-user AES-256-GCM encryption, and adds redline extraction for both DOCX tracked changes and color-annotated PDFs - though the two features land in a single unbundled commit.
The encryption work is self-contained. A new backend/src/lib/encryption.ts handles AES-256-GCM using a 32-byte hex key from MIKENL_ENCRYPTION_KEY. On write, PUT /user/api-key encrypts before storing. On read, userSettings.ts decrypts. The frontend is rewired to save keys through the backend endpoint instead of writing directly to Supabase. If MIKENL_ENCRYPTION_KEY is absent the keys fall through unencrypted, which preserves backward compatibility.
The redline extraction is two-layer. DOCX: docxTrackedChanges.ts gains renderParagraphRedline() which walks w:ins and w:del OOXML nodes and emits {++ins++}, {--del--}, and {>>by AUTHOR: comment<<} markers. PDF: scripts/redline_extract.py uses PyMuPDF to read per-span color values and strikethrough flags, mapping red/strikethrough to deletions, blue to insertions, and green to comments. The Node side shells out to the script via stdin/stdout. extractPdfText() tries the redline path first; if the output is under 50 characters it falls back to pdfjs.
The system prompt is extended with a TRACKED CHANGES AND REDLINE MARKUP section so the model knows how to interpret the markers and how to reason about current vs. original versions.
The two features are in a single commit. Cherry-picking one requires manually splitting the diff - the encryption changes are in encryption.ts, userSettings.ts, routes/user.ts, and UserProfileContext.tsx; the redline changes are in docxTrackedChanges.ts, pdfRedlineExtract.ts, redline_extract.py, and chatTools.ts.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?