All checks were successful
CI/CD / detect-changes (pull_request) Successful in 21s
CI/CD / test-frontend (pull_request) Successful in 5s
CI/CD / test-go-pg (pull_request) Successful in 2m58s
CI/CD / test-sqlite (pull_request) Successful in 3m2s
CI/CD / build-and-deploy (pull_request) Successful in 1m15s
PG-backed cluster registry for horizontal scaling — zero new infrastructure (no etcd/Consul/Redis). MVP convergence point. - node_registry UNLOGGED table (migration 013) - Self-registration, heartbeat tick (10s), stale sweep (30s), self-eviction (os.Exit on 0 rows → K8s restarts) - GET /api/v1/admin/cluster returns nodes with runtime stats - Health endpoints include node_id + cluster size/peers - cluster-dashboard admin surface with auto-refresh - 3-replica E2E test (docker-compose-e2e.yml + ci/e2e-cluster-test.sh) - chat + cluster-dashboard added to curated default bundle - 5 new tests (3 unit + 2 handler), all passing Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
101 lines
1.9 KiB
CSS
101 lines
1.9 KiB
CSS
.cluster-dashboard {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 2rem 1.5rem;
|
|
}
|
|
|
|
.cluster-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.cluster-header h1 {
|
|
margin: 0;
|
|
font-size: 1.5rem;
|
|
color: var(--text-primary, #111);
|
|
}
|
|
|
|
.cluster-status {
|
|
font-size: 0.85rem;
|
|
color: var(--text-secondary, #666);
|
|
background: var(--bg-secondary, #f3f4f6);
|
|
padding: 0.25rem 0.75rem;
|
|
border-radius: 999px;
|
|
}
|
|
|
|
.cluster-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
|
gap: 1rem;
|
|
}
|
|
|
|
.cluster-card {
|
|
background: var(--bg-primary, #fff);
|
|
border: 1px solid var(--border, #e5e7eb);
|
|
border-radius: 8px;
|
|
padding: 1.25rem;
|
|
}
|
|
|
|
.card-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.node-id {
|
|
font-weight: 600;
|
|
font-size: 0.9rem;
|
|
font-family: var(--font-mono, monospace);
|
|
color: var(--text-primary, #111);
|
|
}
|
|
|
|
.heartbeat-badge {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary, #666);
|
|
background: var(--bg-secondary, #f3f4f6);
|
|
padding: 0.15rem 0.5rem;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.node-endpoint {
|
|
font-size: 0.8rem;
|
|
color: var(--text-secondary, #666);
|
|
margin-bottom: 0.75rem;
|
|
font-family: var(--font-mono, monospace);
|
|
}
|
|
|
|
.card-stats {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.15rem;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.03em;
|
|
color: var(--text-secondary, #999);
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 0.9rem;
|
|
font-weight: 500;
|
|
font-family: var(--font-mono, monospace);
|
|
color: var(--text-primary, #111);
|
|
}
|
|
|
|
.cluster-empty {
|
|
color: var(--text-secondary, #666);
|
|
text-align: center;
|
|
padding: 3rem 1rem;
|
|
}
|