--- id: "0022" title: "Init Pipelines" status: completado type: feature domain: [] scope: multi-app priority: alta depends: [] blocks: [] related: [] created: 2026-05-17 updated: 2026-05-17 tags: [] --- # 0022 — Init Pipelines ## Metadata | Campo | Valor | |-------|-------| | **ID** | 0022 | | **Estado** | pendiente | | **Prioridad** | alta | | **Tipo** | feature | ## Dependencias | ID | Titulo | Estado | Requerido | |----|--------|--------|-----------| | 0009 | HTTP Server Foundation | pendiente | si | | 0010 | Auth System | pendiente | si | | 0015 | Database Migrations | pendiente | si | **Bloqueada por:** `#0009` (http_serve, http_router, http_json_response, http_middleware_chain), `#0010` (jwt_middleware, password_hash, session_create), `#0015` (migration_create, migration_up, migration_status). Los pipelines de init generan boilerplate que importa y compone estas funciones — sin ellas, el codigo scaffoldeado no compilaria. **Desbloquea:** cualquier app nueva del registry se puede crear con un solo comando en vez de copiar y adaptar una app existente. --- ## Objetivo Cuatro bash pipelines que scaffold apps completas en `apps/` con un solo comando. Cada uno genera la estructura de directorios, archivos boilerplate, `app.md` con frontmatter correcto, y verifica que el resultado compila. Misma filosofia que `init_jupyter_analysis_bash_pipelines`: componer funciones atomicas del registry para producir un entorno listo para trabajar. ## Contexto - Existen tres init pipelines: `init_go_project_bash_pipelines` (repo Go generico), `init_go_module_bash_pipelines` (modulo Go simple), `init_jupyter_analysis_bash_pipelines` (analysis Jupyter). Todos scaffoldean estructuras basicas. - **No existe ningun pipeline para scaffoldear apps del registry** con HTTP server, auth, DB, frontend, Wails o TUI. Cada app nueva se construye copiando otra y adaptando manualmente. - Las apps existentes (`deploy_server`, `sqlite_api`, `rapid_dashboards`, `pipeline_launcher`) comparten patrones repetitivos: main.go con graceful shutdown, config desde env vars, health check, migrations, app.md. - Con las funciones de 0009 (HTTP), 0010 (auth) y 0015 (migrations) disponibles, el boilerplate de una app API es predecible y automatizable. - El registry ya tiene funciones Wails completas (`scaffold_wails_app_go_infra`, `install_wails_bash_infra`, `wails_build_go_infra`, hooks `use_wails_*_ts_ui`, `wails_provider_ts_ui`) y TUI (`new_base_model_go_tui`, `run_fullscreen_go_tui`, temas, spinners, listas). ## Arquitectura ``` bash/functions/pipelines/ ├── init_api_app.sh — NEW: scaffold Go HTTP API app ├── init_api_app.md — NEW ├── init_web_app.sh — NEW: scaffold full-stack app (Go API + React) ├── init_web_app.md — NEW ├── init_desktop_app.sh — NEW: scaffold Wails desktop app ├── init_desktop_app.md — NEW ├── init_cli_app.sh — NEW: scaffold Go CLI/TUI app ├── init_cli_app.md — NEW ``` Todas son `kind: pipeline`, `purity: impure`, `lang: bash`, `domain: pipelines`. ### Patron de composicion Cada pipeline sigue el mismo patron que `init_jupyter_analysis`: 1. Source funciones atomicas del registry via `source "$REGISTRY_ROOT/bash/functions/..."` 2. Parsear argumentos (nombre obligatorio, flags opcionales) 3. Crear estructura de directorios con `mkdir -p` 4. Escribir archivos boilerplate con heredocs 5. Generar `app.md` con frontmatter correcto 6. Ejecutar `fn index` para registrar la app 7. Verificar con `go vet` / `pnpm build` / `wails build` segun corresponda --- ## Diseno ### Pipeline 1: `init_api_app` Scaffold de Go HTTP API app en `apps/`. **Uso:** ```bash fn run init_api_app my_service fn run init_api_app my_service --port 8080 --with-auth --with-db ``` **Archivos generados:** ``` apps/{nombre}/ ├── main.go — Entry point: config → router → middleware → http_serve con graceful shutdown ├── handlers.go — Handler GET /health + handler de ejemplo GET /api/v1/status ├── config.go — Struct Config con tags + carga desde .env / env vars ├── migrations/ │ └── 001_initial.sql — CREATE TABLE ejemplo con id, created_at, updated_at ├── app.md — Frontmatter con tag service, uses_functions, dir_path ├── Makefile — Targets: build, run, test, vet, clean ├── .env.example — Variables de entorno documentadas (PORT, DB_PATH, etc.) └── .gitignore — Binario, .env, *.db-shm, *.db-wal ``` **Funciones del registry compuestas:** | Funcion | Para que | |---------|---------| | `assert_command_exists_bash_shell` | Verificar que `go` esta instalado | | `http_serve_go_infra` (0009) | Codigo de graceful shutdown en main.go | | `http_router_go_infra` (0009) | Registro de rutas en main.go | | `http_json_response_go_infra` (0009) | Helper en handlers.go | | `http_error_response_go_infra` (0009) | Helper en handlers.go | | `http_middleware_chain_go_infra` (0009) | Composicion de middlewares en main.go | | `http_logger_middleware_go_infra` (0009) | Logging en main.go | | `http_cors_middleware_go_infra` (0009) | CORS en main.go | | `migration_up_go_infra` (0015) | Aplicar migrations en main.go al arrancar | | `config_load_go_infra` (0018) | Carga de config en config.go (si existe) | **Flags opcionales:** | Flag | Efecto | |------|--------| | `--port N` | Puerto por defecto en config y .env.example (default: 8080) | | `--with-auth` | Anade jwt_middleware, handlers de login/register, tabla users en migration | | `--with-db` | Anade operations.db setup, store.go con helpers CRUD basicos | | `--with-ops` | Anade `fn ops init` para crear operations.db con schema completo | **main.go generado (esquema):** ```go package main import ( "context" "log" "os" "os/signal" "fn_registry/functions/infra" ) func main() { cfg := LoadConfig() // Migrations if err := infra.MigrationUp(cfg.DBPath, "migrations"); err != nil { log.Fatal(err) } // Routes routes := []infra.Route{ {Method: "GET", Path: "/health", Handler: healthHandler}, {Method: "GET", Path: "/api/v1/status", Handler: statusHandler}, } mux := infra.HttpRouter(routes) // Middleware middleware := infra.HttpMiddlewareChain( infra.HttpCorsMiddleware(cfg.CORSOrigins, []string{"GET", "POST", "PUT", "DELETE"}), infra.HttpLoggerMiddleware(os.Stdout), ) // Serve ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() log.Printf("starting %s on :%s", cfg.AppName, cfg.Port) if err := infra.HttpServe(":"+cfg.Port, middleware(mux), ctx); err != nil { log.Fatal(err) } } ``` --- ### Pipeline 2: `init_web_app` Scaffold de full-stack app: Go API backend + React frontend con Mantine. **Uso:** ```bash fn run init_web_app my_dashboard fn run init_web_app my_dashboard --port 8080 --with-auth ``` **Archivos generados:** ``` apps/{nombre}/ ├── main.go — Igual que init_api_app + serve static files del frontend build ├── handlers.go — Health + API handlers de ejemplo ├── config.go — Config con FRONTEND_DIR ├── migrations/ │ └── 001_initial.sql ├── app.md — tag service, uses frontend ├── Makefile — Targets: build, build-frontend, run, dev, test, clean ├── .env.example ├── .gitignore ├── docker-compose.yml — Dev: Go API hot-reload + frontend dev server └── frontend/ ├── package.json — pnpm, vite, react, @mantine/core, @mantine/charts, @fn_library ├── vite.config.ts — API proxy a localhost:${port} ├── tsconfig.json ├── index.html ├── postcss.config.cjs └── src/ ├── main.tsx — FnMantineProvider + App mount ├── App.tsx — Router basico con pagina de ejemplo ├── theme.ts — createTheme() con colores del proyecto └── pages/ └── Home.tsx — Pagina de ejemplo usando crud_page_ts_ui o dashboard_layout_ts_ui ``` **Funciones adicionales compuestas (sobre init_api_app):** | Funcion | Para que | |---------|---------| | `mantine_provider_ts_ui` | Provider raiz en main.tsx | | `crud_page_ts_ui` | Pagina de ejemplo funcional | | `app_shell_ts_ui` | Layout con navbar y header | | `data_table_ts_ui` | Tabla de datos en la pagina de ejemplo | **vite.config.ts generado:** ```ts import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import path from "path"; export default defineConfig({ plugins: [react()], resolve: { alias: { "@fn_library": path.resolve(__dirname, "../../frontend/functions/ui"), }, }, server: { proxy: { "/api": { target: "http://localhost:${PORT}", changeOrigin: true, }, "/health": { target: "http://localhost:${PORT}", }, }, }, }); ``` **docker-compose.yml generado:** ```yaml services: api: build: . ports: - "${PORT}:${PORT}" env_file: .env volumes: - ./migrations:/app/migrations frontend: image: node:20-alpine working_dir: /app command: sh -c "corepack enable && pnpm install && pnpm dev" ports: - "5173:5173" volumes: - ./frontend:/app ``` --- ### Pipeline 3: `init_desktop_app` Scaffold de Wails desktop app con Go backend y React frontend con @fn_library. **Uso:** ```bash fn run init_desktop_app my_tool fn run init_desktop_app my_tool --with-db ``` **Archivos generados:** ``` apps/{nombre}/ ├── main.go — Wails entry point con embed del frontend ├── app.go — Struct App con bindings base (Greet, GetVersion) ├── wails.json — Config Wails apuntando a frontend/ ├── go.mod ├── app.md — framework: wails, uses wails hooks ├── .gitignore └── frontend/ ├── package.json — pnpm, vite, react, @mantine/core, @fn_library ├── vite.config.ts ├── tsconfig.json ├── index.html └── src/ ├── main.tsx — WailsProvider + FnMantineProvider + App ├── App.tsx — Ejemplo usando useWailsQuery + data_table └── theme.ts — createTheme() ``` **Funciones del registry compuestas:** | Funcion | Para que | |---------|---------| | `scaffold_wails_app_go_infra` | Genera estructura base Wails (main.go, app.go, wails.json, go.mod) | | `install_wails_bash_infra` | Verifica/instala Wails CLI y deps de sistema | | `wails_provider_ts_ui` | Provider React para IPC cache | | `use_wails_query_ts_ui` | Hook de ejemplo en App.tsx | | `mantine_provider_ts_ui` | Provider Mantine | | `wails_bind_crud_go_infra` | Genera bindings CRUD si `--with-db` | **Flags opcionales:** | Flag | Efecto | |------|--------| | `--with-db` | Anade SQLite con migrations, bindings CRUD generados por `wails_bind_crud_go_infra` | --- ### Pipeline 4: `init_cli_app` Scaffold de Go CLI app con subcomandos y componentes TUI de Bubbletea. **Uso:** ```bash fn run init_cli_app my_cli fn run init_cli_app my_cli --with-tui ``` **Archivos generados:** ``` apps/{nombre}/ ├── main.go — Entry point con subcommand routing (os.Args) ├── cmd_version.go — Subcomando: version ├── cmd_status.go — Subcomando de ejemplo: status (imprime info) ├── app.md — framework vacio (CLI puro) o bubbletea (con --with-tui) ├── Makefile — Targets: build, run, install, test, clean ├── .gitignore └── go.mod ``` **Con `--with-tui`:** ``` apps/{nombre}/ ├── main.go — Entry point con run_fullscreen o run_model ├── model.go — BaseModel + Update + View con tema oscuro ├── cmd_version.go — Subcomando no-TUI ├── app.md — framework: bubbletea ├── Makefile ├── .gitignore └── go.mod ``` **Funciones del registry compuestas:** | Funcion | Para que | |---------|---------| | `assert_command_exists_bash_shell` | Verificar Go | | `new_base_model_go_tui` | Modelo base en model.go | | `dark_styles_go_tui` | Tema oscuro por defecto | | `run_fullscreen_go_tui` | Arranque fullscreen en main.go | | `new_spinner_go_tui` | Componente de ejemplo | | `new_filtered_list_go_tui` | Componente de ejemplo | **main.go generado (sin TUI):** ```go package main import ( "fmt" "os" ) var version = "dev" func main() { if len(os.Args) < 2 { printUsage() os.Exit(1) } switch os.Args[1] { case "version": cmdVersion() case "status": cmdStatus() default: fmt.Fprintf(os.Stderr, "unknown command: %s\n", os.Args[1]) printUsage() os.Exit(1) } } func printUsage() { fmt.Println("Usage: {nombre} ") fmt.Println() fmt.Println("Commands:") fmt.Println(" version Print version") fmt.Println(" status Show status") } ``` --- ## Tareas ### Fase 1: `init_api_app` (pipeline base) - [ ] **1.1** Crear `bash/functions/pipelines/init_api_app.sh` con source de funciones atomicas, parseo de argumentos, y generacion de estructura - [ ] **1.2** Escribir heredocs para `main.go`, `handlers.go`, `config.go` que importen funciones de 0009 y 0015 - [ ] **1.3** Generar `app.md` con frontmatter correcto (tag `service`, `uses_functions` con IDs reales, `dir_path`) - [ ] **1.4** Generar `Makefile`, `.env.example`, `.gitignore`, `migrations/001_initial.sql` - [ ] **1.5** Flag `--with-auth`: anadir imports de 0010, handlers de login/register, tabla users en migration - [ ] **1.6** Flag `--with-db`: anadir `store.go` con helpers CRUD, setup de SQLite al arrancar - [ ] **1.7** Ejecutar `go vet -tags fts5` al final como verificacion - [ ] **1.8** Crear `init_api_app.md` con frontmatter de pipeline ### Fase 2: `init_web_app` (extiende init_api_app) - [ ] **2.1** Crear `bash/functions/pipelines/init_web_app.sh` que primero invoca la logica de `init_api_app` y luego anade el frontend - [ ] **2.2** Generar `frontend/` con `package.json` (pnpm, vite, react, mantine, @fn_library alias) - [ ] **2.3** Generar `vite.config.ts` con proxy al backend y alias `@fn_library` - [ ] **2.4** Generar `src/main.tsx` con `FnMantineProvider`, `src/App.tsx` con `AppShell`, `src/pages/Home.tsx` con ejemplo - [ ] **2.5** Generar `docker-compose.yml` para desarrollo - [ ] **2.6** Actualizar `main.go` para servir static files del frontend build - [ ] **2.7** Ejecutar `pnpm install && pnpm build` como verificacion del frontend - [ ] **2.8** Crear `init_web_app.md` con frontmatter de pipeline ### Fase 3: `init_desktop_app` - [ ] **3.1** Crear `bash/functions/pipelines/init_desktop_app.sh` que invoca `scaffold_wails_app_go_infra` y anade frontend React - [ ] **3.2** Verificar/instalar Wails con `install_wails_bash_infra` - [ ] **3.3** Generar frontend con `WailsProvider` + `FnMantineProvider` y ejemplo con `useWailsQuery` - [ ] **3.4** Flag `--with-db`: invocar `wails_bind_crud_go_infra` para generar bindings - [ ] **3.5** Ejecutar `wails build` como verificacion - [ ] **3.6** Crear `init_desktop_app.md` con frontmatter de pipeline ### Fase 4: `init_cli_app` - [ ] **4.1** Crear `bash/functions/pipelines/init_cli_app.sh` con generacion de estructura CLI basica - [ ] **4.2** Generar `main.go` con routing de subcomandos, `cmd_version.go`, `cmd_status.go` - [ ] **4.3** Flag `--with-tui`: generar `model.go` con `new_base_model`, `dark_styles`, `run_fullscreen` - [ ] **4.4** Ejecutar `go vet` como verificacion - [ ] **4.5** Crear `init_cli_app.md` con frontmatter de pipeline ### Fase 5: Integracion - [ ] **5.1** `fn index` y verificar que los 4 pipelines aparecen en registry.db con kind=pipeline, purity=impure - [ ] **5.2** Verificar `fn run init_api_app test_app` end-to-end: genera, compila, limpia - [ ] **5.3** Verificar `fn run init_web_app test_web` end-to-end - [ ] **5.4** Verificar `fn run init_desktop_app test_desktop` end-to-end - [ ] **5.5** Verificar `fn run init_cli_app test_cli` end-to-end ### Fase 6: Documentacion de uso rapido Cada pipeline debe ser usable sin leer el issue completo. La documentacion va en dos niveles: el `.md` de cada funcion (fuente de verdad para `fn show`) y una guia consolidada. - [ ] **6.1** En cada `.md` de pipeline (`init_api_app.md`, etc.) documentar en la seccion `documentation` del frontmatter: - Sinopsis: `fn run init_api_app [--port N] [--with-auth] [--with-db]` - Descripcion de cada flag y su efecto concreto (que archivos anade, que imports genera) - Listado de archivos generados con una linea de descripcion cada uno - Post-setup: que comandos ejecutar despues (`make run`, `make dev`, `wails dev`, etc.) - Ejemplo rapido: un bloque copy-paste de 3-4 lineas que crea la app y la arranca - [ ] **6.2** En el campo `params` del frontmatter de cada pipeline, documentar cada argumento y flag con `name` y `desc` semantico para que `fn check params` pase y la info sea buscable via FTS5 - [ ] **6.3** En el campo `example` del frontmatter, poner el caso de uso mas comun (una linea): - `init_api_app`: `fn run init_api_app my_service --with-db` - `init_web_app`: `fn run init_web_app my_dashboard --with-auth` - `init_desktop_app`: `fn run init_desktop_app my_tool` - `init_cli_app`: `fn run init_cli_app my_cli --with-tui` - [ ] **6.4** Crear `docs/init-pipelines.md` como guia consolidada de referencia rapida con: - Tabla resumen de los 4 pipelines (nombre, que genera, flags disponibles) - Arbol de decision: "quiero una API" → init_api_app, "quiero frontend" → init_web_app, "quiero desktop" → init_desktop_app, "quiero CLI" → init_cli_app - Seccion de combinaciones comunes (API + auth + DB, web dashboard, desktop con SQLite, CLI con TUI) - FAQ: como anadir auth despues, como cambiar el puerto, como anadir operations.db, como agregar mas paginas al frontend - [ ] **6.5** Verificar que `fn show init_api_app_bash_pipelines` (y los otros 3) muestra la documentacion completa con params, ejemplo y notas de uso --- ## Ejemplo de uso ```bash # API service con auth y database fn run init_api_app billing_api --port 8090 --with-auth --with-db cd apps/billing_api make run # → starting billing_api on :8090 # → curl localhost:8090/health → {"status":"ok"} # Full-stack dashboard fn run init_web_app inventory_dashboard --with-auth cd apps/inventory_dashboard make dev # → API en :8080, frontend en :5173 con proxy # Desktop app con base de datos fn run init_desktop_app data_explorer --with-db cd apps/data_explorer wails dev # → App de escritorio con React + SQLite # CLI con TUI fn run init_cli_app deploy_helper --with-tui cd apps/deploy_helper make run -- status # → TUI fullscreen con lista filtrable ``` **Cada pipeline genera su `app.md` listo para `fn index`:** ```yaml --- name: billing_api lang: go domain: tools description: "API de facturacion." tags: [service] uses_functions: - http_serve_go_infra - http_router_go_infra - http_middleware_chain_go_infra - http_cors_middleware_go_infra - http_logger_middleware_go_infra - http_json_response_go_infra - http_error_response_go_infra - migration_up_go_infra uses_types: [] framework: "net/http" entry_point: "main.go" dir_path: "apps/billing_api" --- ``` --- ## Decisiones de diseno - **Bash, no Go:** los init pipelines generan archivos con heredocs — bash es el lenguaje natural para esto. Go seria overengineering para scaffolding de texto. Coherente con `init_jupyter_analysis` y los demas init existentes. - **Composicion sobre monolito:** cada pipeline sourcea funciones atomicas del registry (`assert_command_exists`, `scaffold_wails_app`, etc.) en vez de reimplementar. Si una funcion atomica mejora, todos los pipelines se benefician. - **init_web_app extiende init_api_app:** el pipeline web reutiliza la logica del API (misma estructura backend) y anade la capa frontend encima. No duplica codigo. - **Verificacion al final:** cada pipeline termina con `go vet`, `pnpm build`, o `wails build` para garantizar que el scaffold compila. Si falla, el pipeline reporta el error antes de declarar exito. - **Flags opcionales con defaults sensatos:** el caso base (sin flags) genera una app funcional minima. `--with-auth`, `--with-db`, `--with-tui` anaden capas incrementales. El usuario no necesita decidir todo upfront. - **@fn_library como alias, no copia:** el frontend generado referencia `@fn_library` via alias en `vite.config.ts` apuntando a `frontend/functions/ui/` del registry. Los componentes se comparten, no se duplican. - **app.md generado automaticamente:** el frontmatter incluye `uses_functions` con los IDs reales de las funciones que el boilerplate importa. `fn index` los valida al registrar la app. - **Sin framework CLI externo para init_cli_app:** routing de subcomandos con `os.Args` y switch — consistente con las apps existentes del registry que no usan cobra/urfave. Para TUI se usa Bubbletea que ya esta en el registry. ## Riesgos - **Dependencias no implementadas:** los tres issues de dependencia (0009, 0010, 0015) estan pendientes. Si alguna funcion cambia de firma durante su implementacion, los heredocs de los pipelines necesitaran ajuste. **Mitigacion:** implementar los pipelines despues de que las dependencias esten merged, o mantener los heredocs parametricos para absorber cambios menores. - **Heredocs fragiles:** generar Go/TS/YAML con heredocs bash es propenso a errores de indentacion, escape de variables y quoting. **Mitigacion:** cada pipeline incluye verificacion final (`go vet` / `pnpm build`) que detecta errores de sintaxis inmediatamente. Tests end-to-end en fase 5. - **Frontend desactualizado respecto a @fn_library:** si los componentes de `frontend/functions/ui/` evolucionan, el boilerplate generado puede quedar desactualizado. **Mitigacion:** el boilerplate es minimo (un Provider, un AppShell, una pagina de ejemplo) — el usuario lo extiende con los componentes actuales del registry. - **Wails como dependencia de sistema:** `init_desktop_app` requiere GTK3 + WebKit2GTK instalados en Linux. `install_wails_bash_infra` lo maneja, pero puede fallar en distros no soportadas. **Mitigacion:** el pipeline verifica la instalacion al inicio y falla rapido con mensaje descriptivo. - **Colision de nombres:** si el usuario elige un nombre que ya existe en `apps/`, el pipeline sobreescribiria archivos. **Mitigacion:** verificar si `apps/{nombre}/` existe al inicio y abortar con error si ya existe.