wip: ops admin panel + migration sync + crud/rbac phase-5 snapshot

Working-tree checkpoint of in-progress work carried across prior
sessions on the feat/crud-rbac branch, committed so it lands on the
remote alongside the CI changes.

- Operaciones admin panel: apps/api/src/ops (ingest upload, backup /
  restore / re-import jobs) wired into app.module + RBAC abilities, and
  the apps/web/src/app/operaciones page. docker-compose gets INGEST_DIR
  / BACKUP_DIR volumes; .gitignore excludes migration/ingest + backups.
- migration/sync.py plus transform_*.py / run_all / config / dbenv /
  blob_extract adjustments for the additive sync path.
- crud/rbac phase-5 web bits: AppShell, api/labels/types libs, globals.
- schema.prisma + PLAN/RESUME doc updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 19:01:36 -07:00
co-authored by Claude Opus 4.8
parent 6ad0993a71
commit f1ef1c70b3
27 changed files with 1480 additions and 107 deletions
+10 -1
View File
@@ -22,6 +22,7 @@ Usage in a script:
from __future__ import annotations
import argparse
import os
from pathlib import Path
from urllib.parse import unquote, urlparse
@@ -48,8 +49,16 @@ def load_env(env: str) -> dict:
return out
def database_url(env: str) -> str:
"""Target DB URL. A DATABASE_URL in the process environment wins over
deploy/.env.<env> — this is how the API container (which has its own
DATABASE_URL and no deploy/.env files) drives a re-import against its own
database."""
return os.environ.get("DATABASE_URL") or load_env(env)["DATABASE_URL"]
def connect(env: str):
url = load_env(env)["DATABASE_URL"]
url = database_url(env)
u = urlparse(url) # mysql://user:pass@host:port/db
return pymysql.connect(
host=u.hostname,