Skip to main content

sesion-mental-health-platform

AI-powered mental health practice management platform for psychologists with scheduling, WhatsApp automation, AFIP billing, video consultations, and Claude AI integration

Ir a la instalación

Datos de origen

Repositorio
reason-machines/devtools-skills
Última actividad en el origen
12 de julio de 2026 a las 14:34
Idioma detectado de SKILL.md
inglés
Estrellas
4
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
sesion-mental-health-platform
description
AI-powered mental health practice management platform for psychologists with scheduling, WhatsApp automation, AFIP billing, video consultations, and Claude AI integration
triggers
["how do I set up the Sesión mental health platform","configure WhatsApp automation for patient appointments","integrate AFIP electronic invoicing in Sesión","set up video consultations with LiveKit","use Claude AI for clinical notes in Sesión","configure MercadoPago payment integration","implement patient journey workflows","troubleshoot Sesión WhatsApp connection"]
# Sesión Mental Health Platform > Skill by [ara.so](https://ara.so) — Devtools Skills collection. Sesión is a comprehensive SaaS platform for psychology clinics and independent practitioners in Argentina. It orchestrates appointment scheduling, automated WhatsApp messaging (via Baileys), AFIP-compliant electronic invoicing, secure video consultations (LiveKit), and AI-powered clinical assistance using Claude Opus 4.6 and Sonnet 4.6. Built with SvelteKit 5, NestJS, Prisma, and TypeScript. ## Installation ### Prerequisites ```bash # Required versions node >= 18.0.0 pnpm >= 8.0.0 postgresql >= 14.0 redis >= 7.0 ``` ### Clone and Setup ```bash git clone https://github.com/fahad-hamid/psique-workflow-clinic.git cd psique-workflow-clinic # Install dependencies pnpm install # Setup environment variables cp .env.example .env ``` ### Environment Configuration ```bash # .env DATABASE_URL="postgresql://user:password@localhost:5432/sesion" REDIS_URL="redis://localhost:6379" # Anthropic AI ANTHROPIC_API_KEY="sk-ant-..." CLAUDE_OPUS_MODEL="claude-opus-4.6" CLAUDE_SONNET_MODEL="claude-sonnet-4.6" # WhatsApp (Baileys) WHATSAPP_SESSION_DIR="./sessions" WHATSAPP_QR_TIMEOUT=60000 # LiveKit Video LIVEKIT_API_KEY="${LIVEKIT_API_KEY}" LIVEKIT_API_SECRET="${LIVEKIT_API_SECRET}" LIVEKIT_WS_URL="wss://your-livekit.cloud.livekit.cloud" # Payment Gateways MERCADOPAGO_ACCESS_TOKEN="${MERCADOPAGO_ACCESS_TOKEN}" STRIPE_SECRET_KEY="${STRIPE_SECRET_KEY}" # AFIP Integration AFIP_CUIT="${AFIP_CUIT}" AFIP_CERT_PATH="./certs/afip.crt" AFIP_KEY_PATH="./certs/afip.key" AFIP_PRODUCTION=false # Application JWT_SECRET="${JWT_SECRET}" APP_URL="http://localhost:5173" API_URL="http://localhost:3000" ``` ### Database Setup ```bash # Run migrations pnpm prisma migrate dev # Seed initial data pnpm prisma db seed ``` ### Start Development Servers ```bash # Frontend (SvelteKit) pnpm dev # Backend (NestJS) pnpm api:dev # Full stack pnpm dev:full ``` ## Architecture Overview ``` sesion/ ├── apps/ │ ├── web/ # SvelteKit 5 frontend │ ├── api/ # NestJS backend │ └── worker/ # Background job processor ├── packages/ │ ├── db/ # Prisma schema & migrations │ ├── ai/ # Claude AI orchestration │ ├── whatsapp/ # Baileys integration │ ├── video/ # LiveKit wrapper │ ├── billing/ # AFIP invoicing │ └── shared/ # Common types & utils └── prisma/ └── schema.prisma ``` ## Core Modules ### 1. Appointment Scheduling #### Create Appointment (NestJS Controller) ```typescript // apps/api/src/appointments/appointments.controller.ts import { Controller, Post, Body, UseGuards } from '@nestjs/common'; import { JwtAuthGuard } from '../auth/jwt-auth.guard'; import { AppointmentsService } from './appointments.service'; import { CreateAppointmentDto } from './dto/create-appointment.dto'; @Controller('appointments') @UseGuards(JwtAuthGuard) export class AppointmentsController { constructor(private readonly appointmentsService: AppointmentsService) {} @Post() async create(@Body() dto: CreateAppointmentDto) { return this.appointmentsService.create(dto); } } ``` #### Appointment Service with Conflict Detection ```typescript // apps/api/src/appointments/appointments.service.ts import { Injectable, ConflictException } from '@nestjs/common'; import { PrismaService } from '@sesion/db'; import { addMinutes, isWithinInterval } from 'date-fns'; @Injectable() export class AppointmentsService { constructor(private prisma: PrismaService) {} async create(dto: CreateAppointmentDto) { // Check for conflicts const conflicts = await this.prisma.appointment.findMany({ where: { practitionerId: dto.practitionerId, status: { not: 'CANCELLED' }, scheduledAt: { gte: dto.scheduledAt, lt: addMinutes(dto.scheduledAt, dto.durationMinutes || 45) } } }); if (conflicts.length > 0) { throw new ConflictException('Time slot already booked'); } // Create appointment const appointment = await this.prisma.appointment.create({ data: { ...dto, status: 'SCHEDULED' }, include: { patient: true, practitioner: true } }); // Trigger WhatsApp confirmation await this.whatsappService.sendConfirmation(appointment); return appointment; } async findUpcoming(practitionerId: string) { return this.prisma.appointment.findMany({ where: { practitionerId, scheduledAt: { gte: new Date() }, status: { in: ['SCHEDULED', 'CONFIRMED'] } }, include: { patient: true }, orderBy: { scheduledAt: 'asc' } }); } } ``` #### Frontend: Appointment Calendar (Svelte 5) ```svelte <!-- apps/web/src/routes/agenda/+page.svelte --> <script lang="ts"> import { onMount } from 'svelte'; import { goto } from '$app/navigation'; let appointments = $state([]); let selectedDate = $state(new Date()); let loading = $state(false); async function loadAppointments() { loading = true; const res = await fetch('/api/appointments/upcoming', { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }); appointments = await res.json(); loading = false; } async function createAppointment(event: CustomEvent) { const res = await fetch('/api/appointments', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(event.detail) }); if (res.ok) { await loadAppointments(); } } onMount(loadAppointments); </script> <div class="agenda-container"> <header> <h1>Agenda</h1> <button onclick={() => goto('/appointments/new')}> Nueva Cita </button> </header> {#if loading} <div class="skeleton"></div> {:else} <div class="appointments-grid"> {#each appointments as apt} <div class="appointment-card" class:urgent={apt.isUrgent}> <time>{new Date(apt.scheduledAt).toLocaleString('es-AR')}</time> <h3>{apt.patient.name}</h3> <span class="type">{apt.type}</span> <span class="status">{apt.status}</span> </div> {/each} </div> {/if} </div> ``` ### 2. WhatsApp Automation (Baileys) #### WhatsApp Connection Service ```typescript // packages/whatsapp/src/whatsapp.service.ts import makeWASocket, { DisconnectReason, useMultiFileAuthState, makeInMemoryStore } from '@whiskeysockets/baileys'; import { Boom } from '@hapi/boom'; import { Injectable, Logger } from '@nestjs/common'; @Injectable() export class WhatsAppService { private sock: any; private readonly logger = new Logger(WhatsAppService.name); async connect() { const { state, saveCreds } = await useMultiFileAuthState( process.env.WHATSAPP_SESSION_DIR || './sessions' ); this.sock = makeWASocket({ auth: state, printQRInTerminal: true }); this.sock.ev.on('creds.update', saveCreds); this.sock.ev.on('connection.update', (update) => { const { connection, lastDisconnect, qr } = update; if (qr) { this.logger.log('QR Code generated, scan with WhatsApp'); } if (connection === 'close') { const shouldReconnect = (lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut; if (shouldReconnect) { this.logger.log('Reconnecting...'); this.connect(); } } else if (connection === 'open') { this.logger.log('WhatsApp connected successfully'); } }); this.sock.ev.on('messages.upsert', async ({ messages }) => { await this.handleIncomingMessage(messages[0]); }); } async sendReminder(appointment: Appointment) { const patientNumber = appointment.patient.phone.replace(/\D/g, '') + '@s.whatsapp.net'; const message = `Hola ${appointment.patient.name}! 👋\n\n` + `Te recordamos tu sesión programada:\n` + `📅 ${format(appointment.scheduledAt, "dd/MM/yyyy 'a las' HH:mm", { locale: es })}\n` + `👨‍⚕️ Con: ${appointment.practitioner.name}\n\n` + `Por favor confirma tu asistencia respondiendo SI o NO.`; await this.sock.sendMessage(patientNumber, { text: message }); await this.prisma.whatsappMessage.create({ data: { appointmentId: appointment.id, to: patientNumber, content: message, type: 'REMINDER', status: 'SENT' } }); } async handleIncomingMessage(message: any) { if (!message.message?.conversation) return; const text = message.message.conversation.toLowerCase(); const from = message.key.remoteJid; // Check for confirmation replies if (['si', 'sí', 'confirmo'].includes(text)) { await this.confirmAppointment(from); } else if (['no', 'cancelar'].includes(text)) { await this.requestCancellation(from); } // Crisis keyword detection if (this.detectCrisisKeywords(text)) { await this.alertPractitioner(from, text); } } private detectCrisisKeywords(text: string): boolean { const crisisKeywords = [ 'suicidio', 'matarme', 'terminar con todo', 'no puedo más', 'crisis', 'emergencia' ]; return crisisKeywords.some(kw => text.includes(kw)); } } ``` #### Automated Reminder Scheduler ```typescript // apps/worker/src/jobs/reminder.job.ts import { Injectable } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { PrismaService } from '@sesion/db'; import { WhatsAppService } from '@sesion/whatsapp'; import { subHours } from 'date-fns'; @Injectable() export class ReminderJob { constructor( private prisma: PrismaService, private whatsapp: WhatsAppService ) {} @Cron(CronExpression.EVERY_HOUR) async send24HourReminders() { const tomorrow = new Date(); tomorrow.setHours(tomorrow.getHours() + 24); const appointments = await this.prisma.appointment.findMany({ where: { scheduledAt: { gte: tomorrow, lt: new Date(tomorrow.getTime() + 60 * 60 * 1000) // +1 hour window }, status: 'SCHEDULED', reminderSent24h: false }, include: { patient: true, practitioner: true } }); for (const apt of appointments) { await this.whatsapp.sendReminder(apt); await this.prisma.appointment.update({ where: { id: apt.id }, data: { reminderSent24h: true } }); } } } ``` ### 3. AFIP Electronic Invoicing #### Invoice Generation Service ```typescript // packages/billing/src/afip.service.ts import { Injectable } from '@nestjs/common'; import Afip from '@afipsdk/afip.js'; import { PrismaService } from '@sesion/db'; @Injectable() export class AfipService { private afip: Afip; constructor(private prisma: PrismaService) { this.afip = new Afip({ CUIT: process.env.AFIP_CUIT, cert: process.env.AFIP_CERT_PATH,
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub