Reports: the LLM reliably used company_enrichment for prose fields but
inconsistently populated the parallel Finding-list/string-list fields from
the same evidence, even with progressively more explicit prompting. Add a
code-level backfill (products, recent developments, financial signals,
strategic initiatives, regulatory signals, risks/opportunities mirrored
from SWOT, unknowns, monitoring recommendations) that only ever fills in
what the model left empty, never overwrites what it produced.
Enrichment tab: reorder sections (Products/Recent updates before
Customers/Competitors) and add a per-section "Refresh" button that
re-fetches just one of NinjaPear's six independent per-company endpoints
when it came back empty - confirmed live that a data-coverage gap (e.g.
Amazon returning no products) is real provider behavior, not a bug.
Auth: the first account registered on a deployment with zero existing
admins is now auto-promoted to admin, closing the chicken-and-egg gap
where the only path to admin access was direct DB access. Self-heals if
the last admin ever deletes their account.
Also bumps nginx's proxy_read_timeout for api.ciagent.org to cover the
enrichment refresh's synchronous funding-endpoint call (up to 5 minutes
per NinjaPear's docs).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Local dev gets an unauthenticated Adminer instance bound to loopback
only. In production, any account with is_admin=true can open it -
the app mints a short-lived token from a live admin session, which
Nginx's new db.ciagent.org block exchanges for a session cookie that
re-checks admin status on every request, instead of a shared static
password that wouldn't scale to multiple admins or revoke live.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
scripts/auto-deploy.sh + a systemd timer (2min interval) that fetches
origin/master and, if ahead, pulls/rebuilds/migrates/restarts - same
sequence as the manual update steps in DEPLOYMENT.md, just scheduled.
Polling instead of a Gitea webhook deliberately: no extra exposed
service, no Docker socket mounted into a container, no shared secret
to manage - it's the same trust boundary as a manual SSH deploy.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
COPY --chown fixes the files being copied in, but WORKDIR had already
created /app as root beforehand - the directory entry itself stayed
root:root (no write bit for appuser), so celery beat's schedule-file write
still failed with Permission denied even after the earlier --chown fix.
Confirmed live on the actual deployment (local testing hadn't caught this).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Sets up everything needed to deploy behind Cloudflare with a self-hosted
git server: multi-stage prod Dockerfiles (non-root), docker-compose.prod.yml
(Postgres/Redis with no host ports, Nginx reverse proxy, Gitea with
public-read/admin-write access control), scripts/bootstrap-env.sh to
auto-generate required secrets on first clone, and DEPLOYMENT.md covering
the full runbook. Provider API keys (Anthropic/Brave/NinjaPear/USPTO/
Turnstile) are deliberately kept out of .env in favor of the existing
DB-backed Settings UI, so the public repo stays safe to expose.
Also fixes two bugs only surfaced by live-testing the prod stack: Celery
beat couldn't write its schedule file as a non-root user, and Gitea's
embedded SSH server conflicted with the base image's own sshd on port 22.
Co-Authored-By: Claude Sonnet 5 <[email protected]>