Vista previa de la aplicación
UI MockupCultivaLeads — CULTIVA IA
| Lead | Servicio | Estado | Fecha | |
|---|---|---|---|---|
|
Sara Montiel
Clínica Dental Nórdica
sara@clinica-nordica.com
|
Automatización IA | Nuevo | 14 jun 2026 | |
|
Marcos Ibáñez
Gym Urban Fit
marcos@urbanfit.es
|
Marketing Contenido | Contactado | 12 jun 2026 | |
|
Laura Crespo
SaaS Contableo
laura@contableo.io
|
Agentes IA | Propuesta | 10 jun 2026 | |
|
Javier Ruiz
E-commerce BioBelleza
javier@biobelleza.com
|
SEO + Contenido | Cerrado ✓ | 5 jun 2026 | |
|
Ana Torres
Consultora Nexo
ana@consultora-nexo.com
|
Web Corporativa | Perdido | 2 jun 2026 |
Notas internas — Sara Montiel
Interesada en automatizar flujos de citas. Llamada inicial el 14/06. Enviar propuesta antes del 18/06 — presupuesto estimado €1.800/mes. Contacto previo con otra agencia, precio fue su freno.
Arquitectura Wails
Diagrama🗄
SQLite
leads.db
offline-first
~/.cultivaleads/
offline-first
~/.cultivaleads/
↑
sql.DB
CRUD ↓
CRUD ↓
◉
Go Backend
App struct
GetLeads / CreateLead
UpdateLead / ExportCSV
GetLeads / CreateLead
UpdateLead / ExportCSV
↑
TS Bindings
auto-gen ↓
auto-gen ↓
⚡
Wails Bridge
Bindings TypeScript
EventsEmit
Dialogs nativos
EventsEmit
Dialogs nativos
↑
import
go/main ↓
go/main ↓
⚛
React Frontend
LeadList / LeadDetail
FilterSidebar
Tailwind CSS
FilterSidebar
Tailwind CSS
Estructura del proyecto
File tree
cultivaleads/
├── app.go ← App struct + métodos Go expuestos al frontend
├── main.go ← Wails options, menú nativo, embed assets
├── go.mod
├── wails.json ← Configuración Wails (nombre, version, frontend dir)
├── frontend/
│ ├── src/
│ │ ├── App.tsx ← Root con sidebar + LeadTable + DetailPanel
│ │ ├── components/
│ │ │ ├── LeadTable.tsx
│ │ │ ├── LeadDetail.tsx
│ │ │ ├── FilterSidebar.tsx
│ │ │ └── StatsHeader.tsx
│ │ ├── hooks/
│ │ │ └── useLeads.ts ← Lógica de estado + llamadas a Go
│ │ └── index.css ← Tailwind + tema oscuro
│ └── wailsjs/ ← AUTO-GENERADO por Wails (no editar)
│ └── go/main/
│ ├── App.d.ts ← Tipos TypeScript desde structs Go
│ └── App.js ← Bindings JS para llamar a Go
└── build/
├── bin/
│ └── CultivaLeads.app ← Binario final macOS (bundle único)
└── windows/
└── CultivaLeads-setup.exe ← Installer NSIS
Go Backend — app.go
Goapp.go — Struct y métodos expuestos
Go
package main import ( "context" "database/sql" "encoding/csv" "os" "path/filepath" _ "modernc.org/sqlite" ) // Lead — struct con json tags → TypeScript interface auto-gen type Lead struct { ID int64 `json:"id"` Nombre string `json:"nombre"` Empresa string `json:"empresa"` Email string `json:"email"` Servicio string `json:"servicio"` Estado string `json:"estado"` Notas string `json:"notas"` FechaAlta string `json:"fechaAlta"` } type App struct { ctx context.Context db *sql.DB } func (a *App) startup(ctx context.Context) { a.ctx = ctx home, _ := os.UserHomeDir() dbPath := filepath.Join(home, ".cultivaleads", "leads.db") os.MkdirAll(filepath.Dir(dbPath), 0755) a.db, _ = sql.Open("sqlite", dbPath) a.db.Exec(`CREATE TABLE IF NOT EXISTS leads ( id INTEGER PRIMARY KEY AUTOINCREMENT, nombre TEXT NOT NULL, empresa TEXT, email TEXT, servicio TEXT, estado TEXT DEFAULT 'nuevo', notas TEXT DEFAULT '', fecha_alta DATETIME DEFAULT CURRENT_TIMESTAMP )`) } // GetLeads — retorna todos los leads (o filtrados por estado) func (a *App) GetLeads(estado string) ([]Lead, error) { query := "SELECT * FROM leads ORDER BY fecha_alta DESC" args := []interface{}{} if estado != "" && estado != "todos" { query = "SELECT * FROM leads WHERE estado=? ORDER BY fecha_alta DESC" args = append(args, estado) } rows, err := a.db.Query(query, args...) // ... scan rows → []Lead return leads, err } // ExportCSV — escribe CSV y devuelve la ruta al frontend func (a *App) ExportCSV() (string, error) { leads, _ := a.GetLeads("todos") path := filepath.Join(os.TempDir(), "cultivaleads-export.csv") f, _ := os.Create(path) w := csv.NewWriter(f) w.Write([]string{"ID", "Nombre", "Empresa", "Email", "Servicio", "Estado", "FechaAlta"}) for _, l := range leads { w.Write([]string{fmt.Sprint(l.ID), l.Nombre, l.Empresa, l.Email, l.Servicio, l.Estado, l.FechaAlta}) } w.Flush() return path, nil }
frontend/src/hooks/useLeads.ts — Lógica de estado
TSX
// Bindings auto-generados por Wails — importar como paquetes Go import { GetLeads, CreateLead, UpdateLead, DeleteLead, ExportCSV } from "../../wailsjs/go/main/App" import { main } from "../../wailsjs/go/models" import { useState, useCallback } from "react" export function useLeads() { const [leads, setLeads] = useState<main.Lead[]>([]) const [filter, setFilter] = useState("todos") const [selected, setSelected] = useState<main.Lead | null>(null) const load = useCallback(async () => { // Llama directo al método Go — retorna typed Lead[] const data = await GetLeads(filter) setLeads(data ?? []) }, [filter]) const create = async (nombre: string) => { const lead = await CreateLead(nombre, "", "", "") if (lead) { setSelected(lead); await load() } } const update = async (l: main.Lead) => { await UpdateLead(l.id, l.nombre, l.empresa, l.email, l.servicio, l.estado, l.notas) await load() } const exportCSV = async () => { const path = await ExportCSV() // Abrir Finder/Explorer en la carpeta del CSV ShowInFinder(path) } return { leads, selected, filter, setFilter, setSelected, load, create, update, exportCSV } }
main.go — Wails App Runner
Gomain.go — Configuración Wails, menú nativo y embed
Go
package main import ( "embed" "github.com/wailsapp/wails/v2" "github.com/wailsapp/wails/v2/pkg/menu" "github.com/wailsapp/wails/v2/pkg/options" "github.com/wailsapp/wails/v2/pkg/options/assetserver" "github.com/wailsapp/wails/v2/pkg/runtime" "github.com/wailsapp/wails/v2/pkg/keys" ) //go:embed all:frontend/dist var assets embed.FS // Frontend React compilado embebido en el binario func main() { app := &App{} // Menú nativo (macOS / Windows) appMenu := menu.NewMenu() fileMenu := appMenu.AddSubmenu("Archivo") fileMenu.AddText("Nuevo lead", keys.CmdOrCtrl("n"), func(_ *menu.CallbackData) { runtime.EventsEmit(app.ctx, "menu:new-lead") // Evento → React }) fileMenu.AddSeparator() fileMenu.AddText("Exportar CSV", keys.CmdOrCtrl("e"), func(_ *menu.CallbackData) { runtime.EventsEmit(app.ctx, "menu:export-csv") }) fileMenu.AddSeparator() fileMenu.AddText("Salir", keys.CmdOrCtrl("q"), func(_ *menu.CallbackData) { runtime.Quit(app.ctx) }) err := wails.Run(&options.App{ Title: "CultivaLeads", Width: 1200, Height: 720, MinWidth: 800, MinHeight: 500, AssetServer: &assetserver.Options{Assets: assets}, OnStartup: app.startup, Menu: appMenu, Bind: []interface{}{app}, // ← Expone todos los métodos de App al frontend // Ventana frameless con título personalizado Frameless: false, DisableResize: false, }) if err != nil { panic(err) } }
Ciclo de desarrollo y distribución
CLI1
Instalar Wails CLI
Prerequisito: Go 1.21+ y Node 18+
go install github.com/wailsapp/wails/v2/cmd/wails@latest
2
Crear proyecto
Template React + TypeScript con estructura completa
wails init -n cultivaleads -t react-ts
3
Modo desarrollo
Hot reload Go + React simultáneo. Bindings regenerados al guardar.
wails dev
4
Build & distribuir
Binario único macOS/Windows/Linux. Installer NSIS opcional.
wails build -platform darwin/amd64
wails build -nsis
wails build -nsis