feat: Slack platform + Claude-powered chat support widget

- Add Slack as customer-facing messaging platform (client, 4 MCP tools, dashboard card)
- Add /api/chat endpoint powered by Claude Haiku with SquareMCP system prompt
- Add embeddable chat-widget.js injected into all 3 sites (docs, app, www)
- Add ANTHROPIC_API_KEY, serve product/ as static files
- Update Platform type to include slack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Garfield
2026-05-15 10:44:24 -04:00
parent 05b4a30759
commit 4bf93d6763
15 changed files with 547 additions and 4 deletions

View File

@@ -36,6 +36,7 @@ import { getAllPlatformHealth } from './multitenancy/platform-health.js';
import { deliverWebhook, isValidWebhookUrl } from './webhooks/delivery.js';
import { notifyNewPilotRequest } from './notifications/index.js';
import redis from './redis.js';
import { handleChat, type ChatMessage } from './chat.js';
const app = express();
app.use(cookieParser());
@@ -57,6 +58,7 @@ app.use(express.urlencoded({ extended: true }));
// ── Static files (videos, assets) ──────────────────────────────────────────
app.use('/public', express.static('/vaults/public'));
app.use(express.static(new URL('../../product', import.meta.url).pathname));
// ── Config ─────────────────────────────────────────────────────────────────
const PORT = process.env.PORT ?? 3456;
@@ -1978,6 +1980,22 @@ app.post('/api/facebook/video', requireAuth, async (req, res) => {
}
});
// ── Chat widget endpoint ────────────────────────────────────────
app.post('/api/chat', async (req, res) => {
const { messages } = req.body as { messages?: ChatMessage[] };
if (!Array.isArray(messages) || messages.length === 0) {
res.status(400).json({ error: 'messages array required' });
return;
}
try {
const reply = await handleChat(messages);
res.json({ reply });
} catch (err) {
console.error('[chat] error:', (err as Error).message);
res.status(500).json({ error: 'Chat unavailable' });
}
});
// ── TikTok REST endpoints ───────────────────────────────────────
app.get('/api/tiktok/profile', requireAuth, async (req, res) => {
const account = req.query.account as string | undefined;