Skip to content

dougdevitre/cotrackpro-partner-engine

Repository files navigation

cotrackpro-partner-engine

LinkedIn PDF → GitHub Pages professional website engine with Claude-powered copy, a widget system, and per-professional repo provisioning.


What It Does

  1. Parses a LinkedIn PDF export into structured profile.json
  2. Enhances the raw data with Claude — rewrites copy into website-ready headlines, bios, positioning statements, and speaking topics
  3. Generates a static HTML site from a configurable widget set
  4. Deploys to GitHub Pages automatically via Actions
  5. Provisions each professional into their own private repo with collaborator access and PR previews

Quick Start

Prerequisites

# macOS
brew install poppler gh

# Ubuntu
sudo apt-get install -y poppler-utils
sudo apt-get install -y gh

# Node.js 20+
node --version

# GitHub CLI auth
gh auth login

Install

git clone https://github.com/dougdevitre/cotrackpro-partner-engine.git
cd cotrackpro-partner-engine
npm install

Test with your own profile

# 1. Export your LinkedIn profile as PDF
#    LinkedIn → Me → View Profile → More → Save to PDF

# 2. Parse it
npx ts-node cli/parse-linkedin.ts ~/Downloads/your-profile.pdf input/

# 3. Enhance with Claude
export ANTHROPIC_API_KEY=sk-ant-...
npx ts-node cli/enhance-profile.ts input/profile.json input/profile.json

# 4. Generate a default config
npx ts-node cli/generate-config.ts input/profile.json config.json

# 5. Build the site
npm run build

# 6. Preview locally
npm run dev   # → http://localhost:3000

Provisioning a New Professional

One command creates a private GitHub repo, parses their PDF, enhances with Claude, generates their config, commits everything, adds them as a collaborator, and enables GitHub Pages.

export ANTHROPIC_API_KEY=sk-ant-...

./scripts/provision.sh \
  lois-creamer \                          # slug (becomes repo name + Pages URL)
  loiscreamerGitHubUsername \             # their GitHub username (gets write access)
  ~/Downloads/lois-creamer-linkedin.pdf \ # their LinkedIn PDF export
  dougdevitre                             # your GitHub org or username

Output:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  ✅ Provisioning complete!

  Name:      Lois Creamer
  Repo:      https://github.com/dougdevitre/lois-creamer
  Site:      https://dougdevitre.github.io/lois-creamer/
  Access:    @loiscreamerGitHubUsername has write access (invite sent)

  ⏳ GitHub Actions is building the site now.
     The URL goes live in ~2 minutes after the first deploy.

  📧 Send them this link to get started:
     https://github.com/dougdevitre/lois-creamer/blob/main/COLLABORATOR.md
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Manage Your Sites

# List all provisioned sites
npm run list

# List + check live HTTP status
./scripts/list-sites.sh --check

# Trigger rebuild on all sites (after engine update)
export DISPATCH_TOKEN=ghp_...
./scripts/rebuild-all.sh

# Dry run — see what would be triggered
./scripts/rebuild-all.sh --dry-run

Widget System

Each professional configures their site via config.json. Widgets are rendered top-to-bottom in the order listed.

Widget ID Description Key options
hero Name, headline, photo, location, social links Always on
about Bio + positioning statement Auto from _enhanced
speaking Speaking topics, fee, CTA topics, fee, cta, ctaUrl
services Service cards grid items[] with icon/title/desc
experience Career timeline maxItems
education Education history None
skills Skills tag cloud maxItems
highlights Claude-generated career bullets items[]
testimonials Client quotes items[] with quote/author/title
media "As Seen In" logo bar logos[] with name/url/logoUrl
calendar Calendly/Cal.com booking embedUrl, style (button/embed)
video YouTube or Loom embed youtubeId or loomUrl
newsletter Email capture form mailchimpUrl or convertkitUrl
contact Contact info + optional form email, phone, linkedin, formspreeId
cta Full-width CTA banner label, subtext, url

Enable/disable a widget

{ "id": "testimonials", "enabled": true }

Reorder widgets

Move entries up/down in the widgets array in config.json.


Themes

Three professionally designed themes — each with light + dark mode.

Theme Best for Accent
speaker Speakers, coaches, consultants Warm amber gold
executive C-suite, investors, board members Sharp navy blue
advocate Attorneys, advocates, social impact Forest green

Set in config.json:

{ "theme": "speaker" }

Pipeline: How a Professional's Site Stays Updated

Professional pushes to their repo
         │
         ▼
  GitHub Actions triggers
         │
    ┌────┴────┐
    │ PDF?    │ → parse-linkedin.ts → profile.json
    └────┬────┘
         │
    ┌────┴────────┐
    │ _enhanced?  │ → enhance-profile.ts (Claude API)
    └────┬────────┘
         │
    generate-site.ts
         │
         ▼
    site/index.html + style.css
         │
         ▼
    gh-pages branch → GitHub Pages live

PR flow:

Collaborator opens PR
         │
         ▼
  preview-pr.yml builds preview
         │
         ▼
  Bot posts preview URL as comment
         │
         ▼
  Collaborator reviews → merges
         │
         ▼
  build-deploy.yml → site goes live

