feat: 8 AI providers, rich text editor, agent notifications, UI contrast & font settings
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m25s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m25s
- Add DeepSeek, OpenRouter, Mistral, Z.AI, LM Studio as AI providers with editable model names via Combobox in admin settings - Fix OpenRouter broken by normalizeProvider bug in config.ts - Convert agent-created notes from Markdown to HTML (TipTap rich text) - Add Notification model + in-app notifications for agent results - Agent notification click opens the created note directly - Add note count display on notebook and inbox headers - Fix checklist toggle in card view (persist state via localCheckItems) - Add checklist creation option in tabs/list view (dropdown on + button) - Fix image description ENOENT error with HTTP fallback - Improve UI contrast across all themes (input, border, checkbox visibility) - Add font family setting (Inter vs System Default) in Appearance settings - Fix CSS font-sans variable conflict (removed dead Geist references) - Update README with new features and 8 providers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
#!/bin/sh
|
||||
# ============================================================
|
||||
# Memento Note — Docker Entrypoint
|
||||
# Automatic DB migration with backup, retry, and cleanup.
|
||||
# Safe for production: no data loss on image updates.
|
||||
# Reliable DB migration for fresh installs and upgrades.
|
||||
# ============================================================
|
||||
# Strategy:
|
||||
# 1. prisma migrate deploy → fresh DB, normal upgrades
|
||||
# 2. prisma db push → fallback for DBs without migration history
|
||||
# ============================================================
|
||||
|
||||
set -e
|
||||
@@ -26,13 +29,12 @@ case "$DATABASE_URL" in
|
||||
esac
|
||||
log "Database type: $DB_TYPE"
|
||||
|
||||
# --- Wait for database to be reachable ---
|
||||
wait_for_db() {
|
||||
if [ "$DB_TYPE" = "sqlite" ]; then
|
||||
log "SQLite — no connection check needed."
|
||||
return 0
|
||||
fi
|
||||
# --- Ensure data directories exist ---
|
||||
mkdir -p "$BACKUP_DIR" 2>/dev/null || true
|
||||
mkdir -p /app/data/uploads/notes 2>/dev/null || true
|
||||
|
||||
# --- Wait for database to be reachable ---
|
||||
if [ "$DB_TYPE" != "sqlite" ]; then
|
||||
log "Waiting for database connection..."
|
||||
i=0
|
||||
while [ "$i" -lt "$DB_WAIT_RETRIES" ]; do
|
||||
@@ -45,107 +47,74 @@ wait_for_db() {
|
||||
s.on('error', () => process.exit(1));
|
||||
" 2>/dev/null; then
|
||||
log "Database is reachable."
|
||||
return 0
|
||||
break
|
||||
fi
|
||||
i=$((i + 1))
|
||||
log " Attempt $i/$DB_WAIT_RETRIES — retrying in ${DB_WAIT_INTERVAL}s..."
|
||||
sleep "$DB_WAIT_INTERVAL"
|
||||
done
|
||||
|
||||
err "Database unreachable after $((DB_WAIT_RETRIES * DB_WAIT_INTERVAL)) seconds. Aborting."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- Create backup before migration ---
|
||||
create_backup() {
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
ts=$(date '+%Y%m%d_%H%M%S')
|
||||
|
||||
case "$DB_TYPE" in
|
||||
postgres)
|
||||
backup_file="$BACKUP_DIR/pre_migrate_${ts}.sql.gz"
|
||||
log "Creating PostgreSQL backup: $backup_file"
|
||||
if command -v pg_dump >/dev/null 2>&1; then
|
||||
if pg_dump --no-owner --no-privileges --format=plain "$DATABASE_URL" 2>/dev/null | gzip > "$backup_file" 2>/dev/null; then
|
||||
size=$(du -h "$backup_file" | cut -f1)
|
||||
log "Backup created successfully ($size)"
|
||||
else
|
||||
warn "pg_dump failed. Continuing without backup."
|
||||
rm -f "$backup_file"
|
||||
fi
|
||||
else
|
||||
warn "pg_dump not available. Skipping PostgreSQL backup."
|
||||
warn "Install postgresql-client in the Docker image for automatic backups."
|
||||
fi
|
||||
;;
|
||||
sqlite)
|
||||
db_path="${DATABASE_URL#file:}"
|
||||
# Handle relative paths
|
||||
case "$db_path" in
|
||||
/*) ;;
|
||||
*) db_path="/app/$db_path" ;;
|
||||
esac
|
||||
backup_file="$BACKUP_DIR/pre_migrate_${ts}.sqlite"
|
||||
if [ -f "$db_path" ]; then
|
||||
log "Creating SQLite backup: $backup_file"
|
||||
cp "$db_path" "$backup_file"
|
||||
size=$(du -h "$backup_file" | cut -f1)
|
||||
log "Backup created successfully ($size)"
|
||||
else
|
||||
warn "SQLite file not found at $db_path — skipping backup (first run)."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
warn "Unknown database type '$DB_TYPE'. Skipping backup."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Clean up old backups (keep last N) ---
|
||||
cleanup_old_backups() {
|
||||
count=$(ls -1 "$BACKUP_DIR"/pre_migrate_* 2>/dev/null | wc -l)
|
||||
if [ "$count" -gt "$MAX_BACKUPS" ]; then
|
||||
to_remove=$((count - MAX_BACKUPS))
|
||||
log "Cleaning up $to_remove old backup(s), keeping last $MAX_BACKUPS..."
|
||||
ls -1t "$BACKUP_DIR"/pre_migrate_* 2>/dev/null | tail -n "$to_remove" | xargs rm -f
|
||||
if [ "$i" -ge "$DB_WAIT_RETRIES" ]; then
|
||||
err "Database unreachable after $((DB_WAIT_RETRIES * DB_WAIT_INTERVAL)) seconds."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# --- Run Prisma migrations ---
|
||||
run_migrations() {
|
||||
log "Running Prisma migrations..."
|
||||
if timeout "$MIGRATE_TIMEOUT" node ./node_modules/prisma/build/index.js migrate deploy 2>&1; then
|
||||
log "Migrations applied successfully."
|
||||
return 0
|
||||
else
|
||||
exit_code=$?
|
||||
err "Migration failed (exit code $exit_code)."
|
||||
return "$exit_code"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Main flow
|
||||
# ============================================================
|
||||
|
||||
# Step 1: Wait for database
|
||||
wait_for_db
|
||||
|
||||
# Step 2: Backup
|
||||
create_backup
|
||||
|
||||
# Step 3: Cleanup old backups
|
||||
cleanup_old_backups
|
||||
|
||||
# Step 4: Migrate
|
||||
if ! run_migrations; then
|
||||
err "Migration failed — server will NOT start to prevent data corruption."
|
||||
err "A backup was saved in $BACKUP_DIR (if backup was successful)."
|
||||
err "To restore: gunzip the .sql.gz file, then: psql DATABASE_URL < backup.sql"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Background scheduler: call /api/cron/agents every 5 minutes
|
||||
# --- Create backup before migration (best-effort) ---
|
||||
if [ "$DB_TYPE" = "postgres" ] && command -v pg_dump >/dev/null 2>&1; then
|
||||
ts=$(date '+%Y%m%d_%H%M%S')
|
||||
backup_file="$BACKUP_DIR/pre_migrate_${ts}.sql.gz"
|
||||
log "Creating backup: $backup_file"
|
||||
if pg_dump --no-owner --no-privileges --format=plain "$DATABASE_URL" 2>/dev/null | gzip > "$backup_file" 2>/dev/null; then
|
||||
size=$(du -h "$backup_file" | cut -f1)
|
||||
log "Backup OK ($size)"
|
||||
else
|
||||
warn "pg_dump failed (DB may be empty). Continuing without backup."
|
||||
rm -f "$backup_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Cleanup old backups ---
|
||||
count=$(ls -1 "$BACKUP_DIR"/pre_migrate_* 2>/dev/null | wc -l)
|
||||
if [ "$count" -gt "$MAX_BACKUPS" ]; then
|
||||
to_remove=$((count - MAX_BACKUPS))
|
||||
log "Cleaning up $to_remove old backup(s)..."
|
||||
ls -1t "$BACKUP_DIR"/pre_migrate_* 2>/dev/null | tail -n "$to_remove" | xargs rm -f
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Migration — two strategies
|
||||
# ============================================================
|
||||
|
||||
PRISMA="node ./node_modules/prisma/build/index.js"
|
||||
|
||||
log "Running database migrations..."
|
||||
|
||||
# Strategy 1: prisma migrate deploy
|
||||
# Works for: fresh DB (empty), existing DB with migration history
|
||||
if timeout "$MIGRATE_TIMEOUT" $PRISMA migrate deploy 2>&1; then
|
||||
log "Migrations applied successfully."
|
||||
else
|
||||
migrate_exit=$?
|
||||
log "prisma migrate deploy failed (exit $migrate_exit)."
|
||||
|
||||
# Strategy 2: prisma db push
|
||||
# Works for: existing DB without migration history (created with db push),
|
||||
# schema drift, or any other case where migrate deploy fails.
|
||||
# This syncs schema.prisma → database, preserving existing data.
|
||||
log "Falling back to prisma db push..."
|
||||
if timeout "$MIGRATE_TIMEOUT" $PRISMA db push --skip-generate --accept-data-loss 2>&1; then
|
||||
log "db push completed successfully."
|
||||
else
|
||||
err "All migration strategies failed."
|
||||
err "To fix manually:"
|
||||
err " docker compose exec memento-note npx prisma migrate deploy"
|
||||
err " docker compose exec memento-note npx prisma db push --skip-generate"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Background cron scheduler ---
|
||||
(
|
||||
sleep 60
|
||||
while true; do
|
||||
@@ -163,6 +132,6 @@ fi
|
||||
done
|
||||
) &
|
||||
|
||||
# Step 5: Start server
|
||||
# --- Start server ---
|
||||
log "Starting server..."
|
||||
exec node server.js
|
||||
|
||||
Reference in New Issue
Block a user