Scaling gitPlumbers: The Angular 20+ Code Analysis Platform for GitHub Apps, Zip Uploads, and Auto‑Fix Recommendations

Scaling gitPlumbers: The Angular 20+ Code Analysis Platform for GitHub Apps, Zip Uploads, and Auto‑Fix Recommendations

How I scaled gitPlumbers into a resilient Nx + Firebase + Docker pipeline that ingests GitHub repos and zip uploads, analyzes code at scale, and generates actionable remediation recommendations.

Rules first, AI optional. If your platform can explain every recommendation, teams will ship the fix today—not next quarter.
Back to all posts

I’ve lived the Monday-morning scramble: a director asks if we can scan 900+ repos and tell them which Angular apps can be upgraded to 20 without breaking prod—by Friday. gitPlumbers was built for that moment. It now ingests GitHub repos, accepts zip uploads for air‑gapped audits, runs Dockerized analyzers, and returns clear remediation steps—fast, explainable, and safe.

This is a platform & delivery breakdown of how I scaled it: Angular 20 + Signals/SignalStore on the front end (PrimeNG for data grids), Firebase for the control plane, and a container farm for analyzers. If you need an Angular consultant or want to hire an Angular developer to build similar enterprise tooling, here’s the playbook I actually ship.

The Monday Scene: GitHub Repos, Zip Dumps, and a Deadline

What landed on my desk

gitPlumbers had to scale from boutique audits to an always‑on pipeline. That meant secure GitHub integration, resumable uploads for zips, and analyzers that could fan out to thousands of jobs without melting the UX or the budget.

  • Hundreds of Angular repos across orgs

  • A zip dump from a vendor who couldn’t grant GitHub access

  • A request for actionable, prioritized fixes—not a PDF report

Constraints I treat as non‑negotiable

As companies plan 2025 Angular roadmaps, leadership wants deterministic timelines. That only happens if the platform is observable and the UX is calm under load. Signals and SignalStore do a lot of heavy lifting here.

  • No tokens in the browser beyond Auth—use a GitHub App + server webhooks

  • Multi‑tenant isolation with org/project scoping

  • Deterministic recommendations (rules first, AI optional)

  • Clear UX: job progress without jitter, cancel/retry, downloadable SARIF/JSON

Why Scaling a Code Analysis Platform Is Hard in 2025

Two ingestion modes, one truth

Both paths must end in the same job orchestration model. A Firestore job document is the single source of truth; analyzers read an artifact URL, write results, and emit progress events.

  • GitHub App: event‑driven, cheap, secure

  • Zip uploads: offline/air‑gapped audits, resumable, virus‑scanned

Speed and explainability

We prioritize rule‑based remediation with typed dependency graphs (pnpm-lock.yaml, package.json, tsconfig) and add LLM suggestions behind a feature flag for long‑tail issues. Teams can accept, modify, or ignore with clear diffs.

  • P95 scan time beats averages for planning

  • Explainable fixes land faster than black‑box AI

gitPlumbers Architecture: Nx Angular 20, Firebase Control Plane, Docker Analyzers

// libs/state/src/lib/ingestion.store.ts
import { signalStore, withState, withMethods, patchState } from '@ngrx/signals';
import { inject } from '@angular/core';
import { JobsApi } from '../data/jobs.api';

export interface IngestionState {
  connectingGitHub: boolean;
  uploadProgress: number; // 0-100
  queueDepth: number;
  recentJobs: { id: string; status: 'queued'|'running'|'done'|'error'; repo?: string }[];
}

const initial: IngestionState = {
  connectingGitHub: false,
  uploadProgress: 0,
  queueDepth: 0,
  recentJobs: []
};

export const IngestionStore = signalStore(
  withState(initial),
  withMethods((store) => {
    const api = inject(JobsApi);
    return {
      async enqueueRepo(owner: string, repo: string) {
        patchState(store, { connectingGitHub: true });
        try {
          const job = await api.createJob({ owner, repo });
          patchState(store, { recentJobs: [job, ...store.recentJobs()] });
        } finally {
          patchState(store, { connectingGitHub: false });
        }
      },
      setUploadProgress(p: number) {
        patchState(store, { uploadProgress: p });
      },
      updateQueueDepth(depth: number) {
        patchState(store, { queueDepth: depth });
      }
    };
  })
);

