mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
- Streaming AI chat via Vercel AI SDK v6 UI message stream — tool-based
generative UI (pick_branch, list_departments, show_clinic_timings,
show_doctors, show_doctor_slots, suggest_booking). Typing indicator,
markdown suppressed, text parts hidden when widgets are rendered.
- Centralized Preact store (store.tsx) for visitor, leadId, captchaToken,
bookingPrefill, doctors roster, branches, selectedBranch — replaces prop
drilling across chat/book/contact tabs.
- Cloudflare Turnstile captcha gate rendered via light-DOM portal so it
renders correctly inside the shadow DOM (Turnstile CSS doesn't cross
shadow boundaries).
- Lead dedup helper (findOrCreateLeadByPhone, 24h phone window) shared
across chat-start / book / contact so one visitor == one lead. Booking
upgrades existing lead status NEW → APPOINTMENT_SET via updateLeadStatus.
- Pre-chat name+phone form captures the visitor; chat transcript logged
to leadActivity records after each stream.
- Booking wizard gains a branch step 0 (skipped for single-branch
hospitals); departments + doctors filtered by selectedBranch. Chat slot
picks prefill the booking details step and lock the branch.
- Window-level captcha gate, modal maximize mode, header badge showing
selected branch, widget font inherits from host page (fix :host { all:
initial } override).
- 23 FA Pro 7.1 duotone icons bundled — medical departments, nav, actions,
hospital/location-dot for branch context.
- main.ts: resolve public/ from process.cwd() so widget.js serves in both
dev and prod. tsconfig: exclude widget-src/public/data from server tsc.
- captcha.guard: switch from reCAPTCHA v3 to Cloudflare Turnstile verify.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { NestFactory } from '@nestjs/core';
|
|
import type { NestExpressApplication } from '@nestjs/platform-express';
|
|
import { join } from 'path';
|
|
import { AppModule } from './app.module';
|
|
import { ConfigService } from '@nestjs/config';
|
|
|
|
async function bootstrap() {
|
|
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
|
const config = app.get(ConfigService);
|
|
|
|
app.enableCors({
|
|
origin: config.get('corsOrigin'),
|
|
credentials: true,
|
|
});
|
|
|
|
// Serve widget.js and other static files from /public
|
|
// In dev mode __dirname = src/, in prod __dirname = dist/ — resolve from process.cwd()
|
|
app.useStaticAssets(join(process.cwd(), 'public'), {
|
|
setHeaders: (res, path) => {
|
|
if (path.endsWith('.js')) {
|
|
res.setHeader('Cache-Control', 'public, max-age=3600');
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
}
|
|
},
|
|
});
|
|
|
|
const port = config.get('port');
|
|
await app.listen(port);
|
|
console.log(`Helix Engage Server running on port ${port}`);
|
|
}
|
|
bootstrap();
|