Synaplan
开源 AI 软件平台,面向企业:自托管 AI 代理,符合 GDPR 的聊天机器人小部件,RAG 知识库,WhatsApp 与 Outlook AI,MCP,多模型路由。支持 Docker、Kubernetes 或在 Germ 托管。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Aplicación web para la gestión de rutas, flotas, cotizaciones, finanzas y equipo de una operación logística. Incluye dashboards por rol (administrador, transportista, colaborador, vendedor, desarrollador), autenticación con Better Auth, permisos granulares por módulo y base de datos PostgreSQL. Dominio: www.jtplogistics.com (el dominio sin www redirige aquí)查看完整 README ↗
Aplicación web para la gestión de rutas, flotas, cotizaciones, finanzas y equipo de una operación logística. Incluye dashboards por rol (administrador, transportista, colaborador, vendedor, desarrollador), autenticación con Better Auth, permisos granulares por módulo y base de datos PostgreSQL.
Dominio: www.jtplogistics.com (el dominio sin www redirige aquí)
Calendar de shadcnLos roles se guardan en inglés en la BD: admin, carrier, collaborator, vendor, developer.
El administrador tiene acceso total. El colaborador no ve nada por defecto: el admin le enciende permisos módulo por módulo desde Colaboradores → editar, con cuatro niveles por módulo (leer, crear, editar, eliminar). Esos permisos viven como columnas booleanas en users (can_view_*, can_create_*, can_update_*, can_delete_*) y se aplican en dos capas:
requireCollaboratorPermission() en el layout.tsx del módulo (redirige si no tiene permiso).gateTasks, gateMural) que responde 403.El admin siempre pasa ambas capas sin necesidad de tener los flags encendidos.
Los mismos módulos que el admin, pero limitados a los permisos que el admin le encienda: rutas, cotizador, cotización marítima, tipos de unidad, mensajes, embarques, finanzas, clientes, proveedores, vendedores, colaboradores, laptops, celulares, correos, ideas, tareas, historial y mural.
Las contraseñas de laptops, celulares, cuentas de correo y las notas de contraseña de colaboradores no son credenciales de acceso a la plataforma: son datos que el administrador necesita poder consultar. Por eso se cifran de forma reversible (AES-256-GCM) en vez de guardarse con hash.
CREDENTIALS_ENCRYPTION_KEY, fuera de la base de datos: un volcado de la BD por sí solo no revela nada.hasPassword. El valor se pide de uno en uno a /api/credentials/<tipo>/<id> al pulsar el ojo.revealed.v1:<iv>:<tag>:<datos>. Los valores sin ese prefijo se tratan como texto plano heredado y se devuelven tal cual, para que la app funcione durante una migración.pnpm db:encrypt-credentials (simulación) y --apply para escribir. Es idempotente.Tablero interno visible solo para el personal de JTP (admin y colaboradores con canViewMural). Transportistas y vendedores quedan fuera.
users.birth_date y employee_profiles.hire_date. Si esas fechas están vacías, la persona no aparece.vercel.json) dispara /api/cron/mural-greetings todos los días a las 14:00 UTC (8:00 en Guadalajara). Felicita a quien cumple años o aniversario y avisa al equipo ese mismo día. No hay resumen diario ni semanal: cada entrada avisa sola al crearse, editarse o cancelarse. Protegido con CRON_SECRET.Para que RH administre el mural, el admin le enciende los cuatro permisos de Mural; al resto del equipo le basta con leer.
jtplogistics/
├── prisma/
│ ├── schema.prisma # Modelos (users, routes, shipments, mural_*, etc.)
│ ├── seed.ts # Datos de prueba (usuarios, rutas, activos)
│ └── migrations/ # SQL versionado (se escribe a mano, ver más abajo)
├── src/
│ ├── app/
│ │ ├── (auth)/ # login, register, forgot-password, reset-password
│ │ ├── admin/dashboard/
│ │ ├── carrier/dashboard/
│ │ ├── collaborator/dashboard/
│ │ ├── vendor/dashboard/
│ │ ├── developer/dashboard/
│ │ └── api/ # auth, admin, collaborator, carrier, vendor, mural, cron
│ ├── components/
│ │ ├── ui/ # shadcn + componentes base (DataTable, DatePicker, Lexical)
│ │ └── dashboard/ # componentes por módulo
│ ├── hooks/
│ ├── lib/ # auth, db, validators, utils, config, data, correos
│ └── types/
├── public/
├── docs/
│ ├── conventions.md # Convenciones de BD y datos
│ └── reporte-ciberseguridad.html # Controles de seguridad (imprimible a PDF)
├── instrumentation.ts # Normalización de BETTER_AUTH_URL al arranque
├── vercel.json # Cron del resumen diario del mural
└── next.config.ts
La interfaz y los textos visibles están en español; el código (rutas, variables, comentarios) en inglés.
Crear .env en la raíz (no se commitea). Ejemplo:
# Base de datos
DATABASE_URL="postgresql://..."
# Better Auth (en producción usar el dominio final CON www)
BETTER_AUTH_SECRET="..." # mínimo 32 caracteres (openssl rand -base64 32)
BETTER_AUTH_URL="http://localhost:3000"
# Opcional: orígenes adicionales (CSRF)
# BETTER_AUTH_TRUSTED_ORIGINS=https://www.jtplogistics.com
# Cloudinary
CLOUDINARY_CLOUD_NAME="..."
CLOUDINARY_API_KEY="..."
CLOUDINARY_API_SECRET="..."
# Resend. Sin RESEND_API_KEY los correos solo se imprimen en consola (útil en dev).
RESEND_API_KEY="..."
EMAIL_FROM="JTP Logistics <[email protected]>"
# URL pública usada en los enlaces y el logo de los correos.
# Sin ella los correos salen sin logo ni botón (no se rompen, usan un respaldo).
NEXT_PUBLIC_APP_URL="http://localhost:3000"
# Secreto del cron del resumen diario del mural. Vercel lo manda como
# "Authorization: Bearer <valor>". Si está vacío, el endpoint no exige credencial
# (cómodo en local, nunca en producción).
CRON_SECRET=""
# Llave del almacén de credenciales de activos (contraseñas de laptops,
# celulares, cuentas de correo y notas de colaborador). Generar con:
# openssl rand -base64 32
CREDENTIALS_ENCRYPTION_KEY=""
Notas:
VERCEL_URL se rellena automáticamente y se usa para trustedOrigins si hace falta.NEXT_PUBLIC_APP_URL se incrusta en el bundle durante el build: al cambiarla hay que redesplegar para que surta efecto.CREDENTIALS_ENCRYPTION_KEY no se puede perder. Sin ella, las contraseñas de activos guardadas quedan irrecuperables. Debe existir una copia fuera de Vercel (gestor de contraseñas o resguardo físico).# Instalar dependencias (también corre prisma generate)
pnpm install
# Aplicar migraciones
pnpm db:migrate:deploy
# (Opcional) Poblar datos de prueba
pnpm db:seed
# (Opcional) Sembrar configuración de portada/branding
pnpm db:seed-settings
# (Opcional) Crear cuenta demo transportista
pnpm db:create-demo-carrier
# Desarrollo
pnpm dev
Abrir http://localhost:3000. Para entrar con datos de prueba, ver el mensaje al final de pnpm db:seed (correos y contraseñas por rol).
pnpm db:migrate(prisma migrate dev) está roto en este proyecto: falla al crear la shadow database en Neon.
El flujo que sí funciona:
prisma/schema.prisma.prisma/migrations/<AAAAMMDDHHMMSS>_<nombre>/migration.sql con el SQL correspondiente.pnpm db:migrate:deploy.pnpm db:generate.Ojo: db:migrate:deploy aplica contra la base de datos de DATABASE_URL, que es la BD real compartida. Revisar el SQL antes de correrlo.
| Comando | Descripción |
|---|---|
pnpm dev | Servidor de desarrollo |
pnpm build | Build de producción |
pnpm start | Servidor de producción |
pnpm lint | ESLint |
pnpm test | Pruebas con Vitest |
pnpm test:watch | Pruebas en modo watch |
pnpm db:generate | Generar Prisma Client |
pnpm db:migrate | Migraciones en desarrollo (roto, ver arriba) |
pnpm db:migrate:deploy | Aplicar migraciones |
pnpm db:seed | Ejecutar seed |
pnpm db:seed-settings | Seed de ajustes/configuración |
pnpm db:create-demo-carrier | Crear cuenta demo transportista |
pnpm db:encrypt-credentials | Cifrar credenciales de activos que sigan en claro |
pnpm db:assign-route-creator | Asignar creador a rutas existentes |
pnpm db:sync-route-destination-states | Sincronizar estados destino de rutas |
pnpm db:studio | Abrir Prisma Studio |
pnpm test corre Vitest sobre la lógica pura (sin BD ni red): coincidencia de embarques y finanzas, búsqueda, fechas de cumpleaños y aniversarios, y armado de los correos de felicitación.
Los módulos con lógica que valga la pena probar se separan de los que tocan Prisma —por ejemplo mural-celebrations.ts (puro) frente a mural-celebrations-query.ts (BD)— porque importar @/lib/db en una prueba falla si no hay DATABASE_URL.
CI (.github/workflows/ci.yml) corre en cada push y PR: typecheck, lint, test y build.
skipDuplicates), pero reinicia otras entidades de prueba.EMAIL_FROM.DATABASE_URL, BETTER_AUTH_SECRET, BETTER_AUTH_URL, NEXT_PUBLIC_APP_URL (con la URL final, https://www.jtplogistics.com) y CRON_SECRET.pnpm build; si BETTER_AUTH_URL no trae protocolo, se normaliza a https:// al arrancar.vercel.json queda registrado solo, sin configuración extra en el panel.Reglas de base de datos, nombres y validaciones: docs/conventions.md.
En resumen: tablas y columnas en snake_case, código en camelCase, correos y slugs normalizados a minúsculas, y los roles guardados en inglés.
Proyecto privado.