mirror of
https://github.com/RGJorge/ContainerFlow.git
synced 2026-08-03 07:21:42 +02:00
v0.0.6
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
# Plan: Monitoreo Multi-Host Docker
|
||||
|
||||
## Objetivo
|
||||
|
||||
Permitir que una sola instancia de DockerFlow se conecte a múltiples Docker daemons (local + remotos) y visualice todos los contenedores en un solo dashboard, agrupados por host.
|
||||
|
||||
## Enfoque
|
||||
|
||||
Usar la API TCP de Docker con TLS. No se instala nada adicional en los servidores remotos — solo se configura el Docker daemon para aceptar conexiones TCP.
|
||||
|
||||
---
|
||||
|
||||
## Fase 1: Configuración de hosts
|
||||
|
||||
### 1.1 Variable de entorno `DOCKER_HOSTS`
|
||||
|
||||
```bash
|
||||
# Formato: nombre=tipo://dirección, separados por coma
|
||||
# El host local usa socket, los remotos usan tcp+tls
|
||||
DOCKER_HOSTS="local=unix:///var/run/docker.sock,server-a=tcp://192.168.1.10:2376,server-b=tcp://192.168.1.20:2376"
|
||||
```
|
||||
|
||||
Si `DOCKER_HOSTS` no está definido, comportamiento actual (solo socket local). Retrocompatible.
|
||||
|
||||
### 1.2 Certificados TLS
|
||||
|
||||
```bash
|
||||
# Directorio de certs por host
|
||||
DOCKER_CERTS_DIR=./certs
|
||||
# Estructura:
|
||||
# certs/
|
||||
# server-a/
|
||||
# ca.pem
|
||||
# cert.pem
|
||||
# key.pem
|
||||
# server-b/
|
||||
# ca.pem
|
||||
# cert.pem
|
||||
# key.pem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fase 2: Cambios en Backend
|
||||
|
||||
### 2.1 `src/server/docker.ts` — Multi-host connections
|
||||
|
||||
**Actual:** Una sola instancia de `dockerode` hardcodeada.
|
||||
|
||||
```ts
|
||||
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
||||
```
|
||||
|
||||
**Nuevo:** Map de instancias `dockerode` por host.
|
||||
|
||||
```ts
|
||||
interface DockerHost {
|
||||
name: string;
|
||||
client: Docker;
|
||||
}
|
||||
|
||||
function createHosts(): DockerHost[] {
|
||||
const hostsEnv = process.env.DOCKER_HOSTS;
|
||||
if (!hostsEnv) {
|
||||
return [{ name: "local", client: new Docker({ socketPath: "/var/run/docker.sock" }) }];
|
||||
}
|
||||
|
||||
const certsDir = process.env.DOCKER_CERTS_DIR || "./certs";
|
||||
|
||||
return hostsEnv.split(",").map((entry) => {
|
||||
const [name, url] = entry.split("=");
|
||||
if (url.startsWith("unix://")) {
|
||||
return { name, client: new Docker({ socketPath: url.replace("unix://", "") }) };
|
||||
}
|
||||
// tcp://host:port
|
||||
const { hostname, port } = new URL(url.replace("tcp://", "https://"));
|
||||
return {
|
||||
name,
|
||||
client: new Docker({
|
||||
host: hostname,
|
||||
port: parseInt(port),
|
||||
ca: fs.readFileSync(`${certsDir}/${name}/ca.pem`),
|
||||
cert: fs.readFileSync(`${certsDir}/${name}/cert.pem`),
|
||||
key: fs.readFileSync(`${certsDir}/${name}/key.pem`),
|
||||
}),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export const dockerHosts = createHosts();
|
||||
```
|
||||
|
||||
### 2.2 `src/shared/types.ts` — Agregar campo `host`
|
||||
|
||||
```ts
|
||||
export interface Service {
|
||||
// ... campos existentes ...
|
||||
host: string; // nombre del host (ej: "local", "server-a")
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 `discoverServices()` — Iterar sobre todos los hosts
|
||||
|
||||
```ts
|
||||
export async function discoverServices(all, projects): Promise<Service[]> {
|
||||
const allServices: Service[] = [];
|
||||
|
||||
for (const { name, client } of dockerHosts) {
|
||||
const containers = await client.listContainers({ all: true });
|
||||
const services = containers.map((c) => ({
|
||||
// ... mapeo actual ...
|
||||
host: name,
|
||||
uid: `${name}/${project}/${serviceName}`, // incluir host en uid
|
||||
}));
|
||||
allServices.push(...services);
|
||||
}
|
||||
|
||||
// filtrar por projects...
|
||||
return allServices;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 `discoverConnections()` — Conexiones solo dentro del mismo host
|
||||
|
||||
Las conexiones por red compartida solo aplican entre contenedores del mismo host. Agregar filtro:
|
||||
|
||||
```ts
|
||||
// Solo conectar servicios del mismo host
|
||||
if (app.host !== infra.host) continue;
|
||||
```
|
||||
|
||||
### 2.5 `getContainerLogs()` y `streamContainerLogs()` — Resolver host
|
||||
|
||||
Actualmente usan `docker.getContainer(id)`. Cambiar para recibir el host y usar el client correcto:
|
||||
|
||||
```ts
|
||||
export async function getContainerLogs(hostName: string, id: string, tail = 200) {
|
||||
const host = dockerHosts.find(h => h.name === hostName);
|
||||
const container = host.client.getContainer(id);
|
||||
// ... resto igual ...
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 `src/server/watcher.ts` — Stats y eventos multi-host
|
||||
|
||||
`pollStats` y `watchDockerEvents` deben iterar sobre todos los hosts. Cada host tiene su propio stream de eventos.
|
||||
|
||||
---
|
||||
|
||||
## Fase 3: Cambios en Frontend
|
||||
|
||||
### 3.1 Agrupación visual por host
|
||||
|
||||
- Usar un **borde/fondo coloreado** alrededor de los nodos de cada host
|
||||
- Mostrar label del host sobre cada grupo
|
||||
- Colores distintos por host (auto-asignados)
|
||||
|
||||
### 3.2 Sidebar/filtro por host
|
||||
|
||||
- Agregar selector de host en la UI para filtrar la vista
|
||||
- Opción "Todos" para ver todo junto
|
||||
|
||||
### 3.3 Panel de stats
|
||||
|
||||
- Mostrar en qué host está cada contenedor
|
||||
- Badge con el nombre del host en cada nodo del grafo
|
||||
|
||||
---
|
||||
|
||||
## Fase 4: Documentación de setup remoto
|
||||
|
||||
### Guía para configurar un Docker daemon remoto
|
||||
|
||||
En el servidor remoto:
|
||||
|
||||
```bash
|
||||
# 1. Generar certificados (una vez)
|
||||
# Usar el script que incluiremos en tools/generate-certs.sh
|
||||
|
||||
# 2. Editar /etc/docker/daemon.json
|
||||
{
|
||||
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
|
||||
"tls": true,
|
||||
"tlscacert": "/etc/docker/ssl/ca.pem",
|
||||
"tlscert": "/etc/docker/ssl/server-cert.pem",
|
||||
"tlskey": "/etc/docker/ssl/server-key.pem",
|
||||
"tlsverify": true
|
||||
}
|
||||
|
||||
# 3. Reiniciar Docker
|
||||
sudo systemctl restart docker
|
||||
```
|
||||
|
||||
### Script de generación de certs
|
||||
|
||||
Incluir `tools/generate-certs.sh` que genere CA + server cert + client cert.
|
||||
|
||||
---
|
||||
|
||||
## Archivos a modificar
|
||||
|
||||
| Archivo | Cambio |
|
||||
|---------|--------|
|
||||
| `src/server/docker.ts` | Multi-host connections, refactor todas las funciones |
|
||||
| `src/server/watcher.ts` | Stats y eventos por host |
|
||||
| `src/server/index.ts` | Pasar host en log subscribe/unsubscribe |
|
||||
| `src/shared/types.ts` | Campo `host` en Service, WSMessage updates |
|
||||
| `src/client/App.tsx` | Agrupación visual, filtros, badges |
|
||||
| `src/client/components/*` | Nodos con indicador de host |
|
||||
|
||||
## Archivos nuevos
|
||||
|
||||
| Archivo | Descripción |
|
||||
|---------|-------------|
|
||||
| `tools/generate-certs.sh` | Script para generar certificados TLS |
|
||||
|
||||
---
|
||||
|
||||
## Orden de implementación
|
||||
|
||||
1. Types (`host` field) — 5 min
|
||||
2. `docker.ts` multi-host — core del cambio
|
||||
3. `watcher.ts` multi-host
|
||||
4. `index.ts` ajustes WebSocket
|
||||
5. Frontend: badges y agrupación
|
||||
6. Script de certs + docs
|
||||
7. Testing con host local (simular con socket duplicado)
|
||||
|
||||
## Consideraciones
|
||||
|
||||
- **Retrocompatible**: sin `DOCKER_HOSTS`, funciona exactamente igual que ahora
|
||||
- **Seguridad**: nunca TCP sin TLS, los certs son obligatorios para hosts remotos
|
||||
- **Performance**: cada host se consulta en paralelo con `Promise.all`
|
||||
- **Errores**: si un host remoto no responde, mostrar el host como "offline" sin afectar los demás
|
||||
+351
@@ -0,0 +1,351 @@
|
||||
# Roadmap para publicar DockerFlow como Open Source
|
||||
|
||||
Estado actual del proyecto: **v0.1.0** | ~1,774 lineas de codigo | 0 tests | 0 CI/CD | Sin licencia formal
|
||||
|
||||
---
|
||||
|
||||
## Fase 1 — Fundamentos legales y limpieza
|
||||
|
||||
> Sin esto, nadie puede usar tu codigo legalmente ni contribuir con confianza.
|
||||
|
||||
### 1.1 Crear archivo LICENSE
|
||||
|
||||
- [ ] Crear `LICENSE` en la raiz con el texto completo de MIT
|
||||
- [ ] El README ya dice "MIT" al final, pero sin el archivo no tiene validez legal
|
||||
- [ ] Opciones alternativas si cambias de opinion:
|
||||
- **MIT** — maxima adopcion, cualquiera puede hacer lo que quiera
|
||||
- **Apache 2.0** — como MIT pero protege contra demandas de patentes
|
||||
- **GPL v3** — obliga a que los forks tambien sean open source
|
||||
|
||||
### 1.2 Auditar secretos en el historial de git
|
||||
|
||||
- [ ] Verificar que `.env` nunca fue commiteado (HECHO: confirmado limpio)
|
||||
- [ ] Verificar que no hay tokens, passwords o claves hardcodeados en el codigo
|
||||
- [ ] Buscar en el historial: `git log -p --all -S 'AUTH_TOKEN' -- '*.ts'`
|
||||
- [ ] Buscar en el historial: `git log -p --all -S 'password' -- '*.ts'`
|
||||
- [ ] Si se encuentra algo comprometido, considerar `git filter-branch` o `bfg` para limpiar
|
||||
|
||||
### 1.3 Eliminar archivos internos del repo publico
|
||||
|
||||
- [ ] Eliminar `tareas/completadas/` — son notas internas de desarrollo, no aportan al usuario final
|
||||
- [ ] Eliminar `docker-project.md` — documento de planificacion interna
|
||||
- [ ] Decidir sobre `PLAN-MULTI-HOST.md` — puede quedarse como roadmap publico o moverse a GitHub Issues/Projects
|
||||
- [ ] Eliminar `.claude/settings.local.json` si contiene paths locales
|
||||
- [ ] Actualizar `.gitignore` para excluir `tareas/` y documentos internos futuros
|
||||
|
||||
### 1.4 Limpiar configuracion local
|
||||
|
||||
- [ ] Verificar que `.dockerflow-positions.json` esta en `.gitignore` (esta)
|
||||
- [ ] Verificar que `.env` esta en `.gitignore` (esta)
|
||||
- [ ] Agregar a `.gitignore`: `PUBLICAR.md`, `tareas/`, `docker-project.md`
|
||||
|
||||
---
|
||||
|
||||
## Fase 2 — Documentacion para la comunidad
|
||||
|
||||
> La documentacion es la primera impresion. Un proyecto sin docs claras no recibe contribuciones.
|
||||
|
||||
### 2.1 README en ingles (idioma principal)
|
||||
|
||||
- [ ] Crear `README.md` en ingles como version principal
|
||||
- [ ] Mover el README actual a `README.es.md` y linkear desde el principal
|
||||
- [ ] Incluir en el README:
|
||||
- [ ] **Hero section**: nombre, descripcion de una linea, badges (license, version, bun)
|
||||
- [ ] **Screenshot/GIF** del dashboard funcionando (esto es CRITICO para adopcion)
|
||||
- [ ] **Quick start** en 4 lineas o menos
|
||||
- [ ] **Features** con iconos o emojis descriptivos
|
||||
- [ ] **Configuration** (tabla de env vars)
|
||||
- [ ] **Flow simulation** con ejemplo YAML
|
||||
- [ ] **MCP integration** (esto es diferenciador, destacarlo)
|
||||
- [ ] **Tech stack** (tabla limpia)
|
||||
- [ ] **Contributing** link
|
||||
- [ ] **License** badge + link
|
||||
|
||||
### 2.2 Captura de pantalla / GIF del dashboard
|
||||
|
||||
- [ ] Levantar el dashboard con containers de ejemplo
|
||||
- [ ] Grabar un GIF de ~10 segundos mostrando:
|
||||
- Vista general con servicios conectados
|
||||
- Particulas animadas fluyendo
|
||||
- Metricas en tiempo real
|
||||
- [ ] Herramientas recomendadas: `peek` (Linux), `gifski`, o `Kap` (macOS)
|
||||
- [ ] Guardar en `docs/assets/demo.gif` y referenciar desde README
|
||||
- [ ] Alternativa: screenshot estatico como fallback
|
||||
|
||||
### 2.3 CONTRIBUTING.md
|
||||
|
||||
- [ ] Crear `CONTRIBUTING.md` con:
|
||||
- [ ] Requisitos: Bun >= 1.0, Docker corriendo
|
||||
- [ ] Setup del entorno de desarrollo (`bun install && bun run dev`)
|
||||
- [ ] Estructura del proyecto (breve, linkear a README)
|
||||
- [ ] Convenciones de codigo (TypeScript estricto, sin `any`, imports absolutos)
|
||||
- [ ] Proceso de PRs: fork → branch → PR con descripcion
|
||||
- [ ] Issues: como reportar bugs, como proponer features
|
||||
- [ ] Commits: formato convencional (`feat:`, `fix:`, `docs:`)
|
||||
|
||||
### 2.4 CODE_OF_CONDUCT.md
|
||||
|
||||
- [ ] Adoptar Contributor Covenant v2.1 (estandar de la industria)
|
||||
- [ ] Copiar de https://www.contributor-covenant.org/
|
||||
- [ ] Personalizar email de contacto
|
||||
|
||||
### 2.5 CHANGELOG.md
|
||||
|
||||
- [ ] Crear `CHANGELOG.md` siguiendo formato Keep a Changelog
|
||||
- [ ] Documentar retroactivamente las versiones existentes:
|
||||
- v0.0.1 — Setup inicial, descubrimiento Docker
|
||||
- v0.0.2 — WebSocket, metricas en tiempo real
|
||||
- v0.0.3 — Nodos visuales, layout React Flow
|
||||
- v0.0.4 — Filtro de proyectos, autenticacion
|
||||
- v0.0.5 — Flujos animados, MCP server, logs, polish
|
||||
- [ ] De aqui en adelante, actualizar con cada release
|
||||
|
||||
---
|
||||
|
||||
## Fase 3 — Calidad de codigo
|
||||
|
||||
> Da confianza a los contribuidores y previene regresiones.
|
||||
|
||||
### 3.1 Configurar linter + formatter
|
||||
|
||||
- [ ] Instalar Biome (rapido, todo-en-uno, compatible con Bun):
|
||||
```bash
|
||||
bun add -d @biomejs/biome
|
||||
bunx biome init
|
||||
```
|
||||
- [ ] Configurar reglas en `biome.json`:
|
||||
- Formatter: tabs/spaces, ancho de linea
|
||||
- Linter: reglas recomendadas de TypeScript + React
|
||||
- Organizar imports automaticamente
|
||||
- [ ] Agregar scripts a `package.json`:
|
||||
```json
|
||||
"lint": "biome check src/",
|
||||
"lint:fix": "biome check --write src/",
|
||||
"format": "biome format --write src/"
|
||||
```
|
||||
- [ ] Ejecutar `bun run lint:fix` una vez para normalizar todo el codigo
|
||||
- [ ] Commit con mensaje: `chore: configure biome linter and format codebase`
|
||||
|
||||
### 3.2 Agregar tests minimos
|
||||
|
||||
- [ ] Usar `bun:test` (ya viene con Bun, zero config)
|
||||
- [ ] Tests prioritarios:
|
||||
- [ ] `src/server/__tests__/docker.test.ts` — parseo de conexiones, deteccion de tipos
|
||||
- [ ] `src/server/__tests__/flows.test.ts` — parseo de flows.yaml, validacion
|
||||
- [ ] `src/shared/__tests__/types.test.ts` — validacion de tipos con Zod si aplica
|
||||
- [ ] `src/client/engine/__tests__/layout.test.ts` — calculo de layout basico
|
||||
- [ ] `src/client/engine/__tests__/particles.test.ts` — motor de particulas
|
||||
- [ ] Agregar script: `"test": "bun test"`
|
||||
- [ ] Meta inicial: cubrir la logica de negocio del server (docker.ts, flows.ts)
|
||||
- [ ] No hace falta 100% coverage, pero si que lo critico este cubierto
|
||||
|
||||
### 3.3 Type checking estricto
|
||||
|
||||
- [ ] Verificar que `bun run build` no genera errores de TypeScript
|
||||
- [ ] Agregar script: `"typecheck": "tsc --noEmit"`
|
||||
- [ ] Corregir cualquier error que aparezca
|
||||
|
||||
---
|
||||
|
||||
## Fase 4 — CI/CD con GitHub Actions
|
||||
|
||||
> Automatiza la verificacion. Cada PR debe pasar lint + tests + build.
|
||||
|
||||
### 4.1 Workflow de CI basico
|
||||
|
||||
- [ ] Crear `.github/workflows/ci.yml`:
|
||||
```yaml
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
- run: bun install
|
||||
- run: bun run lint
|
||||
- run: bun run typecheck
|
||||
- run: bun run test
|
||||
- run: bun run build
|
||||
```
|
||||
- [ ] Verificar que pasa en la primera ejecucion
|
||||
- [ ] Agregar badge de CI al README
|
||||
|
||||
### 4.2 (Opcional) Release automatizado
|
||||
|
||||
- [ ] Configurar workflow de release al pushear tags:
|
||||
```yaml
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
```
|
||||
- [ ] Generar GitHub Release con changelog automatico
|
||||
- [ ] Considerar `changesets` o `release-please` para automatizar versiones
|
||||
|
||||
---
|
||||
|
||||
## Fase 5 — Distribucion y Docker
|
||||
|
||||
> Facilitar que la gente lo pruebe sin clonar el repo.
|
||||
|
||||
### 5.1 Dockerfile
|
||||
|
||||
- [ ] Crear `Dockerfile` multi-stage:
|
||||
```dockerfile
|
||||
# Build
|
||||
FROM oven/bun:1 AS builder
|
||||
WORKDIR /app
|
||||
COPY package.json bun.lock* ./
|
||||
RUN bun install --frozen-lockfile
|
||||
COPY . .
|
||||
RUN bun run build
|
||||
|
||||
# Run
|
||||
FROM oven/bun:1-slim
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/src/server ./src/server
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json .
|
||||
EXPOSE 9470
|
||||
CMD ["bun", "run", "start"]
|
||||
```
|
||||
- [ ] Crear `.dockerignore` (node_modules, .git, tareas, etc.)
|
||||
- [ ] Testear localmente: `docker build -t dockerflow . && docker run -v /var/run/docker.sock:/var/run/docker.sock -p 9470:9470 dockerflow`
|
||||
|
||||
### 5.2 docker-compose.yml de ejemplo
|
||||
|
||||
- [ ] Crear `docker-compose.yml` para que los usuarios levanten con un comando:
|
||||
```yaml
|
||||
services:
|
||||
dockerflow:
|
||||
image: ghcr.io/rgjorge/dockerflow:latest
|
||||
ports:
|
||||
- "9470:9470"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
environment:
|
||||
- AUTH_TOKEN=${AUTH_TOKEN:-}
|
||||
```
|
||||
|
||||
### 5.3 Publicar imagen en GitHub Container Registry
|
||||
|
||||
- [ ] Crear workflow `.github/workflows/docker.yml` para build + push automatico
|
||||
- [ ] Publicar en `ghcr.io/rgjorge/dockerflow`
|
||||
- [ ] Tags: `latest`, `v0.1.0`, `v0.1`, `v0`
|
||||
- [ ] Documentar en README el one-liner de Docker
|
||||
|
||||
---
|
||||
|
||||
## Fase 6 — Preparacion del repositorio
|
||||
|
||||
> Detalles finales antes de hacer el repo publico.
|
||||
|
||||
### 6.1 GitHub repo settings
|
||||
|
||||
- [ ] Descripcion del repo: "Real-time Docker architecture visualization dashboard"
|
||||
- [ ] Topics: `docker`, `monitoring`, `dashboard`, `visualization`, `devtools`, `bun`, `react`, `mcp`
|
||||
- [ ] Website: URL del repo o demo si la hay
|
||||
- [ ] Habilitar Issues
|
||||
- [ ] Habilitar Discussions (opcional, bueno para comunidad)
|
||||
- [ ] Configurar branch protection en `main`:
|
||||
- Require PR reviews
|
||||
- Require status checks (CI)
|
||||
- No force push
|
||||
|
||||
### 6.2 Issue templates
|
||||
|
||||
- [ ] Crear `.github/ISSUE_TEMPLATE/bug_report.md`
|
||||
- [ ] Crear `.github/ISSUE_TEMPLATE/feature_request.md`
|
||||
- [ ] Crear `.github/PULL_REQUEST_TEMPLATE.md`
|
||||
|
||||
### 6.3 Issues iniciales como roadmap publico
|
||||
|
||||
- [ ] Crear issues con label `good first issue` para atraer contribuidores:
|
||||
- "Add dark/light theme toggle"
|
||||
- "Support podman as alternative to Docker"
|
||||
- "Add container restart/stop actions from UI"
|
||||
- "Export dashboard as PNG/SVG"
|
||||
- [ ] Crear issues con label `enhancement` del roadmap:
|
||||
- "Multi-host Docker monitoring (TCP/TLS)"
|
||||
- "Container health check visualization"
|
||||
- "Custom node colors/icons per service type"
|
||||
- [ ] Convertir `PLAN-MULTI-HOST.md` en un issue detallado
|
||||
|
||||
### 6.4 Crear GitHub Release v0.1.0
|
||||
|
||||
- [ ] Tag: `v0.1.0`
|
||||
- [ ] Titulo: "DockerFlow v0.1.0 — Initial Public Release"
|
||||
- [ ] Body: features principales, screenshot, instrucciones de instalacion
|
||||
- [ ] Esto reemplaza los tags internos v0.0.x
|
||||
|
||||
---
|
||||
|
||||
## Fase 7 — Lanzamiento y difusion
|
||||
|
||||
> El codigo listo no sirve si nadie lo ve.
|
||||
|
||||
### 7.1 Preparar assets de lanzamiento
|
||||
|
||||
- [ ] GIF/screenshot de alta calidad del dashboard
|
||||
- [ ] Descripcion corta (1 parrafo) para copiar/pegar en redes
|
||||
- [ ] Lista de features destacadas (3-5 bullet points)
|
||||
|
||||
### 7.2 Publicar en comunidades
|
||||
|
||||
- [ ] **Reddit**: r/selfhosted, r/docker, r/devops, r/opensource
|
||||
- Titulo sugerido: "I built a real-time Docker architecture visualizer with animated data flows"
|
||||
- Incluir GIF y link al repo
|
||||
- [ ] **Hacker News**: Show HN post
|
||||
- Titulo: "Show HN: DockerFlow – Real-time Docker architecture visualization"
|
||||
- [ ] **Twitter/X**: Thread con GIF y features
|
||||
- [ ] **Dev.to**: Articulo sobre como se construyo
|
||||
- [ ] **Discord**: Servidores de Docker, Bun, React
|
||||
- [ ] **Product Hunt**: Si quieres traccion con publico mas amplio
|
||||
|
||||
### 7.3 Post-lanzamiento
|
||||
|
||||
- [ ] Monitorear issues y PRs las primeras 48-72 horas
|
||||
- [ ] Responder rapidamente a las primeras contribuciones (esto define la cultura)
|
||||
- [ ] Agregar un "Star History" badge al README despues de ganar traccion
|
||||
- [ ] Considerar crear un sitio web/landing page si hay interes
|
||||
|
||||
---
|
||||
|
||||
## Orden de ejecucion recomendado
|
||||
|
||||
| Prioridad | Tarea | Esfuerzo | Impacto |
|
||||
|-----------|-------|----------|---------|
|
||||
| 1 | Licencia MIT | 5 min | Critico |
|
||||
| 2 | Limpiar archivos internos | 10 min | Alto |
|
||||
| 3 | Screenshot/GIF del dashboard | 20 min | Critico |
|
||||
| 4 | README en ingles | 1-2 hrs | Critico |
|
||||
| 5 | CONTRIBUTING + CODE_OF_CONDUCT | 30 min | Alto |
|
||||
| 6 | Biome linter + format | 30 min | Medio |
|
||||
| 7 | Tests minimos (bun:test) | 2-3 hrs | Alto |
|
||||
| 8 | GitHub Actions CI | 30 min | Alto |
|
||||
| 9 | Dockerfile + compose | 1 hr | Alto |
|
||||
| 10 | CHANGELOG retroactivo | 30 min | Medio |
|
||||
| 11 | Issue templates + good first issues | 30 min | Medio |
|
||||
| 12 | GitHub Release v0.1.0 | 15 min | Alto |
|
||||
| 13 | Difusion en comunidades | 1-2 hrs | Critico |
|
||||
|
||||
**Tiempo total estimado: 8-12 horas de trabajo**
|
||||
|
||||
---
|
||||
|
||||
## Checklist final antes de hacer publico
|
||||
|
||||
- [ ] `LICENSE` existe y es MIT
|
||||
- [ ] No hay secretos en el codigo ni en el historial de git
|
||||
- [ ] No hay archivos internos/personales en el repo
|
||||
- [ ] README en ingles con screenshot/GIF
|
||||
- [ ] CONTRIBUTING.md existe
|
||||
- [ ] Al menos 1 test pasa
|
||||
- [ ] `bun run build` funciona sin errores
|
||||
- [ ] CI pasa en verde
|
||||
- [ ] GitHub Release creada
|
||||
- [ ] Listo para compartir el link
|
||||
+33
-1
@@ -13,7 +13,7 @@ import {
|
||||
type NodeChange,
|
||||
} from "@xyflow/react";
|
||||
import "@xyflow/react/dist/style.css";
|
||||
import { Wifi, WifiOff, ChevronDown, Check, Lock, LogOut, Eye, EyeOff, Terminal, Database, Zap, Radio, Globe } from "lucide-react";
|
||||
import { Wifi, WifiOff, ChevronDown, Check, Lock, LogOut, Eye, EyeOff, Terminal, Database, Zap, Radio, Globe, Cpu, MemoryStick } from "lucide-react";
|
||||
|
||||
import { ServiceNode } from "./nodes/ServiceNode";
|
||||
import { GroupNode } from "./nodes/GroupNode";
|
||||
@@ -600,6 +600,21 @@ function Dashboard({ token }: { token: string }) {
|
||||
|
||||
const runningCount = filteredServices.filter((s) => s.state === "running").length;
|
||||
|
||||
// Total resource consumption
|
||||
const totalStats = useMemo(() => {
|
||||
let cpu = 0;
|
||||
let mem = 0;
|
||||
for (const svc of filteredServices) {
|
||||
const s = stats.get(svc.uid);
|
||||
if (s) {
|
||||
cpu += s.cpu;
|
||||
mem += s.mem_mb;
|
||||
}
|
||||
}
|
||||
return { cpu, mem };
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [filteredServices, statsVersion]);
|
||||
|
||||
// Highlight edges connected to selected node, dim the rest
|
||||
const connectedNodeIds = useMemo(() => {
|
||||
if (!selectedNode) return null;
|
||||
@@ -662,6 +677,23 @@ function Dashboard({ token }: { token: string }) {
|
||||
<span className="text-xs text-slate-600 font-mono bg-slate-800 px-2 py-0.5 rounded">
|
||||
v0.1
|
||||
</span>
|
||||
|
||||
{/* Total resource usage */}
|
||||
{totalStats.cpu > 0 && (
|
||||
<div className="flex items-center gap-3 ml-2 text-xs font-mono bg-slate-800/80 border border-slate-700/50 px-3 py-1 rounded-md">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Cpu size={12} className="text-cyan-500" />
|
||||
<span className="text-cyan-400">{totalStats.cpu.toFixed(1)}%</span>
|
||||
</div>
|
||||
<div className="w-px h-3 bg-slate-700" />
|
||||
<div className="flex items-center gap-1.5">
|
||||
<MemoryStick size={12} className="text-violet-500" />
|
||||
<span className="text-violet-400">
|
||||
{totalStats.mem >= 1024 ? `${(totalStats.mem / 1024).toFixed(1)} GB` : `${totalStats.mem.toFixed(0)} MB`}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-5">
|
||||
|
||||
Reference in New Issue
Block a user