Front end: Angular 20 + Signals/SignalStore

The UI is an Angular 20 app with Signals to avoid over‑rendering when thousands of job toasts start flying. PrimeNG gives me production‑grade grids and filters out of the box.

  • Nx workspace with libs for models, API, and state

  • PrimeNG DataTable for results, TabView for per‑repo insights

  • SignalStore for ingestion and job orchestration state

Control plane: Firebase

Functions receive GitHub webhooks, enqueue tasks, and write jobs. Storage handles large zips with resumable uploads; an antivirus step (ClamAV in Cloud Run) protects the cluster.

  • Auth (GitHub/Email)

  • Firestore (jobs, results, tenants)

  • Storage (zip artifacts)

  • Functions + Cloud Tasks (webhooks, fan‑out)

  • Optional: Cloud Run for heavy services

Analyzers: Dockerized workers

Workers are ephemeral; they pull artifacts, run rules, and push results back. Horizontal scale is a knob, not a rewrite.

  • Node.js and .NET analyzers for framework‑specific checks

  • Contracts via a typed JSON schema for inputs/outputs

  • Results emitted as SARIF + JSON for UI and IDE consumption

Secure GitHub Ingestion: App Install, OAuth, Webhooks

// functions/src/webhooks.ts
import * as functions from 'firebase-functions/v2/https';
import { Octokit } from 'octokit';
import { getAppJwt, mintInstallationToken, enqueueJob } from './lib/github';

export const githubWebhook = functions.onRequest(async (req, res) => {
  const event = req.headers['x-github-event'];
  const installationId = req.body.installation?.id;
  if (!installationId) return res.status(400).send('no installation');

  const token = await mintInstallationToken(installationId);
  const octokit = new Octokit({ auth: token });

  const repo = req.body.repository?.full_name;
  const sha = req.body.after || req.body.pull_request?.head?.sha;

  await enqueueJob({ repo, sha, installationId });
  return res.status(202).send('enqueued');
});

Install and permissions

Enterprise clients love the audit trail a GitHub App provides. We store only the installation ID; tokens are minted just‑in‑time in Functions.

  • Use a GitHub App with repo:read, checks:write, metadata:read

  • Avoid PATs in the browser; redirect to server‑side OAuth

Webhook handler and fan‑out

One event → many checks. We batch by repo and branch to avoid duplicate work during busy merges.

  • Receive push and pull_request events

  • Debounce noisy repos; coalesce commits

  • Enqueue Firestore jobs via Cloud Tasks

Zip Uploads That Don’t Crash Browsers or Budgets

// apps/web/src/app/upload/upload.component.ts
@Component({ selector: 'gp-upload', templateUrl: './upload.html' })
export class UploadComponent {
  store = inject(IngestionStore);
  async onFile(file: File) {
    const { ref, uploadBytesResumable, getDownloadURL } = await import('firebase/storage');
    const r = ref(storage, `artifacts/${crypto.randomUUID()}/${file.name}`);
    const task = uploadBytesResumable(r, file);
    task.on('state_changed', s => this.store.setUploadProgress(Math.round(100*s.bytesTransferred/s.totalBytes)));
    await task;
    const url = await getDownloadURL(r);
    await this.store.enqueueRepo('zip','artifact:'+url); // unified path through job queue
  }
}

Client: resumable + Signals for calm UX

Zip uploads are for vendors, air‑gapped teams, or historical bundles. Progress and cancel/retry are first‑class.

  • Firebase Storage resumable uploads

  • SignalStore to show progress without jank

  • PrimeNG ProgressBar for clarity

Server: antivirus and artifact URLs

Artifacts never hit analyzer containers until they’re scanned. Results are attached back to the job doc for the UI to stream.

  • ClamAV in Cloud Run for scanning

  • Time‑scoped signed URLs passed to analyzers

