Files
ten31-database/start9/0.4/docker_entrypoint.sh
T
Keysat f357c23c75 Phase 0 complete: fuzzy entity tier, incremental sync, Start9 packaging
- Fuzzy tier (backend/ingest/fuzzy_resolve.py + llm.py): local Qwen adjudicates
  the deterministic resolver's flagged name-variant candidates; merges are
  durable via entity_merges (deterministic re-runs respect them), losers
  soft-deleted, logged. Idempotent.
- Incremental sync (backend/ingest/sync.py): re-embeds only rows changed since a
  watermark (ingest_sync_state); first run / --recreate = full. Tested full→0→1.
- Start9 packaging (start9/0.4): Dockerfile bundles ingest+mcp + fastembed/mcp;
  "Build search index" action runs the init in a subcontainer; MCP shipped as a
  manual stdio server (not a daemon); version 0.1.0:44. INGEST_PACKAGING.md.
- backfill.py: factored embed_and_upsert() shared with sync.

Verified end-to-end on synthetic data + live Sparks/Qwen/Qdrant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:55:12 -05:00

79 lines
4.3 KiB
Bash
Executable File

#!/bin/sh
# ═══════════════════════════════════════════════════════════════
# Ten31 Database container entrypoint (StartOS 0.4 wrapper)
# ═══════════════════════════════════════════════════════════════
#
# Responsibilities:
# 1. Ensure the mounted /data volume directories exist.
# 2. Ensure a persistent CRM_SECRET_KEY exists so issued JWTs
# survive container restarts.
# 3. Launch the Python backend server.
#
# Note: This entrypoint NO LONGER seeds /data from a baked-in
# snapshot. The 0.3.5 → 0.4 migration is complete; from 0.1.0:40
# forward the live /data volume on the StartOS host is the sole
# source of truth. StartOS preserves /data across sideloads, so
# upgrades will not disturb live data.
# ═══════════════════════════════════════════════════════════════
set -eu
DATA_DIR="${CRM_DATA_DIR:-/data}"
SECRET_FILE="$DATA_DIR/.crm-secret"
SECRETS_DIR="$DATA_DIR/secrets"
EMAIL_ATTACHMENTS_DIR="$DATA_DIR/email_attachments"
GMAIL_SA_KEY="$SECRETS_DIR/gmail-service-account.json"
mkdir -p "$DATA_DIR" "$DATA_DIR/backups" "$SECRETS_DIR" "$EMAIL_ATTACHMENTS_DIR"
# /data/secrets holds the Gmail service-account key; lock it down so only
# the container user can read the directory. chmod on the file itself is
# the operator's responsibility when they drop the key in.
chmod 700 "$SECRETS_DIR" 2>/dev/null || true
# ── Persistent JWT secret ───────────────────────────────────────
if [ -z "${CRM_SECRET_KEY:-}" ]; then
if [ -f "$SECRET_FILE" ]; then
CRM_SECRET_KEY="$(cat "$SECRET_FILE")"
else
CRM_SECRET_KEY="$(head -c 48 /dev/urandom | base64 | tr -d '\n' | tr '/+' 'ab')"
printf '%s' "$CRM_SECRET_KEY" > "$SECRET_FILE"
chmod 600 "$SECRET_FILE"
fi
export CRM_SECRET_KEY
fi
# ── Gmail integration env vars ──────────────────────────────────
# The integration is enabled only if the service-account key file is
# actually present on the /data volume. This makes the package
# self-disabling on fresh installs until an operator drops the key in.
if [ -f "$GMAIL_SA_KEY" ]; then
export CRM_GMAIL_INTEGRATION_ENABLED="${CRM_GMAIL_INTEGRATION_ENABLED:-true}"
export CRM_GMAIL_AUTH_METHOD="${CRM_GMAIL_AUTH_METHOD:-dwd}"
export CRM_GMAIL_SA_KEY_PATH="${CRM_GMAIL_SA_KEY_PATH:-$GMAIL_SA_KEY}"
export CRM_GMAIL_WORKSPACE_DOMAIN="${CRM_GMAIL_WORKSPACE_DOMAIN:-ten31.xyz}"
export CRM_GMAIL_SYNC_INTERVAL_MIN="${CRM_GMAIL_SYNC_INTERVAL_MIN:-180}"
echo "[entrypoint] Gmail integration: ENABLED (key at $GMAIL_SA_KEY)"
else
echo "[entrypoint] Gmail integration: DISABLED (no key at $GMAIL_SA_KEY)"
fi
# ── Phase-0 ingest / retrieval env ──────────────────────────────
# These are consumed by the ingest pipeline (backend/ingest/) and the MCP
# server (backend/mcp/) — NOT by the CRM web server, which ignores them.
# They are exported here so the "Build search index" StartOS action and any
# manual `python3 /app/backend/ingest/...` / `backend/mcp/server.py` run on the
# box inherit them.
#
# OPERATOR: the values below are LAN defaults for the Ten31 deployment. Set the
# real ones for your network — either by editing them here before building the
# image, or by overriding the env vars in the StartOS service environment.
# Point SPARK_CONTROL_URL at the Spark Control gateway (TLS, self-signed by
# default → SPARK_CONTROL_VERIFY_TLS=false) and QDRANT_URL at Qdrant on Spark 2.
export CRM_DB_PATH="${CRM_DB_PATH:-$DATA_DIR/crm.db}"
export SPARK_CONTROL_URL="${SPARK_CONTROL_URL:-https://192.168.1.72:62419}"
export SPARK_CONTROL_VERIFY_TLS="${SPARK_CONTROL_VERIFY_TLS:-false}"
export QDRANT_URL="${QDRANT_URL:-http://192.168.1.87:6333}"
# ── Launch the app ──────────────────────────────────────────────
exec python3 /app/backend/server.py