Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Growth Charter Renderer — PDGMS CRM Module

A fullstack web application that renders personalized Growth Charter documents from CRM node data stored in MongoDB. Built for the DeepThought Full-Stack Developer assignment.

What This Does

The Growth Charter is an auto-generated narrative document that mirrors a manufacturing company founder's growth ambition, execution gaps, and infrastructure reality back to them. It's assembled from structured CRM node data — not written by hand.

This app:

  1. Stores CRM node data in MongoDB — 10 classification nodes per company, each with 8 possible values
  2. Renders a Growth Charter — uses a markdown template, regex pattern, and render map to convert node values into readable narrative text
  3. (Part B) Extracts node values from a founder conversation transcript using Google's Gemini API

Setup Instructions

Prerequisites

  • Node.js (v18+)
  • MongoDB (local install or Atlas free tier)
  • (Optional) Gemini API key from Google AI Studio for Part B

Steps

# 1. Clone the repo
git clone <your-repo-url>
cd growth-charter-renderer

# 2. Install dependencies
npm install

# 3. Configure environment
cp .env.example .env
# Edit .env with your MongoDB URI (default: mongodb://localhost:27017/growth-charter)
# For Part B: add your GEMINI_API_KEY

# 4. Start MongoDB (if running locally)
mongod

# 5. Start the app
npm start
# Server runs at http://localhost:3000

# 6. Open browser → http://localhost:3000
# Click "Seed Database" to load sample data
# Select "Sureflow Formulations" → View Growth Charter

Architecture Overview

Frontend (Vanilla JS)  →  Express API  →  MongoDB
     |                       |                |
  index.html            /api/seed         accounts collection
  charter.html          /api/accounts     nodes collection
  extract.html          /api/charter/:id
                        /api/extract

Frontend: Static HTML + vanilla JavaScript. No React or framework — this is a document renderer, not a SPA. The charter page fetches rendered HTML from the API and injects it into the DOM.

Backend: Node.js + Express. Four routes handle seeding, listing accounts, rendering charters, and (Part B) transcript extraction. The rendering logic lives in server/lib/renderCharter.js.

Database: MongoDB with Mongoose. Two collections: accounts (company info) and nodes (one document per classification dimension per company, linked by accountId).

Rendering happens server-side: The backend builds a placeholder map from node data + render map, replaces {{placeholders}} in the markdown template using a regex, converts to HTML with marked, and sends the final HTML to the frontend.


Which Parts of context.md Drove the Data Model

  1. Node structure (Section "What Is a Node?") — Each node has a nodeId, name, value (1-8), optional companion fields, and optional verbatim fields. This directly maps to the nodes collection schema.

  2. Companion fields summary table — K1 has name/title/background, F2 has actualRevenue/revenueSource, C7 has systemsInUse, D2 has primaryMetric/currentValue/targetValue. These are stored as a flexible Mixed type in Mongoose because each node has different companion fields.

  3. The placeholder-to-data mapping table (Step 3) — This table in context.md is basically the spec for renderCharter.js. Each placeholder maps to either an account field, a render-map lookup, or a companion field. I built the placeholder map exactly from this table.

  4. Verbatim table handling (Step 5) — context.md says verbatim table replacement must happen BEFORE the main regex pass. This drove the order of operations in the rendering function.

  5. Compound unique index { accountId: 1, nodeId: 1 } — Directly from the MongoDB schema section. Prevents duplicate node entries.


Key Design Decisions

Why Vanilla JS instead of React

The assignment says "any framework." But the app has two pages: a form and a document display. React would be overkill and would signal "I used a generator" rather than "I understood the problem." The rendering complexity is server-side (template + regex), not client-side.

Guardrails Against AI Hallucination

  1. Render map key type mismatchrender-map.json uses string keys ("1") but seed-data.json stores values as numbers (1). I convert to string before lookup (String(node.value)) and assert the result isn't undefined.

  2. Verbatim table replacement ordercontext.md explicitly says to replace {{verbatimTable}} before the main regex pass. I do this in two separate steps in renderCharter.js.

  3. Gemini response parsing — LLMs often wrap JSON in markdown code fences. I strip ```json wrappers before parsing and validate the response structure.


What I'd Improve With More Time

  1. Add a node editor — Let a DT consultant score nodes directly in the browser instead of only seeding from JSON. A form with 10 dropdowns (one per node), companion field inputs, and a save button. This would make the app actually usable in a workflow.

  2. Charter version history — Store each rendered charter as a snapshot with a timestamp, so you can see how a company's charter changed as nodes were re-scored over time.

  3. Structured validation for Part B — After Gemini extracts nodes, show each extracted value alongside the actual transcript quote that supported it, and let the user correct any misclassifications before saving. Right now the review step just shows node IDs and values.

  4. PDF export — Add a "Download as PDF" button using a library like puppeteer or html-pdf. The Growth Charter is meant to be shared with founders, and PDF is the natural format for that.

  5. Will be pasting the google drive link for the video walkthrough!


Project Structure

growth-charter-renderer/
├── server/
│   ├── index.js              # Express server entry point
│   ├── models/
│   │   ├── Account.js        # Mongoose schema for accounts
│   │   └── Node.js           # Mongoose schema for nodes
│   ├── routes/
│   │   ├── seed.js           # POST /api/seed — load sample data
│   │   ├── accounts.js       # GET /api/accounts — list all
│   │   ├── charter.js        # GET /api/charter/:id — render charter
│   │   └── extract.js        # POST /api/extract — Gemini extraction (Part B)
│   ├── lib/
│   │   ├── renderCharter.js  # Core rendering logic (template + regex + render map)
│   │   └── gemini.js         # Gemini API wrapper for Part B
│   └── data/
│       ├── seed-data.json    # Sample company data from assignment
│       ├── render-map.json   # Node value → text mapping from assignment
│       ├── sample-transcript.json  # Sample transcript for Part B
│       └── charter-template.md    # Markdown template with {{placeholders}}
├── public/
│   ├── index.html            # Homepage — seed + account selector
│   ├── charter.html          # Charter display page
│   ├── extract.html          # Part B — transcript input
│   ├── css/style.css         # Styles
│   └── js/
│       ├── main.js           # Homepage logic
│       ├── charter.js        # Charter display logic
│       └── extract.js        # Part B logic
├── .env.example
├── .gitignore
├── package.json
└── README.md

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages