feat: Agente-Marketing initial commit

This commit is contained in:
2026-07-03 12:23:34 -04:00
commit 293522436a
52 changed files with 13522 additions and 0 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+145
View File
@@ -0,0 +1,145 @@
# Calendario de Contenido — Prisa Yachts LLC
## Mayo 5 - Junio 1, 2026
---
## SETS DE HASHTAGS
**Set A — Trabajo Técnico / Instalaciones**
`#MarineElectrical #BoatWiring #MarineElectrician #LithiumBatteryBank #BoatRewiring #MarineInstallation #BoatElectrical #MarineTech #YachtElectrical #MarineServices #SouthFloridaBoating #FloridaBoating #StuartFL #TreasureCoastBoating #BoaterLife`
**Set B — Seguridad / Educación**
`#BoatSafety #MarineSafety #ElectricalSafety #BoatMaintenance #PreventiveMaintenance #MarineEducation #BoatTips #SailboatLife #PowerBoat #LiveaboardLife #FloridaYachts #JacksonvilleBoating #MarineElectrics #BoatLife #CostaEsteFL`
**Set C — B2B / Referidos / Comercial**
`#MarineProfessionals #MarinaMaintenance #YachtCaptain #BoatBroker #MarineIndustry #CommercialMarine #FleetMaintenance #MarineTechnician #YachtServices #MarinaManager #BoatDealers #MarineContractor #FloridaMarina #TreasureCoast #PrisaYachts`
---
## SEMANA 1: Mayo 6-11
| Fecha | Hora ET | Plataforma | Caption # | Tema | Visual | Hashtags |
|-------|---------|-----------|-----------|------|--------|---------|
| Lun Mayo 6 | 11:00 AM | Instagram | #1 | Battery Bank Install (EN) | Foto litio instalado, cables etiquetados | Set A |
| Lun Mayo 6 | 12:00 PM | Facebook Page | #1 | Mismo + CTA "DM para cotización" | Misma foto | Set A |
| Mar Mayo 7 | 10:00 AM | LinkedIn | #11 | Marina Managers/Captains (B2B) | Foto profesional del dueño en barco | Set C |
| Mié Mayo 8 | 9:00 AM | Instagram | #4 | Safety Warning Shore Power (EN) | Foto conector dañado - close-up impactante | Set B |
| Jue Mayo 9 | 11:00 AM | Instagram | #3 | Trabajo de Cableado (ES) | Foto cableado ordenado | Set A |
| Vie Mayo 10 | 10:00 AM | Facebook Page | #8 | Hurricane Season Checklist (EN) | Gráfico tipo lista o foto del tablero | Set B |
| Sáb Mayo 11 | 9:00 AM | Instagram | REEL S1 | "Panel Transformation - Watch This" | Slideshow 5 fotos: antes→durante→después | Set A+B |
**Reel S1:** Texto en pantalla: Foto 1 "Before" / Foto 3 "During" / Foto 5 "After - Clean. Safe. Done." | CTA: "DM for a quote - Stuart to Jacksonville" | Duración: 15-20 seg
---
## SEMANA 2: Mayo 12-18
| Fecha | Hora ET | Plataforma | Caption # | Tema | Visual | Hashtags |
|-------|---------|-----------|-----------|------|--------|---------|
| Lun Mayo 12 | 11:00 AM | Instagram | #5 | Lithium vs AGM (EN) | Infografía 2 columnas o foto ambas baterías | Set B |
| Lun Mayo 12 | 5:00 PM | Facebook Groups | FB GROUP #1 | Space/Treasure Coast Power Boat Club | Ver texto abajo | Set B |
| Mar Mayo 13 | 10:00 AM | LinkedIn | #10 | Liveaboard Focus (EN) | Foto sistema completo: panel, baterías, cableado | Set C |
| Mié Mayo 14 | 9:00 AM | Instagram | #6 | Before/After Panel (EN) | Foto antes/después lado a lado | Set A |
| Jue Mayo 15 | 11:00 AM | Instagram | #9 | Seguridad Eléctrica (ES) | Foto materiales correctos vs incorrectos | Set B |
| Vie Mayo 16 | 10:00 AM | Facebook Page | #5 | Lithium vs AGM (republica) | Misma infografía | Set B |
| Sáb Mayo 17 | 9:00 AM | Instagram | REEL S2 | "Lithium vs AGM - The Numbers Don't Lie" | 4 slides comparativos con texto superpuesto | Set B |
**Reel S2:** CTA: "Comment BATTERY for a free quote" | Duración: 20-25 seg | Bilingüe EN/ES
---
## SEMANA 3: Mayo 19-25
| Fecha | Hora ET | Plataforma | Caption # | Tema | Visual | Hashtags |
|-------|---------|-----------|-----------|------|--------|---------|
| Lun Mayo 19 | 11:00 AM | Instagram | #7 | Washdown System (EN) | Foto sistema instalado, bomba + mangueras | Set A |
| Lun Mayo 19 | 6:00 PM | Facebook Groups | FB GROUP #2 | Freedom Boat Club Florida | Ver texto abajo | Set C |
| Mar Mayo 20 | 10:00 AM | LinkedIn | #13 | Call for Referrals (EN) | Foto del equipo o logo Prisa Yachts | Set C |
| Mié Mayo 21 | 9:00 AM | Instagram | #12 | Diagrama Eléctrico (ES) | Foto del diagrama + manos del técnico | Set A |
| Jue Mayo 22 | 11:00 AM | Instagram | #2 | Rewiring Job (EN) | Foto cableado nuevo, alta estética | Set A |
| Vie Mayo 23 | 10:00 AM | Facebook Page | #7 | Washdown System (republica) | Misma foto | Set A |
| Sáb Mayo 24 | 9:00 AM | Instagram | REEL S3 | "Lo que nadie te dice del rewiring" | 5 fotos: cable incorrecto→herramientas→resultado→logo | Set A+C |
**Reel S3:** Texto #1: "Most boat fires start here" | Texto #5: "Prisa Yachts LLC - Marine Electrical" | CTA: "Save this - share with your marina neighbor" | Duración: 15 seg
---
## SEMANA 4: Mayo 26 - Junio 1
| Fecha | Hora ET | Plataforma | Caption # | Tema | Visual | Hashtags |
|-------|---------|-----------|-----------|------|--------|---------|
| Lun Mayo 26 | 11:00 AM | Instagram | #14 | Banco de Baterías Litio (ES) | Foto batería litio instalada | Set A |
| Mar Mayo 27 | 10:00 AM | LinkedIn | #15 | Pre-Temporada (ES) | Foto barco en marina o checklist mantenimiento | Set B |
| Mié Mayo 28 | 9:00 AM | Instagram | #15 | Pre-Temporada (ES) | Foto mantenimiento activo o panel antes de revisión | Set B |
| Jue Mayo 29 | 11:00 AM | Instagram | #13 | Call for Referrals (EN) | Foto trabajo exitoso o testimonio | Set C |
| Vie Mayo 30 | 10:00 AM | Facebook Page | #14 | Banco Baterías Litio (republica) | Misma foto | Set A |
| Vie Mayo 30 | 2:00 PM | LinkedIn | #13 | Call for Referrals (segundo empuje) | Foto cliente/trabajo exitoso | Set C |
| Sáb Mayo 31 | 9:00 AM | Instagram | REEL S4 | "Hurricane Season Prep - 5-Point Checklist" | 6 fotos checklist visual + logo final | Set B+C |
**Reel S4:** Bilingüe — cada punto en EN, CTA final en ES | Texto final: "Prisa Yachts LLC - (xxx) xxx-xxxx" | CTA: "Save this. Share this. Call us before June 1st." | MAYOR POTENCIAL VIRAL por seasonality
---
## POSTS PARA GRUPOS DE FACEBOOK
### FB GROUP POST #1 — Space/Treasure Coast Power Boat Club
**Publicar:** Lunes Mayo 12, 5:00 PM
> Hey everyone - I work as a marine electrical technician out of Stuart and wanted to introduce myself to the group. I specialize in rewiring, lithium battery banks, solar/shore power systems, and washdown installs - all with marine-grade materials from stem to stern.
>
> If you've been putting off an electrical issue or want a pre-season inspection before hurricane season hits, I'm currently booking jobs from Stuart up to Jacksonville. Happy to do a free 20-minute phone consult before committing to anything.
>
> Prisa Yachts LLC - bilingual service (EN/ES). Drop a comment or DM if you want details.
---
### FB GROUP POST #2 — Freedom Boat Club Florida
**Publicar:** Lunes Mayo 19, 6:00 PM
> Asking because I've been seeing a lot of AGM batteries failing early this season - usually from improper charging profiles or undersized alternators. It's one of those things that shows up quietly until the boat doesn't start.
>
> I'm a marine electrician based out of Stuart (Prisa Yachts LLC) - if anyone's had intermittent power issues, flickering lights, or slow starts, it might be worth having the system load-tested before it becomes an emergency.
>
> Currently working Stuart to Jacksonville. Bilingual (EN/ES). Free phone consult before any commitment. Happy to answer questions here too.
---
## ESTRUCTURA DEL GOOGLE SHEET PARA n8n
**Nombre del sheet:** `PrisaYachts_ContentCalendar`
**Tab activa:** `Schedule`
| Col | Header exacto | Tipo | Ejemplo |
|-----|--------------|------|---------|
| A | `post_id` | Texto | `PY-2026-001` |
| B | `publish_date` | Fecha ISO 8601 | `2026-05-06` |
| C | `publish_time_et` | Hora HH:MM | `11:00` |
| D | `platform` | Texto fijo | `instagram` / `facebook_page` / `facebook_group` / `linkedin` |
| E | `caption_number` | Entero | `1` |
| F | `caption_text` | Texto largo | (caption completo) |
| G | `hashtag_set` | Texto | `A` / `B` / `C` / `A+B` |
| H | `visual_type` | Texto | `photo_installation` / `before_after` / `reel_slideshow` |
| I | `visual_filename` | Texto | `battery_install_may06.jpg` |
| J | `status` | Texto fijo | `pending` / `approved` / `published` / `skipped` |
| K | `language` | Texto | `EN` / `ES` / `EN+ES` |
| L | `content_type` | Texto | `educational` / `portfolio` / `safety` / `b2b` / `reel` |
| M | `cta` | Texto | `DM for quote` / `Save this` |
| N | `campaign_week` | Entero | `1` / `2` / `3` / `4` |
| O | `notes` | Texto libre | (notas internas) |
**Reglas críticas:**
1. n8n filtra filas donde `status = "approved"` Y `publish_date` <= fecha actual
2. `platform` en minúsculas exactas sin tildes
3. Fechas en formato `YYYY-MM-DD` (no MM/DD/YYYY)
4. Después de publicar, n8n actualiza `status` a `"published"` para evitar repost
5. Para `facebook_group`: poner el Group ID numérico en columna O (la API requiere ID, no nombre)
---
## RESUMEN: 28 publicaciones en 4 semanas
- Instagram: 15 posts (11 captions + 4 Reels)
- Facebook Page: 5 republicas
- Facebook Groups: 2 posts de comunidad
- LinkedIn: 5 posts B2B
**Distribución:** 10 EN / 4 ES / 1 bilingüe | Sábados siempre Reel (máximo algoritmo de fin de semana)
@@ -0,0 +1,12 @@
# Prisa Yachts LLC — Tips Eléctrico ABYC/NMEA
## 5 Tips + Carrusel "5 Errores Que Pueden Incendiar Tu Barco"
### TIP 1 — Calibre de cable correcto (ABYC E-11)
### TIP 2 — Cable estañado (tinned wire)
### TIP 3 — NMEA 2000 vs NMEA 0183
### TIP 4 — Fusibles y breakers correctamente dimensionados
### TIP 5 — Ground vs Bonding: la diferencia crítica
### CARRUSEL — 7 slides "5 Errores Eléctricos Que Pueden Incendiar Tu Barco"
[Ver contenido completo en el archivo fuente — todos los captions EN/ES listos para copiar]
+12
View File
@@ -0,0 +1,12 @@
# Prisa Yachts LLC — Tips Hardware Marino
## 5 Tips + Carrusel "Pre-Season Hardware Checklist"
### TIP 1 — Winches: lubricación correcta
### TIP 2 — Cadena de ancla: inspección, marcado y reemplazo
### TIP 3 — Herrajes inoxidable: por qué se oxidan y cómo prevenirlo
### TIP 4 — Tornillería: 316 SS o bronce marino (nunca galvanizado)
### TIP 5 — Escotillas y sellos: mantenimiento preventivo
### CARRUSEL — 5 slides "Pre-Season Hardware Checklist"
[Ver contenido completo en archivo fuente — todos los captions EN/ES listos]
+256
View File
@@ -0,0 +1,256 @@
# Prisa Yachts LLC — Motores y Filtración Marina
## 5 Tips Técnicos + Carrusel "Annual Engine Service Checklist"
---
## TIP 1 — THE IMPELLER
### "The $30 Part That Can Kill a $15,000 Engine"
**Caption EN**
That small rubber wheel inside your raw-water pump? It costs $30. When it fails while you're underway in Florida heat, your engine can overheat in under 5 minutes — we're talking warped heads, seized bearings, cracked heat exchangers. The repair? Easily $5,000 to $15,000.
The impeller is the single most overlooked part in marine engine maintenance. Florida's warm saltwater makes rubber degrade faster than you'd expect. Best practice: replace every 200 hours OR once per season — whichever comes first. And always carry a spare onboard.
Signs it's failing: rising engine temperature, reduced raw-water flow from the exhaust, or rubber fragments in your strainer basket. Don't wait for an alarm. By then, the damage is done.
At Prisa Yachts LLC, impeller replacement is part of every seasonal service we perform — from Stuart to Jacksonville. We check the full raw-water circuit, not just the pump.
DM us for preventive maintenance — Stuart to Jacksonville.
`#ImpellerReplacement #MarineEngine #RawWaterPump #BoatMaintenance #FloridaBoating #MarineMechanic #PreventiveMaintenance #SaltwaterBoating #YachtMaintenance #PrisaYachtsLLC`
---
**Caption ES**
Esa pequeña rueda de goma dentro de tu bomba de agua bruta cuesta $30. Cuando falla mientras navegas en el calor de Florida, tu motor puede sobrecalentarse en menos de 5 minutos — estamos hablando de culatas dobladas, cojinetes agarrotados, intercambiadores fisurados. La reparación? Fácil $5,000 a $15,000.
El impeller es la pieza más ignorada en el mantenimiento de motores marinos. El agua salada caliente de Florida degrada el caucho mucho más rápido de lo que imaginas. Lo correcto: cambiarlo cada 200 horas O una vez por temporada — lo que ocurra primero. Y siempre lleva uno de repuesto a bordo.
Señales de fallo: temperatura del motor subiendo, poco flujo de agua en el escape, o fragmentos de goma en la canastilla del filtro. No esperes la alarma. Para entonces, el daño ya está hecho.
En Prisa Yachts LLC, el cambio de impeller es parte de todo servicio de temporada — de Stuart a Jacksonville. Revisamos todo el circuito de agua bruta, no solo la bomba.
Escríbenos para mantenimiento preventivo — de Stuart a Jacksonville.
`#ImpellerReplacement #MarineEngine #RawWaterPump #BoatMaintenance #FloridaBoating #MarineMechanic #PreventiveMaintenance #SaltwaterBoating #YachtMaintenance #PrisaYachtsLLC`
---
## TIP 2 — ZINCS / ÁNODOS
### "Zincs: The Sacrificial Guards Your Engine Needs"
**Caption EN**
Saltwater is relentless. The moment your boat touches it, electrochemical reactions start attacking your underwater metals — aluminum lower units, stainless shafts, bronze fittings. The only thing standing between your engine and accelerated corrosion is a small piece of zinc or aluminum worth a few dollars.
Anodes work by corroding first, sacrificing themselves so your expensive components don't. But here's what most people miss: a depleted anode is worse than no anode — because it gives you false confidence. In Florida's warm, conductive saltwater, anodes can go from full to 50% consumed in a single season.
Inspection schedule: every 3-6 months. Replace at 50% consumed — not 100%. On outboards, check your lower unit anode AND your trim tab. On inboard diesels, inspect shaft zincs, rudder zincs, and hull plates.
Saltwater doesn't take days off. Neither do we.
DM us for preventive maintenance — Stuart to Jacksonville.
`#ZincAnodes #GalvanicCorrosion #MarineCorrosionProtection #AnodeReplacement #SaltwaterBoating #OutboardMaintenance #InboardDiesel #FloridaBoating #MarineMechanic #PrisaYachtsLLC`
---
**Caption ES**
El agua salada no para. Desde el momento en que tu barca toca el agua, reacciones electroquímicas atacan tus metales sumergidos — unidades inferiores de aluminio, ejes de acero inoxidable, accesorios de bronce. Lo único que está entre tu motor y la corrosión acelerada es un pequeño trozo de zinc o aluminio que cuesta unos pocos dólares.
Los ánodos funcionan corroiéndose primero, sacrificándose para que tus piezas caras no lo hagan. Pero esto es lo que la mayoría ignora: un ánodo agotado es peor que no tenerlo — porque te da una falsa sensación de seguridad. En el agua salada cálida de Florida, un ánodo puede pasar de nuevo a 50% consumido en una sola temporada.
Frecuencia de inspección: cada 3 a 6 meses. Reemplaza cuando esté al 50% — no al 100%. En fuera de borda, revisa el ánodo de la unidad inferior Y el trim tab. En diesel inboard, inspecciona los zincs del eje, del timón y las placas del casco.
El agua salada no descansa. Nosotros tampoco.
Escríbenos para mantenimiento preventivo — de Stuart a Jacksonville.
`#ZincAnodes #GalvanicCorrosion #MarineCorrosionProtection #AnodeReplacement #SaltwaterBoating #OutboardMaintenance #InboardDiesel #FloridaBoating #MarineMechanic #PrisaYachtsLLC`
---
## TIP 3 — FILTRO DE COMBUSTIBLE: PRIMARIO vs. SECUNDARIO
### "Two Filters, One Mission: Keeping Bad Fuel Out of Your Engine"
**Caption EN**
Your diesel engine has two lines of defense against bad fuel — and most boat owners only know about one of them.
The PRIMARY filter (Racor bowl-type) does the heavy lifting: it pulls water out of your diesel and catches large sediment before it reaches the lift pump. That clear bowl? Inspect it every 50 hours. If you see water or dark sludge — stop. Deal with it before you go offshore.
The SECONDARY filter is mounted on the engine itself. It catches particles down to 2 microns — protecting your injection pump and injectors. Modern common-rail diesels can have injector tolerances tighter than a human hair. Contaminated fuel reaching those injectors means $300-$800 per injector in repairs. Replace this filter at every oil change.
Florida's humidity and temperature swings cause constant condensation inside fuel tanks. That means water, and water means diesel algae. Two-stage filtration is not optional here — it's survival.
DM us for preventive maintenance — Stuart to Jacksonville.
`#FuelFilter #RacorFilter #MarineDiesel #FuelFiltration #DieselMaintenance #MarineEngine #FloridaBoating #BoatMaintenance #PreventiveMaintenance #PrisaYachtsLLC`
---
**Caption ES**
Tu motor diesel tiene dos líneas de defensa contra el combustible contaminado — y la mayoría de los dueños de embarcaciones solo conoce una.
El filtro PRIMARIO (tipo bowl Racor) hace el trabajo pesado: separa el agua del diesel y captura sedimentos grandes antes de que lleguen a la bomba de cebado. Ese bowl transparente? Inspecciónalo cada 50 horas. Si ves agua o lodo oscuro — para. Resuélve eso antes de salir a mar abierto.
El filtro SECUNDARIO está montado en el motor mismo. Captura partículas de hasta 2 micrones, protegiendo tu bomba de inyección y los inyectores. Los dieseles common-rail modernos tienen tolerancias en los inyectores más finas que un cabello humano. Combustible contaminado llegando a esos inyectores significa $300 a $800 por inyector en reparaciones. Cambia este filtro en cada cambio de aceite.
La humedad y los cambios de temperatura en Florida causan condensación constante dentro de los depósitos. Eso significa agua, y el agua significa algas en el diesel. La filtración en dos etapas no es opcional aquí — es supervivencia.
Escríbenos para mantenimiento preventivo — de Stuart a Jacksonville.
`#FuelFilter #RacorFilter #MarineDiesel #FuelFiltration #DieselMaintenance #MarineEngine #FloridaBoating #BoatMaintenance #PreventiveMaintenance #PrisaYachtsLLC`
---
## TIP 4 — CAMBIO DE ACEITE MARINO vs. AUTOMOTRIZ
### "Your Boat Engine Is Not Your Car"
**Caption EN**
Your car tells you when to change the oil. Your boat doesn't. And the consequences of getting this wrong are far more expensive on the water.
Marine engines run at sustained high loads for hours. They sit in humid environments. Raw-water cooling systems push moisture into the engine compartment. All of that destroys oil far faster than a highway commute ever could.
The rules are different here:
- Gasoline inboard: every 100 hours OR once per season
- Diesel inboard: every 100-150 hours (check your manual)
- Stored for the season? Change the oil before AND after storage — not just one.
Also critical: do NOT use automotive "Energy Conserving" oil in a marine gasoline engine. Those friction modifiers can cause your marine transmission clutch to slip. Use oil rated and specified for your exact engine.
And always — always — change the filter at the same time.
DM us for preventive maintenance — Stuart to Jacksonville.
`#MarineOilChange #OilChange #MarineEngine #InboardDiesel #BoatMaintenance #MarineMechanic #PreventiveMaintenance #FloridaBoating #SaltwaterBoating #PrisaYachtsLLC`
---
**Caption ES**
Tu carro te avisa cuando cambiar el aceite. Tu barca no. Y las consecuencias de equivocarse son mucho más caras en el agua.
Los motores marinos trabajan a cargas altas sostenidas durante horas. Están en ambientes húmedos. Los sistemas de refrigeración de agua bruta empujan humedad al compartimento del motor. Todo eso destruye el aceite mucho más rápido que un viaje en autopista.
Las reglas son distintas aquí:
- Gasolina inboard: cada 100 horas O una vez por temporada
- Diesel inboard: cada 100 a 150 horas (revisa tu manual)
- ¿Guardaste la barca por la temporada? Cambia el aceite ANTES y DESPUÉS — no solo una vez.
También crítico: NO uses aceite automotriz "Energy Conserving" en un motor marino de gasolina. Los modificadores de fricción de esos aceites pueden hacer que el embrague de la transmisión marina patine. Usa aceite especificado para tu motor exacto.
Y siempre — siempre — cambia el filtro al mismo tiempo.
Escríbenos para mantenimiento preventivo — de Stuart a Jacksonville.
`#MarineOilChange #OilChange #MarineEngine #InboardDiesel #BoatMaintenance #MarineMechanic #PreventiveMaintenance #FloridaBoating #SaltwaterBoating #PrisaYachtsLLC`
---
## TIP 5 — COLORES DEL HUMO DEL ESCAPE
### "Read the Smoke Before the Engine Can't Talk Anymore"
**Caption EN**
Your engine can't text you. But it can talk through its exhaust — if you know how to listen.
WHITE SMOKE (persistent, not startup condensation): Water or coolant in the combustion chamber. Head gasket, cracked head, or heat exchanger failure. If your oil looks milky, shut down NOW. Do not restart.
BLACK SMOKE: Too much fuel, not enough air. Clogged air filter, dirty injectors, failing turbo, restricted intake. Less urgent than white, but fix it — carbon buildup adds up fast and fuel efficiency drops.
BLUE SMOKE: Oil burning in the combustion chamber. Worn piston rings, valve seals, or a turbo seal failure. Startup blue that clears? Likely valve seals. Persistent blue under load? That's a mechanical inspection — now.
Florida heat, saltwater exposure, and high humidity accelerate every one of these failure modes. Read your exhaust at startup, during acceleration, and under load. Make it a habit every single time you leave the dock.
DM us for preventive maintenance — Stuart to Jacksonville.
`#ExhaustSmoke #MarineEngineDiagnostics #WhiteSmoke #BlackSmoke #BlueSmoke #MarineEngine #BoatMaintenance #FloridaBoating #MarineMechanic #PrisaYachtsLLC`
---
**Caption ES**
Tu motor no puede mandarte un mensaje. Pero puede hablar a través de su escape — si sabes escuchar.
HUMO BLANCO (persistente, no condensación al arranque): Agua o refrigerante en la cámara de combustión. Junta de culata, culata fisurada, o fallo del intercambiador de calor. Si el aceite se ve lechoso, APAGA el motor YA. No lo vuelvas a encender.
HUMO NEGRO: Demasiado combustible, poco aire. Filtro de aire obstruido, inyectores sucios, turbo fallando, toma de aire restringida. Menos urgente que el blanco, pero soluciónalo — la acumulación de carbón es costosa y el rendimiento cae.
HUMO AZUL: Aceite quemándose en la cámara de combustión. Anillos de pistón desgastados, retenes de válvulas, o fallo del sello del turbo. ¿Azul al arranque que desaparece? Probablemente retenes de válvulas. ¿Azul persistente bajo carga? Inspección mecánica — ahora.
El calor de Florida, la exposición al agua salada y la humedad aceleran todos estos modos de fallo. Lee tu escape al arrancar, durante la aceleración y bajo carga. Haz un hábito de esto cada vez que salgas del muelle.
Escríbenos para mantenimiento preventivo — de Stuart a Jacksonville.
`#ExhaustSmoke #MarineEngineDiagnostics #WhiteSmoke #BlackSmoke #BlueSmoke #MarineEngine #BoatMaintenance #FloridaBoating #MarineMechanic #PrisaYachtsLLC`
---
## CARRUSEL — "Annual Engine Service Checklist — Florida Saltwater Edition"
### SLIDE 1 — Cover
**HEADLINE:** Annual Engine Service Checklist — Florida Saltwater Edition
**SUBTEXT:** 10 things your engine needs every year to survive Florida's saltwater environment. (Most boat owners skip at least 3 of these.)
**Bottom tag:** @prisayachts | Stuart to Jacksonville
---
### SLIDE 2 — Fluids and Filters
**HEADLINE:** Step 1 — Fluids and Filters
- Change engine oil and oil filter (per manufacturer hours)
- Replace primary fuel filter element (Racor bowl)
- Replace secondary engine fuel filter
- Check and replace gear oil in transmission/outdrive
- Inspect coolant concentration and condition (50/50 minimum)
- Drain and inspect raw-water strainer basket
**Florida tip:** Diesel tanks collect condensation year-round. Inspect Racor bowl every 50 hours — never skip it.
---
### SLIDE 3 — Raw Water Cooling System
**HEADLINE:** Step 2 — Raw Water Cooling Circuit
- Replace raw-water impeller (every 200 hours or annually)
- Inspect and flush heat exchanger
- Check all raw-water hoses for cracking, softness, or swelling
- Inspect thermostat — replace every 2 seasons in saltwater
- Clean seacock strainer and test seacock operation
- Verify exhaust water flow at startup (look for a steady stream)
**Florida tip:** A failed impeller in summer heat can destroy a motor in under 5 minutes. Replace it every season — do not test it.
---
### SLIDE 4 — Belts, Hoses and Anodes
**HEADLINE:** Step 3 — Belts, Hoses and Anodes
- Inspect and replace serpentine/V-belts (check for cracking, glazing, fraying)
- Replace all zincs/anodes: lower unit, trim tab, shaft, rudder, hull plates
- Inspect all coolant hoses — squeeze test for hardness or sponginess
- Check all fuel hose connections for seepage or cracking
- Inspect motor mounts for deterioration
- Check engine alignment (inboard)
**Florida tip:** Replace anodes when 50% consumed — not 100%. Aluminum anodes outperform zinc in full saltwater.
---
### SLIDE 5 — Ignition, Electrical and Final Checks
**HEADLINE:** Step 4 — Ignition, Electrical and Final Checks
- Inspect and clean battery terminals — check electrolyte levels
- Test alternator output voltage (13.8-14.4V at charge)
- Inspect spark plugs or glow plugs depending on engine type
- Test all engine alarms: overheat, low oil pressure, no raw-water flow
- Run engine to full operating temperature — observe exhaust color
- Log engine hours and record all service performed with dates
**Florida tip:** Test your alarms with every service. An alarm that doesn't sound gives you zero warning when it matters most.
**CTA (all slides):** Need this done right? DM us for your annual engine service. Prisa Yachts LLC — Stuart to Jacksonville | @prisayachts
`#AnnualBoatService #MarineEngineService #BoatMaintenance #FloridaBoating #SaltwaterBoating #MarineMechanic #EngineChecklist #PreventiveMaintenance #YachtMaintenance #PrisaYachtsLLC`
+333
View File
@@ -0,0 +1,333 @@
# Prisa Yachts LLC — Recuperación de Teca y Detailing
## 5 Tips Técnicos + 3 Captions Before/After para fotos reales
---
## TIP 1 — ¿SE PUEDE SALVAR TU TECA?
### "Can Your Teak Be Saved? (Visual Evaluation)"
**Caption EN**
Your teak is gray and looks rough — but is it actually dead?
Here's the honest evaluation we do before touching a single plank. Run your thumbnail across the grain: if the wood is dense, firm, and fibers don't lift, that gray surface is just oxidation. The honey-brown color is still underneath, waiting. That's a recovery job.
What tells us replacement is the real answer: soft spots that compress under pressure, caulking seams that have pulled away from the wood by more than an inch, planks cracking along the grain from the inside out, or wood that's gone thin from years of aggressive sanding.
In Florida, two seasons of zero maintenance is often the turning point. We've recovered teak that looked destroyed — and we've also had the honest conversation when replacement was the smarter investment.
If you're not sure which side of that line you're on, send us a few photos. We'll give you a straight answer before you spend a dollar.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakRecovery #MarineTeak #BoatMaintenance #FloridaBoating #YachtDetailing #TeakDeck #MarineServices #BoatCare #SouthFloridaYachts`
---
**Caption ES**
Tu teca está gris y se ve mal — pero, ¿realmente está muerta?
Esta es la evaluación honesta que hacemos antes de tocar una sola tabla. Pasa la uña a contrapelo: si la madera está densa, firme y las fibras no se levantan, esa superficie gris es solo oxidación. El color miel todavía está adentro, esperando. Eso es trabajo de recuperación.
Lo que nos dice que el reemplazo es la respuesta real: zonas blandas que ceden bajo presión, costuras de sellado separadas más de 2 cm, tablas con grietas a lo largo de la veta desde adentro, o madera que se ha adelgazado por lijados agresivos previos.
En Florida, dos temporadas sin mantenimiento suelen ser el punto de quiebre. Hemos recuperado teca que parecía destruida — y también hemos tenido la conversación honesta cuando el reemplazo era la inversión más inteligente.
Si no sabes de qué lado estás, mándanos unas fotos. Te damos una respuesta directa antes de que gastes un dólar.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #RecuperacionDeTeca #TecaMarina #MantenimientoNautico #YachtsFlorida #DetallingMarino #TecaNautica #ServiciosMarinos #CuidadoDeBarco #YachtsSurFlorida`
---
## TIP 2 — EL PROCESO: CLEAN → SAND → OIL → SEAL
**Caption EN**
Teak recovery isn't magic — it's a sequence. And most DIY jobs fail because they skip a step.
Here's the actual process we follow:
CLEAN — Two-part teak cleaner. Part A breaks down oxidation and gray surface cells. Part B neutralizes the wood's pH. You're starting with a clean canvas, not covering problems.
SAND — 80-grit to open the grain, 120-grit to smooth. Always with the grain. Never cross-grain with a random orbit sander — you'll create water traps invisible to the eye.
OIL — Penetrating marine teak oil, thin coats, wiped before it skins. This feeds the wood from the inside. You're not painting it, you're conditioning it.
SEAL — UV-blocking teak sealer for high-traffic areas. Florida sun will reoxidize bare teak in one season. The sealer buys you 12 to 18 months before the next maintenance cycle.
Skip any of these steps and you're spending money to fail faster.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakRestoration #MarineTeak #BoatDetailingFlorida #TeakDeckCare #MarineWoodcare #FloridaYacht #BoatMaintenance #YachtCare #MarineDetailing`
---
**Caption ES**
La recuperación de teca no es magia — es una secuencia. Y la mayoría de los trabajos fallan porque se salta un paso.
Este es el proceso real que seguimos:
LIMPIAR — Limpiador de teca en dos partes. La parte A rompe la oxidación y las células grises de la superficie. La parte B neutraliza el pH de la madera. Empiezas con una superficie limpia, no cubriendo problemas.
LIJAR — Lija 80 para abrir el grano, 120 para alisar. Siempre a favor de la veta. Nunca transversal con lijadora orbital — creas trampas de agua invisibles al ojo.
ACEITAR — Aceite marino de teca penetrante, capas finas, limpiando el exceso antes de que forme película. Nutres la madera desde adentro. No la estás pintando, la estás acondicionando.
SELLAR — Sellador UV para zonas de alto tráfico. El sol de Florida reoxida la teca sin protección en una sola temporada. El sellador te da 12 a 18 meses hasta el próximo ciclo de mantenimiento.
Sáltate cualquiera de estos pasos y estás gastando dinero para fallar más rápido.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #RestauracionTeca #TecaMarina #DetallingFlorida #CuidadoTeca #MaderaMaritima #YachtFlorida #MantenimientoNautico #CuidadoYacht #DetallingNautico`
---
## TIP 3 — TEAK OIL vs. TEAK SEALER: CUÁL Y CUÁNDO
**Caption EN**
Teak oil and teak sealer are not the same product. Using the wrong one at the wrong time is one of the most expensive mistakes in boat maintenance.
Here's the difference:
TEAK OIL is a penetrating product. It goes INTO the wood, not onto it. It feeds depleted wood — replacing the natural oils that Florida sun and salt air pull out month after month. Use it after a full clean and sand, when the wood is porous and dry. If it doesn't absorb within 20 minutes, something is wrong with the prep.
TEAK SEALER is a surface barrier. It doesn't feed the wood — it seals the surface against UV, moisture movement, and reoxidation. Use it AFTER oiling, as the final layer on horizontal surfaces that take direct sun and standing water.
The order matters: oil first, sealer second. Putting sealer on dry, un-oiled teak in Florida gives you 90 days of results before it starts peeling — because the wood is moving underneath and there's nothing holding it stable.
Two products. Two jobs. Both necessary. Neither optional in this climate.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakOil #TeakSealer #MarineTeak #BoatWoodcare #FloridaBoating #TeakMaintenance #YachtCare #MarineDetailing #BoatMaintenance`
---
**Caption ES**
El aceite de teca y el sellador de teca no son el mismo producto. Usar el equivocado en el momento equivocado es uno de los errores más caros en el mantenimiento de embarcaciones.
La diferencia:
ACEITE DE TECA es un producto penetrante. Va DENTRO de la madera, no sobre ella. Nutre la madera agotada — reemplazando los aceites naturales que el sol de Florida y el aire salado extraen mes a mes. Úsalo después de una limpieza y lijado completo, cuando la madera está porosa y seca. Si no absorbe en 20 minutos, algo está mal con la preparación.
SELLADOR DE TECA es una barrera superficial. No nutre la madera — sella la superficie contra los rayos UV, el movimiento de humedad y la reoxidación. Úsalo DESPUÉS del aceite, como capa final en superficies horizontales que reciben sol directo y agua estancada.
El orden importa: aceite primero, sellador después. Poner sellador en teca seca sin aceite en Florida te da 90 días de resultados antes de que empiece a despegarse — porque la madera se está moviendo por debajo y no hay nada que la estabilice.
Dos productos. Dos funciones. Ambos necesarios. Ninguno es opcional en este clima.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #AceiteDeTeca #SelladorTeca #TecaMarina #MaderaMaritima #NavegacionFlorida #MantenimientoTeca #CuidadoYacht #DetallingMarino #MantenimientoNautico`
---
## TIP 4 — POR QUÉ EL SOL DE FLORIDA DESTRUYE LA TECA EN 2 TEMPORADAS
**Caption EN**
Florida is not a forgiving environment for teak. And a lot of boat owners don't understand why until they're looking at a replacement quote.
Here's what's actually happening to your deck every season you skip maintenance:
UV INDEX 10-11 from March through October. That's among the highest in the continental US. It bleaches the lignin — the natural binder that holds teak fibers together — and oxidizes the surface oils that give the wood its density. Once the lignin is gone, the fibers start separating.
SALT AIR deposits salt crystals in the open grain. Those crystals absorb moisture and expand and contract with the daily heat cycle, physically prying the wood open from the inside.
THERMAL CYCLING on a dark deck surface means 35-40°F swings between 7 AM and 2 PM. That's constant wood movement — and it accelerates everything above.
Teak planks start at 5/8 inch from the factory. Every aggressive sanding to fix neglect removes material that doesn't come back. Two seasons of zero maintenance in Florida can take a recoverable deck and make it a replacement conversation.
One maintenance cycle per year stops all three damage channels. The math on prevention versus replacement is not close.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #FloridaBoating #TeakDeck #UVDamage #MarineTeak #BoatMaintenance #TeakProtection #FloridaYacht #MarineDetailing #YachtCare`
---
**Caption ES**
Florida no es un ambiente generoso con la teca. Y muchos dueños de embarcaciones no lo entienden hasta que están viendo un presupuesto de reemplazo.
Esto es lo que le pasa a tu cubierta cada temporada que saltas el mantenimiento:
ÍNDICE UV 10-11 de marzo a octubre. Es uno de los más altos de los Estados Unidos continentales. Blanquea la lignina — el aglutinante natural que mantiene las fibras de teca unidas — y oxida los aceites superficiales que le dan densidad a la madera. Una vez que la lignina se va, las fibras comienzan a separarse.
AIRE SALADO deposita cristales de sal en el grano abierto. Esos cristales absorben humedad y se expanden y contraen con el ciclo de calor diario, abriendo físicamente la madera desde adentro.
CICLOS TÉRMICOS en una cubierta oscura significan cambios de 18-22°C entre las 7 AM y las 2 PM. Eso es movimiento constante de la madera — y acelera todo lo anterior.
Las tablas de teca salen de fábrica a 16 mm de espesor. Cada lijado agresivo para corregir el abandono elimina material que no vuelve. Dos temporadas sin mantenimiento en Florida pueden convertir una cubierta recuperable en una conversación de reemplazo.
Un ciclo de mantenimiento al año detiene los tres canales de daño. La diferencia entre prevención y reemplazo no admite discusión.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #NavegacionFlorida #TecaMarina #DañoUV #CubertaDeTeca #MantenimientoNautico #ProteccionTeca #YachtFlorida #DetallingMarino #CuidadoYacht`
---
## TIP 5 — GELCOAT DETAILING: OXIDACIÓN LEVE vs. SEVERA
**Caption EN**
Not all oxidation is the same — and treating them the same way is how you either under-correct or burn through your gelcoat.
Here's how to read what you're dealing with:
LIGHT OXIDATION: Surface looks hazy, colors seem flat instead of vibrant. Drag a white rag across it — faint chalk residue. At this stage, a fine-cut polish on a DA polisher restores the gloss without removing significant gelcoat. Follow with a quality marine wax or sealant. In Florida, that protection lasts 3 to 6 months.
SEVERE OXIDATION: Heavy chalking when touched, original color has shifted toward white or gray, surface feels matte and doesn't respond to light polishing. Now you're in cutting compound territory — wool or foam cutting pad, rotary or forced-rotation polisher. The risk: gelcoat is only 0.5 to 0.8mm thick. Heavy cutting requires experienced hands or you break through.
The rule we follow: start with the least aggressive correction that solves the problem. You can always cut more. You can't put gelcoat back.
After any cut: finishing polish to remove cut marks, then wax or sealant to protect what you've restored.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #GelcoatRestoration #BoatDetailing #MarineDetailing #FloridaBoating #GelcoatPolishing #BoatWax #YachtDetailing #OxidationRemoval #BoatCare`
---
**Caption ES**
No toda oxidación es igual — y tratarlas igual es como se corrige de menos o se quema la capa de gelcoat.
Así se lee lo que tienes frente a ti:
OXIDACIÓN LEVE: La superficie se ve opaca, los colores parecen apagados en vez de vibrantes. Pasa un trapo blanco — residuo de tiza leve. En este punto, una pulida fina con pulidora DA restaura el brillo sin remover gelcoat significativo. Termina con cera marina o sellador. En Florida, esa protección dura 3 a 6 meses.
OXIDACIÓN SEVERA: Tizamiento fuerte al tacto, el color original se ha ido hacia el blanco o gris, la superficie se siente mate y no responde al pulido leve. Ahora estás en territorio de compuesto de corte — pad de lana o espuma de corte, pulidora rotativa o de rotación forzada. El riesgo: el gelcoat tiene solo 0.5 a 0.8mm de espesor. El corte agresivo requiere manos con experiencia o lo atraviesas.
La regla que seguimos: empezar siempre con la corrección menos agresiva que resuelve el problema. Siempre puedes cortar más. No puedes devolver el gelcoat.
Después de cualquier corte: pulido de acabado para eliminar las marcas, luego cera o sellador para proteger lo que restauraste.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #RestauracionGelcoat #DetallingNautico #DetallingMarino #NavegacionFlorida #PulidoGelcoat #CeraParaBarcos #DetallingYacht #EliminacionOxidacion #CuidadoBarco`
---
## CAPTIONS BEFORE/AFTER — PARA TUS 10 FOTOS REALES DE TECA
### CAPTION A — RESTAURACIÓN DRAMÁTICA (Muy deteriorada → Perfecta)
**Caption EN**
This is what two seasons of Florida sun and zero maintenance does to teak. And this is what the same deck looks like after a full recovery.
No replacement. No new planks. The same wood — cleaned, sanded, oiled, and sealed by hand.
What you're seeing on the left: gray, fiber-lifting, salt-embedded teak that most people would write off. What you're seeing on the right: the same deck, same wood, after a full two-part clean, progressive sanding, penetrating marine oil, and UV-blocking sealer.
The honey-brown color was there the entire time. We just had to take the time to find it.
This is why we evaluate before we quote. A lot of teak that looks dead in Florida isn't. It's just asking for the right process.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakBeforeAfter #TeakRestoration #MarineTeak #FloridaBoating #BoatDetailingFlorida #TeakDeck #BeforeAndAfter #YachtCare #MarineDetailing`
---
**Caption ES**
Esto es lo que dos temporadas de sol de Florida y cero mantenimiento le hacen a la teca. Y esto es lo que luce el mismo deck después de una recuperación completa.
Sin reemplazo. Sin tablas nuevas. La misma madera — limpiada, lijada, aceitada y sellada a mano.
Lo que ves a la izquierda: teca gris, fibras levantadas, sal incrustada, que la mayoría descartaría. Lo que ves a la derecha: el mismo deck, la misma madera, después de una limpieza en dos partes, lijado progresivo, aceite marino penetrante y sellador con bloqueo UV.
El color miel estaba ahí todo el tiempo. Solo había que tomarse el tiempo de encontrarlo.
Por eso evaluamos antes de cotizar. Mucha teca que parece muerta en Florida no lo está. Solo necesita el proceso correcto.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #TecaAntesYDespues #RestauracionTeca #TecaMarina #NavegacionFlorida #DetallingFlorida #CubertaTeca #AntesYDespues #CuidadoYacht #DetallingMarino`
---
### CAPTION B — MANTENIMIENTO PREVENTIVO (Teca ya cuidada → Mejor aún)
**Caption EN**
Preventive maintenance doesn't make the news. But this is what it actually looks like.
This deck wasn't neglected. The owner was already doing the right things — keeping it clean, protecting it seasonally. We came in for a maintenance detail: light clean, light sand to refresh the grain, one coat of oil, sealer applied on horizontal surfaces.
The difference between left and right isn't dramatic. It's deliberate.
This is what protects a deck from ever needing the dramatic before/after. This is what adds years to the life of a teak investment. This is what the deck looks like when the owner treats it like the asset it is.
One maintenance cycle per year in Florida. That's the whole strategy.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakMaintenance #PreventiveMaintenance #MarineTeak #BoatCare #FloridaYacht #TeakDeck #YachtMaintenance #MarineDetailing #BoatDetailing`
---
**Caption ES**
El mantenimiento preventivo no sale en los titulares. Pero así es como se ve en la realidad.
Esta cubierta no estaba abandonada. El propietario ya estaba haciendo las cosas bien — manteniéndola limpia, protegiéndola cada temporada. Llegamos para un detailing de mantenimiento: limpieza leve, lijado suave para refrescar el grano, una capa de aceite, sellador en las superficies horizontales.
La diferencia entre la izquierda y la derecha no es dramática. Es intencional.
Esto es lo que protege una cubierta de necesitar el antes/después dramático. Esto es lo que le agrega años de vida a una inversión en teca. Así luce una cubierta cuando el propietario la trata como el activo que es.
Un ciclo de mantenimiento al año en Florida. Esa es toda la estrategia.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #MantenimientoTeca #MantenimientoPreventivo #TecaMarina #CuidadoBarco #YachtFlorida #CubertaTeca #MantenimientoYacht #DetallingMarino #DetallingNautico`
---
### CAPTION C — EN PROCESO (Mostrando el trabajo)
**Caption EN**
Somewhere between gray and honey-brown, there's a lot of work.
This is what teak recovery looks like mid-process. Two-part cleaner done. First sand done. The color is already starting to come back — you can see the honey showing through in the sections we've finished, still gray in the ones we haven't reached yet.
This is the part that doesn't get skipped. No shortcuts between the before and after.
Every plank by hand. Every seam inspected. Sanding with the grain, not against it. Wiping off the oil before it skins. Letting each coat dry before the next one goes on.
The finished result is in the next post. But we wanted you to see this part too — because this is where the job actually gets done.
DM us for a quote — Stuart to Jacksonville.
`#PrisaYachts #TeakRecovery #BehindTheScenes #MarineTeak #BoatDetailingFlorida #TeakRestoration #WorkInProgress #YachtCare #MarineDetailing #FloridaBoating`
---
**Caption ES**
Entre el gris y el color miel, hay mucho trabajo.
Así luce una recuperación de teca a la mitad del proceso. Limpiador en dos partes listo. Primer lijado listo. El color ya está empezando a volver — puedes ver el miel asomando en las secciones que terminamos, todavía gris en las que no hemos llegado.
Esta es la parte que no se salta. No hay atajos entre el antes y el después.
Cada tabla a mano. Cada costura inspeccionada. Lijando a favor de la veta, nunca en contra. Limpiando el aceite antes de que forme película. Dejando que cada capa seque antes de aplicar la siguiente.
El resultado final está en el próximo post. Pero queríamos que vieras esta parte también — porque aquí es donde realmente se hace el trabajo.
Escríbenos para un presupuesto — Stuart to Jacksonville.
`#PrisaYachts #RecuperacionTeca #DetrásDeEscena #TecaMarina #DetallingFlorida #RestauracionTeca #EnProceso #CuidadoYacht #DetallingMarino #NavegacionFlorida`
+757
View File
@@ -0,0 +1,757 @@
"""
Prisa Yachts LLC — Bilingual PDF Brochure Generator
Generates 3 professional PDFs using ReportLab.
"""
import os
from reportlab.lib.pagesizes import letter, landscape
from reportlab.lib.units import inch
from reportlab.lib.colors import Color, HexColor, white, black
from reportlab.pdfgen import canvas
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import Paragraph
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from PIL import Image as PILImage
import textwrap
# ── Brand constants ────────────────────────────────────────────────────────────
NAVY = HexColor('#1B3A6B')
GOLD = HexColor('#C9A84C')
WHITE = HexColor('#FFFFFF')
LIGHT_NAVY = HexColor('#2A5298')
LIGHT_GRAY = HexColor('#F5F5F5')
DARK_GRAY = HexColor('#333333')
LOGO_PATH = r"D:\Prisa Yachts LLC\WhatsApp Image 2026-03-11 at 22.24.00.jpeg"
OUTPUT_DIR = r"D:\Proyectos Software\Agente Marketing\prisa-yachts\brochures"
TAGLINE = "Safe Command ◇ Luxury Maintenance and Care"
WEBSITE = "prisayachts.com"
AREA = "Stuart to Jacksonville, FL"
# ── Helper: draw logo or text placeholder ─────────────────────────────────────
def draw_logo(c, x, y, width, height, centered=True):
"""Draw the logo image; fall back to a styled text block if unavailable."""
if os.path.exists(LOGO_PATH):
try:
if centered:
c.drawImage(LOGO_PATH, x - width / 2, y - height,
width=width, height=height,
preserveAspectRatio=True, mask='auto')
else:
c.drawImage(LOGO_PATH, x, y - height,
width=width, height=height,
preserveAspectRatio=True, mask='auto')
return
except Exception:
pass
# Fallback placeholder
bx = x - width / 2 if centered else x
by = y - height
c.setFillColor(NAVY)
c.rect(bx, by, width, height, fill=1, stroke=0)
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 10)
c.drawCentredString(bx + width / 2, by + height / 2 - 4, "PRISA YACHTS LLC")
c.setFont("Helvetica", 7)
c.setFillColor(WHITE)
c.drawCentredString(bx + width / 2, by + height / 2 - 16, "prisayachts.com")
def draw_gold_line(c, x1, y, x2, thickness=1.0):
c.setStrokeColor(GOLD)
c.setLineWidth(thickness)
c.line(x1, y, x2, y)
def draw_gold_divider(c, x, y, width, thickness=1.0):
draw_gold_line(c, x, y, x + width, thickness)
# ── Text wrapping helper ───────────────────────────────────────────────────────
def draw_wrapped_text(c, text, x, y, max_width, font_name, font_size,
line_height, color=None, align='left'):
"""Draw text wrapping within max_width, returns final y position."""
if color:
c.setFillColor(color)
c.setFont(font_name, font_size)
words = text.split()
lines = []
current = []
for word in words:
test_line = ' '.join(current + [word])
if c.stringWidth(test_line, font_name, font_size) <= max_width:
current.append(word)
else:
if current:
lines.append(' '.join(current))
current = [word]
if current:
lines.append(' '.join(current))
for line in lines:
if align == 'center':
c.drawCentredString(x + max_width / 2, y, line)
elif align == 'right':
c.drawRightString(x + max_width, y, line)
else:
c.drawString(x, y, line)
y -= line_height
return y
def draw_section_header(c, text, x, y, width, bg_color=NAVY, text_color=GOLD,
font_size=11, padding=5):
"""Draw a colored section header bar."""
bar_h = font_size + padding * 2
c.setFillColor(bg_color)
c.rect(x, y - bar_h, width, bar_h, fill=1, stroke=0)
c.setFillColor(text_color)
c.setFont("Helvetica-Bold", font_size)
c.drawString(x + padding + 2, y - bar_h + padding, text)
return y - bar_h
def draw_bullet_item(c, text, x, y, max_width, font_name="Helvetica",
font_size=8.5, line_height=12, bullet_color=GOLD,
text_color=DARK_GRAY):
"""Draw a gold diamond bullet followed by wrapped text."""
bullet = ""
indent = 14
c.setFont("Helvetica-Bold", font_size)
c.setFillColor(bullet_color)
c.drawString(x, y, "")
y = draw_wrapped_text(c, text, x + indent, y,
max_width - indent, font_name, font_size,
line_height, color=text_color)
return y - 2
# ══════════════════════════════════════════════════════════════════════════════
# BROCHURE 1 — General Services (landscape letter, 3 columns)
# ══════════════════════════════════════════════════════════════════════════════
def generate_brochure1():
path = os.path.join(OUTPUT_DIR, "PrisaYachts_General_Services.pdf")
pw, ph = landscape(letter) # 792 x 612 pts
c = canvas.Canvas(path, pagesize=landscape(letter))
c.setTitle("Prisa Yachts LLC — Professional Marine Services")
c.setAuthor("Prisa Yachts LLC")
c.setSubject("General Marine Services Brochure EN/ES")
margin = 0.35 * inch
col_gap = 0.18 * inch
usable_w = pw - 2 * margin
left_col_w = usable_w * 0.24
center_col_w = usable_w * 0.38
right_col_w = usable_w - left_col_w - center_col_w - 2 * col_gap
left_x = margin
center_x = left_x + left_col_w + col_gap
right_x = center_x + center_col_w + col_gap
top_y = ph - margin
bottom_y = margin
# ── Full background white ──
c.setFillColor(WHITE)
c.rect(0, 0, pw, ph, fill=1, stroke=0)
# ── LEFT COLUMN — navy background ────────────────────────────────────────
col_h = ph - 2 * margin
c.setFillColor(NAVY)
c.rect(left_x, bottom_y, left_col_w, col_h, fill=1, stroke=0)
# Logo
logo_y = top_y - 0.15 * inch
logo_w = left_col_w - 0.3 * inch
logo_h = 1.0 * inch
draw_logo(c, left_x + left_col_w / 2, logo_y, logo_w, logo_h, centered=True)
cur_y = logo_y - logo_h - 0.1 * inch
# Company name
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 12)
c.drawCentredString(left_x + left_col_w / 2, cur_y, "Prisa Yachts LLC")
cur_y -= 0.22 * inch
# Tagline (gold italic, wrapped)
c.setFillColor(GOLD)
c.setFont("Helvetica-Oblique", 7.5)
tagline_parts = ["Safe Command ◇", "Luxury Maintenance and Care"]
for part in tagline_parts:
c.drawCentredString(left_x + left_col_w / 2, cur_y, part)
cur_y -= 0.16 * inch
cur_y -= 0.05 * inch
# Service area
c.setFillColor(WHITE)
c.setFont("Helvetica", 7.5)
c.drawCentredString(left_x + left_col_w / 2, cur_y, AREA)
cur_y -= 0.18 * inch
# Gold divider
pad = 0.15 * inch
draw_gold_divider(c, left_x + pad, cur_y, left_col_w - 2 * pad, 1.5)
cur_y -= 0.2 * inch
# Contact blocks
contacts = [
("Alberto", "(954) 655-4084", "technical@prisayachts.com"),
("Federico", "(754) 209-3375", "management@prisayachts.com"),
]
for name, phone, email in contacts:
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8.5)
c.drawCentredString(left_x + left_col_w / 2, cur_y, name)
cur_y -= 0.15 * inch
c.setFillColor(WHITE)
c.setFont("Helvetica", 7.5)
c.drawCentredString(left_x + left_col_w / 2, cur_y, phone)
cur_y -= 0.14 * inch
c.setFont("Helvetica", 6.8)
c.drawCentredString(left_x + left_col_w / 2, cur_y, email)
cur_y -= 0.2 * inch
# Gold divider
draw_gold_divider(c, left_x + pad, cur_y, left_col_w - 2 * pad, 1.0)
cur_y -= 0.18 * inch
# Website
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8)
c.drawCentredString(left_x + left_col_w / 2, cur_y, WEBSITE)
# ── CENTER COLUMN — English services ─────────────────────────────────────
# Column background (very light)
c.setFillColor(WHITE)
c.rect(center_x, bottom_y, center_col_w, col_h, fill=1, stroke=0)
# Thin navy left border
c.setFillColor(NAVY)
c.rect(center_x, bottom_y, 3, col_h, fill=1, stroke=0)
cur_y = top_y - 0.15 * inch
# Header
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 14)
c.drawString(center_x + 0.15 * inch, cur_y, "Professional Marine Services")
cur_y -= 0.12 * inch
draw_gold_divider(c, center_x + 0.15 * inch, cur_y,
center_col_w - 0.2 * inch, 2.0)
cur_y -= 0.22 * inch
en_services = [
"Marine Electrical (ABYC E-11 Certified)",
"Lithium Battery Bank Design & Installation",
"Shore Power & Inverter/Charger Systems",
"Solar & Alternator Upgrades",
"Full Rewiring (Tinned Wire, Labeled Circuits)",
"Teak Deck Recovery & Restoration",
"Gelcoat Polishing & Oxidation Removal",
"Washdown System Installation",
"Anchor Windlass & Bilge Systems",
"NMEA 2000 / 0183 Integration",
"Pre-Season Inspection & Annual Service",
]
bx = center_x + 0.15 * inch
bw = center_col_w - 0.25 * inch
for svc in en_services:
cur_y = draw_bullet_item(c, svc, bx, cur_y, bw,
font_size=8.5, line_height=11.5)
cur_y -= 1
# Footer band
footer_h = 0.55 * inch
footer_y = bottom_y
c.setFillColor(LIGHT_GRAY)
c.rect(center_x, footer_y, center_col_w, footer_h, fill=1, stroke=0)
draw_gold_divider(c, center_x, footer_y + footer_h,
center_col_w, 1.5)
c.setFillColor(NAVY)
c.setFont("Helvetica-Oblique", 7)
footer_text = ("All electrical work performed to ABYC E-11 standards. "
"Bilingual service EN/ES.")
c.drawString(center_x + 0.1 * inch, footer_y + 0.28 * inch, footer_text)
# ── RIGHT COLUMN — Spanish services ──────────────────────────────────────
c.setFillColor(WHITE)
c.rect(right_x, bottom_y, right_col_w, col_h, fill=1, stroke=0)
# Thin gold left border
c.setFillColor(GOLD)
c.rect(right_x, bottom_y, 3, col_h, fill=1, stroke=0)
cur_y = top_y - 0.15 * inch
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 14)
c.drawString(right_x + 0.15 * inch, cur_y, "Servicios Marinos Profesionales")
cur_y -= 0.12 * inch
draw_gold_divider(c, right_x + 0.15 * inch, cur_y,
right_col_w - 0.2 * inch, 2.0)
cur_y -= 0.22 * inch
es_services = [
"Instalaciones Eléctricas Marinas (Estándar ABYC E-11)",
"Diseño e Instalación de Banco de Baterías de Litio",
"Sistemas de Alimentación en Puerto e Inversor/Cargador",
"Mejoras Solar y de Alternador",
"Recableado Completo (Cable Estañado, Circuitos Etiquetados)",
"Recuperación y Restauración de Teca",
"Pulido de Gelcoat y Eliminación de Oxidación",
"Instalación de Sistema Washdown",
"Sistemas de Molinete y Achique",
"Integración NMEA 2000 / 0183",
"Inspección Pre-Temporada y Servicio Anual",
]
bx2 = right_x + 0.15 * inch
bw2 = right_col_w - 0.25 * inch
for svc in es_services:
cur_y = draw_bullet_item(c, svc, bx2, cur_y, bw2,
font_size=8.5, line_height=11.5)
cur_y -= 1
# Footer band
c.setFillColor(LIGHT_GRAY)
c.rect(right_x, footer_y, right_col_w, footer_h, fill=1, stroke=0)
draw_gold_divider(c, right_x, footer_y + footer_h, right_col_w, 1.5)
c.setFillColor(NAVY)
c.setFont("Helvetica-Oblique", 7)
es_footer = ("Todo trabajo eléctrico realizado según estándar ABYC E-11. "
"Servicio bilingüe EN/ES.")
c.drawString(right_x + 0.1 * inch, footer_y + 0.28 * inch, es_footer)
c.save()
print(f" [OK] {path}")
return path
# ══════════════════════════════════════════════════════════════════════════════
# BROCHURE 2 — Marine Electrical (portrait letter, 2 columns)
# ══════════════════════════════════════════════════════════════════════════════
def generate_brochure2():
path = os.path.join(OUTPUT_DIR, "PrisaYachts_Electrical.pdf")
pw, ph = letter # 612 x 792 pts
c = canvas.Canvas(path, pagesize=letter)
c.setTitle("Prisa Yachts LLC — Marine Electrical Services")
c.setAuthor("Prisa Yachts LLC")
c.setSubject("Marine Electrical Brochure EN/ES")
margin = 0.4 * inch
col_gap = 0.2 * inch
usable_w = pw - 2 * margin
col_w = (usable_w - col_gap) / 2
# ── Header band ───────────────────────────────────────────────────────────
header_h = 1.05 * inch
header_y = ph - header_h
c.setFillColor(NAVY)
c.rect(0, header_y, pw, header_h, fill=1, stroke=0)
# Gold bottom border on header
c.setStrokeColor(GOLD)
c.setLineWidth(2.5)
c.line(0, header_y, pw, header_y)
# Logo in header (left side)
draw_logo(c, margin, ph - 0.08 * inch, 1.5 * inch, 0.85 * inch, centered=False)
# Title center
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 18)
c.drawCentredString(pw / 2, ph - 0.42 * inch, "Marine Electrical Services")
# ABYC badge right
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 9.5)
c.drawRightString(pw - margin, ph - 0.38 * inch, "ABYC E-11 Certified")
c.setFillColor(WHITE)
c.setFont("Helvetica", 8)
c.drawRightString(pw - margin, ph - 0.55 * inch, "Stuart to Jacksonville, FL")
# ── Body columns ─────────────────────────────────────────────────────────
body_top = header_y - 0.22 * inch
footer_h = 0.55 * inch
body_bottom = margin + footer_h + 0.1 * inch
left_x = margin
right_x = margin + col_w + col_gap
# Vertical gold divider between columns
mid_x = margin + col_w + col_gap / 2
c.setStrokeColor(GOLD)
c.setLineWidth(1.0)
c.line(mid_x, body_bottom, mid_x, body_top)
def draw_electrical_column(start_x, cur_y, lang='en'):
cw = col_w - 0.05 * inch
line_sm = 10.5
line_md = 12
if lang == 'en':
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 10.5)
c.drawString(start_x, cur_y, "Expert Marine Electrical — Stuart to Jacksonville")
cur_y -= 0.18 * inch
draw_gold_divider(c, start_x, cur_y, cw, 1.5)
cur_y -= 0.18 * inch
sections = [
("WHY ABYC CERTIFIED WORK MATTERS",
"Marine electrical failures are the #1 cause of boat fires. Every "
"installation we do meets or exceeds ABYC E-11 standards: correct wire "
"gauge, tinned marine-grade wire, properly sized overcurrent protection, "
"and labeled circuits from stem to stern."),
("FULL REWIRING",
"Complete vessel rewiring using marine-grade tinned wire. Correct gauge "
"per ABYC E-11. Every circuit labeled and documented."),
("LITHIUM BATTERY BANKS",
"Custom LiFePO4 battery bank design and installation. BMS integration, "
"proper charge profiles, and full system documentation."),
("SOLAR & SHORE POWER",
"Solar panel installation with MPPT charge controllers. Shore power "
"systems, isolation transformers, and inverter/charger integration."),
("SYSTEMS & ELECTRONICS",
"NMEA 2000 backbone design and installation. Bilge pumps, washdown "
"systems, anchor windlass, lighting upgrades."),
("DIAGNOSTICS & INSPECTION",
"Pre-purchase electrical inspection. Annual safety audit. "
"Load testing and fault finding."),
]
icons = ["", "", "\U0001f50b", "☀️", "\U0001f50c", "\U0001f50d"]
else:
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 10.5)
c.drawString(start_x, cur_y,
"Instalaciones Eléctricas Marinas — Stuart a Jacksonville")
cur_y -= 0.18 * inch
draw_gold_divider(c, start_x, cur_y, cw, 1.5)
cur_y -= 0.18 * inch
sections = [
("POR QUÉ IMPORTA EL ESTÁNDAR ABYC",
"Los fallos eléctricos son la causa número 1 de incendios en embarcaciones. "
"Cada instalación que realizamos cumple o supera el estándar ABYC E-11: "
"calibre de cable correcto, cable marino estañado, protección contra "
"sobrecorriente correctamente dimensionada, y circuitos etiquetados de proa a popa."),
("RECABLEADO COMPLETO",
"Recableado total de la embarcación con cable estañado de grado marino. "
"Calibre correcto según ABYC E-11. Cada circuito etiquetado y documentado."),
("BANCO DE BATERÍAS DE LITIO",
"Diseño e instalación personalizada de banco LiFePO4. Integración de BMS, "
"perfiles de carga correctos y documentación completa del sistema."),
("SOLAR Y ALIMENTACIÓN EN PUERTO",
"Instalación de paneles solares con controladores MPPT. Sistemas de shore power, "
"transformadores de aislamiento e integración inversor/cargador."),
("SISTEMAS Y ELECTRÓNICA",
"Diseño e instalación de backbone NMEA 2000. Bombas de achique, sistemas "
"washdown, molinete de ancla, mejoras de iluminación."),
("DIAGNÓSTICO E INSPECCIÓN",
"Inspección eléctrica previa a compra. Auditoría de seguridad anual. "
"Pruebas de carga y localización de fallos."),
]
icons = ["", "", "\U0001f50b", "☀️", "\U0001f50c", "\U0001f50d"]
for i, (title, body) in enumerate(sections):
if i == 0:
# First section: intro paragraph, no icon
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(start_x, cur_y, title)
cur_y -= 0.14 * inch
cur_y = draw_wrapped_text(c, body, start_x, cur_y, cw,
"Helvetica", 8, line_sm, color=DARK_GRAY)
cur_y -= 0.12 * inch
else:
# Service sections with colored mini-header
bar_h = 14
c.setFillColor(NAVY)
c.rect(start_x, cur_y - bar_h + 3, cw, bar_h, fill=1, stroke=0)
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(start_x + 4, cur_y - bar_h + 6, title)
cur_y -= bar_h + 2
cur_y = draw_wrapped_text(c, body, start_x + 4, cur_y, cw - 4,
"Helvetica", 7.8, line_sm, color=DARK_GRAY)
cur_y -= 0.1 * inch
# Quote
cur_y -= 0.05 * inch
draw_gold_divider(c, start_x, cur_y, cw, 1.0)
cur_y -= 0.16 * inch
if lang == 'en':
quote = '"Every wire we touch, we own. No shortcuts."'
else:
quote = '"Cada cable que tocamos, lo respaldamos. Sin atajos."'
c.setFillColor(NAVY)
c.setFont("Helvetica-BoldOblique", 8)
cur_y = draw_wrapped_text(c, quote, start_x, cur_y, cw,
"Helvetica-BoldOblique", 8, 11, color=NAVY)
return cur_y
draw_electrical_column(left_x, body_top, 'en')
draw_electrical_column(right_x, body_top, 'es')
# ── Footer ────────────────────────────────────────────────────────────────
c.setFillColor(NAVY)
c.rect(0, 0, pw, margin + footer_h, fill=1, stroke=0)
c.setStrokeColor(GOLD)
c.setLineWidth(1.5)
c.line(0, margin + footer_h, pw, margin + footer_h)
c.setFillColor(WHITE)
c.setFont("Helvetica", 8)
c.drawString(margin, margin + footer_h - 0.18 * inch,
"Alberto | (954) 655-4084 | technical@prisayachts.com")
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8.5)
c.drawRightString(pw - margin, margin + footer_h - 0.18 * inch, WEBSITE)
c.setFillColor(WHITE)
c.setFont("Helvetica", 7)
c.drawCentredString(pw / 2, margin + 0.15 * inch, AREA)
c.save()
print(f" [OK] {path}")
return path
# ══════════════════════════════════════════════════════════════════════════════
# BROCHURE 3 — Teak & Detailing (portrait letter, 2 columns)
# ══════════════════════════════════════════════════════════════════════════════
def generate_brochure3():
path = os.path.join(OUTPUT_DIR, "PrisaYachts_Teak_Detailing.pdf")
pw, ph = letter
c = canvas.Canvas(path, pagesize=letter)
c.setTitle("Prisa Yachts LLC — Teak Restoration & Marine Detailing")
c.setAuthor("Prisa Yachts LLC")
c.setSubject("Teak & Detailing Brochure EN/ES")
margin = 0.4 * inch
col_gap = 0.2 * inch
usable_w = pw - 2 * margin
col_w = (usable_w - col_gap) / 2
# ── Header band ───────────────────────────────────────────────────────────
header_h = 1.05 * inch
header_y = ph - header_h
c.setFillColor(NAVY)
c.rect(0, header_y, pw, header_h, fill=1, stroke=0)
c.setStrokeColor(GOLD)
c.setLineWidth(2.5)
c.line(0, header_y, pw, header_y)
draw_logo(c, margin, ph - 0.08 * inch, 1.5 * inch, 0.85 * inch, centered=False)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 16)
c.drawCentredString(pw / 2, ph - 0.4 * inch, "Teak Restoration & Marine Detailing")
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 9)
c.drawRightString(pw - margin, ph - 0.38 * inch, "Stuart to Jacksonville")
c.setFillColor(WHITE)
c.setFont("Helvetica", 8)
c.drawRightString(pw - margin, ph - 0.55 * inch, "Florida's Saltwater Environment")
# ── Body ─────────────────────────────────────────────────────────────────
body_top = header_y - 0.22 * inch
footer_h = 0.55 * inch
body_bottom = margin + footer_h + 0.1 * inch
left_x = margin
right_x = margin + col_w + col_gap
# Vertical gold divider
mid_x = margin + col_w + col_gap / 2
c.setStrokeColor(GOLD)
c.setLineWidth(1.0)
c.line(mid_x, body_bottom, mid_x, body_top)
def draw_teak_column(start_x, cur_y, lang='en'):
cw = col_w - 0.05 * inch
line_sm = 10.5
if lang == 'en':
subtitle = "Teak & Detailing Specialists — Floridas Saltwater Environment"
h2 = "IS YOUR TEAK WORTH SAVING?"
p1 = ("Gray teak isnt always dead teak. Before we quote any job, we do an honest "
"hands-on assessment — and well tell you straight if recovery makes "
"financial sense or if replacement is the smarter move. Most teak we see in "
"Florida is recoverable. It just needs the right process.")
steps_title = "THE RECOVERY PROCESS"
steps = [
("Step 1 — CLEAN",
"Two-part oxalic acid cleaner. Part A removes oxidation and gray surface "
"cells. Part B neutralizes pH. Clean canvas only — never cover problems."),
("Step 2 — SAND",
"80-grit to open the grain. 120-grit to smooth. Always with the grain. "
"Never cross-grain — water traps are invisible until they rot your plank from inside."),
("Step 3 — OIL",
"Penetrating marine teak oil, thin coats, wiped before skinning. "
"Feeds the wood from inside. Conditions, doesnt coat."),
("Step 4 — SEAL",
"UV-blocking teak sealer on all horizontal surfaces. Florida sun reoxidizes "
"bare teak in one season. Proper sealing buys 1218 months."),
]
det_title = "DETAILING SERVICES"
det_items = [
"Gelcoat oxidation removal (light & heavy cut)",
"Machine polish & wax — DA and rotary",
"Hull cleaning & brightwork",
"Caulking inspection & reseam",
"Full exterior detail packages",
]
quote = '"Weve restored teak that owners wanted to scrap. Send us a photo before you decide."'
else:
subtitle = "Especialistas en Teca y Detailing — Ambiente Marino de Florida"
h2 = "¿VALE LA PENA SALVAR TU TECA?"
p1 = ("La teca gris no siempre está muerta. Antes de cotizar cualquier trabajo, "
"hacemos una evaluación honesta — y te diremos directamente si la "
"recuperación tiene sentido económico o si el reemplazo es la decisión "
"más inteligente. La mayoría de la teca que vemos en Florida es recuperable. "
"Solo necesita el proceso correcto.")
steps_title = "EL PROCESO DE RECUPERACIÓN"
steps = [
("Paso 1 — LIMPIAR",
"Limpiador de ácido oxálico en dos partes. La parte A elimina la oxidación "
"y las células grises. La parte B neutraliza el pH. Solo superficie limpia — "
"nunca cubrir problemas."),
("Paso 2 — LIJAR",
"Lija 80 para abrir el grano. Lija 120 para alisar. Siempre a favor de la veta. "
"Nunca transversal — las trampas de agua son invisibles hasta que pudren la tabla desde adentro."),
("Paso 3 — ACEITAR",
"Aceite marino penetrante de teca, capas finas, limpiando antes de que forme película. "
"Nutre la madera desde adentro. Acondiciona, no recubre."),
("Paso 4 — SELLAR",
"Sellador UV en todas las superficies horizontales. El sol de Florida reoxida la teca "
"sin protección en una temporada. El sellado correcto da 12 a 18 meses."),
]
det_title = "SERVICIOS DE DETAILING"
det_items = [
"Eliminación de oxidación de gelcoat (corte suave y profundo)",
"Pulido a máquina y encerado — DA y rotativa",
"Limpieza de casco y herrajes brillantes",
"Inspección de sellado y recalafateo",
"Paquetes completos de detailing exterior",
]
quote = '"Hemos restaurado teca que los dueños querían desechar. Mándanos una foto antes de decidir."'
# Subtitle
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 9.5)
cur_y = draw_wrapped_text(c, subtitle, start_x, cur_y, cw,
"Helvetica-Bold", 9.5, 12, color=NAVY)
cur_y -= 0.1 * inch
draw_gold_divider(c, start_x, cur_y, cw, 1.5)
cur_y -= 0.16 * inch
# H2
c.setFillColor(NAVY)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(start_x, cur_y, h2)
cur_y -= 0.14 * inch
# Intro paragraph
cur_y = draw_wrapped_text(c, p1, start_x, cur_y, cw,
"Helvetica", 7.8, line_sm, color=DARK_GRAY)
cur_y -= 0.15 * inch
# Recovery process header
bar_h = 14
c.setFillColor(NAVY)
c.rect(start_x, cur_y - bar_h + 3, cw, bar_h, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(start_x + 4, cur_y - bar_h + 6, steps_title)
cur_y -= bar_h + 6
# Steps
for step_title, step_body in steps:
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8)
c.drawString(start_x + 4, cur_y, step_title)
cur_y -= 0.13 * inch
cur_y = draw_wrapped_text(c, step_body, start_x + 10, cur_y, cw - 10,
"Helvetica", 7.5, 10.5, color=DARK_GRAY)
cur_y -= 0.08 * inch
cur_y -= 0.05 * inch
# Detailing services header
c.setFillColor(NAVY)
c.rect(start_x, cur_y - bar_h + 3, cw, bar_h, fill=1, stroke=0)
c.setFillColor(WHITE)
c.setFont("Helvetica-Bold", 8.5)
c.drawString(start_x + 4, cur_y - bar_h + 6, det_title)
cur_y -= bar_h + 6
for item in det_items:
cur_y = draw_bullet_item(c, item, start_x + 4, cur_y,
cw - 4, font_size=7.8, line_height=10.5)
cur_y -= 1
# Quote
cur_y -= 0.08 * inch
draw_gold_divider(c, start_x, cur_y, cw, 1.0)
cur_y -= 0.14 * inch
cur_y = draw_wrapped_text(c, quote, start_x, cur_y, cw,
"Helvetica-BoldOblique", 7.8, 11, color=NAVY)
return cur_y
draw_teak_column(left_x, body_top, 'en')
draw_teak_column(right_x, body_top, 'es')
# ── Footer ────────────────────────────────────────────────────────────────
c.setFillColor(NAVY)
c.rect(0, 0, pw, margin + footer_h, fill=1, stroke=0)
c.setStrokeColor(GOLD)
c.setLineWidth(1.5)
c.line(0, margin + footer_h, pw, margin + footer_h)
c.setFillColor(WHITE)
c.setFont("Helvetica", 8)
c.drawString(margin, margin + footer_h - 0.18 * inch,
"Federico | (754) 209-3375 | management@prisayachts.com")
c.setFillColor(GOLD)
c.setFont("Helvetica-Bold", 8.5)
c.drawRightString(pw - margin, margin + footer_h - 0.18 * inch, WEBSITE)
c.setFillColor(WHITE)
c.setFont("Helvetica", 7)
c.drawCentredString(pw / 2, margin + 0.15 * inch, AREA)
c.save()
print(f" [OK] {path}")
return path
# ── Main ───────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
import sys
print("Prisa Yachts LLC — Brochure Generator")
print(f"Output: {OUTPUT_DIR}\n")
files = []
try:
files.append(generate_brochure1())
except Exception as e:
print(f" [ERROR] Brochure 1: {e}", file=sys.stderr)
try:
files.append(generate_brochure2())
except Exception as e:
print(f" [ERROR] Brochure 2: {e}", file=sys.stderr)
try:
files.append(generate_brochure3())
except Exception as e:
print(f" [ERROR] Brochure 3: {e}", file=sys.stderr)
print("\nFile sizes:")
for f in files:
size = os.path.getsize(f)
print(f" {os.path.basename(f)}: {size:,} bytes ({size/1024:.1f} KB)")
+475
View File
@@ -0,0 +1,475 @@
# n8n Workflow — Tip Auto-Publisher con IA Local
## Prisa Yachts LLC | SearXNG + Ollama + WordPress
## Versión: 1.0 | 2026-05-05
---
## ARQUITECTURA COMPLETA
```
[Schedule Trigger: Lun/Mié/Vie 8AM ET]
[Google Sheets: leer próximo tema pendiente]
[SearXNG: buscar referencias del tema]
[Ollama qwen2.5:14b: generar tip EN+ES en JSON]
¿Hay foto?
/ \
SÍ NO
↓ ↓
[Vision: [WP Post
analiza] directo]
[WP Media Upload]
[WordPress: crear post bilingüe]
[Google Sheets: marcar publicado + agregar a ContentCalendar Instagram]
```
---
## VARIABLES DE ENTORNO (agregar en n8n)
```env
PRISA_WP_URL=https://prisayachts.com
PRISA_WP_USER=admin # usuario WordPress
PRISA_WP_APP_PASSWORD=xxxx xxxx xxxx xxxx # Application Password (ver Paso 0)
PRISA_OLLAMA_URL=http://localhost:11434 # o host.docker.internal:11434 si n8n es Docker
PRISA_SEARXNG_URL=http://localhost:8080 # o el container name si están en misma red Docker
PRISA_TOPICS_SHEET_ID=1BxiMVs...
PRISA_TOPICS_SHEET_NAME=TipTopics
```
---
## PASO 0: PREPARACIÓN PREVIA A n8n
### A) WordPress Application Password
```
WordPress Admin → Usuarios → Tu perfil
→ Bajar hasta "Contraseñas de aplicación"
→ Nombre: "n8n Publisher"
→ Añadir contraseña
→ GUARDAR el password que aparece (formato: xxxx xxxx xxxx xxxx)
```
### B) Google Sheet — Tab "TipTopics"
| Col | Header | Tipo | Ejemplo |
|-----|--------|------|---------|
| A | `topic_id` | Texto | `TIP-001` |
| B | `topic_EN` | Texto | `How to inspect your anchor chain` |
| C | `topic_ES` | Texto | `Cómo inspeccionar tu cadena de ancla` |
| D | `pillar` | Texto | `hardware` / `electrical` / `teak` / `engine` / `safety` |
| E | `status` | Texto | `pending` / `publishing` / `published` / `skipped` |
| F | `drive_photo_id` | Texto | FILE_ID de Google Drive (vacío si no hay foto) |
| G | `wp_post_id` | Número | Lo escribe el workflow |
| H | `wp_post_url` | URL | Lo escribe el workflow |
| I | `published_at` | Datetime | Lo escribe el workflow |
| J | `ig_added` | Boolean | `true` cuando se agrega al ContentCalendar |
### C) Verificar acceso Ollama desde n8n
Desde la terminal del servidor:
```bash
curl http://localhost:11434/api/tags
# Debe devolver lista de modelos instalados
```
Si n8n corre como Docker container:
```bash
# Agregar al docker-compose de n8n:
extra_hosts:
- "host.docker.internal:host-gateway"
# Luego usar: http://host.docker.internal:11434
```
---
## WORKFLOW COMPLETO — NODO POR NODO
### NODO 1: Schedule Trigger
```
Tipo: Schedule Trigger
Cron: 0 8 * * 1,3,5 ← Lun, Mié, Vie a las 8AM
Timezone: America/New_York
```
---
### NODO 2: Google Sheets — Leer próximo tema
```
Tipo: Google Sheets
Operación: Get Many Rows
Sheet ID: {{ $env.PRISA_TOPICS_SHEET_ID }}
Sheet Name: TipTopics
Filters:
- Column: status
- Value: pending
Limit: 1
Sort: topic_id ASC
```
→ Si no hay filas: **NoOp** (fin silencioso)
---
### NODO 3: Google Sheets — Marcar "publishing" (lock anti-duplicado)
```
Tipo: Google Sheets
Operación: Update Row
Row Number: {{ $json.row_number }}
status: publishing
```
---
### NODO 4: HTTP Request — SearXNG Search
```
Tipo: HTTP Request
Método: GET
URL: {{ $env.PRISA_SEARXNG_URL }}/search
Query Parameters:
q: {{ $json.topic_EN }} marine Florida boat
format: json
language: en
categories: general
pageno: 1
Headers:
Accept: application/json
```
**Code: Extraer snippets relevantes**
```javascript
const results = $input.first().json;
const items = results.results || [];
// Tomar los primeros 4 resultados, extraer título + snippet
const snippets = items.slice(0, 4).map(r => ({
title: r.title || '',
snippet: r.content || r.snippet || ''
}));
const referenceText = snippets
.map((s, i) => `[${i+1}] ${s.title}: ${s.snippet}`)
.join('\n\n');
return [{ json: {
...($input.first().json),
searchReference: referenceText
}}];
```
---
### NODO 5: HTTP Request — Ollama qwen2.5:14b Generar Contenido
```
Tipo: HTTP Request
Método: POST
URL: {{ $env.PRISA_OLLAMA_URL }}/api/chat
Headers:
Content-Type: application/json
Body (JSON):
{
"model": "qwen2.5:14b",
"stream": false,
"format": "json",
"options": {
"temperature": 0.7,
"num_ctx": 4096
},
"messages": [
{
"role": "system",
"content": "You are a professional marine content writer for Prisa Yachts LLC, a marine electrical and maintenance company serving Stuart to Jacksonville, FL. You write authoritative, practical tips for boat owners in both English and Spanish. Your tone is expert but approachable. Always include specific Florida saltwater context. Return ONLY valid JSON, no other text."
},
{
"role": "user",
"content": "Write a detailed marine tip blog post about: \"{{ $json.topic_EN }}\"\n\nReference material from web search:\n{{ $json.searchReference }}\n\nReturn this exact JSON structure:\n{\n \"title_EN\": \"SEO-optimized title in English (max 60 chars)\",\n \"title_ES\": \"Título optimizado en español (max 60 chars)\",\n \"excerpt_EN\": \"Meta description in English (max 155 chars)\",\n \"excerpt_ES\": \"Meta descripción en español (max 155 chars)\",\n \"content_EN\": \"Full HTML blog post in English (400-600 words). Use <h2> for subheadings, <ul> for lists, <strong> for emphasis. Include Florida-specific context. End with a CTA to contact Prisa Yachts LLC at (954) 655-4084 or management@prisayachts.com\",\n \"content_ES\": \"Artículo completo en HTML en español (400-600 palabras). Misma estructura. CTA al final con los mismos datos de contacto.\",\n \"tags\": [\"tag1\", \"tag2\", \"tag3\", \"tag4\", \"tag5\"],\n \"ig_caption_EN\": \"Instagram caption in English (max 200 words) with CTA to DM\",\n \"ig_caption_ES\": \"Caption de Instagram en español (max 200 palabras) con CTA\"\n}"
}
]
}
```
---
### NODO 6: Code — Parsear respuesta de Ollama
```javascript
const response = $input.first().json;
const messageContent = response.message?.content || response.response || '';
let parsed;
try {
// Ollama con format:json devuelve JSON limpio
parsed = JSON.parse(messageContent);
} catch(e) {
// Fallback: buscar JSON dentro del texto
const jsonMatch = messageContent.match(/\{[\s\S]*\}/);
if (jsonMatch) {
parsed = JSON.parse(jsonMatch[0]);
} else {
throw new Error('Ollama no devolvió JSON válido: ' + messageContent.substring(0, 200));
}
}
// Construir el contenido WordPress: EN arriba, ES abajo con separador
const wpContent = `
${parsed.content_EN}
<hr class="prisa-separator"/>
<h2 style="color:#1B3A6B;">─── Versión en Español ───</h2>
${parsed.content_ES}
`;
return [{ json: {
...($input.first().json), // mantener topic_id, drive_photo_id, etc.
title_EN: parsed.title_EN,
title_ES: parsed.title_ES,
excerpt_EN: parsed.excerpt_EN,
excerpt_ES: parsed.excerpt_ES,
wp_content: wpContent,
tags: parsed.tags || [],
ig_caption_EN: parsed.ig_caption_EN || '',
ig_caption_ES: parsed.ig_caption_ES || ''
}}];
```
---
### NODO 7: IF — ¿Tiene foto en Drive?
```
Condición: {{ $json.drive_photo_id }} is not empty
```
---
### RAMA A: CON FOTO (drive_photo_id existe)
#### NODO 8A: HTTP Request — Descargar foto de Google Drive
```
Tipo: HTTP Request
Método: GET
URL: https://drive.google.com/uc?export=download&id={{ $json.drive_photo_id }}
Response Format: File
```
#### NODO 9A: HTTP Request — Ollama llama3.2-vision — Analizar foto
```
Tipo: HTTP Request
Método: POST
URL: {{ $env.PRISA_OLLAMA_URL }}/api/generate
Body (JSON):
{
"model": "llama3.2-vision:latest",
"prompt": "Describe this marine work photo in 1-2 sentences for use as an image alt text on a professional marine services website. Be specific about what you see (teak deck, electrical panel, battery installation, etc). Keep it under 125 characters.",
"stream": false,
"images": ["{{ $binary.data.toString('base64') }}"]
}
```
#### NODO 10A: HTTP Request — WordPress Media Upload
```
Tipo: HTTP Request
Método: POST
URL: {{ $env.PRISA_WP_URL }}/wp-json/wp/v2/media
Authentication: Basic Auth
Username: {{ $env.PRISA_WP_USER }}
Password: {{ $env.PRISA_WP_APP_PASSWORD }}
Headers:
Content-Type: image/jpeg
Content-Disposition: attachment; filename="prisa-tip-{{ $json.topic_id }}.jpg"
Body: [binary image data]
```
→ Respuesta guarda `media_id` = `$json.id`
---
### RAMA B: SIN FOTO
#### NODO 8B: Set
```
Operación: Set Value
media_id: 0
alt_text: ""
```
---
### NODO 11: Merge — Reunir ambas ramas
---
### NODO 12: HTTP Request — WordPress Get/Create Tags
```javascript
// Code node: preparar tags
// Obtener o crear cada tag vía WP REST API
// Devolver array de tag IDs
const tags = $json.tags || [];
const wpUrl = $env.PRISA_WP_URL;
const auth = 'Basic ' + Buffer.from(`${$env.PRISA_WP_USER}:${$env.PRISA_WP_APP_PASSWORD}`).toString('base64');
const tagIds = [];
for (const tagName of tags) {
// Buscar si existe
const searchResp = await $helpers.httpRequest({
method: 'GET',
url: `${wpUrl}/wp-json/wp/v2/tags?search=${encodeURIComponent(tagName)}&per_page=1`,
headers: { Authorization: auth }
});
if (searchResp[0]) {
tagIds.push(searchResp[0].id);
} else {
// Crear nuevo tag
const createResp = await $helpers.httpRequest({
method: 'POST',
url: `${wpUrl}/wp-json/wp/v2/tags`,
headers: { Authorization: auth, 'Content-Type': 'application/json' },
body: JSON.stringify({ name: tagName })
});
tagIds.push(createResp.id);
}
}
return [{ json: { ...($input.first().json), tag_ids: tagIds }}];
```
---
### NODO 13: HTTP Request — WordPress Crear Post
```
Tipo: HTTP Request
Método: POST
URL: {{ $env.PRISA_WP_URL }}/wp-json/wp/v2/posts
Authentication: Basic Auth
Username: {{ $env.PRISA_WP_USER }}
Password: {{ $env.PRISA_WP_APP_PASSWORD }}
Headers:
Content-Type: application/json
Body (JSON):
{
"title": "{{ $json.title_EN }} | {{ $json.title_ES }}",
"content": "{{ $json.wp_content }}",
"excerpt": "{{ $json.excerpt_EN }}",
"status": "publish",
"featured_media": {{ $json.media_id }},
"tags": {{ $json.tag_ids }},
"meta": {
"tip_topic_id": "{{ $json.topic_id }}",
"tip_pillar": "{{ $json.pillar }}"
}
}
```
→ Respuesta: `{ "id": 123, "link": "https://prisayachts.com/..." }`
---
### NODO 14: Google Sheets — Actualizar TipTopics
```
Tipo: Google Sheets
Operación: Update Row
Row: {{ $json.row_number }}
status: published
wp_post_id: {{ $json.wp_response.id }}
wp_post_url: {{ $json.wp_response.link }}
published_at: {{ new Date().toISOString() }}
```
---
### NODO 15: Google Sheets — Agregar a ContentCalendar Instagram
Append nueva fila al tab `ContentCalendar` del sheet principal de n8n:
```
post_id: PY-TIP-{{ $json.topic_id }}
scheduled_date: (fecha de mañana)
scheduled_time: 11:00
platform: instagram
caption_EN: {{ $json.ig_caption_EN }}
caption_ES: {{ $json.ig_caption_ES }}
hashtags: (según pillar → set A/B/C)
image_url: (URL pública Drive si existe)
pillar: {{ $json.pillar }}
status: draft
```
---
## FLUJO DE IMPLEMENTACIÓN
### Semana 1: Base
1. [ ] Crear Application Password en WordPress
2. [ ] Crear Google Sheet TipTopics con los temas del plan de contenido
3. [ ] Verificar: `curl http://localhost:11434/api/tags` desde el servidor
4. [ ] Verificar: `curl http://localhost:8080/search?q=marine+electrical&format=json` desde el servidor
5. [ ] Configurar variables de entorno en n8n
### Semana 2: Workflow
6. [ ] Construir Nodos 1-6 (trigger → Ollama) y probar con 1 tema
7. [ ] Verificar que el JSON de Ollama sale correcto
8. [ ] Agregar Nodo 13 (post a WordPress) y verificar que publica
9. [ ] Agregar Nodo 14-15 (actualizar sheets)
### Semana 3: Fotos
10. [ ] Agregar rama con foto (Nodos 8A-10A)
11. [ ] Probar con una foto real de teca de Google Drive
12. [ ] Verificar alt text generado por llama3.2-vision
---
## TEMAS INICIALES PARA GOOGLE SHEET TIPTOPICS
| topic_id | topic_EN | topic_ES | pillar |
|----------|----------|----------|--------|
| TIP-001 | How to inspect your raw water impeller | Cómo inspeccionar el impeller de agua bruta | engine |
| TIP-002 | Why boat batteries fail in Florida heat | Por qué las baterías marinas fallan en el calor de Florida | electrical |
| TIP-003 | Teak deck gray vs. dead: how to tell the difference | Teca gris vs. teca muerta: cómo saberlo | teak |
| TIP-004 | Shore power safety: what every liveaboard needs to know | Seguridad en shore power: lo que todo liveaboard necesita saber | electrical |
| TIP-005 | How to read exhaust smoke color on your diesel | Cómo interpretar el color del humo de escape en tu diesel | engine |
| TIP-006 | 316 stainless vs. galvanized: never again | Inoxidable 316 vs. galvanizado: nunca más | hardware |
| TIP-007 | Pre-hurricane season electrical checklist | Lista de verificación eléctrica pre-temporada de huracanes | safety |
| TIP-008 | Lithium vs AGM: the real numbers for Florida boaters | Litio vs AGM: los números reales para navegantes en Florida | electrical |
| TIP-009 | Zinc anodes in Florida saltwater: replacement schedule | Ánodos de zinc en Florida: calendario de reemplazo | hardware |
| TIP-010 | Gelcoat oxidation: light vs. severe — what to do | Oxidación de gelcoat: leve vs. severa — qué hacer | teak |
| TIP-011 | Marine fuel filtration: primary vs. secondary filter | Filtración de combustible marino: filtro primario vs. secundario | engine |
| TIP-012 | ABYC E-11: why wire gauge matters on your boat | ABYC E-11: por qué el calibre del cable importa en tu barco | electrical |
---
## NOTAS TÉCNICAS
**Tiempo de respuesta Ollama qwen2.5:14b:**
- En servidor con GPU: ~15-30 segundos por post
- Sin GPU (CPU only): ~3-8 minutos por post
- Ajustar timeout del nodo HTTP Request a 600000ms (10 min) para CPU
**Si Ollama no devuelve JSON válido:**
- Agregar nodo "Error Handler" que reintenta con temperatura=0.3
- O cambiar modelo a qwen2.5:32b si hay RAM disponible
**WordPress SEO:**
- Si tienen Yoast o RankMath instalado, se puede agregar los campos SEO vía meta fields adicionales en el POST body
**Categorías WordPress:**
- Crear categorías en WP Admin: Electrical / Teak & Detailing / Engine / Hardware / Safety
- Mapear pillar → category_id en un Code node antes del post
+274
View File
@@ -0,0 +1,274 @@
# n8n Workflows — Prisa Yachts LLC
## Instancia: n8n.crewinghunters.com
## Versión: 1.0 | 2026-05-04
---
## RESUMEN DE WORKFLOWS
| Workflow | Trigger | Qué hace |
|----------|---------|----------|
| WF1: Content Buffer Publisher | Cron 9AM / 12PM / 5PM ET diario | Lee Google Sheet → publica en Instagram y Facebook automáticamente |
| WF2: LinkedIn Reminder | Cron Lu/Mié/Vie 12PM ET | Envía email con el texto del día listo para copiar en LinkedIn |
| WF3: Weekly Analytics Report | Cron Domingo 7PM ET | Jala métricas de Meta API → guarda en Sheet → envía resumen por email |
| WF4: Content Prep Reminder | Cron Domingo 8AM ET | Detecta posts sin imagen para la semana y alerta por email |
---
## VARIABLES DE ENTORNO (configurar en n8n antes de todo)
```env
PRISA_META_PAGE_ACCESS_TOKEN=EAA... # Long-lived Page Access Token (60 días)
PRISA_IG_USER_ID=17841400000000000 # Instagram Business Account ID (numérico)
PRISA_FB_PAGE_ID=100000000000000 # Facebook Page ID (numérico)
PRISA_CONTENT_SHEET_ID=1BxiMVs... # ID del Google Sheet (del URL)
PRISA_CONTENT_SHEET_NAME=ContentCalendar
PRISA_NOTIFY_EMAIL=alro65@gmail.com
```
---
## GOOGLE SHEETS — ESTRUCTURA
### Tab 1: ContentCalendar
| Col | Header | Tipo | Valores permitidos |
|-----|--------|------|-------------------|
| A | `post_id` | Texto | `PY-2026-001` |
| B | `scheduled_date` | Fecha ISO | `2026-05-06` |
| C | `scheduled_time` | Hora 24h | `11:00` |
| D | `platform` | Texto fijo | `instagram` / `facebook` / `both` |
| E | `caption_EN` | Texto largo | Caption en inglés (max 2200 chars) |
| F | `caption_ES` | Texto largo | Caption en español |
| G | `hashtags` | Texto | `#tag1 #tag2 #tag3` |
| H | `image_url` | URL | URL directa pública (ver nota crítica abajo) |
| I | `pillar` | Texto | `electrical` / `battery` / `education` / `safety` / `promo` |
| J | `status` | Texto fijo | `draft` / `scheduled` / `publishing` / `published` / `failed` / `skipped` |
| K | `published_at` | Datetime | Lo escribe WF1 automáticamente |
| L | `ig_media_id` | Texto | Lo escribe WF1 automáticamente |
| M | `fb_post_id` | Texto | Lo escribe WF1 automáticamente |
| N | `error_message` | Texto | Lo escribe WF1 si hay error |
| O | `linkedin_copy` | Texto largo | Caption adaptado para LinkedIn (lo usa WF2) |
### Tab 2: Analytics
Columnas A-R: `report_date`, `post_id`, `platform`, `published_date`, `pillar`, métricas IG (impressions, reach, likes, comments, saved, shares), métricas FB, engagement rates. WF3 appenda filas aquí cada domingo.
---
## WF1: CONTENT BUFFER PUBLISHER
### Flujo completo
```
[Schedule Trigger: 9AM / 12PM / 5PM ET]
→ [Google Sheets: Read ALL rows de ContentCalendar]
→ [Code: Filter — status=scheduled AND fecha=hoy AND hora±30min]
→ ¿Hay filas? NO → [NoOp Exit] FIN
→ ¿Hay filas? SÍ → [Split In Batches: 1 por vez]
→ [Google Sheets: Update status="publishing"] ← lock anti-duplicado
→ [Switch por platform:]
instagram → [Code: Build caption] → [HTTP: Create IG Container] → [Wait 10s] → [HTTP: Publish IG Container]
facebook → [Code: Build caption] → [HTTP: POST /photos a Facebook Page]
both → ambas ramas secuencial (IG primero, luego FB)
→ [SUCCESS] → [Google Sheets: Update status="published", published_at, ig_media_id, fb_post_id]
→ [FAILURE] → [Google Sheets: Update status="failed", error_message] → [Gmail: Notify alro65@gmail.com]
```
### API Calls exactas
**Instagram — Crear container:**
```
POST https://graph.facebook.com/v21.0/{PRISA_IG_USER_ID}/media
?image_url={image_url}
&caption={caption_EN}\n\n{caption_ES}\n\n{hashtags}
&access_token={PRISA_META_PAGE_ACCESS_TOKEN}
```
Respuesta: `{ "id": "container_id" }` → esperar 10s → publicar
**Instagram — Publicar container:**
```
POST https://graph.facebook.com/v21.0/{PRISA_IG_USER_ID}/media_publish
?creation_id={container_id}
&access_token={PRISA_META_PAGE_ACCESS_TOKEN}
```
Respuesta: `{ "id": "published_media_id" }` → guardar en columna L
**Facebook — Post con imagen:**
```
POST https://graph.facebook.com/v21.0/{PRISA_FB_PAGE_ID}/photos
?url={image_url}
&message={caption_EN}\n\n{caption_ES}\n\n{hashtags}
&access_token={PRISA_META_PAGE_ACCESS_TOKEN}
```
Respuesta: `{ "post_id": "...", "id": "..." }` → guardar en columna M
### Manejo de errores
| Error | Acción |
|-------|--------|
| Token expirado (code 190) | Halt todo, email crítico a alro65@gmail.com |
| imagen_url inválida (code 100) | Marcar fila `failed`, email, continuar con siguiente |
| Container no listo (code 9007) | Retry 4x con delay 15s, luego `failed` |
| Rate limit (429) | Retry 3x con delay 60s, luego `failed` |
| Sheet no accesible | Halt todo, email crítico |
### Estados del row (ciclo completo)
```
draft → (operador promueve) → scheduled
scheduled → (WF1 bloquea) → publishing
publishing → (éxito) → published
publishing → (error) → failed
failed → (operador resetea) → scheduled
```
---
## WF2: LINKEDIN REMINDER
```
[Schedule Trigger: Lun/Mié/Vie 12PM ET]
→ [Google Sheets: Read ContentCalendar]
→ [Code: Filter — fecha=hoy AND status=scheduled/published]
→ ¿Hay post? NO → [Gmail: "No hay post de LinkedIn hoy"]
→ ¿Hay post? SÍ → [Code: Build email — usar linkedin_copy si existe, sino caption_EN+ES]
→ [Gmail: Enviar a alro65@gmail.com con texto listo para copiar/pegar]
```
**Formato del email:**
```
Asunto: [Prisa Yachts] LinkedIn post listo — 2026-05-06
LinkedIn post de hoy:
---
[texto del post]
---
Instrucciones:
1. Ir a LinkedIn
2. Crear nuevo post
3. Copiar texto arriba
4. Subir imagen desde Google Drive
5. Publicar
```
---
## WF3: WEEKLY ANALYTICS REPORT
```
[Schedule Trigger: Domingo 7PM ET]
→ [Google Sheets: Read ContentCalendar]
→ [Code: Filter — status=published AND published_at últimos 7 días]
→ ¿Posts? NO → [Gmail: "Sin publicaciones esta semana"]
→ ¿Posts? SÍ → [Split In Batches: 1 por vez]
→ [IF ig_media_id existe] → [HTTP GET /{ig_media_id}/insights?metric=impressions,reach,likes,comments,saved,shares]
→ [IF fb_post_id existe] → [HTTP GET /{fb_post_id}/insights?metric=post_impressions,post_impressions_unique,...]
→ [Code: Calcular engagement rate = (likes+comments+saves+shares)/reach*100]
→ [Google Sheets: Append row a Analytics tab]
→ [Merge: Esperar todos los items]
→ [Code: Build reporte — ordenar por engagement desc, top post, tabla completa]
→ [Gmail: Enviar reporte a alro65@gmail.com]
```
**Instagram insights endpoint:**
```
GET https://graph.facebook.com/v21.0/{ig_media_id}/insights
?metric=impressions,reach,likes,comments,saved,shares
&access_token={token}
```
---
## WF4: CONTENT PREP REMINDER
```
[Schedule Trigger: Domingo 8AM ET]
→ [Google Sheets: Read ContentCalendar]
→ [Code: Filter — scheduled_date próximos 7 días AND status=scheduled/draft]
→ ¿Hay posts? NO → [Gmail: "Sin posts programados para la semana"]
→ ¿Hay posts? SÍ → [Code: Separar los que tienen image_url vs los que no]
→ [Code: Build email]
SI hay faltantes → "ACTION REQUIRED: X posts sin imagen"
SI todos tienen → "Todo listo para la semana"
→ [Gmail: Enviar a alro65@gmail.com]
```
---
## GUÍA DE IMPLEMENTACIÓN — ORDEN DE PASOS
### Paso 1: Credenciales en n8n
1. **Google Sheets OAuth2** — autorizar con la cuenta que tiene el Sheet
2. **Gmail OAuth2** — autorizar con alro65@gmail.com
3. **Meta API** — Header Auth: `Bearer {PRISA_META_PAGE_ACCESS_TOKEN}`
### Paso 2: Obtener los IDs de Meta
**Page Access Token (long-lived):**
```
1. developers.facebook.com → Graph API Explorer
2. Seleccionar App + Facebook Page
3. Pedir permisos: instagram_content_publish, pages_manage_posts, pages_read_engagement, instagram_manage_insights
4. GET /me/accounts → copiar access_token de tu página
5. Convertir a long-lived:
GET https://graph.facebook.com/v21.0/oauth/access_token
?grant_type=fb_exchange_token
&client_id={APP_ID}
&client_secret={APP_SECRET}
&fb_exchange_token={SHORT_TOKEN}
```
**Instagram Business Account ID:**
```
GET https://graph.facebook.com/v21.0/{PAGE_ID}
?fields=instagram_business_account
&access_token={LONG_TOKEN}
→ respuesta: { "instagram_business_account": { "id": "ESTE_ES_EL_IG_USER_ID" } }
```
### Paso 3: Crear el Google Sheet
1. Crear spreadsheet con 2 tabs: `ContentCalendar` y `Analytics`
2. Agregar headers exactos según tabla arriba
3. Agregar fila de prueba con status=`scheduled` y fecha=mañana
### Paso 4: Orden de construcción (de menor a mayor riesgo)
1. **WF4 primero** — solo lectura, envía email → probar sin riesgo
2. **WF2 segundo** — solo lectura + email → probar sin riesgo
3. **WF1 tercero** — publicación real → probar con 1 fila de prueba primero
4. **WF3 último** — requiere posts publicados con IDs reales para probar
---
## ⚠️ NOTA CRÍTICA: URLs DE IMÁGENES
Meta Graph API NO acepta links de Google Drive del tipo:
```
❌ https://drive.google.com/file/d/{ID}/view
```
Formato correcto (compartir como "Cualquiera con el link"):
```
✅ https://drive.google.com/uc?export=download&id={FILE_ID}
```
Para obtener el FILE_ID: en el link de compartir de Drive, el ID es el string alfanumérico largo.
Alternativa recomendada para producción: subir fotos a **Google Cloud Storage** con acceso público — URLs más estables y sin límites de descarga.
---
## TOKEN REFRESH (importante)
El Page Access Token expira en **60 días**. Antes de que expire:
- Opción A: Agregar WF5 "Token Expiry Reminder" que envía email cada 30 días
- Opción B (recomendada): Usar **System User Token** en Meta Business Manager — no expira nunca
---
## PREGUNTAS A RESOLVER ANTES DEL PRIMER DEPLOY
1. ¿Tienes Meta Developer App creada para Prisa Yachts?
2. ¿Instagram está como cuenta Business vinculada a tu Facebook Page?
3. ¿Las fotos irán a Google Drive o a otro storage?
4. ¿Los posts serán bilingües (EN+ES en el mismo post) o separados?
+628
View File
@@ -0,0 +1,628 @@
# PLAN MAESTRO DE MARKETING — PRISA YACHTS LLC
## Electricidad Marina | Stuart a Jacksonville, FL
### Generado: Mayo 2026
---
## RESUMEN EJECUTIVO
**Negocio:** Prisa Yachts LLC — Técnico eléctrico marino independiente, bilingüe (EN/ES)
**Servicios:** Rewiring, bancos de baterías, paneles, washdown, mantenimiento preventivo, teca, detailing
**Área:** Stuart → Vero Beach → Melbourne → Cocoa Beach → Daytona → Jacksonville
**Diferenciadores:** Bilingüe, independiente (sin overhead de taller), viaja a la marina del cliente, documenta todo con diagramas
---
## MÓDULO 1: SEO LOCAL
### Top 25 Keywords (prioridad de implementación)
**Tier 1 — Dinero inmediato:**
- "marine electrician Stuart FL"
- "boat electrician Vero Beach FL"
- "marine electrical contractor Melbourne FL"
- "boat rewiring Florida"
- "lithium battery bank installation boat Florida"
**Tier 2 — Alto volumen:**
- "boat battery replacement Florida east coast"
- "marine electrical repair near me"
- "yacht electrical contractor Florida"
- "ABYC marine electrician Florida"
- "boat panel upgrade Stuart FL"
**Tier 3 — Long tail, alta conversión:**
- "boat won't start battery dead Stuart FL"
- "marine electrical inspection before buying boat Florida"
- "boat shore power problems Fort Pierce"
- "liveaboard electrical upgrade Florida"
- "bilingual marine electrician Florida"
### Google Business Profile
- **Categoría primaria:** Electrician (Marine Electrician no disponible como categoría)
- **Área de servicio:** Stuart, Vero Beach, Fort Pierce, Sebastian, Melbourne, Cocoa Beach, Titusville, Daytona Beach, Ormond Beach, Jacksonville
- **Posts semanales:** 1 foto de trabajo completado + descripción con keyword local
- **Responder todas las reseñas** en 24 horas
### Arquitectura de Páginas de Servicio (prisayachts.com)
```
/services/boat-rewiring/
/services/battery-bank-installation/
/services/marine-panel-upgrade/
/services/shore-power-systems/
/services/washdown-system-installation/
/services/marine-electrical-inspection/
/services/liveaboard-electrical/
```
### Páginas de Área de Servicio
```
/service-area/stuart-fl/
/service-area/vero-beach-fl/
/service-area/melbourne-fl/
/service-area/daytona-beach-fl/
/service-area/jacksonville-fl/
```
### 3 Blog Posts para autoridad SEO
1. "My Boat Battery Won't Hold a Charge: 5 Causes and Fixes (Stuart FL)"
2. "Lithium vs AGM Marine Batteries: The Complete Guide for Florida Boaters"
3. "Why Every Boat Needs a Proper Electrical Diagram (And How to Get One)"
### 10 Directorios prioritarios
1. Google Business Profile
2. Yelp for Business
3. Angi (HomeAdvisor)
4. Houzz
5. Thumbtack
6. ABYC Member Directory (si aplica)
7. MarineMax service partner listings
8. BoatUS Cooperating Marina network
9. Facebook Business
10. Nextdoor Business
---
## MÓDULO 2: REDES SOCIALES — ESTRATEGIA DE PLATAFORMAS
### Prioridad de plataformas
| Prioridad | Plataforma | Por qué |
|-----------|-----------|---------|
| #1 | **Instagram** | Dueños de yates 35-65 años, Reels = descubrimiento orgánico masivo, geotagging en marinas |
| #2 | **Facebook** | Grupos de boating locales = leads directos, demografía 45-65 compradora |
| #3 | **LinkedIn** | B2B: marina managers, capitanes, brokers, contratos de flota |
| #4 | **Nextdoor** | Alta confianza local, recomendaciones de vecinos de marina |
| #5 | **TikTok** | Activar en Día 60 con contenido reutilizado de Instagram |
### Calendario Semanal de Publicación
| Día | Hora ET | Plataforma | Pilar | Formato |
|-----|---------|-----------|-------|---------|
| Lunes | 7:30 AM | Instagram + Facebook | Seguridad | Reel o foto |
| Lunes | 12:00 PM | LinkedIn | Educación | Texto + foto |
| Martes | 8:00 AM | Instagram | Trabajo real | Carousel 3-5 fotos |
| Martes | 6:00 PM | Facebook Groups | Detrás del técnico | Post nativo |
| Miércoles | 7:30 AM | Instagram + Facebook | Prueba social | Testimonio/reseña |
| Miércoles | 11:00 AM | LinkedIn | Seguridad/Autoridad | Texto + foto |
| Jueves | 8:00 AM | Instagram | Trabajo real | Reel instalación |
| Jueves | 7:00 PM | Nextdoor | Cualquier pilar | Update de negocio |
| Viernes | 7:30 AM | Instagram + Facebook | Educación | Carousel |
| Viernes | 12:00 PM | LinkedIn | Prueba social | Foto de proyecto |
| Sábado | 8:30 AM | Instagram | Detrás del técnico | Reel en el muelle |
| **Domingo** | — | — | — | **Día de preparación de contenido** |
### 5 Pilares de Contenido
1. **Muestra el Trabajo (Prueba)** — Fotos antes/después de instalaciones reales
2. **Educa para Ganar Confianza (Autoridad)** — Tips técnicos, explicaciones claras
3. **Seguridad y Prevención (Urgencia)** — Alertas sobre riegos reales
4. **Detrás del Técnico (Confianza y Personalidad)** — Bilingüe, independiente, llega a tu marina
5. **Prueba Social y Resultados (Conversión)** — Testimonios, reseñas, proyectos completados
---
## MÓDULO 3: INSTAGRAM — PERFIL Y CONTENIDO
### Bio Optimizada
**Inglés:**
```
Prisa Yachts LLC ⚡
Marine Electrical Technician | FL Coast
Rewiring · Battery Banks · Panels · Washdown
Stuart to Jacksonville — We Come to Your Marina
📲 DM for a free quote
🔗 prisayachts.com
```
**Español:**
```
Prisa Yachts LLC ⚡
Electricista Marino | Costa de Florida
Cableado · Baterías · Paneles · Washdown
Stuart hasta Jacksonville — Vamos a tu marina
📲 Escríbenos para cotización gratis
🔗 prisayachts.com
```
### Highlights a crear INMEDIATAMENTE
1. **Our Work** — Mejor trabajo terminado (fotos limpias de instalaciones)
2. **Before & After** — Solo transformaciones
3. **Services** — Una diapositiva por servicio con "DM for quote"
4. **Where We Work** — Mapa Stuart a Jacksonville, marinas donde has trabajado
5. **Tips** — Slides educacionales guardados
6. **Reviews** — Screenshots de clientes satisfechos
### Rotación de Posts (ciclo de 3)
- Post Tipo 1: Foto de trabajo terminado (prueba)
- Post Tipo 2: Antes/Después (transformación)
- Post Tipo 3: Educación/confianza
### Regla de CTA en cada post
Exactamente **1 CTA al final** — nunca dos, nunca cero. Rotar entre:
- "DM us for a free quote. We come to your marina."
- "Send us a photo of your setup and we will tell you what it needs."
- "Tag a boat owner who needs to see this."
- "Save this — you will want to refer back to it."
- "Escríbenos por DM — cotización gratis, sin compromiso."
### Hashtags por post (usar 8-12, mezclar tiers)
**Tier A (volumen alto):** #MarineElectrical #BoatLife #YachtLife #FloridaBoating #BoatMaintenance #MarineElectrician
**Tier B (intención alta):** #YachtElectrical #LithiumBattery #MarineBatteries #VictronEnergy #BoatWiring #MarineSafety
**Tier C (geográfico, conversión alta):** #TreasureCoast #SpaceCoast #StuartFL #FortPierce #CocoaBeach #FloridaYacht
### Reels con solo fotos (NO necesitas video)
**Estructura del Reel de Transformación:**
1. Frame texto: "Here is what we found." (1-2 seg)
2. Frames 2-4: Fotos del ANTES (problema)
3. Frame texto: "Here is what we did." (1 seg)
4. Frames 6-8: Fotos del DESPUÉS (trabajo limpio)
5. Frame final: "Stuart to Jacksonville. DM for a free quote. Prisa Yachts LLC"
**Audio:** Buscar sonidos trending en home renovation / "satisfying work" — este nicho cruza perfecto.
---
## MÓDULO 4: TIKTOK — SCRIPTS LISTOS PARA FILMAR
### Top 5 Formatos de Video
1. **Antes/Después** — El de mayor rendimiento en trades. Muestra problema, trabaja, revela resultado limpio.
2. **"Why Your Boat Did That"** — Lead con síntoma conocido (baterías muriendo, luces parpadeando) → explica causa raíz
3. **POV Día de Trabajo** — Cámara mostrando lo que ves mientras trabajas. Con audio trending.
4. **Transparencia de Costos** — Desglosa qué cuesta un trabajo y por qué. Filtra clientes de precio, atrae serios.
5. **Safety Warning Bilingüe** — Tip de seguridad en inglés, punto clave repetido en español.
### 10 Hooks de Apertura (primeros 3 segundos)
1. "This boat almost burned down last week because of this." [muestra cable dañado]
2. "If you own a boat, stop what you are doing and look at your battery terminals right now."
3. "Six hundred thousand dollar yacht. Wire nuts."
4. "I pulled two hundred and thirty feet of wrong wire out of one boat today."
5. "The previous owner of this boat was three bad connections away from losing everything."
6. "Nobody tells boat owners this about shore power."
7. "This is what your battery bank looks like after five years if nobody services it."
8. "Day one versus day three on a full rewire. Watch."
9. "Your bilge pump wiring is probably wrong. Here is why it matters."
10. "I have been doing marine electrical for twelve years and this is still the most common mistake I find."
### Estructura Universal de Video (Hook → Proof → Value → Anchor)
- **0-3 seg: Hook** — Una afirmación. Una imagen. Genera miedo, curiosidad o reconocimiento.
- **3-15 seg: Proof** — Muestra que lo que dijiste en el hook es real. En la locación, tocando el problema.
- **15-40 seg: Value** — La información, demostración o transformación real. Aquí ocurren los "saves".
- **40-55 seg: Anchor** — Razón para seguir, comentar o contactar. Elegir UNO:
- Anchor Comunidad: "Drop your question in the comments"
- Anchor Negocio: "If your boat needs this, I work Stuart to Jacksonville — DM me"
**Regla:** Contenido tutorial → Anchor Comunidad. Contenido de transformación/seguridad → Anchor Negocio.
### Script #1 — "The Battery That Almost Burned This Boat Down" (55 seg)
[Abrir en terminales corroídas, zoom lento]
"Look at this. I got called to a 42-foot Viking today because the owner kept losing power every time he ran the AC. He thought it was the inverter. It was not the inverter."
[Pan al banco de baterías completo — conexiones flojas, corrosión, cableado incorrecto]
"Three Group 31 batteries. None of them properly terminated. The positive bus bar is connected with the wrong gauge wire — this thing is a heat source waiting to find something to burn."
[Corte al trabajo — limpiando terminales, crimpando nuevas terminaciones]
"We are pulling all of this out, cleaning every contact point, installing proper tinned marine wire and rebuilding this battery bank the right way."
[Corte a la instalación terminada — limpia, etiquetada, bien organizada]
"Same boat. Thirty-six hours later. Every connection torqued to spec, labeled, heat-shrink on every terminal. That AC runs all night and the owner sleeps without worrying about waking up to smoke."
[Mirar a cámara]
"If your batteries are more than five years old and you have not had them inspected, call someone. Not because I want the work. Because boats burn."
[Overlay: Stuart to Jacksonville FL | DM for inspection]
---
### Script #2 — "Why Your Shore Power Is Dangerous Right Now" (45 seg, Bilingüe)
[En el muelle de la marina, pedestal de shore power visible]
"Real quick — if you are plugged into shore power and you have not replaced your shore power cord in the last three to five years, go check it right now."
[Mostrar conector deteriorado — pines corroídos, carcasa agrietada]
"This came off a boat at the marina this morning. The owner had no idea. This connector was pulling 30 amps through connections that were partially melted. That is a fire."
[Mostrar cable nuevo al lado del dañado]
"Thirty-amp cords — inspect the male end, inspect the female end. Any discoloration, any heat marks, any corrosion — replace it."
[Cambiar a español, misma energía]
"Para mis amigos hispanos — el cable de shore power de su barco, reviselo hoy. Si el conector tiene corrosión o marcas de calor, cámbielo antes de su próximo viaje."
[Volver a inglés]
"Stuart to Jacksonville, I do shore power inspections. Link in bio."
---
### Script #3 — "What a Full Rewire Actually Looks Like" (30 seg, POV)
[Sin intro, abrir directamente en manos sacando cableado viejo de un panel]
"This is day two of a full rewire on a 38-foot trawler. The previous owner ran extensions. Everywhere. Instead of running proper circuits, they just ran extension cords and stapled them to the bulkhead."
[Corte a la pila de cable viejo removido]
"That pile is 230 feet of wrong wire pulled out of one boat."
[Corte al nuevo cableado siendo instalado, limpio y organizado]
"New tinned marine wire, color-coded, properly fused at the source. Every circuit labeled."
[Toma final: panel terminado]
"This is what a real electrical system looks like."
[Overlay: Full rewires, Stuart to Jax FL]
---
### Script #9 — Historia Personal Bilingüe (60 seg, Brand Story)
[Cámara de frente, luz natural]
"Quick story — people ask me why I specialize in marine electrical. The honest answer is that I did not plan to."
[Caminar y hablar, moviéndose por la marina]
"I came to Florida from Colombia. My first years in the trades were general electrical — residential, commercial, everything. Then a friend asked me to help him troubleshoot his boat. I spent four hours on that boat and I was completely hooked."
[Parar, mirar a cámara]
"Marine electrical is harder than residential. The environment is hostile. Everything corrodes. Vibration loosens connections. You are working in confined spaces. And if you get it wrong, the consequences are not a tripped breaker — the consequences are someone stranded offshore or worse."
[Cambiar a español]
"Para los que me siguen en español — soy colombiano, hablo inglés y español, y atiendo clientes en ambos idiomas desde Stuart hasta Jacksonville. Hay muy pocos técnicos bilingües en este nicho y quiero que la comunidad hispana tenga acceso al mismo nivel de servicio."
[Volver a inglés]
"Prisa Yachts LLC. Marine electrical done right. Link in bio."
---
### Frecuencia y Timing TikTok
**Frecuencia:** 3 videos/semana (meses 1-2) → 4-5/semana (mes 3+)
**Mejores horarios ET:**
- Martes 7:00-9:00 AM
- Miércoles 12:00-1:00 PM
- Jueves 7:00-9:00 PM
- Sábado 8:00-10:00 AM
**Por día:**
- Lunes: Contenido de seguridad (urgencia del lunes impulsa shares)
- Miércoles: Tutorial/educación (saves de mitad de semana)
- Viernes/Sábado: Antes/Después (audiencia del fin de semana)
---
## MÓDULO 5: CAPTIONS LISTAS — COPY AND PASTE
### 15 Captions de Instagram listas para usar
**[1] Battery Bank Install (EN)**
"This 200Ah lithium bank replaced a pair of AGM batteries that were 6 years past their prime.
The owner had been losing shore power every night. Now he has full power through sunrise — without plugging in.
We installed, wired, programmed the BMS, and were gone before noon.
If your batteries are struggling to hold a charge, DM us. We work at marinas from Stuart to Jacksonville. Quote is free.
#marineelectrical #yachtlife #lithiumbattery #batterybank #boatlife #marinetech #floridaboating #marinafl"
---
**[2] Rewiring Job (EN)**
"This boat came to us with 40 feet of original wiring from the late 90s. Brittle insulation. Undersized conductors. Three mystery circuits no one could trace.
We pulled it all. Started clean.
Every wire labeled. Every run secured. Every circuit documented.
DM us for a full rewiring quote. We travel to your marina.
#rewiring #marineelectrical #boatsafety #yachtrepair #marineelectrician #floridamarina #boatmaintenance"
---
**[3] Trabajo de Cableado (ES)**
"Cableado completo de un velero de 42 pies. Todo el sistema original estaba fuera de norma.
Cada cable marcado. Cada circuito documentado. Cada conexión sellada.
Cuando terminamos, el dueño sabía exactamente qué hacía cada interruptor en su tablero — por primera vez en años.
Servicio en marinas desde Stuart hasta Jacksonville.
Cotización gratis por mensaje directo.
#electricidadmarina #cableado #velero #marineelectrician #floridamarina #mantenimientonaval"
---
**[4] Safety Warning — Shore Power (EN)**
"This shore power connection failed a GFCI test during a routine inspection. The boat owner had no idea — everything 'worked fine.'
Shore power is the #1 cause of electrical fires on boats at the dock.
If your boat lives at a marina and you have not had a shore power inspection in the last 2 years, this post is for you.
DM me to schedule. I work at your marina — Stuart to Jacksonville.
#MarineElectricalSafety #ShorePower #BoatFire #MarineSafety #BoatInspection #MarineElectrician #FloridaBoating"
---
**[5] Lithium vs AGM (EN)**
"AGM or Lithium — here is the short version:
AGM: Lower upfront cost, reliable, best for occasional boaters.
Lithium: 3-4x usable capacity, charges faster, lasts 8-10x longer — best for liveaboards and high-draw systems.
The honest answer: it depends on how you use your boat. I do a load calculation and tell you what actually makes sense.
DM me for a no-pressure consultation.
#LithiumVsAGM #MarineBatteries #BoatBatteries #MarineElectrical #floridaboating"
---
**[6] Before/After Panel (EN)**
"Before: Old panel. Corroded terminals. Half the breakers tripped and never reset.
After: New panel. Clean runs. Every circuit marked and tested. Full wiring diagram delivered.
Serving Florida marinas from Stuart to Jacksonville. Free quotes via DM.
⚡ Tag a boat owner who needs this.
#electricalpanel #marinepanel #boatelectrical #yachtmaintenance #marineelectrical #floridaboating"
---
**[7] Washdown System (EN)**
"A saltwater washdown system is one of the best upgrades you can add to a working vessel.
We install complete systems: pump, plumbing, deck fittings, wired and tested.
Takes about 3-4 hours. Takes care of your boat for years.
DM us to schedule. We come to your slip.
#washdownsystem #marineinstallation #yachtupgrade #boatlife #marinework #floridayacht"
---
**[8] Hurricane Season Checklist (EN)**
"5 electrical checks before hurricane season:
1. Shore power cord — look for discoloration or cracks
2. Battery terminals — white powder = sulfation, needs attention
3. Cycle all breakers manually — replace any that feel spongy
4. Test bilge pump float switch
5. Check running lights — they fail silently
Florida hurricane season starts June 1. Save this. Share with a boat neighbor.
#HurricaneSeason #BoatMaintenance #MarineElectrical #FloridaBoating #BoatSafety"
---
**[9] Seguridad Eléctrica (ES)**
"El cableado eléctrico marino no es igual al terrestre.
El ambiente salado corroe todo. La vibración afloja conexiones. La humedad crea cortos donde menos lo esperas.
Por eso usamos materiales certificados para uso marino en cada instalación. Sin atajos.
Si tu barco tiene más de 10 años y nunca ha tenido una revisión eléctrica completa — es momento.
DM para inspecciones y cotizaciones.
#seguridadmarina #inspeccionelectrica #electricidadmarina #barcosfl #marineelectrical"
---
**[10] Liveaboard Focus (EN)**
"Liveaboards have different electrical needs than weekend boaters.
You need consistent power, redundancy, and a system that handles daily household loads.
We have designed and installed full liveaboard electrical systems including shore power management, 12V banks, inverters, and solar integration.
DM us if your liveaboard electrical feels like a patchwork of band-aids.
#liveaboard #liveaboardlife #marineelectrical #batterybank #solarboat #floridamarina #yachtlife"
---
**[11] Marina Managers/Captains (EN)**
"Marina managers and captains — we keep you on the water.
Electrical issues are the #1 cause of unexpected downtime on working vessels. We prioritize commercial and fleet clients with faster scheduling and documented service records.
Stuart to Jacksonville. DM or share with your marina manager.
#marinebusiness #captainslife #yachtcaptain #fleetmaintenance #marineelectrical #floridamarina"
---
**[12] Diagrama Eléctrico (ES)**
"Cada instalación nueva que hago incluye un diagrama eléctrico completo.
No porque sea obligatorio — porque el próximo técnico que trabaje en tu barco merece saber exactamente qué está viendo.
Un cálculo de carga correcto también te dice si tu sistema de carga puede mantenerse al ritmo de tu consumo.
Escríbeme para precios.
#DiagramaElectrico #ElectricidadMarina #BarcosEnFlorida #TecnicoNautico"
---
**[13] Call for Referrals (EN)**
"Good referrals run this industry.
If your marina neighbor has been complaining about battery problems, flickering lights, or a panel that looks like it was last touched in 2003 — send them our way.
Honest work, fair prices, we document everything.
Florida coast, Stuart to Jacksonville. Tag them below.
#marineelectrical #referral #yachtlife #boatmaintenance #floridamarina"
---
**[14] Banco de Baterías Litio (ES)**
"Banco de baterías de litio instalado en un crucero en Stuart.
El cliente llevaba dos años lidiando con baterías AGM que no aguantaban la noche. Hoy tiene energía de sobra, BMS programado y diagrama de cableado en mano.
Trabajamos en marinas de toda la costa de Florida.
Escríbenos por DM para una cotización sin costo.
#electricidadmarina #baterias #litio #yachtlife #floridaboating #barcosfl"
---
**[15] Pre-Temporada (ES)**
"Antes de la próxima temporada de navegación — revisión eléctrica completa.
Los problemas que ignoraste el año pasado no desaparecen solos. Las conexiones corroídas empeoran. Las baterías débiles se mueren.
Una inspección ahora te ahorra una avería después.
Cotización gratis. DM esta semana.
⚡ Comparte con alguien que esté preparando su barco.
#temporadanavegacion #electricidadmarina #mantenimientonaval #floridaboating"
---
## MÓDULO 6: KPIs Y MÉTRICAS
### Días 1-30 (Fundación)
- Instagram: 200 cuentas únicas alcanzadas por post para fin de semana 4
- Instagram: Tasa de engagement 3.5%+ (likes + comments + saves / reach)
- Facebook: 1 contacto directo (DM o llamada) originado de redes sociales
- LinkedIn: 50 vistas de perfil por post
- Nextdoor: perfil verificado en 5 zip codes costeros
### Días 31-60 (Tracción)
- Instagram: +75-150 seguidores nuevos
- Instagram: Al menos 1 Reel con 1,000+ vistas de no-seguidores
- Facebook Groups: 3+ conversaciones iniciadas, 1 resultando en DM
- LinkedIn: Primer mensaje entrante de marina manager, capitán o broker
- Lead: 3+ consultas directamente atribuidas a contenido de redes sociales
### Días 61-90 (Conversión)
- Instagram: 300+ seguidores, engagement 4%+ consistente
- LinkedIn: +25 conexiones en audiencia objetivo
- Revenue: 1 trabajo/mes que el cliente atribuye a haber visto Prisa Yachts en redes
- Método: preguntar a cada cliente nuevo "¿cómo nos encontraste?"
### 5 Métricas semanales a trackear (para n8n → Google Sheets)
1. Posts publicados (objetivo vs. real)
2. Alcance total de la semana
3. Engagement total (likes + comments + shares + saves)
4. Tasa de engagement (%)
5. Contactos entrantes atribuidos a redes (DMs, llamadas, emails)
---
## MÓDULO 7: AUTOMATIZACIÓN EN n8n
### Workflows a construir en n8n.crewinghunters.com
**Workflow 1: Buffer de Contenido (Google Sheets → Instagram/Facebook)**
- Google Sheet con columnas: plataforma, fecha/hora, caption EN, caption ES, hashtag set, image URL (Google Drive)
- Schedule Trigger con cron según calendario semanal
- HTTP Node → Meta Graph API para publicación automática
- Rotación de sets de hashtags por pilar de contenido
**Workflow 2: Reminder de LinkedIn**
- Schedule Trigger (Lu/Mi/Vi 12 PM)
- Notificación push al teléfono con el texto del post del día
- LinkedIn no permite publicación automática via API para posts personales
**Workflow 3: Recordatorio de Grupos de Facebook**
- Schedule Trigger (Ma/Ju)
- Notificación al dueño con el post de valor de la semana para copiar/pegar en grupos
**Workflow 4: Reporte Semanal (Domingo noche)**
- Cron cada domingo 7 PM
- Leer métricas de Meta Graph API y LinkedIn API
- Guardar en Google Sheets
- Enviar resumen por email a alro65@gmail.com
**Workflow 5: Preparación de Contenido (Domingo)**
- Trigger manual o cron domingo 8 AM
- Lista de qué fotografiar esta semana
- Recordatorio de cargar fotos a Google Drive por folder de pilar
### Grupos de Facebook donde participar
- Space/Treasure Coast Power Boat Club
- Freedom Boat Club of the Space and Treasure Coasts
- Grupos de marinas locales por ciudad del área de servicio
---
## PLAN DE ACCIÓN — PRIMERAS 2 SEMANAS
### Semana 1: Establecer Presencia
- [ ] Actualizar bio de Instagram (versión EN o ES)
- [ ] Crear los 6 Highlights inmediatamente (aunque tengan 1 sola story cada uno)
- [ ] Publicar los primeros 3 posts (rotación Tipo 1/2/3 con fotos de trabajos existentes)
- [ ] Agregar geotag a cada post y story desde ahora
- [ ] Registrar perfil de negocio en Nextdoor en 5 zip codes
- [ ] Verificar/crear Google Business Profile
### Semana 2: Primer Reel y Grupos
- [ ] Publicar primer Reel usando formato "Job Story" con fotos antes/después
- [ ] Unirse a 3 grupos de Facebook de boating de Florida
- [ ] Hacer 1 post de valor en cada grupo (no vender, educar)
- [ ] Crear perfil de LinkedIn y publicar primer post con foto de proyecto
- [ ] Responder todos los comments y DMs en menos de 2 horas
---
*Plan generado por Claude con especialistas: Social Media Strategist, Instagram Curator, TikTok Strategist, SEO Specialist*
*Para implementación de n8n: ir a n8n.crewinghunters.com y crear los 5 workflows del Módulo 7*
+481
View File
@@ -0,0 +1,481 @@
# WhatsApp Automation — Prisa Yachts LLC
## Evolution API + n8n | Zero Additional Cost
## Versión: 1.0 | 2026-05-04
---
## ARQUITECTURA GENERAL
```
Cliente envía WhatsApp
Evolution API
(Docker en tu servidor)
Webhook → n8n.crewinghunters.com
n8n procesa mensaje
Evolution API → responde al cliente
```
**Costo adicional:** $0 — todo corre en infraestructura existente.
**Número:** Tu número personal/negocio actual (solo hay que escanearlo con QR una vez).
---
## PASO 1: INSTALAR EVOLUTION API
### Opción A — Docker Compose (recomendado)
En tu servidor, crear el archivo `/opt/evolution-api/docker-compose.yml`:
```yaml
version: "3.7"
services:
evolution-api:
image: atendai/evolution-api:latest
container_name: evolution-api
restart: always
ports:
- "8080:8080"
environment:
- SERVER_URL=https://wa.crewinghunters.com # subdominio que apuntes a este servidor
- AUTHENTICATION_TYPE=apikey
- AUTHENTICATION_API_KEY=PRISA_WA_SECRET_KEY_AQUI
- AUTHENTICATION_EXPOSE_IN_FETCH_INSTANCES=true
- QRCODE_LIMIT=30
- WEBHOOK_GLOBAL_ENABLED=true
- WEBHOOK_GLOBAL_URL=https://n8n.crewinghunters.com/webhook/prisa-whatsapp
- WEBHOOK_EVENTS_MESSAGES_UPSERT=true
- WEBHOOK_EVENTS_MESSAGES_UPDATE=true
- WEBHOOK_EVENTS_CONNECTION_UPDATE=true
- DATABASE_ENABLED=false
- CACHE_REDIS_ENABLED=false
volumes:
- evolution_instances:/evolution/instances
volumes:
evolution_instances:
```
```bash
cd /opt/evolution-api
docker-compose up -d
```
### Conectar tu número (una sola vez)
```bash
# 1. Crear instancia
curl -X POST https://wa.crewinghunters.com/instance/create \
-H "apikey: PRISA_WA_SECRET_KEY_AQUI" \
-H "Content-Type: application/json" \
-d '{"instanceName": "prisa-yachts", "qrcode": true}'
# 2. Obtener QR
curl https://wa.crewinghunters.com/instance/connect/prisa-yachts \
-H "apikey: PRISA_WA_SECRET_KEY_AQUI"
# → responde con imagen QR en base64 o URL
# 3. Escanear QR desde WhatsApp en tu teléfono
# WhatsApp → Dispositivos Vinculados → Vincular dispositivo → Escanear QR
```
Una vez escaneado, el número queda conectado. Si el servidor se reinicia, Evolution API reconecta solo usando la sesión guardada.
---
## PASO 2: CONFIGURAR NGINX (si usas reverse proxy)
```nginx
server {
listen 80;
server_name wa.crewinghunters.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name wa.crewinghunters.com;
# SSL (certbot o tu certificado)
ssl_certificate /etc/letsencrypt/live/wa.crewinghunters.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wa.crewinghunters.com/privkey.pem;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```
---
## PASO 3: WORKFLOWS EN n8n
### Variables de entorno (agregar en n8n)
```env
PRISA_WA_API_URL=https://wa.crewinghunters.com
PRISA_WA_API_KEY=PRISA_WA_SECRET_KEY_AQUI
PRISA_WA_INSTANCE=prisa-yachts
PRISA_OWNER_PHONE=1XXXXXXXXXX # número del dueño en formato internacional sin +
```
---
### WA-WF1: AUTO-RESPUESTA INTELIGENTE
**Trigger:** Webhook POST en `/webhook/prisa-whatsapp`
**Lógica completa:**
```
[Webhook: recibe mensaje de Evolution API]
→ [Code: extraer remoteJid, message.conversation, pushName]
→ [Code: normalizar mensaje — trim, toLowerCase]
→ [Switch — detectar intención:]
COTIZACIÓN ("quote", "cotiz", "precio", "cost", "how much", "cuánto")
→ [HTTP: Evolution API → enviar mensaje texto]
→ [Wait 2s]
→ [HTTP: Evolution API → enviar brochure PDF]
TECA ("teak", "teca", "wood", "madera", "deck")
→ [HTTP: Evolution API → enviar respuesta teca + brochure teca]
ELÉCTRICO ("electric", "eléctric", "wiring", "cable", "battery", "batería", "panel")
→ [HTTP: Evolution API → enviar respuesta eléctrico + brochure eléctrico]
UBICACIÓN ("where", "dónde", "location", "area", "stuart", "jacksonville")
→ [HTTP: Evolution API → enviar área de servicio]
EMERGENCIA ("emergency", "urgente", "urgent", "fire", "fuego", "smoke", "humo")
→ [HTTP: Evolution API → enviar número directo]
→ [Gmail: notificar al dueño inmediatamente]
HOLA / SALUDO (primeras palabras: "hi", "hello", "hola", "buenos", "good")
→ [HTTP: Evolution API → enviar bienvenida]
DEFAULT (cualquier otro mensaje)
→ [HTTP: Evolution API → enviar menú de opciones]
→ [Gmail: notificar al dueño — lead sin clasificar]
```
---
### MENSAJES EXACTOS
**BIENVENIDA** (trigger: saludo genérico o primer contacto):
```
Hi! 👋 Thanks for reaching out to *Prisa Yachts LLC*.
I'm Alberto, marine electrical technician based out of Stuart, FL — serving Stuart to Jacksonville.
What can I help you with today?
1️⃣ Request a quote
2️⃣ Teak restoration & detailing
3️⃣ Marine electrical (ABYC certified work)
4️⃣ Our service area
5️⃣ Emergency / urgent issue
Just reply with the number or describe your situation.
```
---
**COTIZACIÓN RECIBIDA** (trigger: "quote", "cotización", "precio", etc.):
```
Great — I'd love to give you a quote! 🛥️
To get you an accurate estimate, I need a few quick details:
*What service?* (electrical, teak, detailing, batteries, washdown, or full service)
*Boat type and length?* (e.g., 38ft sailboat, 45ft twinscrew)
• *Your marina/location?*
• *Best time to call?*
Reply here or call me directly. I'll also send you our services overview right now.
```
*(seguido del brochure PDF general)*
---
**SERVICIOS DE TECA** (trigger: "teak", "teca", "deck", "wood"):
```
Teak restoration is one of our specialties. 🌿
We handle everything from quick maintenance cycles to full recoveries — and we do an honest assessment before quoting so you know if recovery or replacement makes more sense.
*Our teak services:*
• Two-part clean + sand + oil + seal
• Before/after documentation
• Gelcoat polishing & oxidation removal
• Caulking inspection and reseam
Send me a photo of your deck and I can give you a rough idea before we even schedule a visit.
Sending you our teak & detailing brochure now 👇
```
*(seguido del brochure PDF teca)*
---
**SERVICIOS ELÉCTRICOS** (trigger: "electric", "wiring", "battery", "panel"):
```
Marine electrical is our core specialty — all work done to ABYC E-11 standards. ⚡
*What we do:*
• Full rewiring (tinned wire, proper gauge, labeled circuits)
• Lithium battery bank design & installation
• Shore power systems & inverter/charger
• Solar & alternator upgrades
• NMEA 2000 / 0183 integration
• Bilge pump, washdown, anchor windlass
We work Stuart to Jacksonville. No job too small.
Sending you our electrical services brochure now 👇
```
*(seguido del brochure PDF eléctrico)*
---
**ÁREA DE SERVICIO** (trigger: "where", "location", "area"):
```
📍 *Service Area — Prisa Yachts LLC*
We're based out of *Stuart, FL* and cover the full east coast of Florida:
• Stuart / Treasure Coast ✅
• Fort Pierce ✅
• Vero Beach ✅
• Sebastian / Brevard ✅
• Titusville / Space Coast ✅
• Daytona Beach ✅
• Jacksonville ✅
Travel fees may apply for jobs north of Daytona. Free 20-min phone consult for any location before committing.
Want to schedule a consult?
```
---
**EMERGENCIA** (trigger: "emergency", "urgent", "fire", "smoke"):
```
⚠️ *URGENT — Prisa Yachts LLC*
For an active emergency (fire, flooding, electrical failure), call me directly right now:
📞 *[PHONE_NUMBER]*
If it's an electrical emergency:
• Turn off shore power at the dock pedestal
• Turn off your main breaker
• If there's smoke, get everyone off the boat
I'm responding to your message now.
```
*(+ email automático al dueño: "URGENT: WhatsApp emergency message from [nombre] at [número]")*
---
**MENÚ DEFAULT** (cualquier mensaje no clasificado):
```
Thanks for reaching out to *Prisa Yachts LLC*! 🛥️
I want to make sure I get you to the right place. What are you looking for?
1️⃣ *Quote* — I need a price for a job
2️⃣ *Teak & Detailing* — restoration, polishing, gelcoat
3️⃣ *Marine Electrical* — wiring, batteries, solar, panels
4️⃣ *Service Area* — where do you work?
5️⃣ *Emergency* — I need help now
Reply with a number or describe your situation and I'll get back to you shortly.
— Alberto | Prisa Yachts LLC | Stuart to Jacksonville
```
---
### WA-WF2: NOTIFICACIÓN DE LEAD AL DUEÑO
**Trigger:** Todos los mensajes entrantes (paralelo a WA-WF1)
**Flujo:**
```
[Webhook: recibe mensaje]
→ [Code: formatear — nombre, número, texto, hora ET]
→ [Code: ¿es número propio? → IF sí → NoOp (ignorar mensajes del dueño)]
→ [Gmail: enviar a alro65@gmail.com]
```
**Formato del email:**
```
Asunto: [Prisa Yachts WA] Nuevo mensaje — Juan Pérez
Nuevo mensaje de WhatsApp recibido:
Nombre: Juan Pérez
Número: +1 (772) 555-0123
Hora: 2026-05-04 10:32 AM ET
Mensaje:
"Hi I need a quote for my 42ft Hatteras rewiring. I'm in Fort Pierce."
---
Respuesta automática enviada: COTIZACIÓN
Brochure enviado: prisa_yachts_general.pdf
Responder: https://wa.me/17725550123
```
---
### WA-WF3: FOLLOW-UP AUTOMÁTICO (24 HORAS)
**Trigger:** Cron — cada hora, revisar leads sin respuesta humana
**Lógica:**
```
[Schedule Trigger: cada hora]
→ [Google Sheets: leer tab WALeads]
→ [Code: filtrar — status="auto_replied" AND created_at > 24h ago AND no_human_reply=true]
→ [IF hay leads pendientes]
→ [HTTP: Evolution API → enviar follow-up]
→ [Google Sheets: update status="followed_up"]
→ [Gmail: notificar al dueño]
```
**Mensaje follow-up (24h después):**
```
Hi [nombre]! Just wanted to follow up on your message yesterday about [tema].
Have you had a chance to think about it? I'm happy to answer any questions before you decide.
📞 Or call me directly: [PHONE_NUMBER]
— Alberto | Prisa Yachts LLC
```
---
### WA-WF4: LOG DE CONVERSACIONES (Google Sheets)
Cada mensaje recibido appenda una fila al tab `WALeads`:
| Col | Header | Ejemplo |
|-----|--------|---------|
| A | `timestamp` | `2026-05-04 10:32:00` |
| B | `phone` | `+17725550123` |
| C | `name` | `Juan Pérez` |
| D | `message` | `Hi I need a quote...` |
| E | `intent` | `quote` / `teak` / `electrical` / `emergency` / `default` |
| F | `auto_response_sent` | `yes` |
| G | `brochure_sent` | `general` / `teak` / `electrical` / `none` |
| H | `status` | `auto_replied` / `followed_up` / `converted` / `closed` |
| I | `notes` | (notas manuales del dueño) |
---
## PASO 4: API CALLS EXACTAS A EVOLUTION API
### Enviar mensaje de texto:
```
POST https://wa.crewinghunters.com/message/sendText/prisa-yachts
Headers: apikey: PRISA_WA_SECRET_KEY_AQUI
Body: {
"number": "17725550123", ← sin +, sin espacios
"text": "Hola mensaje aquí"
}
```
### Enviar documento/brochure PDF:
```
POST https://wa.crewinghunters.com/message/sendMedia/prisa-yachts
Headers: apikey: PRISA_WA_SECRET_KEY_AQUI
Body: {
"number": "17725550123",
"mediatype": "document",
"mimetype": "application/pdf",
"media": "https://drive.google.com/uc?export=download&id={FILE_ID}",
"fileName": "PrisaYachts_Services.pdf",
"caption": "Here's our services overview 👆"
}
```
### Enviar imagen:
```
POST https://wa.crewinghunters.com/message/sendMedia/prisa-yachts
Body: {
"number": "17725550123",
"mediatype": "image",
"mimetype": "image/jpeg",
"media": "https://...",
"caption": "Before & After — Teak Restoration"
}
```
---
## FLUJO DE IMPLEMENTACIÓN (orden)
### Semana 1: Setup
1. [ ] Instalar Evolution API con Docker en tu servidor
2. [ ] Configurar DNS: `wa.crewinghunters.com` → IP del servidor
3. [ ] Configurar Nginx + SSL (certbot)
4. [ ] Escanear QR y conectar número
5. [ ] Verificar que el webhook llega a n8n (test con mensaje de prueba)
### Semana 2: Workflows básicos
6. [ ] Construir WA-WF2 (notificación al dueño) — mínimo viable, sin riesgo
7. [ ] Construir WA-WF4 (log en Google Sheets) — solo lectura/escritura
8. [ ] Probar con mensaje real de tu propio teléfono
### Semana 3: Respuesta automática
9. [ ] Construir WA-WF1 (auto-respuesta) — empezar solo con el menú DEFAULT
10. [ ] Agregar lógica de cotización
11. [ ] Subir brochures a Google Drive, obtener FILE_IDs
12. [ ] Conectar envío de PDFs
13. [ ] Agregar resto de intenciones (teca, eléctrico, emergencia)
### Semana 4: Follow-up
14. [ ] Construir WA-WF3 (follow-up 24h)
15. [ ] Probar flujo completo end-to-end
---
## PREGUNTAS A RESOLVER ANTES DEL PRIMER DEPLOY
1. ¿Cuál es la IP o hostname de tu servidor?
2. ¿Ya tienes Docker instalado en el servidor?
3. ¿Usas Nginx o Caddy como reverse proxy?
4. ¿Cuál es tu número de WhatsApp (formato +1XXXXXXXXXX)?
5. ¿Tienes los brochures PDF listos o hay que crearlos primero?
---
## NOTAS IMPORTANTES
**Riesgo de ban:** WhatsApp tolera la automatización con números conectados via QR siempre que:
- Los mensajes sean respuestas a conversaciones iniciadas por el cliente (no bulk messaging)
- No envíes mensajes masivos no solicitados
- El comportamiento sea similar al humano (con delays entre mensajes)
Esta arquitectura cumple todo eso — solo responde a mensajes entrantes.
**Sesión persistente:** Evolution API guarda la sesión en el volumen Docker. Si reinicias el servidor, reconecta solo en <30 segundos sin necesidad de escanear el QR de nuevo.
**Backup del QR:** Después de conectar el número, hacer backup del volumen: `docker run --rm -v evolution_instances:/data alpine tar czf - /data > evolution_backup.tar.gz`