Files
Momento/memento-note/docker-entrypoint.sh
Antigravity 30da592ba2
All checks were successful
CI / Lint, Unit Tests & Build (push) Successful in 7m3s
CI / Deploy production (on server) (push) Successful in 23s
feat(dashboard): tableau de bord Second Brain configurable avec chargement progressif
Briefing granulaire, pistes rapides puis enrichissement async, layout persisté v5,
suggestions agents, intégration Gmail et navigation sidebar alignée sur /home.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 16:50:53 +00:00

169 lines
5.7 KiB
Bash

#!/bin/sh
# ============================================================
# Memento Note — Docker Entrypoint
# 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
BACKUP_DIR="/app/data/backups"
MAX_BACKUPS=5
DB_WAIT_RETRIES=30
DB_WAIT_INTERVAL=2
MIGRATE_TIMEOUT=120
# --- Logging ---
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [entrypoint] $*"; }
warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [entrypoint] WARNING: $*" >&2; }
err() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] [entrypoint] ERROR: $*" >&2; }
# --- Detect database type ---
DB_TYPE="unknown"
case "$DATABASE_URL" in
postgres://*|postgresql://*) DB_TYPE="postgres" ;;
file:*) DB_TYPE="sqlite" ;;
esac
log "Database type: $DB_TYPE"
# --- 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
if node -e "
const m = process.env.DATABASE_URL.match(/@([^:\/]+):(\d+)/);
if (!m) process.exit(1);
const net = require('net');
const s = net.createConnection(parseInt(m[2]), m[1], () => { s.end(); process.exit(0); });
s.setTimeout(3000, () => { s.destroy(); process.exit(1); });
s.on('error', () => process.exit(1));
" 2>/dev/null; then
log "Database is reachable."
break
fi
i=$((i + 1))
log " Attempt $i/$DB_WAIT_RETRIES — retrying in ${DB_WAIT_INTERVAL}s..."
sleep "$DB_WAIT_INTERVAL"
done
if [ "$i" -ge "$DB_WAIT_RETRIES" ]; then
err "Database unreachable after $((DB_WAIT_RETRIES * DB_WAIT_INTERVAL)) seconds."
exit 1
fi
fi
# --- 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 node ./node_modules/prisma/build/index.js migrate deploy"
err " docker compose exec memento-note node ./node_modules/prisma/build/index.js db push --skip-generate"
exit 1
fi
fi
# --- Background cron scheduler ---
(
sleep 60
CRON_SECRET="${CRON_SECRET:-}"
tick=0
while true; do
if [ -n "$CRON_SECRET" ]; then
CRON_TICK="$tick" node -e "
const http = require('http');
const secret = process.env.CRON_SECRET || '';
const tick = Number(process.env.CRON_TICK || '0');
const call = (path, method) => new Promise((resolve) => {
const req = http.request({
hostname: 'localhost',
port: 3000,
path,
method: method || 'POST',
headers: { Authorization: 'Bearer ' + secret },
}, (res) => {
let body = '';
res.on('data', (d) => body += d);
res.on('end', () => { console.log('[Scheduler]', path, res.statusCode, body.slice(0, 200)); resolve(); });
});
req.on('error', (e) => { console.error('[Scheduler]', path, e.message); resolve(); });
req.end();
});
(async () => {
await call('/api/cron/agents');
await call('/api/cron/agent-suggestions');
if (tick % 12 === 0) {
await call('/api/cron/reminders');
await call('/api/cron/sync-usage');
}
if (tick % 72 === 0) {
await call('/api/cron/clusters', 'GET');
}
if (tick % 288 === 0) {
await call('/api/cron/gmail');
}
})();
" 2>&1 || true
else
warn "CRON_SECRET unset — scheduled crons disabled"
fi
tick=$((tick + 1))
sleep 300
done
) &
# --- Start server ---
log "Starting server..."
exec node server.js