[object Object]

← back to build-pages

api: /api/fleet/buckets — daily commit buckets with ISO labels (fleet + per-project) + 3 smoke

e8b65d299ec6a93087f14087875a84babcba8563 · 2026-05-13 19:24:52 -0700 · SteveStudio2

Files touched

Diff

commit e8b65d299ec6a93087f14087875a84babcba8563
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 19:24:52 2026 -0700

    api: /api/fleet/buckets — daily commit buckets with ISO labels (fleet + per-project) + 3 smoke
---
 server.js     | 36 ++++++++++++++++++++++++++++++++++++
 test/smoke.js |  6 ++++++
 2 files changed, 42 insertions(+)

diff --git a/server.js b/server.js
index 519126c..862731a 100644
--- a/server.js
+++ b/server.js
@@ -690,6 +690,41 @@ app.get('/p/:slug/c/:hash', async (req, res, next) => {
   } catch (e) { next(e); }
 });
 
+// /api/fleet/buckets — daily commit-count buckets for the last N days
+// (?days=7, max 90), both per-project and fleet-wide. Useful for charting
+// libraries that want raw counts rather than the ASCII sparkline. Each bucket
+// is anchored to a calendar day (ISO yyyy-mm-dd) so callers can plot it.
+app.get('/api/fleet/buckets', async (req, res, next) => {
+  const days = Math.min(Math.max(parseInt(req.query.days, 10) || 7, 1), 90);
+  try {
+    const fleetCommits = [];
+    const byProject = [];
+    for (const [slug, p] of Object.entries(PROJECTS)) {
+      const bundle = await getProjectBundle(slug, p).catch(() => null);
+      if (!bundle) continue;
+      fleetCommits.push(...bundle.commits);
+      const s = sparkline(bundle.commits, days);
+      byProject.push({ slug, name: p.name, buckets: s.buckets, spark: s.spark });
+    }
+    const fleet = sparkline(fleetCommits, days);
+    // Label each bucket with its calendar date (oldest first → newest last).
+    const labels = [];
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    for (let i = days - 1; i >= 0; i--) {
+      const d = new Date(today.getTime() - i * 86400000);
+      labels.push(d.toISOString().slice(0, 10));
+    }
+    res.setHeader('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
+    res.json({
+      days,
+      labels,
+      fleet:      { buckets: fleet.buckets, spark: fleet.spark },
+      by_project: byProject,
+    });
+  } catch (e) { next(e); }
+});
+
 // /api/fleet/authors — fleet-wide author tallies (post-alias-normalization).
 app.get('/api/fleet/authors', async (_req, res, next) => {
   try {
@@ -1098,6 +1133,7 @@ app.get('/api', (_req, res) => {
       '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/authors':                'Fleet-wide author tallies (post-alias-normalization, so SteveStudio2/Steve/Steve Abrams collapse to one)',
+      'GET /api/fleet/buckets':                'Daily commit-count buckets for the last N days (?days=7, max 90) — fleet + per-project, with ISO date labels',
       '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',
diff --git a/test/smoke.js b/test/smoke.js
index 4074c32..7fc052b 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -231,6 +231,12 @@ function check(name, cond, hint = '') {
   check('fleet/all: velocity',     /"velocity":/.test(r.body));
   check('fleet/all: top_skills',   /"top_skills":\[/.test(r.body));
 
+  // 13b2c. fleet/buckets — daily counts for charts
+  r = await fetch('/api/fleet/buckets?days=7');
+  check('fleet/buckets: 200',      r.status === 200);
+  check('fleet/buckets: labels',   /"labels":\[/.test(r.body));
+  check('fleet/buckets: fleet',    /"fleet":/.test(r.body));
+
   // 13b3. fleet/velocity — rolling-window commit counts
   r = await fetch('/api/fleet/velocity');
   check('fleet/velocity: 200',     r.status === 200);

← fdee564 refactor: extract sparkline(commits, days) helper — DRY acro  ·  back to build-pages  ·  ui: /about page explaining build-pages + sitemap + footer li e4c31da →