[object Object]

← back to build-pages

api: /api/fleet/all one-shot aggregate (projects + velocity + recent + top skills/agents) + 4 smoke

b6ddd076403021d2f0fc3c0d1ca9199c2a7fbaaf · 2026-05-13 17:43:03 -0700 · SteveStudio2

Files touched

Diff

commit b6ddd076403021d2f0fc3c0d1ca9199c2a7fbaaf
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 17:43:03 2026 -0700

    api: /api/fleet/all one-shot aggregate (projects + velocity + recent + top skills/agents) + 4 smoke
---
 server.js     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 test/smoke.js |  7 +++++++
 2 files changed, 52 insertions(+)

diff --git a/server.js b/server.js
index 7d3a03c..2fe46ca 100644
--- a/server.js
+++ b/server.js
@@ -630,6 +630,50 @@ app.get('/p/:slug/c/:hash', async (req, res, next) => {
   } catch (e) { next(e); }
 });
 
+// /api/fleet/all — one-shot aggregate for dashboards that don't want to make
+// 5 separate calls. Pulls velocity + top agents + top skills + recent commits
+// in parallel. Each piece is already cache-warm via the per-repo bundle, so
+// this lands in ~5-15ms after the first hit.
+app.get('/api/fleet/all', async (_req, res, next) => {
+  try {
+    const now = Date.now();
+    const dayMs = 24 * 60 * 60 * 1000;
+    let last24 = 0, last7d = 0;
+    const recent = [];
+    const skillTallies = new Map(), agentTallies = new Map();
+    const byProject = [];
+    for (const [slug, p] of Object.entries(PROJECTS)) {
+      const bundle = await getProjectBundle(slug, p).catch(() => null);
+      if (!bundle) continue;
+      let d24 = 0, d7 = 0;
+      for (const c of bundle.commits) {
+        const age = now - new Date(c.dateISO).getTime();
+        if (age < dayMs) d24++;
+        if (age < 7 * dayMs) d7++;
+      }
+      last24 += d24;
+      last7d += d7;
+      byProject.push({ slug, name: p.name, commits: bundle.commits.length, last_24h: d24, last_7d: d7 });
+      for (const c of bundle.commits.slice(0, 10)) {
+        recent.push({ slug, project: p.name, hash: c.shortHash, date: c.dateISO, subject: c.subject });
+      }
+      for (const f of bundle.facets.skills) skillTallies.set(f.name, (skillTallies.get(f.name) || 0) + f.count);
+      for (const f of bundle.facets.agents) agentTallies.set(f.name, (agentTallies.get(f.name) || 0) + f.count);
+    }
+    recent.sort((a, b) => (b.date < a.date ? -1 : b.date > a.date ? 1 : 0));
+    const top = (m) => [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, 15).map(([name, count]) => ({ name, count }));
+    res.setHeader('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
+    res.json({
+      projects: byProject,
+      velocity: { last_24h: last24, last_7d: last7d },
+      recent:   recent.slice(0, 10),
+      top_skills: top(skillTallies),
+      top_agents: top(agentTallies),
+      as_of: new Date().toISOString(),
+    });
+  } catch (e) { next(e); }
+});
+
 // /api/fleet/velocity — commit counts in rolling windows across every project.
 // Returns total + per-project breakdown for last-24h and last-7d. Useful for
 // "is the work continuing?" dashboards. Same cache lifetime as /api/fleet/*.
@@ -908,6 +952,7 @@ app.get('/api', (_req, res) => {
       'GET /api/fleet/agents':                 'Fleet-wide agent tallies merged across every project',
       'GET /api/fleet/skills':                 'Fleet-wide skill tallies merged across every project',
       'GET /api/fleet/velocity':               'Commits-per-rolling-window across the fleet — last 24h + last 7d, with per-project breakdown',
+      'GET /api/fleet/all':                    'One-shot dashboard aggregate — velocity + recent + top skills/agents + per-project counts',
       'GET /p/:slug':                          'Project journal HTML page (?q= deep-link supported)',
       'GET /p/:slug/c/:hash':                  'Commit detail page — full diff + body',
       'GET /p/:slug/feed.atom':                'Atom 1.0 feed — up to 50 recent commits, autodiscovered on project page',
diff --git a/test/smoke.js b/test/smoke.js
index 8e4c412..ca8cdfd 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -212,6 +212,13 @@ function check(name, cond, hint = '') {
     check(`fleet/${f}: field`,       new RegExp(`"${f}":\\[`).test(r.body));
   }
 
+  // 13b4. fleet/all — one-shot aggregate
+  r = await fetch('/api/fleet/all');
+  check('fleet/all: 200',          r.status === 200);
+  check('fleet/all: projects',     /"projects":\[/.test(r.body));
+  check('fleet/all: velocity',     /"velocity":/.test(r.body));
+  check('fleet/all: top_skills',   /"top_skills":\[/.test(r.body));
+
   // 13b3. fleet/velocity — rolling-window commit counts
   r = await fetch('/api/fleet/velocity');
   check('fleet/velocity: 200',     r.status === 200);

← 982149f p/:slug: per-project velocity (last 24h + last 7d) in meta l  ·  back to build-pages  ·  ui: prev/next project nav on /p/:slug — wraps at registry en 0c0d61c →