Automated Remediation: Rules First, LLMs Optional

# rules/angular-upgrade.yaml
- id: rxjs-8-imports
  match: "import { of, from, map } from 'rxjs'"
  suggest: "Use path imports: 'rxjs/of', 'rxjs/map'"
  autofix:
    type: codemod
    command: npx rxjs-ts-morph-codemod --target=8
  docs: https://rxjs.dev/guides/v8-migration

- id: zone-cleanup
  match: tsconfig.json
  suggest: "Consider zoneless + Signals; migrate change detection incrementally"
  docs: https://angular.dev/guide/going-zoneless

Explainable rules

We ship a rule pack for Angular 9→20 upgrades, RxJS 7→8 changes, zone.js cleanup, and PrimeNG theming migrations.

  • Typed rules over AST and dependency graphs

  • Deterministic diffs as patches/PRs

When AI helps

LLM suggestions are annotated with confidence and links to docs. Teams can disable per‑tenant.

  • Long‑tail suggestions behind a feature flag

  • Safety: rate limits, content filters, retries with taxonomy

CI/CD and Scale: From One Repo to Thousands

# .github/workflows/gitplumbers-scan.yml
name: gitPlumbers Scan
on: [pull_request]
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with: { version: 9 }
      - run: pnpm i --frozen-lockfile
      - name: Upload lockfiles for dependency analysis
        run: |
          curl -X POST "$GP_API/jobs" \
            -H "Authorization: Bearer ${{ secrets.GP_TOKEN }}" \
            -F repo=${{ github.repository }} \
            -F sha=${{ github.sha }} \
            -F lock=@pnpm-lock.yaml \
            -F pkg=@package.json

Kick scans from CI

We keep compute near code. A lightweight CI step triggers scans and uploads lockfiles.

  • Checks API comments on PRs

  • Artifacts uploaded once; reused by analyzers

Autoscale analyzers

Bursty traffic is normal after branch cutoffs. Autoscaling saves cost while keeping P95 under target.

  • Cloud Run minInstances=0, maxInstances tuned

  • Warm caches for pnpm/npm

Observability and Metrics That Keep You Honest

Measure what matters

Angular DevTools and Lighthouse don’t matter here—latency and clarity do. In the UI, Signals stream job state while we chart throughput with PrimeNG + Highcharts.

  • P95 scan time per repo size bucket

  • Queue depth and time‑to‑first‑result

  • Recommendation acceptance rate

  • Cost per 100 scans

Telemetry and alerting

When a rule regresses, we can roll it back in seconds with Firebase Remote Config.

  • OpenTelemetry traces from Functions and analyzers

  • Firebase Logs‑based alerts to Slack

  • Feature flags for risky rules

When to Hire an Angular Developer for Legacy Rescue

You likely need help if

This is where an Angular expert earns their keep. If you need to stabilize and modernize fast, I can step in as a remote Angular developer or Angular consultant and get you to green builds without outages. See how we can "stabilize your Angular codebase" at gitPlumbers.

  • Your repos span Angular 9–15 and you can’t inventory debt

  • CI is flaky after AI‑generated refactors

  • You need deterministic migration plans with rollbacks

Engagement patterns that work

Discovery call within 48 hours. Assessment in 1 week. Pilot org in 2–4 weeks. Then scale.

  • 2–4 week assessment with dashboards and rule packs

  • 4–8 week upgrade/migration sprints

  • Ongoing CI policy + analyzer tuning

Example Walkthrough: Scanning a Telecom Analytics Repo

From webhook to pull request comment

In one recent run (ads analytics platform for a telecom provider), P95 was 6m12s across 130 repos. 72% of autofixes merged cleanly; the rest generated PRs with code diffs and screening notes for reviewers.

  • Webhook enqueues job → analyzer pulls lockfiles → rules run → SARIF posted

UX under load

The UI stayed at 60fps on mid‑range laptops during multi‑org scans. That’s the difference Signals + careful change detection make.

  • Signals kept render counts low; no spinner storms

  • PrimeNG DataTable virtualized 25k+ findings

