Cómo Desplegar en Mi Plante
Audiencia: cada desarrollador nuevo, antes de abrir su primer PR. Objetivo: explicar el flujo de despliegue honestamente — qué funciona, qué está roto y cuál es el camino seguro en este momento.
Este documento no es aspiracional. Describe el sistema como existe hoy. Donde el proceso documentado diverge de la realidad auditada (p. ej., el pipeline de CI que en realidad no corre tests contra una base de datos real — ver L-25), este archivo lo dice claramente y apunta a la corrección.
Cuando el equipo eventualmente cierre esas brechas, este documento se actualiza. Hasta entonces, léelo de principio a fin antes de hacer push.
1. El flujo de despliegue
flowchart LR
A[Branch from main] --> B[Code + test locally]
B --> C[Lint: composer pint + npm run lint]
C --> D[Commit with conventional message]
D --> E[Push to origin]
E --> F[Open PR against main]
F --> G[Reviewer approves]
G --> H[Squash and merge]
H --> I[CI runs lint workflow]
I --> J[Manual deploy to staging by deployer]
J --> K[Smoke test on staging]
K --> L[Manual deploy to prod]
L --> M[Watch laravel.log + frontend_error_logs for 30 min]
El flujo está intencionalmente conducido por humanos en el paso de despliegue. No hay pipeline de CI/CD hoy (L-23). El deployer (hoy: tu tech lead) hace pull de la rama merged al servidor. Hasta que esa automatización aterrice, cada merge tiene un humano real en el loop.
Si estás leyendo esto y el trabajo de CI/CD ha aterrizado, este diagrama y los pasos a continuación necesitan actualizarse. Ver sección 5 abajo para el estado actual de CI.
2. Convención de nombrado de ramas
<initials>/<type>/<short-desc>Recomendado:
| Parte | Regla | Ejemplo |
|---|---|---|
<initials> | Tus iniciales, en minúsculas. | jp (Juan Pérez) |
<type> | fix, feat, chore, docs, refactor, test. | fix |
<short-desc> | Descripción en kebab-case. Referencia un ID de landmine si aplica. | L-26-frontend-error-logger |
Ejemplos completos:
jp/fix/L-26-frontend-error-logger(una corrección de landmine de Nivel 1)jp/feat/T2-01-mock-integration-provider(una funcionalidad de Nivel 2)jp/chore/seed-cliente-scenarios(una mejora no funcional de experiencia de desarrollo)jp/docs/landmine-l-19-update(cambio solo de documentación)
El prefijo <initials>/ importa en un remote compartido — hace git branch -a legible y permite a cada desarrollador hacer grep de su propio trabajo. El <type>/ del medio coincide con conventional commits, así que los revisores pueden clasificar mentalmente el PR antes de hacer clic.
Evita ramas de larga duración. Aterriza dentro de una semana o haz rebase sobre main. Las ramas obsoletas acumulan conflictos.
3. Convención de mensajes de commit
Mi Plante sigue conventional commits. La historia existente del repo es mixta (algunas oraciones largas en español, algunas más cortas en inglés — ejecuta git log --oneline -30 para ver). De aquí en adelante, escribe los mensajes de commit con esta forma:
<type>: <imperative summary in 50 chars or less>
<optional body — wrap at 72 chars>- Reference landmine: L-XX- Reference task: T1-XX or T2-XX
<optional footers — refs, breaking-change markers>Tipos en uso:
| Tipo | Cuándo | Ejemplo |
|---|---|---|
fix | Una corrección de bug. | fix: stop interceptor logging successes (L-26) |
feat | Una nueva capacidad. | feat(jobs): add failed() handler to GenerarCreditoDeVenta |
chore | Tooling, configs, deps. | chore: bump phpunit to 11.5.3 |
docs | Solo documentación. | docs: clarify L-19 reproduction steps |
refactor | Cambio de código sin cambio de comportamiento. | refactor: extract VentaService scenario query |
test | Solo agregar o cambiar tests. | test: lock the rate-limit on /api/v1/datacredito/historial |
Si tu PR toca un landmine, nómbralo en el resumen: fix: ... (L-XX). La referencia al landmine es la pieza de contexto de mayor valor que un lector futuro buscará.
Ejemplos de PRs reales de Mi Plante que puedes imitar:
fix: align Profile.vue with backend nombres/apellidos contract (L-18)feat: build local integration mock provider (T2-01 PR 1)chore(seed): add clientes-en-mora scenariodocs: add Tier 1 first-contribution tasks
Evita:
- Mensajes sin tipo:
update VentaService - Resúmenes vagos:
fix bug,minor changes,wip - Commits multi-propósito:
fix L-18 and refactor cart, also tests— divídelos en tres.
Los commits históricos de Mi Plante son largos. Coincide con el estilo conventional-commits de aquí en adelante; no imites los resúmenes largos existentes. El equipo ha decidido migrar a mensajes más cortos y tipados — tus commits establecen la nueva línea base.
4. La plantilla de PR
Copia esto al cuerpo del PR cuando lo abras. Cada sección importa; no las dejes en blanco.
## What<one-line summary of the change>
## Why<the bug or the feature. Link to a landmine if applicable: see docs/onboarding/04-the-landmines/01-known-bugs.md for the L-XX entry>
## How<bullets, what changed at the file level>- `app/.../File.php`: <change>- `resources/js/.../File.vue`: <change>
## Test plan- [ ] Manual: <specific steps>- [ ] Tests added: `<test file paths>`- [ ] Lint passes: `npm run lint && composer pint`- [ ] No regression in <related feature>
## Risk- [ ] Low — no production data affected, no schema change, no integration change- [ ] Medium — touches a landmine zone (specify which: L-XX)- [ ] High — production data affected (requires sign-off from <senior person>)
## Screenshots<for UI changes — drag into the GitHub PR>
## Follow-ups- [ ] <future tasks, ideally linked to landmine IDs or new task IDs>La sección “Risk” es la más omitida y la más importante. Sé honesto. Si tu corrección toca el pipeline de crédito, márcala Media aunque el cambio parezca pequeño — el código circundante es frágil (ver las zonas “ask-before-refactor” del CLAUDE.md).
5. Pipeline de CI — estado actual
El repo tiene dos workflows de GitHub Actions en .github/workflows/:
| Workflow | Triggers | Qué hace | Estado |
|---|---|---|---|
tests.yml | push/PR en main y develop | Instala PHP/Node, hace build del frontend, ejecuta ./vendor/bin/phpunit | Roto según L-25. No se declara contenedor de servicio MySQL, pero phpunit.xml configura DB_CONNECTION=mysql. Los tests crashean en la conexión o se ponen falsamente en verde si tragan errores de conexión. |
lint.yml | push/PR en main y develop | Ejecuta vendor/bin/pint, npm run format, npm run lint. | Funciona. Sin DB requerida; gateaa confiablemente el estilo de código. |
Implicaciones prácticas para tu primer PR:
- Ejecuta los tests localmente antes de abrir el PR. Hasta que L-25 aterrice, el workflow de tests de CI es una señal poco confiable. Trátalo como “¿al menos compiló?” y confía en
php artisan testlocal. - El workflow de lint es el gate. Si lint falla en tu PR, arréglalo localmente y vuelve a hacer push.
- No confíes en CI para atrapar una regresión. CI hoy atrapa problemas de lint y errores de sintaxis de PHP; eso es todo.
La corrección de L-25 es una tarea de Nivel 3. El parche es directo (agregar un contenedor de servicio MySQL a tests.yml) pero entonces revela cada test que estaba fallando silenciosamente — lo cual es su propio alcance. Hacer este trabajo apropiadamente es una de las tareas de nivel 3 de mayor apalancamiento; nomina a alguien con ancho de banda.
Hasta entonces, la disciplina de testing local es la línea de defensa:
# Before opening a PR, every developer runs:composer pint # PHP stylenpm run lint # JS/TS stylenpm run format:check # Prettier formattingphp artisan test # PHPUnitLos cuatro deben pasar. El revisor asume que los has ejecutado; si no, el PR no está listo.
6. El proceso de revisión
| Rol | Quién, hoy | Qué busca |
|---|---|---|
| Autor | Tú | Auto-revisado, lint limpio, tests agregados, plantilla de PR llenada. |
| Revisor | Otro desarrollador (rota) | El código se lee, sin emojis, términos de dominio en español preservados, zonas de landmine respetadas, los tests cubren el comportamiento, seguimientos documentados. |
| Aprobador de merge | El revisor (PR pequeño) o el tech lead (PR grande/riesgoso) | Decisión final go/no-go. |
| Deployer | El tech lead (hoy; después: cualquier desarrollador con acceso a prod) | Hace pull de la rama merged a staging luego a prod. Observa logs por 30 minutos post-despliegue. |
La barra:
- Una aprobación de revisor para un PR de Nivel 1 (corrección de landmine único).
- Dos revisores (o uno + tech lead) para un PR de Nivel 2 (funcionalidad multi-archivo).
- Aprobación del tech lead para cualquier cosa en las zonas “ask-before-refactor” en
CLAUDE.md(pipeline de crédito, generación de cuotas, Certicámara, aritmética de cupo).
SLA de revisión: el revisor responde dentro de un día laboral. Si pasan 24h sin revisión, escala en el canal del equipo — los backlogs silenciosos son un code smell.
7. Despliegue
Según L-23, este repo no tiene artefactos de despliegue. Sin Dockerfile, sin compose, sin Procfile, sin terraform. El workflow de despliegue actual está documentado aquí por honestidad:
- El deployer hace SSH al servidor de producción.
cd /var/www/miplante && git pull origin main.composer install --no-dev --optimize-autoloader.npm ci && npm run build.php artisan migrate --force(solo si se envió una migración).php artisan config:cache && php artisan route:cache && php artisan view:cache.php artisan queue:restart.- Reinicia el proceso PHP-FPM / nginx según se requiera.
- Observa
storage/logs/laravel.logy la tablafrontend_error_logspor 30 minutos.
Esto es un único punto de falla. La corrección es un deploy script, una imagen docker, o un pipeline de CI/CD — todas tareas de Nivel 3. Hasta entonces:
- No hagas push directo a main. Todos los cambios pasan por PRs.
- No programes un despliegue cuando el deployer no esté disponible. No hay rollback automatizado; si el deployer está dormido y algo se rompe a las 3am, el sitio queda roto hasta que despierte.
- Sí incluye una línea “Procedimiento de rollback” en la descripción de tu PR para cualquier cosa riesgosa. El deployer necesita ese asidero.
Después de que la infraestructura de despliegue de Nivel 3 aterrice, esta sección se vuelve “Haz push, CI despliega a staging, tú haces smoke-test, tú haces clic en deploy-to-prod”. Aún no estamos ahí.
8. Migraciones de base de datos
Zona de cuidado especial. Las tablas ventas, cuentas, clientes, cuotas y orden_compras son territorio de landmines — ver L-10, L-11, L-12, L-14 en el doc de landmines.
Antes de escribir una migración:
- Lee la historia de migraciones existentes para la tabla que intentas cambiar.
ls database/migrations/ | grep <table>y lee cada una. - Identifica si tu cambio es aditivo (nueva columna, nuevo índice) o destructivo (rename, drop, cambio de tipo).
- Las migraciones aditivas son seguras — entrégalas.
- Las migraciones destructivas necesitan coordinación del equipo. Abre un hilo en el canal del equipo antes de escribir la migración, no después.
Antes de hacer merge de una migración:
- Ejecútala localmente:
php artisan migrate. - Confirma que hace rollback limpiamente:
php artisan migrate:rollback. - Re-ejecuta hacia adelante:
php artisan migrate. - Re-ejecuta la suite de tests para atrapar cualquier ruptura silenciosa por el cambio de esquema.
En el despliegue: el deployer ejecuta php artisan migrate --force después del pull. No hay danza de coordinación de migraciones porque el equipo es pequeño. A medida que el equipo crece, un patrón “PR de esquema antes de PR de código” se volverá necesario — anótalo como tarea futura.
Llaves foráneas, índices, constraints únicos: estos son parte del modelo de datos. Afectan cada query y cada escritura concurrente. Agregar un constraint unique(['venta_id', 'numero_cuota']) (la corrección recomendada para L-10) es de alto apalancamiento pero también puede rechazar filas duplicadas existentes — limpia los datos sucios primero, luego envía el constraint.
9. Canales de comunicación
Hoy, el equipo es pequeño. Al último handoff de equipo:
| Canal | Usar para | Expectativa de latencia |
|---|---|---|
| Comentarios en PR de GitHub | Code review, discusión inline | Un día laboral |
| GitHub Issues | Reportes de bug, solicitudes de funcionalidad, triage de landmines | Un día laboral |
| Chat de equipo (Slack o Discord — confirmar con el equipo) | Sync, preguntas urgentes, coordinación de despliegue | Minutos durante horas laborales |
| Standup (diario o como se acuerde) | Estado, bloqueadores | Tiempo real |
| 1:1 con el tech lead | Preguntas de onboarding, carrera, arquitectura | Semanal |
Async primero: prefiere un comentario escrito de PR o hilo de chat sobre una reunión. A veces el acto de escribir la pregunta la responde.
Ruta de escalación: si un PR está bloqueado por > 24h, etiqueta al tech lead. Si un problema de producción está pasando justo ahora, llama al on-call (confirma la lista de escalación al inicio de tu tenencia).
10. Checklist de code review (para revisores)
Cuando revises un PR, recorre esta lista. Cualquier ítem marcado significa que puedes aprobar el PR. Cualquier ítem no marcado es un comentario a dejar.
- Se lee limpio sin comentarios. El código explica lo que está haciendo. Los comentarios están reservados para por qué el código es inusual (un workaround, un invariante no obvio), no qué está haciendo.
- Sin emojis nuevos. Según CLAUDE.md.
- Términos de dominio en español preservados.
cupo,cuota,aliado,venta,pagaré— español. Términos del framework PHP-Laravel (Service,Controller,Job) — inglés. La convención de nombrado es una elección deliberada de legibilidad de código; no anglicices el español ni hispanices el inglés. - Sin tocar zonas de landmine sin coordinación. Si el diff toca archivos listados en el Índice por Directorio de
docs/onboarding/04-the-landmines/01-known-bugs.md, la descripción del PR debe mencionarlo. - Tests agregados para cambios de comportamiento. Un refactor puro está bien sin tests nuevos si los tests existentes siguen pasando. Un cambio de comportamiento sin un test es una bandera roja.
- Sin seguridad bypaseada. Sin
--no-verify, singit push --force, sin llamadasapp/Exceptions/Handler::reportque traguen errores. - Convenciones de CLAUDE.md respetadas. Patrón Service-DTO, dual-guard auth, sin lógica de negocio en controladores, sin emojis.
- Descripción de PR completa. What/Why/How/Test plan/Risk/Follow-ups todos llenos.
- El diff es revisable en una sola sesión. Si el diff es > 600 líneas netas y no es un archivo generado (p. ej., un lockfile), sugiere dividirlo.
- Sin secretos committed. Sin archivos
.env, sin claves de API en código, sin dumps de DB con PII.
Si un PR falla tres o más de estos chequeos, solicita cambios y déjale saber al autor qué arreglar antes de re-revisión. Si un PR falla uno, deja un comentario y pueden abordarlo en el mismo ciclo de revisión.
11. Qué NO desplegar en tu primera semana
Una lista corta. Estas son las zonas de peligro; no quieres que tu primer PR sea una de estas.
| Evitar | Por qué | Cuándo puedes hacerlo |
|---|---|---|
| Refactores grandes (>10 archivos, cambio estructural) | Radio de impacto alto, difícil de revisar. | Después de 4-6 semanas, con aprobación del tech lead. |
Cualquier cosa que toque app/Services/AprobarCupo* | Pipeline de aprobación de crédito. Múltiples landmines (L-28, L-29, L-30). | Un desarrollador senior te empareja. Nunca solo. |
| Lógica de generación de cuotas | Matemáticas de dinero, duplicación multi-ruta (L-10, L-11). | Después de paired-pairing con alguien que haya entregado una corrección relacionada con cuotas. |
| Deshabilitar tests existentes | Los tests son el único piso hoy. | Solo con una justificación escrita en la descripción del PR y un test de seguimiento que reemplace lo que removiste. |
Middleware del pipeline de crédito (EnsureClienteRegistroCompleto, ConsultarCupoDelCliente, VerificarClientePresentaMora, CheckIntentosLimiteDiarios) | Estos son los gates de runtime en el flujo de crédito. Ajuste equivocado = clientes equivocados aprobados. | Aprobación del tech lead + paired pairing. |
Integración de Certicámara (CerticamaraService, ProcesarPagareDigital, el handler del webhook) | El flujo de pagaré firmado es vigilado por el regulador. | Aprobación del tech lead; envía a staging primero; verifica end-to-end antes de prod. |
Migraciones de base de datos en ventas, cuotas, cuentas, clientes, orden_compras | Zona de landmines (ver L-10, L-11, L-12, L-14). | Coordinación de equipo vía el canal del equipo antes de escribir la migración. |
| Cualquier cosa que agregue una ruta de cara al público a servicios de buró o de firma | Exposición a regulador de Habeas Data (L-02). | Aprobación del tech lead; las rutas nuevas pasan por auth + throttle por defecto. |
En caso de duda: abre un PR borrador con solo la descripción (sin código aún) y pregunta en el canal del equipo “¿es esto algo que puedo enviar como primer PR?” La conversación de 2 minutos ahorra la reescritura de 2 horas.
12. La celebración del “primer PR”
Cuando entregues tu primer PR — aterrizado, merged, desplegado, sin rollback — regístralo en docs/onboarding/_internal/first-ships.md. Una línea simple:
- 2026-MM-DD — <Your name> — <PR title> — landmine L-XX or task T1-XXEs un pequeño ritual. El archivo es la memoria viviente del equipo de quién entregó qué primero. Después de tres meses se vuelve el documento que un nuevo contratado lee cuando pregunta “¿cómo se ve un primer PR aquí?”
Después de tu primer PR, también reflexiona con el tech lead en tu 1:1 semanal:
- ¿Qué te sorprendió?
- ¿Qué omitió la documentación?
- ¿Qué te habría ahorrado una hora?
Las respuestas alimentan actualizaciones de docs. El onboarding es un documento permanentemente mutable.
Apéndice A — cheatsheet de comandos locales útiles
# Start everything (server, queue, log viewer, vite)composer dev
# Backend onlyphp artisan servephp artisan queue:listenphp artisan tinker
# Frontend onlynpm run dev
# Migrationsphp artisan migratephp artisan migrate:fresh --seedphp artisan migrate:rollback
# Testsphp artisan test # full suitephp artisan test --filter=GenerarCreditoDeVenta # single test by namephp artisan test tests/Feature/Jobs/ # one directory
# Lint and formatcomposer pint # PHPnpm run lint # JS/TSnpm run format # Prettier writenpm run format:check # Prettier check only
# Helpful tinker snippetsphp artisan tinker>>> \App\Models\Cliente::count();>>> \App\Models\Facturacion\Venta::where('estado','pendiente')->count();>>> \Illuminate\Support\Facades\DB::table('frontend_error_logs')->where('creado_en','>', now()->subHour())->count();>>> \Illuminate\Support\Facades\Queue::size('creditos');Apéndice B — cuándo pedir ayuda
Si pasas más de 30 minutos atorado en el mismo problema, pregunta. El equipo es lo suficientemente pequeño para que alguien leyendo tu pregunta en el chat sea más rápido que tus siguientes 30 minutos solo. Patrón:
@team — I'm working on T1-03 (failed() handler for GenerarCreditoDeVenta).I've added the method, written a test, and the test fails because `Precio::factory()`doesn't seem to populate `inventario` consistently. I've looked at:- database/factories/PrecioFactory.php (line 18 sets `inventario` to a random int)- the test setup
What I expect: precio->inventario starts at 5, after job->failed() runs, it's 7.What I see: precio->inventario starts at 14 (random), after failed() it's 16.
Question: should I .conInventario(5) the factory call, or is the factory wrong to randomize?Esa pregunta es respondible en 30 segundos por cualquiera que haya usado la factory. Una pregunta más vaga (“¿por qué falla mi test?”) genera un hilo de 5 minutos.
El mismo patrón funciona en Claude Code — contexto específico, pregunta específica, resultado deseado específico.
Cuando hayas leído este documento y entregado tu primer PR, has completado el hito de “Primeras Contribuciones” del onboarding. Siguientes paradas:
docs/onboarding/06-ai-pair-programming/— cómo Mi Plante usa Claude Code en la práctica.docs/onboarding/04-the-landmines/01-known-bugs.md— mantén esto abierto en una pestaña; lo referenciarás a diario.
Bienvenido al código base.