Skip to content

Ops Nervous System

Status: Design complete; Phase 0 pending Nisarg. Owner: Dan (app layer), Nisarg (replica infrastructure, one-time) Last updated: 2026-04-18

Vision

Every person at Scott Recycling always knows their numbers and where they should be — in real time, through their phone. Dan's Personal Assistant becomes company-aware and delivers specific, grounded, actionable briefs. A single live data surface powers both systems; the app layer evolves fast without ever touching Odoo production.

The shorthand: prod Odoo is the museum — curated, protected, slow-moving. The app layer is the workshop — fast, messy, and owned by Dan. A live read-only replica is the clean window between them.

Architecture — three layers

Layer 1: Replica (Nisarg-owned, one-time setup)

A PostgreSQL streaming read replica of the Odoo production database, hosted on EXP.

  • Primary stays on prod (untouched).
  • Replica runs as a second Postgres cluster on EXP, on port 5433.
  • WAL streams from prod to replica within milliseconds.
  • Physically read-only at the engine level — no query from any app can write anything, ever.
  • All Odoo tables mirrored — not a curated subset. Everything is available.

Two Postgres roles created on the replica:

  • dan_assistant_readerSELECT on all tables. For the Personal Assistant.
  • scoreboard_readerSELECT only on operational tables (pickups, boxes, KPIs, employees, attendance, trucks, etc.). For the new sr-pulse employee-facing app.

Layer 2: Reporting DB (Dan-owned, writable)

The existing scott_reporting database on EXP is repurposed as a derived/aggregated data store:

  • Daily/weekly/monthly employee rollups (pre-aggregated; queries are instant)
  • Trend tables and 30/60/90-day baselines
  • Cross-system joins (Odoo + Health ERP + Financial + Superstore)
  • Targets per role/metric

Populated by scheduled ETL jobs Dan writes: Replica → ETL → reporting DB → apps.

Layer 3: Apps (Dan-owned, fast-moving)

Two independent applications, both reading the replica:

  • Personal Assistant (/opt/personal-assistant) — existing Django app. Gains a 5th adapter via dan_assistant_reader. Its 6:30am / 1pm / 9pm briefs become company-aware.
  • sr-pulse (new, /opt/sr-pulse) — employee-facing Django app. Reads via scoreboard_reader. Delivers mobile PWAs, scoreboards, and nudges.

The two apps never share a process or a Postgres role. Security boundary enforced architecturally.

Key principles

  • Real-time during the day, not end-of-shift digests. Production employees need live PWAs that update as they add units — scoreboards that affect behavior while it's happening, not after.
  • Targets defined over time, not up front. Pilot launches with count-only views; targets fill in per position as Dan and managers set realistic numbers. Architecture supports no-target, target-defined, and target-revised states without code changes.
  • Reports become nudges become products. Don't plan exhaustively; build the ability to create any report/nudge in minutes. Discover value by running things, then codify what works.
  • Odoo changes stay Nisarg's. New fields, modified views, workflows — all in Odoo. The app layer never tries to replace Odoo; it consumes and signals.

Scope boundaries

In scope (app layer, Dan-owned):

  • Reading, computing, deciding, signaling
  • Scoreboards, leaderboards, dashboards, PWAs
  • SMS, email, PDF exports, webhooks
  • LLM summaries, anomaly explanations, Q&A over data
  • Cross-system views combining Odoo with other business systems

Out of scope (stays in Odoo, Nisarg-owned):

  • Adding new Odoo data types, fields, or models
  • Modifying Odoo's UI, forms, reports, or workflows
  • Writing back into Odoo records (narrow XML-RPC exceptions if truly needed)

Phased rollout

Phase 0 — Replica plumbing (Nisarg, one-time, ~2–3 hours) See Replica Phase-0 Spec.

Phase 1 — First pilot scoreboard (Dan, ~2–3 days)

  • Role: sort line techs
  • Metric: boxes_sorted today
  • Primary delivery: mobile PWA each tech opens on their phone or workstation. Live count, updating within seconds as boxes are added in Odoo.
  • Secondary delivery: end-of-shift SMS summary.
  • Targets are initially count-only; realistic per-shift numbers defined with the warehouse manager during pilot.

Phase 2 — Personal Assistant replica adapter (Dan, ~2 hours)

  • 5th adapter added to /opt/personal-assistant; existing 6:30am / 1pm / 9pm briefs gain live company data.

Phase 3 — Fan-out (Dan, ongoing)

  • More scoreboards for more roles: dispatch, sales, office, yard, warehouse.
  • Manager-facing digests ("who needs a conversation today").
  • Employee-facing PWAs.

Phase 4 — LLM personalization + corrective actions (Dan, ongoing)

  • Claude drafts personalized messages grounded in real per-person data.
  • Review loop before auto-send; then turn on.
  • Pre-curated corrective action menu per role/metric.

Phase 5 — Cross-system reporting (Dan, ongoing)

  • Combine replica with Financial, Health ERP, Superstore, Personal Assistant data.
  • Unified business dashboard.

Roles

  • Nisarg — Phase 0 only (replica + roles + brief README). After that, out of the critical path for this initiative. Optionally later: configure base_automation webhook triggers for event-driven nudges.
  • Dan — app layer. Queries, ETL, prompts, delivery, UX, iteration.
  • Claude — drafting content, helping design, grounded analysis of replica data.

Success criteria

Phase 0 complete when:

  • psql as scoreboard_reader against the replica connects and reads the expected operational tables.
  • A row updated on prod appears in the replica within 2 seconds.
  • A write attempt as scoreboard_reader is rejected by Postgres.

Phase 1 complete when:

  • A sort line tech has a PWA open showing their live boxes_sorted count for the shift, updating within seconds as they add boxes in Odoo.
  • End-of-shift SMS lands with the final count and a one-line supportive message.

Steady state:

  • Dan ships a new report or nudge in under an hour, end to end.
  • Nisarg is not on the critical path for any of it.
  • Every employee knows their numbers every day.