Synaplan
Open-source AI platform for companies: self-hosted AI agents, GDPR-compliant chatbot widget, RAG knowledge base, WhatsApp and Outlook AI, MCP, multi-model routing. Docker, Kubernetes or hosted in Germ
翻訳待ち
No updates detected yet. GitHub releases will appear here.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Un asistente de turnos para locales de servicios argentinos. El cliente escanea un QR, chatea (el asistente entiende “el viernes a la tarde”) y saca el turno solo. El dueño ve agenda, caja y recordatorios en su panel.
Stack: Next.js 15 (App Router, TypeScript) · Postgres en Neon · Drizzle ORM · desplegable en Vercel. Una sola app para todos los locales.
| Qué | Dónde |
|---|---|
| Chat del cliente (por local) | /t/[slug] — el que abre el QR |
| Panel del dueño: agenda + caja + configurar | /panel |
| QR imprimible del local | /panel/qr |
| Alta de un local / login del dueño | /registro, /login |
| Esquema de la base | src/db/schema.ts (migraciones en drizzle/) |
| Reglas de negocio puras (disponibilidad, seña) | src/lib/negocio.ts |
| Intérprete de lenguaje natural (sin IA externa) | src/lib/interprete.ts |
Acceso a datos (siempre filtrado por local_id) | src/server/repo.ts |
| Login OTP + sesión | src/server/auth.ts |
| API pública del chat / API privada del panel | src/app/api/t/[slug]/* · src/app/api/panel/* |
Aislamiento entre locales: toda fila lleva local_id y toda función de repo.ts lo recibe y filtra por él. En /api/panel/* el local sale siempre de la sesión (cookie firmada), nunca del pedido. En /api/t/[slug]/* sale de la URL pública, y esa API solo expone la ficha y qué huecos están ocupados (nunca nombres ni teléfonos de otros clientes).
Identidad del cliente = su teléfono (últimos 8 dígitos). No hay cuentas de cliente. Cancelar/confirmar/declarar seña desde el chat exige el mismo teléfono con el que se reservó.
npm install
npm run dev
Sin DATABASE_URL, en desarrollo la app usa una base Postgres embebida (PGlite) que se guarda en .data/ y se precarga sola con dos locales de ejemplo. Abrí http://localhost:3000.
[email protected]. El código de 6 números aparece en pantalla (modo desarrollo) y en la consola del servidor. Ahí ves el turno en la agenda, lo cerrás con el pago (caja), mandás el recordatorio por WhatsApp (link wa.me), etc./t/padel-club-sur (dueño [email protected], con seña obligatoria). Podés dar de alta uno nuevo en /registro.Para borrar los datos locales: parar el servidor y borrar la carpeta .data/.
AWS South America (São Paulo), la más cercana a Argentina).postgresql://...neon.tech/neondb?sslmode=require)..env.local (tu archivo, no se sube a git):
DATABASE_URL=postgresql://...
SESSION_SECRET=<un secreto largo>
Para generar el secreto: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"npm run db:migrar
npm run db:seed
DATABASE_URL, SESSION_SECRET y NEXT_PUBLIC_BASE_URL (la URL pública final, ej. https://turnos.tudominio.com; se usa para armar el QR).npm run db:migrar apuntando a esa misma base (desde tu compu con el .env.local de producción).En producción la app exige DATABASE_URL y SESSION_SECRET (si faltan, falla a propósito en vez de usar valores de desarrollo). Y el código de login no se muestra en pantalla.
wa.me de 1 toque con el mensaje armado.Sin credenciales queda apagado y la app sigue funcionando con el link wa.me manual.
This is the beginning of the README. Read the rest at the original. Read the full README ↗