Cascade rebuild (engine updates):

You push widget/theme update to engine repo
         │
         ▼
  cascade-rebuild.yml dispatches workflow_dispatch
  to every repo in profile-registry.json
         │
         ▼
  All client sites rebuild with new engine

Repository Structure

cotrackpro-partner-engine/
├── cli/
│   ├── parse-linkedin.ts       # PDF → profile.json (pdftotext-based)
│   ├── enhance-profile.ts      # profile.json → Claude-enhanced copy
│   ├── generate-config.ts      # profile.json → default config.json
│   ├── generate-site.ts        # profile.json + config.json → site/
│   ├── build-assets.ts         # Pre-minify CSS/JS for all themes
│   └── validate-config.ts      # Validate config + profile data
├── widgets/
│   ├── index.ts                # Registry + renderer
│   ├── hero.ts, about.ts, experience.ts, education.ts
│   ├── skills.ts, highlights.ts, speaking.ts, services.ts
│   ├── testimonials.ts, media.ts, calendar.ts, video.ts
│   ├── newsletter.ts, contact.ts, cta.ts
│   ├── faq.ts                  # FAQ accordion (Claude-generated)
│   └── certifications.ts       # Certifications list
├── utils/
│   ├── cache.ts                # Content-hash build cache
│   ├── escape.ts               # XSS protection (HTML/URL escaping)
│   └── minify.ts               # Lightweight CSS/JS minification
├── themes/
│   ├── base.css                # Layout, reset, shared components
│   ├── speaker.css             # Warm amber editorial
│   ├── executive.css           # Sharp navy
│   └── advocate.css            # Forest green
├── tests/
│   ├── parse-linkedin.test.ts  # PDF parsing tests
│   ├── escape.test.ts          # XSS/URL safety tests
│   ├── widgets.test.ts         # All 17 widget rendering tests
│   ├── generate-config.test.ts # Config generation tests
│   ├── validate-config.test.ts # Validation rule tests
│   ├── minify.test.ts          # Minification tests
│   ├── build-pipeline.test.ts  # End-to-end integration tests
│   └── fixtures.ts             # Shared test helpers
├── scripts/
│   ├── provision.sh            # Create new professional repo end-to-end
│   ├── batch-provision.sh      # Bulk provision from CSV
│   ├── list-sites.sh           # Status dashboard
│   └── rebuild-all.sh          # Trigger cascade rebuild manually
├── .github/workflows/
│   ├── build-deploy.yml        # Main deploy pipeline (in client repos)
│   ├── preview-pr.yml          # PR preview + comment (in client repos)
│   └── cascade-rebuild.yml     # Engine → trigger all clients (in engine repo)
├── schema/
│   ├── profile.schema.json
│   └── config.schema.json
├── example/
│   ├── profile.json            # Lois Creamer example
│   └── config.json
├── types.ts                    # Shared TypeScript interfaces
├── vitest.config.ts            # Test configuration
├── profile-registry.json       # Auto-managed list of all provisioned sites
├── package.json
├── tsconfig.json
└── README.md

Secrets & Security

Secret Where Used for
ANTHROPIC_API_KEY Client repo → Settings → Secrets Claude enhancement in CI
GITHUB_TOKEN Auto-provided by Actions Pages deploy (no setup needed)
DISPATCH_TOKEN Engine repo → Settings → Secrets Cascade rebuild across client repos

Setup ANTHROPIC_API_KEY per client repo:

gh secret set ANTHROPIC_API_KEY \
  --repo dougdevitre/lois-creamer \
  --body "sk-ant-..."

Or set for all repos at org level (if using GitHub org):

GitHub Org → Settings → Secrets → Actions → New org secret

Custom Domain

Add to config.json:

{ "meta": { "customDomain": "www.loiscreamer.com" } }

Then in the domain's DNS, add a CNAME record:

www → dougdevitre.github.io

The build pipeline writes a CNAME file to the Pages branch automatically.


Adding a New Widget

  1. Create widgets/my-widget.ts:
import { LinkedInProfile } from "../types";

export function myWidget(
  profile: LinkedInProfile,
  options: Record<string, unknown>
): { html: string; warning?: string } {
  return { html: `<section class="widget widget-my" data-widget="my">...</section>` };
}
  1. Register in widgets/index.ts:
import { myWidget } from "./my-widget";
const WIDGET_REGISTRY = {
  // ...existing
  my: myWidget,
};
  1. Add CSS to themes/base.css (or per-theme files for overrides)

  2. Add to example/config.json under widgets

  3. Push to engine repo → cascade-rebuild.yml optionally triggers all clients


Local Development

# Parse, enhance, and build in one go
npm run parse -- ~/Downloads/profile.pdf input/
npm run enhance -- input/profile.json input/profile.json
npm run config -- input/profile.json config.json
npm run build
npm run dev    # localhost:3000

# Or shorthand if profile.json + config.json are already in input/
npm run build && npm run dev

License

Private — for use by Doug DeVitre and authorized clients.

Built with cotrackpro-partner-engine.

About

Strategic partner matching engine — connecting families with vetted service providers, attorneys, and support organizations by jurisdiction.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors