Skip to main content
← Back to work

Governed risk-management platform inside Zoho Projects

Every project manager was supposed to log delivery risks each month. Nobody could tell who actually did, whose projects were flying blind, or what a risk looked like six months ago. The “risk register” was a spreadsheet nobody trusted and no one audited.

JavaScriptVanilla JSZohoZoho Projects Widget SDKZohoZoho Named ConnectionPythonPythonFlaskFlaskGoogle CloudGoogle Cloud RunPostgreSQLCloud SQL (PostgreSQL, IAM)asyncpgGoogle Cloud StorageGoogle Cloud StorageZohoZoho Analytics APISendGridGoogle ChatGoogle Chat API

How it fits together

01 Zoho Projects widget vanilla-JS SPA
02 Named Connection auth brokered by Zoho
03 Flask API Google Cloud Run
04 PostgreSQL Cloud SQL, IAM auth
Security principle

No token ever reaches the browser. Every call is brokered server-side by Zoho.

  • Zoho Analytics: the authoritative compliance join
  • SendGrid + Google Chat: per-owner alerts
risk platform / architecture

A global software consultancy ran dozens of concurrent client projects, each meant to report delivery risks every month. In practice risks lived as free-text comments buried in tasks. No register, no history, no access control, and no way for leadership to see which active projects were non-compliant or which risks were going stale.

“Risk tracking” was really two hard problems wearing one hat: a governed data model (risks need immutable history, soft-delete with recovery, and exactly one current version per project and category. Not rows you overwrite), and a compliance engine you can only trust if it joins the register against an authoritative source of truth for which projects are actually active and who owns them.

  • Built the frontend as a vanilla-JS single-page widget embedded in the Zoho Projects right panel. No framework, loaded as dependency-ordered modules with a stale-while-revalidate cache on Zoho app storage.
  • Brokered all auth through a Zoho Named Connection: the widget makes zero direct network calls and never holds a token. Zoho injects credentials server-side, and the Cloud Run backend is the only whitelisted egress.
  • Backed it with a Flask API on Cloud Run over PostgreSQL (Cloud SQL, IAM auth) with a seven-table schema: the register, an append-only audit timeline, a soft-delete archive, threaded discussions, and three JSONB settings tables.
  • Enforced ‘exactly one current risk per project and category’ as a Postgres partial unique index. A database-level invariant, not application hope. While preserving full version history.
  • Recorded every change as a field-level JSONB diff (from → to) with actor, IP, and parsed device: compliance-grade provenance for who changed what, from where.
  • Computed monthly PM compliance automatically, joining the register against live Zoho Analytics project metadata so cancelled projects never pollute the numbers, and pushed results to each owner via SendGrid email and Google Chat.
  • Built a category-locking create/edit/renew wizard that auto-detects intent and hard-aborts on category drift, plus an admin tool that parsed and de-duplicated the old pipe-delimited text risks into the new store.
  • Bridged synchronous Flask to the async Cloud SQL IAM connector with one long-lived event loop on a daemon thread. The connector attaches its RSA-key work to whatever loop exists at construction, so a fresh loop per request causes ‘Future attached to a different loop’ crashes.
  • Coordinated Zoho OAuth across a fleet of serverless workers with a GCS-backed distributed lock and a fleet-wide cooldown, so independent token refreshes stop tripping Zoho’s per-token throttle.
  • Made identity resilient to a company-wide email-domain migration and Unicode name mismatches (NFD normalization), so role and admin lookups don’t silently fail.
Risk record integrity
Overwritable spreadsheet rows, no history Versioned records with a DB-enforced single-current-version invariant + audit trail
Monthly PM compliance
Manual, unreliable, no authoritative active-project list Auto-computed per active project against live metadata, with per-PM alerts
Access control
Anyone on a project could edit risk text Backend-verified PM / PC / admin gate on view and every change
Deletion safety
Hard deletes, lost data Soft-delete with full provenance and restore

My role

Sole engineer. Widget frontend, Flask/PostgreSQL backend, data model, compliance engine, and the migration and rollout.

Stack & scope

Company-wide across the consultancy’s project portfolio: one risk register per project, served by a serverless backend tuned for a multi-dozen-worker fleet.

Client and internal identifiers changed to preserve confidentiality.