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.