Lalabase
Tickets, Doku, Zeiterfassung und Kundengespräche an einem Ort, durchsuchbar per KI. Für Softwarefirmen mit Kundenprojekten. Open Source: auf deinem eigenen Server oder in unserer Cloud in Deutschland.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Sistema de turnos y gestión comercial para una peluquería de operación unipersonal: un profesional, una estación de trabajo. • Portal público (/, /reservar, /turno/[token]): el cliente elige servicio, día y horario, deja sus datos y recibe un link propio para seguir su turno. Sin pago ni seña previa. • Panel privado (/admin): agenda, bandeja de solicitudes, catálogo de servicios y configuración de disponibilidad.查看完整 README ↗
Sistema de turnos y gestión comercial para una peluquería de operación unipersonal: un profesional, una estación de trabajo.
/, /reservar, /turno/[token], /baja/[token]): el
cliente elige servicio, día y horario, deja sus datos y recibe un link propio
para seguir su turno. Sin pago ni seña previa. Un botón flotante abre
WhatsApp con el local./admin): Hoy, agenda, bandeja de solicitudes, caja por
categoría y, desde Más, servicios, productos, disponibilidad y alta de
clientes.South America (São Paulo)).anon y la clave service_role.cp .env.local.example .env.local
Completar NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY y
SUPABASE_SERVICE_ROLE_KEY.
Generar también MANAGE_TOKEN_SECRET, con el que se derivan los links de
autogestión (/turno/[token]) a partir del id de cada turno:
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
MANAGE_TOKEN_SECRETtiene que tener el mismo valor en.env.localy en Vercel: los dos entornos usan la misma base, y un turno reservado en uno puede recibir emails armados en el otro. Si cambia, los links de los turnos ya reservados dejan de coincidir.
Para los emails y la tarea diaria completar también:
NEXT_PUBLIC_SITE_URL: la URL pública (https://houssestudio.com.ar en
producción), base de los links de los mails.RESEND_API_KEY, EMAIL_FROM (remitente verificado en Resend) y
ADMIN_EMAIL (la casilla del peluquero, que recibe los avisos).CRON_SECRET: lo exige /api/cron/reminders, que Vercel Cron llama todos
los días a las 10 de Buenos Aires (vercel.json). Se genera con el mismo
comando que MANAGE_TOKEN_SECRET y se carga igual en Vercel.
SUPABASE_SERVICE_ROLE_KEYsaltea todas las políticas de seguridad de la base. Nunca se commitea ni se expone al navegador: los módulos que la usan importanserver-only, así que el build falla si alguna vez terminan alcanzados por código de cliente.
En el SQL Editor de Supabase, ejecutar en orden los archivos de
supabase/migrations/:
0001_schema.sql — tablas, tipos y la restricción anti-solapamiento.0002_rls.sql — Row Level Security.0003_seed.sql — servicios y horario comercial iniciales.0004_dni.sql — DNI como identidad del cliente.0005_ventana_de_reserva.sql — ventana de reserva configurable.0006_horario_partido.sql — segundo tramo horario (reemplazado por la 0009).0007_ventas_sueltas.sql — ventas sueltas y cobro atómico de turnos.0008_ventas_productos.sql — venta de productos además de servicios.0009_horario_bloques.sql — horario con N bloques por día.0010_retira_columnas_horario.sql — retira las columnas de horario
anteriores a la 0009.0011_email_aceptacion.sql — tipo de email para el turno confirmado.0012_productos_y_categorias.sql — categorías y productos, ventas
sueltas con varios ítems y la función que las registra.0013_email_vuelta.sql — tipo de email del recordatorio para volver.
Va sola: Postgres no deja usar un valor de enum recién agregado en la
misma ejecución.0014_recordatorio_vuelta.sql — baja de ese recordatorio
(customers.comeback_opt_out_at) y el índice que impide repetirlo.Cada archivo depende de los anteriores: la 0009 copia a bloques el horario que dejan cargado la 0003 y la 0006, y la 0010 recién después borra esas columnas.
No hay registro público: la cuenta se crea a mano.
User UID y habilitarlo como administrador desde el SQL Editor:insert into public.admins (user_id) values ('<pegar-el-user-uid>');
npm run dev
El portal público queda en http://localhost:3000 y el panel en
http://localhost:3000/admin.
npm run dev
npm test
npm run typecheck
npm run build
| Capa | Ubicación |
|---|---|
| Motor de disponibilidad | lib/availability.ts — función pura, cubierta por tests |
| Lecturas del portal público | lib/data/availability.ts, lib/data/public.ts |
| Lecturas del panel | lib/data/appointments.ts |
| Escrituras | lib/actions/ — una Server Action por dominio |
| Emails | lib/email/ — plantillas puras (con tests) y envío por Resend |
| Tarea diaria | app/api/cron/reminders/route.ts — los dos recordatorios, aislados |
| Navegación por fecha (Agenda y Caja) | components/admin/period-navigation.tsx, lib/period-nav.ts |
| Esquema | supabase/migrations/ |
Tres decisiones que conviene conocer antes de tocar el código:
Los horarios se encadenan según la duración del servicio. Dentro de cada hueco libre los slots arrancan en el borde del hueco y avanzan de a la duración del servicio elegido. Aprovecha mejor la agenda de una estación única, y trae como consecuencia que los horarios ofrecidos cambien según el servicio — por eso el flujo de reserva pide el servicio antes que la hora.
El portal público nunca habla directo con Postgres. RLS está activo en todas
las tablas y anon no tiene ninguna política. Todo el tráfico público pasa por
Server Actions que usan la service_role del lado del servidor, así que hay una
sola superficie de entrada que auditar.
Contra el doble booking manda la base, no el frontend. Una restricción de exclusión GiST sobre el rango de cada turno impide dos turnos activos solapados. La validación previa mejora el mensaje de error, pero entre leer la disponibilidad y escribir el turno siempre hay una ventana: la que cierra la base.
Todo se guarda en UTC (timestamptz) y se muestra en
America/Argentina/Buenos_Aires. Las fechas de agenda se identifican por su
clave local yyyy-MM-dd y no por un Date, porque un Date arrastra una hora
que al cruzar zonas corre los turnos de día.
Fase 1 completa: reservas públicas, agenda, solicitudes, servicios y disponibilidad.
Fase 2 completa (ver SPEC.md): emails transaccionales con el diseño de
la web, autogestión de cancelaciones, registro de cobros, venta suelta con
carrito de catálogo, productos con categorías y cierre de caja por categoría.
Fase 3 completa: recordatorio automático el día anterior al turno, con
dominio propio para los emails ([email protected]).
Mejoras de octubre completas (ver SPEC.md §9 y
tasks/plan-mejoras-octubre.md): botón de WhatsApp, alta de clientes de otra
zona, estados de carga del panel y recordatorio "Ya pasó un mes" con baja.
Pendiente (ver tasks/todo.md): pasar ADMIN_EMAIL a la casilla del
peluquero, Vercel Pro y copias de seguridad de Supabase antes de usarla con
clientes reales. CRM y reportes quedan para más adelante.