#!/bin/bash # Migrate hash-based document IDs to date-slug format # Usage: ./migrate-ids.sh [--dry-run] set -euo pipefail DOCSYS_DIR="/srv/docsys" DB="$DOCSYS_DIR/index/docsys.db" STORE="$DOCSYS_DIR/store" RECORDS="$DOCSYS_DIR/records" DRY_RUN="${1:-}" migrate() { local old_id="$1" new_id="$2" echo " $old_id → $new_id" if [ "$DRY_RUN" = "--dry-run" ]; then return; fi # Rename store files for ext in .pdf .txt .png .md ""; do if [ -f "$STORE/$old_id$ext" ]; then mv "$STORE/$old_id$ext" "$STORE/$new_id$ext" echo " store: $old_id$ext → $new_id$ext" fi done # Update record file if it exists local rec=$(sqlite3 "$DB" "SELECT record_path FROM documents WHERE id='$old_id';") if [ -n "$rec" ] && [ -f "$rec" ]; then local dir=$(dirname "$rec") local newrec="$dir/$new_id.md" mv "$rec" "$newrec" sqlite3 "$DB" "UPDATE documents SET record_path='$newrec' WHERE id='$old_id';" echo " record: $(basename $rec) → $new_id.md" fi # Update DB: documents, embeddings, shares, FTS sqlite3 "$DB" "UPDATE documents SET id='$new_id', pdf_path=REPLACE(COALESCE(pdf_path,''),'$old_id','$new_id') WHERE id='$old_id';" sqlite3 "$DB" "UPDATE embeddings SET doc_id='$new_id' WHERE doc_id='$old_id';" sqlite3 "$DB" "UPDATE shares SET doc_id='$new_id' WHERE doc_id='$old_id';" # FTS will be rebuilt on restart } echo "=== DocSys ID Migration ===" [ "$DRY_RUN" = "--dry-run" ] && echo "(DRY RUN - no changes)" echo # Stop service if [ "$DRY_RUN" != "--dry-run" ]; then echo "Stopping docsys..." systemctl --user stop docsys 2>/dev/null || true # Backup DB cp "$DB" "$DB.bak-$(date +%Y%m%d%H%M%S)" echo "DB backed up" echo fi # Define migrations (old_id new_id) declare -A RENAMES=( ["e37d1295e9505e4a"]="2026-01-07-st-petersburg-utility-bill-jan-2026" ["dae28e167002431c"]="2026-02-04-st-petersburg-utility-bill-feb-2026" ["9cb67ca54c94a00e"]="2026-02-09-hostkey-hosting-invoice" ["b1ba43f7d4b9838f"]="undated-diana-geegan-business-card" ["a52c68f7df88a965"]="2026-01-08-fedex-shipping-receipt" ["05282dcf1da896a1"]="2026-01-09-parkshore-grill-receipt" ["d9cdc7038fb9486d"]="2026-01-15-american-airlines-receipt" ["a62399f94087ed04"]="2025-07-01-social-security-retirement-publication" ["e569c01b4676add9"]="2025-12-10-valley-bank-heloc-renewal-notice" ["2e2ff8472d8afff5"]="2025-12-31-optum-hsa-statement-q4-2025" ["f8871fd13b609bbd"]="2025-12-31-voya-retirement-statement-2025" ["2b4444a5a92bec9e"]="2025-12-31-alliant-savings-statement" ["79ba22cec092fbd8"]="2025-12-31-voya-retirement-account-2025" ["2bf818fe2975e1ae"]="2026-01-21-achmea-pension-statement-jan-2026" ["da65059758f7be28"]="2025-11-13-miele-microwave-service" ["249e08e266ec2216"]="2026-02-03-sellers-net-sheet" ["0706a83eef188e5a"]="2025-03-01-nfip-claims-history-report" ["5cc409ac61a1af04"]="2025-11-24-umbrella-insurance-invoice" ["44d71c266fb381a6"]="2025-11-26-flood-insurance-renewal-notice" ["e67d1787863aa29b"]="2025-12-07-selective-flood-renewal-bill" ["d8878b9a5b957569"]="2026-01-06-flood-insurance-renewal-notice" ["78ab51124773bda5"]="2026-01-21-wright-flood-policy-renewal-2026" ["eb4fe6c8236c0e6c"]="2026-01-22-flood-insurance-requirement-notice" ["a201962321fd109e"]="2025-03-20-nvc-visa-availability-notice" ["be8d89694c05c7da"]="2026-02-09-llc-formation-receipt" ["77181a9186c0dc47"]="2025-11-25-baycare-medical-bill-nov-2025" ["80d668195458c32e"]="2025-12-25-baycare-medical-bill-a" ["4e70650454bb45bb"]="2025-12-25-baycare-medical-bill-b" ["c09a129d73e21fe6"]="2026-01-08-sophia-jongsma-medical-bill" ["669bdec86f28d83d"]="2025-form-1098-mortgage-interest" ["1947d2b3d8ac0437"]="2026-01-06-irs-withholding-compliance-letter" ) for old_id in "${!RENAMES[@]}"; do migrate "$old_id" "${RENAMES[$old_id]}" done echo echo "Done! ${#RENAMES[@]} documents migrated." if [ "$DRY_RUN" != "--dry-run" ]; then echo "Starting docsys..." systemctl --user start docsys echo "Service started (FTS will rebuild automatically)" fi