Phase 4.1: AI Writing Assistant - GPT-4o integration with OpenAI API (fallback to local parsing) - Six AI actions: summarize, expand, rewrite, extract actions, suggest links, smart schedule - TipTap inline AI assistant panel with streaming-ready architecture - Apply/dismiss UI for AI suggestions - Rewrite style selector (concise, formal, simpler, detailed) Phase 4.2: Natural Language Input - /api/v1/natural-language endpoint for parsing unstructured text - AI-powered extraction of type, title, date, priority, participants - Local regex fallback when no API key configured - Priority parsing (!1-5) and date detection (tomorrow, next week) Phase 4.3: Knowledge Graph - D3.js-ready graph visualization container - Zoom in/out/fit controls - Placeholder state with guidance for content creation - Data model for nodes, links, and groups Phase 4.4: Semantic Search Infrastructure - Unified search bar with debounced input (300ms) - Type-based result icons (note, task, event) - Search result display with title and content preview - pgvector and embedding pipeline data model in schema
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import Fastify from 'fastify';
|
|
import cors from '@fastify/cors';
|
|
import helmet from '@fastify/helmet';
|
|
import rateLimit from '@fastify/rate-limit';
|
|
import fastifySwagger from '@fastify/swagger';
|
|
import fastifySwaggerUi from '@fastify/swagger-ui';
|
|
import fastifyWebsocket from '@fastify/websocket';
|
|
import fastifyCookie from '@fastify/cookie';
|
|
import fastifyJwt from '@fastify/jwt';
|
|
import { PrismaClient } from '@yetanother/db';
|
|
import { API_PREFIX } from '@yetanother/utils';
|
|
import { authPlugin } from './plugins/auth.js';
|
|
import { authRoutes } from './routes/auth.js';
|
|
import { nodeRoutes } from './routes/nodes.js';
|
|
import { workspaceRoutes } from './routes/workspaces.js';
|
|
import { searchRoutes } from './routes/search.js';
|
|
import { aiRoutes } from './routes/ai.js';
|
|
|
|
const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 4000;
|
|
const envHost = process.env.HOST ?? '0.0.0.0';
|
|
const jwtSecret = process.env.JWT_SECRET ?? 'dev-secret-change-in-production';
|
|
|
|
export async function buildApp() {
|
|
const prisma = new PrismaClient();
|
|
|
|
const app = Fastify({
|
|
logger: {
|
|
transport: process.env.NODE_ENV !== 'production'
|
|
? { target: 'pino-pretty', options: { colorize: true } }
|
|
: undefined,
|
|
},
|
|
});
|
|
|
|
await app.register(cors, { origin: true, credentials: true });
|
|
await app.register(helmet, { contentSecurityPolicy: false });
|
|
await app.register(rateLimit, { max: 100, timeWindow: '1 minute' });
|
|
await app.register(fastifyCookie);
|
|
await app.register(fastifyJwt, { secret: jwtSecret });
|
|
await app.register(fastifyWebsocket);
|
|
await app.register(fastifySwagger, {
|
|
openapi: {
|
|
info: { title: 'YetAnotherSuite API', version: '1.0.0' },
|
|
},
|
|
});
|
|
await app.register(fastifySwaggerUi, { routePrefix: '/docs' });
|
|
|
|
app.decorate('prisma', prisma);
|
|
await app.register(authPlugin);
|
|
|
|
await app.register(authRoutes, { prefix: `${API_PREFIX}/auth` });
|
|
await app.register(nodeRoutes, { prefix: API_PREFIX });
|
|
await app.register(workspaceRoutes, { prefix: API_PREFIX });
|
|
await app.register(searchRoutes, { prefix: API_PREFIX });
|
|
await app.register(aiRoutes, { prefix: API_PREFIX });
|
|
|
|
app.get('/health', async () => ({ status: 'ok', timestamp: new Date().toISOString() }));
|
|
|
|
return app;
|
|
}
|
|
|
|
async function main() {
|
|
const app = await buildApp();
|
|
|
|
try {
|
|
await app.listen({ port: envPort, host: envHost });
|
|
app.log.info(`Server running at http://${envHost}:${envPort}`);
|
|
} catch (err) {
|
|
app.log.error(err);
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
main();
|