@@ -310,6 +340,55 @@ export default function OpsPage() {
)}
+
{[
{ id: 'overview', label: 'Overview', icon: Activity },
diff --git a/dashboards/admin-web/src/lib/ops-cockpit.ts b/dashboards/admin-web/src/lib/ops-cockpit.ts
new file mode 100644
index 00000000..d63fbc10
--- /dev/null
+++ b/dashboards/admin-web/src/lib/ops-cockpit.ts
@@ -0,0 +1,180 @@
+export type ServiceStatus = 'healthy' | 'degraded' | 'down' | 'maintenance';
+export type OverallStatus = 'healthy' | 'degraded' | 'critical';
+
+export interface OpsService {
+ id: string;
+ name: string;
+ group: string;
+ target: string;
+ status: ServiceStatus;
+ latency: number;
+ version?: string;
+ message?: string;
+ lastChecked: string;
+}
+
+export interface OpsStatusInput {
+ overall: OverallStatus;
+ timestamp: string;
+ services: OpsService[];
+}
+
+export interface InventoryService extends OpsService {
+ description: string;
+ management: 'docker' | 'vm';
+ exposure: 'internal' | 'public';
+ port?: number;
+ restartable: boolean;
+}
+
+export interface InventoryDataInput {
+ timestamp: string;
+ counts: {
+ services: number;
+ healthy: number;
+ degraded: number;
+ down: number;
+ hostTools: number;
+ };
+ services: InventoryService[];
+ hostTools: unknown[];
+}
+
+export interface ValkeyDataInput {
+ timestamp: string;
+ pattern: string;
+ limit: number;
+ summary: {
+ ping: string;
+ dbsize: number;
+ matchedKeys: number;
+ version: string;
+ usedMemoryHuman: string;
+ usedMemoryPeakHuman: string;
+ };
+ keys: unknown[];
+}
+
+export interface OpsCockpitTile {
+ label: string;
+ value: string;
+ detail: string;
+ tone: 'success' | 'warning' | 'danger' | 'neutral';
+}
+
+export interface OpsCockpitAction {
+ serviceId?: string;
+ action: string;
+ detail: string;
+ severity: 'critical' | 'warning' | 'info';
+}
+
+export interface OpsCockpit {
+ headline: string;
+ summary: string;
+ tiles: OpsCockpitTile[];
+ priorityActions: OpsCockpitAction[];
+}
+
+export function buildOpsCockpit(input: {
+ status: OpsStatusInput | null;
+ inventory: InventoryDataInput | null;
+ valkey: ValkeyDataInput | null;
+}): OpsCockpit {
+ const { status, inventory, valkey } = input;
+
+ if (!status && !inventory && !valkey) {
+ return {
+ headline: 'Waiting for live ops telemetry',
+ summary: 'Refresh Mission Control to collect service, inventory, and cache health.',
+ tiles: [
+ { label: 'Services', value: '--', detail: 'No sample yet', tone: 'neutral' },
+ { label: 'Cache keys', value: '--', detail: 'Valkey not loaded', tone: 'neutral' },
+ {
+ label: 'Restartable issues',
+ value: '--',
+ detail: 'Inventory not loaded',
+ tone: 'neutral',
+ },
+ ],
+ priorityActions: [
+ {
+ action: 'Refresh telemetry',
+ detail: 'Load the latest service and cache status before taking action.',
+ severity: 'info',
+ },
+ ],
+ };
+ }
+
+ const unhealthyServices = status?.services.filter(service => service.status !== 'healthy') ?? [];
+ const restartableIssues = unhealthyServices.filter(service =>
+ inventory?.services.some(inv => inv.id === service.id && inv.restartable)
+ );
+ const cacheHealthy = valkey?.summary.ping === 'PONG';
+ const criticalCount = unhealthyServices.filter(service => service.status === 'down').length;
+ const degradedCount = unhealthyServices.filter(service => service.status === 'degraded').length;
+
+ const priorityActions: OpsCockpitAction[] = restartableIssues.map(service => ({
+ serviceId: service.id,
+ action: 'Restart service',
+ detail: `${service.name} is ${service.status}${service.message ? ` — ${service.message}` : ''}`,
+ severity: service.status === 'down' ? 'critical' : 'warning',
+ }));
+
+ if (!cacheHealthy && valkey) {
+ priorityActions.push({
+ action: 'Inspect Valkey',
+ detail: `Cache ping returned ${valkey.summary.ping}; inspect hot keys and dependent services.`,
+ severity: 'warning',
+ });
+ }
+
+ if (priorityActions.length === 0) {
+ priorityActions.push({
+ action: 'Review deploy readiness',
+ detail: 'All loaded systems are healthy; check recent errors before starting a deployment.',
+ severity: 'info',
+ });
+ }
+
+ const overall =
+ status?.overall ??
+ (criticalCount > 0 ? 'critical' : degradedCount > 0 ? 'degraded' : 'healthy');
+ const headline =
+ overall === 'critical'
+ ? `Critical ops attention needed (${criticalCount} down)`
+ : overall === 'degraded'
+ ? `Ops degraded (${degradedCount} warning${degradedCount === 1 ? '' : 's'})`
+ : 'Ops cockpit healthy';
+
+ return {
+ headline,
+ summary: `${inventory?.counts.healthy ?? 0}/${inventory?.counts.services ?? status?.services.length ?? 0} services healthy · Valkey ${cacheHealthy ? 'ready' : 'needs review'}`,
+ tiles: [
+ {
+ label: 'Healthy services',
+ value: String(
+ inventory?.counts.healthy ??
+ status?.services.filter(s => s.status === 'healthy').length ??
+ 0
+ ),
+ detail: `${inventory?.counts.services ?? status?.services.length ?? 0} tracked`,
+ tone: criticalCount > 0 ? 'danger' : degradedCount > 0 ? 'warning' : 'success',
+ },
+ {
+ label: 'Cache keys',
+ value: String(valkey?.summary.dbsize ?? 0),
+ detail: valkey ? `${valkey.summary.usedMemoryHuman} used` : 'Valkey not loaded',
+ tone: cacheHealthy ? 'success' : 'warning',
+ },
+ {
+ label: 'Restartable issues',
+ value: String(restartableIssues.length),
+ detail: restartableIssues.length ? 'Safe action available' : 'No restart needed',
+ tone: restartableIssues.length ? 'danger' : 'success',
+ },
+ ],
+ priorityActions,
+ };
+}
diff --git a/dashboards/tracker-web/src/__tests__/execution-pipeline.test.ts b/dashboards/tracker-web/src/__tests__/execution-pipeline.test.ts
new file mode 100644
index 00000000..6e0c03df
--- /dev/null
+++ b/dashboards/tracker-web/src/__tests__/execution-pipeline.test.ts
@@ -0,0 +1,51 @@
+import { describe, expect, it } from 'vitest';
+
+import {
+ buildExecutionPipeline,
+ buildIssueDraft,
+ type ExecutionItem,
+} from '@/lib/execution-pipeline';
+
+const baseItem: ExecutionItem = {
+ id: 'item-1',
+ productId: 'bytelyst',
+ type: 'feature',
+ status: 'open',
+ priority: 'high',
+ title: 'Add export pipeline',
+ description: 'Users need CSV exports for reports.',
+ labels: ['customer-request'],
+ assignee: null,
+ reportedBy: 'sam@example.com',
+ source: 'user_submitted',
+ visibility: 'public',
+ voteCount: 12,
+ commentCount: 3,
+ targetRelease: null,
+ createdAt: '2026-05-01T00:00:00Z',
+ updatedAt: '2026-05-30T00:00:00Z',
+};
+
+describe('buildExecutionPipeline', () => {
+ it('ranks public roadmap items by execution leverage', () => {
+ const pipeline = buildExecutionPipeline([
+ { ...baseItem, id: 'low', priority: 'low', voteCount: 1, commentCount: 0, title: 'Low' },
+ { ...baseItem, id: 'critical', priority: 'critical', voteCount: 4, title: 'Critical' },
+ { ...baseItem, id: 'active', status: 'in_progress', voteCount: 8, title: 'Active' },
+ ]);
+
+ expect(pipeline.nextUp[0].id).toBe('critical');
+ expect(pipeline.inFlight[0].id).toBe('active');
+ expect(pipeline.summary).toMatchObject({ ready: 2, inFlight: 1, done: 0 });
+ });
+
+ it('builds a copyable issue draft for implementation handoff', () => {
+ const draft = buildIssueDraft(baseItem);
+
+ expect(draft.title).toBe('[feature] Add export pipeline');
+ expect(draft.body).toContain('Users need CSV exports for reports.');
+ expect(draft.body).toContain('/status/item-1');
+ expect(draft.labels).toContain('roadmap');
+ expect(draft.labels).toContain('customer-request');
+ });
+});
diff --git a/dashboards/tracker-web/src/app/roadmap/page.tsx b/dashboards/tracker-web/src/app/roadmap/page.tsx
index e6bb124c..d2416b19 100644
--- a/dashboards/tracker-web/src/app/roadmap/page.tsx
+++ b/dashboards/tracker-web/src/app/roadmap/page.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useEffect, useState, useCallback } from 'react';
+import { useEffect, useState, useCallback, useMemo } from 'react';
import {
SegmentedControl,
Button,
@@ -23,6 +23,7 @@ import {
type TrackerItem,
type PublicRoadmapStats,
} from '@/lib/tracker-client';
+import { buildExecutionPipeline, buildIssueDraft, type IssueDraft } from '@/lib/execution-pipeline';
type BadgeVariant = NonNullable
;
@@ -53,6 +54,7 @@ export default function RoadmapPage() {
const [search, setSearch] = useState('');
const [typeFilter, setTypeFilter] = useState('');
const [view, setView] = useState<'board' | 'list'>('board');
+ const [issueDraft, setIssueDraft] = useState(null);
// Submit form state
const [showSubmit, setShowSubmit] = useState(false);
@@ -185,6 +187,11 @@ export default function RoadmapPage() {
};
const itemsByStatus = (status: string) => items.filter(i => i.status === status);
+ const executionPipeline = useMemo(() => buildExecutionPipeline(items), [items]);
+
+ const openIssueDraft = (item: TrackerItem) => {
+ setIssueDraft(buildIssueDraft(item));
+ };
return (
@@ -220,6 +227,37 @@ export default function RoadmapPage() {
)}
+ {!loading && items.length > 0 && (
+
+
+
+
Execution pipeline
+
+ Promote the strongest roadmap signal into implementation work.
+
+
+
+ {executionPipeline.summary.ready} ready · {executionPipeline.summary.inFlight} in
+ flight
+
+
+
+
+
+
+
+ )}
+
{/* Filters */}
+
+
{
+ if (!open) setIssueDraft(null);
+ }}
+ title="Implementation issue draft"
+ description="Copy this into Gitea/GitHub to promote roadmap signal into execution."
+ >
+ {issueDraft && (
+
+
+
+
+ {issueDraft.labels.map(label => (
+
+ {label}
+
+ ))}
+
+
+
+
+
+
+ )}
+
);
}
@@ -466,6 +542,54 @@ const voteButtonClass = (hasVoted: boolean) =>
: 'border-border bg-muted/50 text-muted-foreground hover:border-primary hover:text-primary'
}`;
+function ExecutionLane({
+ title,
+ empty,
+ items,
+ onDraft,
+}: {
+ title: string;
+ empty: string;
+ items: Array;
+ onDraft: (item: TrackerItem) => void;
+}) {
+ return (
+
+
{title}
+ {items.length === 0 ? (
+
+ {empty}
+
+ ) : (
+ items.map(item => (
+
+
+
+
{item.title}
+
{item.executionReason}
+
+
+ {item.executionScore}
+
+
+
+
+ ))
+ )}
+
+ );
+}
+
function ItemCard({
item,
votedItems,
diff --git a/dashboards/tracker-web/src/app/status/[id]/page.tsx b/dashboards/tracker-web/src/app/status/[id]/page.tsx
index b24e8b50..67c9bee5 100644
--- a/dashboards/tracker-web/src/app/status/[id]/page.tsx
+++ b/dashboards/tracker-web/src/app/status/[id]/page.tsx
@@ -1,167 +1,141 @@
'use client';
-import Link from 'next/link';
-import { useParams } from 'next/navigation';
import { useEffect, useState } from 'react';
+import { useParams } from 'next/navigation';
+import { Badge, StatusDot, type StatusTone } from '@/components/ui/Primitives';
import { getPublicItem, type TrackerItem } from '@/lib/tracker-client';
-const STATUS_COPY: Record = {
- open: {
- label: 'Open',
- description: 'We received this submission and it is waiting for triage.',
- },
- in_progress: {
- label: 'In Progress',
- description: 'This item is actively being worked on.',
- },
- done: {
- label: 'Complete',
- description: 'This item has been shipped or otherwise completed.',
- },
- closed: {
- label: 'Closed',
- description: 'This item has been closed.',
- },
- wont_fix: {
- label: "Won't Fix",
- description: 'This item was reviewed but is not currently planned.',
- },
+const STATUS_TONE: Record = {
+ open: 'info',
+ in_progress: 'warning',
+ done: 'success',
+ closed: 'neutral',
+ wont_fix: 'neutral',
};
-function formatStatus(status: string) {
- return STATUS_COPY[status]?.label ?? status.replaceAll('_', ' ');
-}
+const STATUS_LABEL: Record = {
+ open: 'Planned',
+ in_progress: 'In progress',
+ done: 'Shipped',
+ closed: 'Closed',
+ wont_fix: "Won't fix",
+};
-function formatDate(value: string) {
- return new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', year: 'numeric' }).format(
- new Date(value)
- );
-}
-
-export default function SubmissionStatusPage() {
+export default function PublicStatusPage() {
const params = useParams<{ id: string }>();
- const id = params?.id;
const [item, setItem] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
let cancelled = false;
-
- async function loadItem() {
- if (!id) return;
+ async function load() {
+ if (!params.id) return;
setLoading(true);
setError(null);
try {
- const nextItem = await getPublicItem(id);
- if (!cancelled) setItem(nextItem);
- } catch (_err) {
- if (!cancelled) setError('not_found');
+ const result = await getPublicItem(params.id);
+ if (!cancelled) setItem(result);
+ } catch (err) {
+ if (!cancelled) setError(err instanceof Error ? err.message : 'Unable to load status');
} finally {
if (!cancelled) setLoading(false);
}
}
-
- void loadItem();
+ void load();
return () => {
cancelled = true;
};
- }, [id]);
-
- if (loading) {
- return (
-
-
-
Submission status
-
Loading submission…
-
-
- );
- }
-
- if (error || !item) {
- return (
-
-
-
Submission status
-
Submission not found
-
- We could not find a public roadmap item for this status link. It may have been made
- internal, merged into another item, or removed.
-
-
- View roadmap
-
-
-
- );
- }
-
- const status = STATUS_COPY[item.status] ?? {
- label: formatStatus(item.status),
- description: 'This submission is being tracked by the ByteLyst roadmap team.',
- };
+ }, [params.id]);
return (
-
-
-
- Back to roadmap
-
-
-
- Submission status
-
-
-
{item.title}
-
{item.description}
-
-
- {status.label}
-
-
-
-
-
-
Status
-
{status.label}
-
{status.description}
-
-
-
- Votes
-
-
{item.voteCount} votes
-
Community interest signal.
-
-
-
- Activity
-
-
{item.commentCount} comments
-
- Last updated {formatDate(item.updatedAt)}.
-
-
-
-
-
-
- What happens next?
-
-
- Keep this link to check progress. Public roadmap status updates, votes, and completion
- state will appear here without requiring an account.
+
+
+
+
+
Roadmap status
+
+ Follow progress from public request to shipped work.
-
-
-
+
+ Back to roadmap
+
+
+
+ {loading ? (
+
+ ) : error ? (
+
+
Submission not found
+
+ {error}. The request may have been merged, removed, or kept internal.
+
+
+ View roadmap
+
+
+ ) : item ? (
+
+
+
+
{item.title}
+
Submission status
+
{item.description}
+ {item.status === 'open' && (
+
+ We received this submission and it is waiting for triage.
+
+ )}
+
+
+ {STATUS_LABEL[item.status] ?? item.status}
+
+
+
+
+
+
Votes
+
{item.voteCount} votes
+
+
+
Priority
+
{item.priority}
+
+
+
Comments
+
{item.commentCount}
+
+
+
+
+ {['open', 'in_progress', 'done'].map(status => {
+ const active = status === item.status;
+ return (
+
+
+
+ {STATUS_LABEL[status]}
+
+ {active && current}
+
+ );
+ })}
+
+
+ ) : null}
+
+
);
}
diff --git a/dashboards/tracker-web/src/lib/execution-pipeline.ts b/dashboards/tracker-web/src/lib/execution-pipeline.ts
new file mode 100644
index 00000000..09189840
--- /dev/null
+++ b/dashboards/tracker-web/src/lib/execution-pipeline.ts
@@ -0,0 +1,140 @@
+export interface ExecutionItem {
+ id: string;
+ productId: string;
+ type: 'bug' | 'feature' | 'task';
+ status: 'open' | 'in_progress' | 'done' | 'closed' | 'wont_fix';
+ priority: 'critical' | 'high' | 'medium' | 'low';
+ title: string;
+ description: string;
+ labels: string[];
+ assignee: string | null;
+ reportedBy: string;
+ source: 'internal' | 'user_submitted' | 'auto_detected';
+ visibility: 'internal' | 'public';
+ voteCount: number;
+ commentCount: number;
+ targetRelease: string | null;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface ExecutionCandidate extends ExecutionItem {
+ executionScore: number;
+ executionReason: string;
+}
+
+export interface ExecutionPipeline {
+ nextUp: ExecutionCandidate[];
+ inFlight: ExecutionCandidate[];
+ done: ExecutionCandidate[];
+ summary: {
+ ready: number;
+ inFlight: number;
+ done: number;
+ totalVotes: number;
+ };
+}
+
+export interface IssueDraft {
+ title: string;
+ body: string;
+ labels: string[];
+}
+
+const PRIORITY_SCORE: Record = {
+ critical: 100,
+ high: 70,
+ medium: 40,
+ low: 10,
+};
+
+const STATUS_SCORE: Record = {
+ open: 20,
+ in_progress: 80,
+ done: 0,
+ closed: -20,
+ wont_fix: -40,
+};
+
+export function scoreExecutionItem(item: ExecutionItem): number {
+ return (
+ PRIORITY_SCORE[item.priority] +
+ STATUS_SCORE[item.status] +
+ Math.min(item.voteCount * 3, 60) +
+ Math.min(item.commentCount * 2, 20) +
+ (item.source === 'user_submitted' ? 10 : 0) +
+ (item.visibility === 'public' ? 5 : 0)
+ );
+}
+
+export function buildExecutionReason(item: ExecutionItem): string {
+ const parts = [
+ `${item.priority} priority`,
+ `${item.voteCount} vote${item.voteCount === 1 ? '' : 's'}`,
+ ];
+ if (item.commentCount > 0)
+ parts.push(`${item.commentCount} comment${item.commentCount === 1 ? '' : 's'}`);
+ if (item.source === 'user_submitted') parts.push('customer submitted');
+ return parts.join(' · ');
+}
+
+function toCandidate(item: ExecutionItem): ExecutionCandidate {
+ return {
+ ...item,
+ executionScore: scoreExecutionItem(item),
+ executionReason: buildExecutionReason(item),
+ };
+}
+
+function sortByExecutionScore(a: ExecutionCandidate, b: ExecutionCandidate): number {
+ if (b.executionScore !== a.executionScore) return b.executionScore - a.executionScore;
+ return b.updatedAt.localeCompare(a.updatedAt);
+}
+
+export function buildExecutionPipeline(items: ExecutionItem[], limit = 5): ExecutionPipeline {
+ const candidates = items.map(toCandidate).sort(sortByExecutionScore);
+ const nextUp = candidates.filter(item => item.status === 'open').slice(0, limit);
+ const inFlight = candidates.filter(item => item.status === 'in_progress').slice(0, limit);
+ const done = candidates.filter(item => item.status === 'done').slice(0, limit);
+
+ return {
+ nextUp,
+ inFlight,
+ done,
+ summary: {
+ ready: items.filter(item => item.status === 'open').length,
+ inFlight: items.filter(item => item.status === 'in_progress').length,
+ done: items.filter(item => item.status === 'done').length,
+ totalVotes: items.reduce((sum, item) => sum + item.voteCount, 0),
+ },
+ };
+}
+
+export function buildIssueDraft(item: ExecutionItem): IssueDraft {
+ const labels = Array.from(new Set(['roadmap', item.type, item.priority, ...item.labels]));
+ return {
+ title: `[${item.type}] ${item.title}`,
+ labels,
+ body: [
+ `## Roadmap request`,
+ ``,
+ item.description || '_No description provided._',
+ ``,
+ `## Signal`,
+ `- Priority: ${item.priority}`,
+ `- Votes: ${item.voteCount}`,
+ `- Comments: ${item.commentCount}`,
+ `- Source: ${item.source}`,
+ `- Reporter: ${item.reportedBy}`,
+ ``,
+ `## Links`,
+ `- Public status: /status/${item.id}`,
+ `- Tracker item: /dashboard/items/${item.id}`,
+ ``,
+ `## Acceptance criteria`,
+ `- [ ] Confirm scope and user impact`,
+ `- [ ] Implement with tests`,
+ `- [ ] Update roadmap status when shipped`,
+ ].join('\n'),
+ };
+}