## Translation Files - Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ missing translation keys across all 15 languages - New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels - Update nav section with workspace, quickAccess, myLibrary keys ## Component Updates - Update 15+ components to use translation keys instead of hardcoded text - Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc. - Replace 80+ hardcoded English/French strings with t() calls - Ensure consistent UI across all supported languages ## Code Quality - Remove 77+ console.log statements from codebase - Clean up API routes, components, hooks, and services - Keep only essential error handling (no debugging logs) ## UI/UX Improvements - Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500) - Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items) - Make "+" button permanently visible in notebooks section - Fix grammar and syntax errors in multiple components ## Bug Fixes - Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json - Fix syntax errors in notebook-suggestion-toast.tsx - Fix syntax errors in use-auto-tagging.ts - Fix syntax errors in paragraph-refactor.service.ts - Fix duplicate "fusion" section in nl.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Ou une version plus courte si vous préférez : feat(i18n): Add 15 languages, remove logs, update UI components - Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ translation keys: notebook, pagination, AI features - Update 15+ components to use translations (80+ strings) - Remove 77+ console.log statements from codebase - Fix JSON syntax errors in 4 translation files - Fix component syntax errors (toast, hooks, services) - Update logo to yellow post-it style - Change selection colors (#FEF3C6, #EFB162) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
548 lines
11 KiB
Markdown
548 lines
11 KiB
Markdown
# Migration Guide: Tags → Notebooks
|
||
|
||
**Project:** Keep - Notebooks & Labels Contextuels
|
||
**Date:** 2026-01-11
|
||
**Status:** READY FOR EXECUTION
|
||
**Version:** 1.0
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
1. [Overview](#overview)
|
||
2. [Pre-Migration Checklist](#pre-migration-checklist)
|
||
3. [Migration Process](#migration-process)
|
||
4. [Post-Migration Verification](#post-migration-verification)
|
||
5. [Rollback Procedure](#rollback-procedure)
|
||
6. [Troubleshooting](#troubleshooting)
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
### What This Migration Does
|
||
|
||
This migration transforms Keep's **flat tags system** into a **contextual notebooks system**:
|
||
|
||
✅ **Creates** a new `Notebook` model for organizing notes
|
||
✅ **Updates** the `Label` model to belong to notebooks (contextual)
|
||
✅ **Updates** the `Note` model to optionally belong to a notebook
|
||
✅ **Preserves** all existing data (zero data loss)
|
||
✅ **Maintains** backward compatibility (existing features still work)
|
||
|
||
### What Changes
|
||
|
||
| Before | After |
|
||
|--------|-------|
|
||
| Labels are **global** (shared across all notes) | Labels are **contextual** to notebooks |
|
||
| Labels belong to users | Labels belong to notebooks |
|
||
| No concept of notebooks | Notes can be organized into notebooks |
|
||
| All labels in one flat list | Labels isolated per notebook |
|
||
|
||
### What Doesn't Change
|
||
|
||
- ✅ All existing notes are preserved
|
||
- ✅ All existing labels are preserved
|
||
- ✅ Notes remain accessible (in "Notes générales" / Inbox)
|
||
- ✅ No breaking changes to the UI
|
||
- ✅ Existing features continue to work
|
||
|
||
---
|
||
|
||
## Pre-Migration Checklist
|
||
|
||
### 1. Backup Database
|
||
|
||
**CRITICAL:** Always backup before migration!
|
||
|
||
```bash
|
||
# Navigate to project directory
|
||
cd D:\dev_new_pc\Keep
|
||
|
||
# Backup SQLite database
|
||
cp keep-notes/prisma/dev.db keep-notes/prisma/dev.db.backup-$(date +%Y%m%d)
|
||
|
||
# Verify backup exists
|
||
ls -lh keep-notes/prisma/dev.db.backup-*
|
||
```
|
||
|
||
### 2. Stop Application
|
||
|
||
Stop the development server to prevent conflicts:
|
||
|
||
```bash
|
||
# Stop Next.js dev server if running
|
||
# Press Ctrl+C in the terminal or run:
|
||
pkill -f "next dev"
|
||
```
|
||
|
||
### 3. Review Migration Plan
|
||
|
||
Understand what will happen:
|
||
|
||
- [ ] I have a database backup
|
||
- [ ] I understand that labels will be moved to a "Labels Migrés" notebook
|
||
- [ ] I understand that notes will remain in "Notes générales" (Inbox)
|
||
- [ ] I know how to rollback if needed
|
||
- [ ] I have 5-10 minutes of downtime scheduled
|
||
|
||
### 4. Check Prisma Status
|
||
|
||
Ensure Prisma is properly installed:
|
||
|
||
```bash
|
||
cd keep-notes
|
||
npx prisma --version
|
||
# Should show: 5.22.0 or higher
|
||
|
||
# Generate Prisma client (if not already done)
|
||
npx prisma generate
|
||
```
|
||
|
||
---
|
||
|
||
## Migration Process
|
||
|
||
### Step 1: Apply Prisma Schema Changes
|
||
|
||
The Prisma schema has already been updated with the new models.
|
||
|
||
Generate and apply the migration:
|
||
|
||
```bash
|
||
cd keep-notes
|
||
|
||
# Create migration
|
||
npx prisma migrate dev --name add_notebooks
|
||
|
||
# This will:
|
||
# 1. Update the database schema
|
||
# 2. Create the Notebook table
|
||
# 3. Add notebookId to Label and Note tables
|
||
# 4. Create indexes for performance
|
||
```
|
||
|
||
**Expected Output:**
|
||
|
||
```
|
||
✔ Generated Prisma Client
|
||
✔ The following migration has been created and applied from new schema changes:
|
||
|
||
migrations/
|
||
└─ 20260111XXXXXX_add_notebooks/
|
||
└─ migration.sql
|
||
|
||
Applying migration `20260111XXXXXX_add_notebooks`
|
||
|
||
The following migration(s) have been created and applied from new schema changes:
|
||
|
||
migrations/
|
||
└─ 20260111XXXXXX_add_notebooks/
|
||
└─ migration.sql
|
||
```
|
||
|
||
### Step 2: Verify Schema Applied
|
||
|
||
Check that the new tables exist:
|
||
|
||
```bash
|
||
# Open SQLite database
|
||
sqlite3 keep-notes/prisma/dev.db
|
||
|
||
# List tables
|
||
.tables
|
||
|
||
# You should see:
|
||
# - Notebook (NEW)
|
||
# - Label (MODIFIED)
|
||
# - Note (MODIFIED)
|
||
# - _NoteToLabel (NEW - junction table)
|
||
|
||
# Exit SQLite
|
||
.quit
|
||
```
|
||
|
||
### Step 3: Run Data Migration Script
|
||
|
||
Migrate the existing labels to the default notebook:
|
||
|
||
```bash
|
||
# From project root
|
||
npx tsx scripts/migrate-to-notebooks.ts
|
||
```
|
||
|
||
**Expected Output:**
|
||
|
||
```
|
||
🚀 Starting migration to notebooks...
|
||
|
||
📊 Fetching users...
|
||
✅ Found 1 user(s)
|
||
|
||
👤 Processing user: ramez@example.com (user-123)
|
||
|
||
📁 Creating "Labels Migrés" notebook...
|
||
✅ Created notebook: migrate-user-123
|
||
|
||
🏷️ Migrating labels...
|
||
✅ Migrated 15 label(s)
|
||
ℹ️ User has 47 note(s) (will remain in "Notes générales")
|
||
|
||
============================================================
|
||
|
||
✅ Migration complete!
|
||
|
||
📊 Summary:
|
||
Users processed: 1
|
||
Notebooks created: 1
|
||
Labels migrated: 15
|
||
Notes affected: 47 (all remain in Inbox)
|
||
|
||
✨ Migration successful!
|
||
|
||
📌 Next steps:
|
||
1. Test the application to ensure everything works
|
||
2. Users can now organize their notes into notebooks
|
||
3. Users can move labels from "Labels Migrés" to new notebooks
|
||
4. Consider deleting old labels field from Note model after verification
|
||
```
|
||
|
||
### Step 4: Verify Migration Success
|
||
|
||
Run the verification queries:
|
||
|
||
```bash
|
||
sqlite3 keep-notes/prisma/dev.db
|
||
|
||
# Check notebooks exist
|
||
SELECT COUNT(*) FROM "Notebook";
|
||
# Should be: 1 (or more if multiple users)
|
||
|
||
# Check labels have notebookId
|
||
SELECT COUNT(*) FROM "Label" WHERE notebookId != '';
|
||
# Should match your label count
|
||
|
||
# Check notes are still accessible
|
||
SELECT COUNT(*) FROM "Note";
|
||
# Should match your note count
|
||
|
||
# Verify notes are in Inbox (notebookId is NULL)
|
||
SELECT COUNT(*) FROM "Note" WHERE notebookId IS NULL;
|
||
# Should be all notes
|
||
|
||
.quit
|
||
```
|
||
|
||
---
|
||
|
||
## Post-Migration Verification
|
||
|
||
### 1. Start Development Server
|
||
|
||
```bash
|
||
cd keep-notes
|
||
npm run dev
|
||
```
|
||
|
||
### 2. Test Application Functionality
|
||
|
||
Open `http://localhost:3000` and verify:
|
||
|
||
#### Core Functionality
|
||
|
||
- [ ] Homepage loads without errors
|
||
- [ ] All notes are visible (in "Notes générales")
|
||
- [ ] Can create new notes
|
||
- [ ] Can edit existing notes
|
||
- [ ] Can delete notes
|
||
- [ ] Search works
|
||
|
||
#### Labels
|
||
|
||
- [ ] Labels are still visible on notes
|
||
- [ ] Can add labels to notes
|
||
- [ ] Can remove labels from notes
|
||
- [ ] Labels show the correct colors
|
||
|
||
#### Notebooks (NEW)
|
||
|
||
- [ ] "Labels Migrés" notebook exists in sidebar
|
||
- [ ] Can create a new notebook
|
||
- [ ] Can rename notebooks
|
||
- [ ] Can delete notebooks
|
||
- [ ] Can move notes between notebooks
|
||
|
||
### 3. Check Console for Errors
|
||
|
||
Open browser DevTools (F12) and check:
|
||
|
||
```
|
||
Console: No errors
|
||
Network: All requests return 200
|
||
```
|
||
|
||
### 4. Verify Data Integrity
|
||
|
||
```bash
|
||
sqlite3 keep-notes/prisma/dev.db
|
||
|
||
# No orphaned labels (all labels have notebookId)
|
||
SELECT COUNT(*) FROM "Label" WHERE notebookId = '' OR notebookId IS NULL;
|
||
# Should be: 0
|
||
|
||
# No orphaned notebook references (all notebookIds reference existing notebooks)
|
||
SELECT COUNT(*) FROM "Note"
|
||
WHERE notebookId IS NOT NULL
|
||
AND notebookId NOT IN (SELECT id FROM "Notebook");
|
||
# Should be: 0
|
||
|
||
.quit
|
||
```
|
||
|
||
---
|
||
|
||
## Rollback Procedure
|
||
|
||
### When to Rollback
|
||
|
||
Rollback if you encounter:
|
||
|
||
- ❌ Data corruption
|
||
- ❌ Application crashes
|
||
- ❌ Critical functionality broken
|
||
- ❌ Performance severe degradation
|
||
|
||
### How to Rollback
|
||
|
||
**Step 1: Stop Application**
|
||
|
||
```bash
|
||
pkill -f "next dev"
|
||
```
|
||
|
||
**Step 2: Run Rollback Script**
|
||
|
||
```bash
|
||
# DRY RUN FIRST (see what will happen)
|
||
npx tsx scripts/rollback-notebooks.ts --dry-run
|
||
|
||
# ACTUAL ROLLBACK (requires --confirm)
|
||
npx tsx scripts/rollback-notebooks.ts --confirm
|
||
```
|
||
|
||
**Step 3: Restore Database Backup**
|
||
|
||
```bash
|
||
cd keep-notes/prisma
|
||
|
||
# Find your backup
|
||
ls -lh dev.db.backup-*
|
||
|
||
# Restore from backup
|
||
cp dev.db.backup-YYYYMMDD dev.db
|
||
```
|
||
|
||
**Step 4: Restart Application**
|
||
|
||
```bash
|
||
cd keep-notes
|
||
npm run dev
|
||
```
|
||
|
||
### Verify Rollback Success
|
||
|
||
- [ ] Application starts without errors
|
||
- [ ] All notes are accessible
|
||
- [ ] Labels work as before (flat list)
|
||
- [ ] No notebooks exist in database
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### Issue: "Prisma migrate fails with foreign key error"
|
||
|
||
**Cause:** Old data conflicts with new schema constraints
|
||
|
||
**Solution:**
|
||
|
||
```bash
|
||
# 1. Check for data that violates constraints
|
||
sqlite3 keep-notes/prisma/dev.db
|
||
|
||
# Find labels without userId
|
||
SELECT * FROM "Label" WHERE userId IS NULL;
|
||
|
||
# 2. Fix data manually
|
||
UPDATE "Label" SET userId = 'YOUR_USER_ID' WHERE userId IS NULL;
|
||
|
||
# 3. Re-run migration
|
||
npx prisma migrate dev --name add_notebooks
|
||
```
|
||
|
||
### Issue: "Migration script hangs"
|
||
|
||
**Cause:** Large dataset or database lock
|
||
|
||
**Solution:**
|
||
|
||
```bash
|
||
# 1. Check database is not locked
|
||
sqlite3 keep-notes/prisma/dev.db "PRAGMA database_list;"
|
||
|
||
# 2. Kill any hanging processes
|
||
pkill -f "node"
|
||
pkill -f "prisma"
|
||
|
||
# 3. Try again
|
||
npx tsx scripts/migrate-to-notebooks.ts
|
||
```
|
||
|
||
### Issue: "Labels disappear after migration"
|
||
|
||
**Cause:** Labels migrated to "Labels Migrés" notebook but UI doesn't show them
|
||
|
||
**Solution:**
|
||
|
||
1. Check that "Labels Migrés" notebook exists
|
||
2. Verify labels have correct notebookId
|
||
3. Refresh the page (hard refresh: Ctrl+Shift+R)
|
||
4. Check browser console for errors
|
||
|
||
### Issue: "Performance degradation after migration"
|
||
|
||
**Cause:** Missing indexes or inefficient queries
|
||
|
||
**Solution:**
|
||
|
||
```bash
|
||
# Rebuild indexes
|
||
sqlite3 keep-notes/prisma/dev.db "REINDEX;"
|
||
|
||
# Analyze database for query optimization
|
||
sqlite3 keep-notes/prisma/dev.db "ANALYZE;"
|
||
|
||
# If still slow, check slow queries
|
||
# Add more indexes if needed
|
||
```
|
||
|
||
### Issue: "Cannot create notebook - 'notebookId' is required"
|
||
|
||
**Cause:** Label table has NOT NULL constraint on notebookId
|
||
|
||
**Solution:**
|
||
|
||
This is expected behavior. Labels must belong to a notebook.
|
||
|
||
1. Create a notebook first
|
||
2. Then create labels within that notebook
|
||
|
||
---
|
||
|
||
## Post-Migration Cleanup (Optional)
|
||
|
||
After verifying everything works, you can clean up deprecated fields:
|
||
|
||
### 1. Remove Deprecated Label.userId Field
|
||
|
||
**⚠️ ONLY DO THIS AFTER VERIFICATION (1-2 weeks later)**
|
||
|
||
```prisma
|
||
// prisma/schema.prisma
|
||
|
||
model Label {
|
||
id String @id @default(cuid())
|
||
name String
|
||
color String @default("gray")
|
||
notebookId String
|
||
notebook Notebook @relation(fields: [notebookId], references: [id], onDelete: Cascade)
|
||
notes Note[]
|
||
// REMOVE THESE TWO LINES:
|
||
// userId String?
|
||
// user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@unique([notebookId, name])
|
||
@@index([notebookId])
|
||
}
|
||
```
|
||
|
||
Then run:
|
||
|
||
```bash
|
||
npx prisma migrate dev --name remove_label_user_id
|
||
```
|
||
|
||
### 2. Remove Deprecated Note.labels Field
|
||
|
||
**⚠️ ONLY DO THIS AFTER MIGRATING ALL LABEL-NOTE RELATIONS**
|
||
|
||
```prisma
|
||
// prisma/schema.prisma
|
||
|
||
model Note {
|
||
// ... other fields
|
||
// REMOVE THIS LINE:
|
||
// labels String? // DEPRECATED: Array of label names stored as JSON string
|
||
|
||
// Keep the new relation:
|
||
labelRelations Label[]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
### Migration Checklist
|
||
|
||
**Before Migration:**
|
||
- [ ] Database backed up
|
||
- [ ] Application stopped
|
||
- [ ] Migration plan reviewed
|
||
- [ ] Prisma client generated
|
||
|
||
**During Migration:**
|
||
- [ ] Prisma schema applied
|
||
- [ ] Data migration script run
|
||
- [ ] No errors in console
|
||
- [ ] Statistics verified
|
||
|
||
**After Migration:**
|
||
- [ ] Application tested
|
||
- [ ] All notes accessible
|
||
- [ ] Labels work correctly
|
||
- [ ] Notebooks functional
|
||
- [ ] No performance issues
|
||
|
||
### Success Metrics
|
||
|
||
- ✅ Zero data loss
|
||
- ✅ All existing functionality works
|
||
- ✅ New notebooks feature works
|
||
- ✅ No errors in console
|
||
- ✅ Performance acceptable (< 300ms queries)
|
||
|
||
### Support
|
||
|
||
If you encounter issues not covered in this guide:
|
||
|
||
1. Check the browser console for errors
|
||
2. Check the server logs for stack traces
|
||
3. Verify database integrity with SQLite queries
|
||
4. Try rollback if critical
|
||
5. Contact the development team
|
||
|
||
---
|
||
|
||
**Document Status:** ✅ COMPLETE
|
||
**Ready for Migration:** YES
|
||
**Estimated Downtime:** 5-10 minutes
|
||
**Rollback Time:** 2-5 minutes
|
||
|
||
---
|
||
|
||
*Last Updated: 2026-01-11*
|
||
*Author: Winston (Architect AI Agent)*
|