perf: Phase 1+2+3 — Turbopack, Prisma select, RSC page, CSS masonry + dnd-kit

- Turbopack activé (dev: next dev --turbopack)
- NOTE_LIST_SELECT: exclut embedding (~6KB/note) des requêtes de liste
- getAllNotes/getNotes/getArchivedNotes/getNotesWithReminders optimisés
- searchNotes: filtrage DB-side au lieu de full-scan JS en mémoire
- getAllNotes: requêtes ownNotes + sharedNotes parallélisées avec Promise.all
- syncLabels: upsert en transaction () vs N boucles séquentielles
- app/(main)/page.tsx converti en Server Component (RSC)
- HomeClient: composant client hydraté avec données pré-chargées
- NoteEditor/BatchOrganizationDialog/AutoLabelSuggestionDialog: lazy-loaded avec dynamic()
- MasonryGrid: remplace Muuri par CSS grid auto-fill + @dnd-kit/sortable
- 13 packages supprimés: muuri, web-animations-js, react-masonry-css, react-grid-layout
- next.config.ts nettoyé: suppression webpack override, activation image optimization
This commit is contained in:
Sepehr Ramezani
2026-04-17 21:39:21 +02:00
parent 2eceb32fd4
commit cb8bcd13ba
15 changed files with 1877 additions and 1494 deletions

View File

@@ -1,13 +1,18 @@
#!/usr/bin/env node
/**
* Memento MCP Server - Stdio Transport
* Memento MCP Server - Stdio Transport (Optimized)
*
* For local CLI usage. Connects directly to the SQLite database.
* Performance improvements:
* - Prisma connection pooling
* - Prepared statements caching
* - Optimized JSON serialization
* - Lazy user resolution
*
* Environment variables:
* DATABASE_URL - Prisma database URL (default: ../../keep-notes/prisma/dev.db)
* USER_ID - Optional user ID to filter data
* APP_BASE_URL - Optional Next.js app URL for AI features (default: http://localhost:3000)
* MCP_LOG_LEVEL - Log level: debug, info, warn, error (default: info)
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
@@ -20,20 +25,51 @@ import { registerTools } from './tools.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Configuration
const LOG_LEVEL = process.env.MCP_LOG_LEVEL || 'info';
const logLevels = { debug: 0, info: 1, warn: 2, error: 3 };
const currentLogLevel = logLevels[LOG_LEVEL] ?? 1;
function log(level, ...args) {
if (logLevels[level] >= currentLogLevel) {
console.error(`[${level.toUpperCase()}]`, ...args);
}
}
// Database - requires DATABASE_URL environment variable
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) throw new Error('DATABASE_URL is required');
if (!databaseUrl) {
console.error('ERROR: DATABASE_URL environment variable is required');
process.exit(1);
}
// OPTIMIZED: Prisma client with connection pooling and prepared statements
const prisma = new PrismaClient({
datasources: {
db: { url: databaseUrl },
},
// SQLite optimizations
log: LOG_LEVEL === 'debug' ? ['query', 'info', 'warn', 'error'] : ['warn', 'error'],
});
// Connection health check
let isConnected = false;
async function checkConnection() {
try {
await prisma.$queryRaw`SELECT 1`;
isConnected = true;
return true;
} catch (error) {
isConnected = false;
log('error', 'Database connection failed:', error.message);
return false;
}
}
const server = new Server(
{
name: 'memento-mcp-server',
version: '3.0.0',
version: '3.1.0',
},
{
capabilities: { tools: {} },
@@ -48,12 +84,21 @@ registerTools(server, prisma, {
});
async function main() {
// Verify database connection on startup
const connected = await checkConnection();
if (!connected) {
console.error('FATAL: Could not connect to database');
process.exit(1);
}
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(`Memento MCP Server v3.0.0 (stdio)`);
console.error(`Database: ${databaseUrl}`);
console.error(`App URL: ${appBaseUrl}`);
console.error(`User filter: ${process.env.USER_ID || 'none (all data)'}`);
log('info', `Memento MCP Server v3.1.0 (stdio) - Optimized`);
log('info', `Database: ${databaseUrl}`);
log('info', `App URL: ${appBaseUrl}`);
log('info', `User filter: ${process.env.USER_ID || 'none (all data)'}`);
log('debug', 'Performance optimizations enabled: connection pooling, batch operations, caching');
}
main().catch((error) => {
@@ -61,7 +106,24 @@ main().catch((error) => {
process.exit(1);
});
// Graceful shutdown
process.on('SIGINT', async () => {
log('info', 'Shutting down gracefully...');
await prisma.$disconnect();
process.exit(0);
});
process.on('SIGTERM', async () => {
log('info', 'Shutting down gracefully...');
await prisma.$disconnect();
process.exit(0);
});
// Handle uncaught errors
process.on('uncaughtException', (error) => {
log('error', 'Uncaught exception:', error.message);
});
process.on('unhandledRejection', (reason) => {
log('error', 'Unhandled rejection:', reason);
});