Practical Takeaways and Next Instrumentation

If you copy one thing, copy this

You can add fancy later. Deterministic foundations pay off forever.

  • Single job model for both GitHub and zips

  • Rules first, AI optional

  • SignalStore for calm, reliable state

What to instrument next

Tie every metric back to business outcomes—faster upgrades, fewer outages, lower CI cost.

  • Auto‑PR merge rate vs. revert rate

  • Time to first green build after recommendations

  • Tenant‑level cost and cache hit ratios

Related Resources

Key takeaways

  • Use a GitHub App for secure, event-driven ingestion; zip uploads cover private/offline repos.
  • Model all ingestion and scan state with SignalStore to avoid jittery UX under load.
  • Separate the analyzer farm (Docker) from the control plane (Firebase/Firestore) to scale safely.
  • Blend static rules with typed dependency graphs for fast, explainable remediation; keep LLMs optional.
  • Instrument P95 scan time, queue depth, and recommendation acceptance rate to target real outcomes.

Implementation checklist

  • Register a GitHub App with repo:read, checks:write, and webhooks for push/pull_request.
  • Provision Firebase: Auth (GitHub + Email), Firestore (multi-tenant), Storage (resumable uploads), Functions (webhooks), Cloud Tasks/Run (worker fan-out).
  • Create an Nx monorepo: Angular 20+ app, shared libs, analyzer contracts, and Firebase Functions.
  • Implement SignalStore for ingestion + job orchestration state; use PrimeNG to visualize jobs/queues.
  • Build Dockerized analyzers (Node.js/.NET) that pull artifacts, run rules, post results.
  • Set CI with GitHub Actions to trigger scans, build/push analyzer images, and e2e with Cypress.
  • Add observability: OpenTelemetry traces, Firebase Logs, custom metrics for P95 and queue depth.
  • Gate releases with feature flags; ship incrementally (org-level pilots before global enablement).

Questions we hear from teams

How much does it cost to hire an Angular developer to build a code analysis platform?
Most teams start with a 2–4 week assessment ($12k–$30k) to validate architecture and ROI, then 4–8 week delivery sprints. Fixed‑fee pilots are available for one org or 50–100 repos. I’m a remote Angular consultant and can scope quickly after a 30‑minute call.
How long does GitHub App integration and zip upload support take?
A secure GitHub App with webhooks typically ships in 3–5 days. Zip uploads with resumable storage and antivirus add 2–3 days. End‑to‑end with dashboards and SignalStore usually fits in a 2‑week sprint if environments are ready.
What does automated remediation include?
Deterministic rules for Angular upgrades, RxJS 8 changes, zone.js cleanup, and PrimeNG theming. Optional AI suggestions are gated by feature flags. Output is SARIF/JSON and PRs with diffs so reviewers can accept or tweak confidently.
Will this work with our CI/CD (GitHub Actions, Jenkins, Azure DevOps)?
Yes. We use a simple API trigger and artifact upload pattern that ports to GitHub Actions, Jenkins, and Azure DevOps. Analyzers run in Docker, so you can host on AWS/GCP/Azure or on‑prem. Observability is via OpenTelemetry and Firebase Logs.
What’s involved in a typical engagement?
Discovery call within 48 hours. Assessment deck and metrics in 1 week. Pilot org scans in weeks 2–4. Rollout with CI policy and rule tuning in weeks 4–8. I can continue as an Angular contractor to maintain analyzers and dashboards.

Ready to level up your Angular experience?

Let AngularUX review your Signals roadmap, design system, or SSR deployment plan.

Hire Matthew — Remote Angular Expert, Available Now See gitPlumbers Code Rescue in Action

NG Wave

Angular Component Library

A comprehensive collection of 110+ animated, interactive, and customizable Angular components. Converted from React Bits with full feature parity, built with Angular Signals, GSAP animations, and Three.js for stunning visual effects.

Explore Components
NG Wave Component Library

Related resources