kenso war das

This commit is contained in:
2026-02-03 23:27:25 +01:00
parent 6bf3c603d8
commit ef2faa21fd
73 changed files with 8416 additions and 257 deletions

View File

@@ -2,8 +2,8 @@ import 'dotenv/config';
import { Client, Databases, ID, Permission, Role } from "node-appwrite";
/**
* EmailSorter Database Bootstrap Script v2
* Creates all required collections for the full EmailSorter app
* MailFlow Database Bootstrap Script v2
* Creates all required collections for the full MailFlow app
*/
const requiredEnv = [
@@ -26,8 +26,8 @@ const client = new Client()
const db = new Databases(client);
const DB_ID = process.env.APPWRITE_DATABASE_ID || 'emailsorter';
const DB_NAME = 'EmailSorter';
const DB_ID = process.env.APPWRITE_DATABASE_ID || 'mailflow';
const DB_NAME = 'MailFlow';
// Helper: create database if not exists
async function ensureDatabase() {
@@ -262,7 +262,7 @@ async function setupCollections() {
async function main() {
console.log('\n========================================');
console.log(' EmailSorter Database Bootstrap v2');
console.log(' MailFlow Database Bootstrap v2');
console.log('========================================\n');
await ensureDatabase();

View File

@@ -1,5 +1,5 @@
/**
* EmailSorter - Database Cleanup Script
* MailFlow - Database Cleanup Script
*
* ⚠️ WICHTIG: Liest Credentials aus Umgebungsvariablen (.env)
* Keine hardcoded API Keys mehr!

View File

@@ -33,11 +33,11 @@ try {
const productsResponse = await databases.listDocuments(
process.env.APPWRITE_DATABASE_ID,
'products',
[Query.equal('slug', 'email-sorter'), Query.equal('isActive', true)]
[Query.equal('slug', 'mailflow'), Query.equal('isActive', true)]
);
if (productsResponse.documents.length === 0) {
console.error('❌ No active product found with slug "email-sorter"');
console.error('❌ No active product found with slug "mailflow"');
process.exit(1);
}

View File

@@ -1,5 +1,5 @@
# ═══════════════════════════════════════════════════════════════════════════
# EmailSorter Backend - Konfiguration
# MailFlow Backend - Konfiguration
# ═══════════════════════════════════════════════════════════════════════════
# Kopiere diese Datei nach `.env` und fülle die Werte aus.
@@ -21,7 +21,7 @@ FRONTEND_URL=http://localhost:5173
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=dein_projekt_id
APPWRITE_API_KEY=dein_api_key_mit_allen_berechtigungen
APPWRITE_DATABASE_ID=email_sorter_db
APPWRITE_DATABASE_ID=mailflow_db
# ─────────────────────────────────────────────────────────────────────────────
# Stripe (ERFORDERLICH)

View File

@@ -1,5 +1,5 @@
/**
* EmailSorter Backend Server
* MailFlow Backend Server
* Main entry point
*/

View File

@@ -1,7 +1,7 @@
{
"name": "email-sorter-server",
"name": "mailflow-server",
"version": "2.0.0",
"description": "EmailSorter Backend Server - KI-gestützte E-Mail-Sortierung",
"description": "MailFlow Backend Server - KI-gestützte E-Mail-Sortierung",
"main": "index.mjs",
"type": "module",
"engines": {

View File

@@ -164,7 +164,7 @@ router.post('/connect-demo',
}),
asyncHandler(async (req, res) => {
const { userId } = req.body
const demoEmail = `demo-${userId.slice(0, 8)}@emailsorter.demo`
const demoEmail = `demo-${userId.slice(0, 8)}@mailflow.demo`
// Check if demo account already exists
const existingAccounts = await emailAccounts.getByUser(userId)
@@ -456,7 +456,7 @@ router.post('/sort',
try {
const gmail = await getGmailService(account.accessToken, account.refreshToken)
// FIRST: Clean up old "EmailSorter/..." labels
// FIRST: Clean up old "MailFlow/..." labels
const deletedLabels = await gmail.cleanupOldLabels()
if (deletedLabels > 0) {
log.success(`${deletedLabels} old labels cleaned up`)
@@ -528,7 +528,7 @@ router.post('/sort',
for (const nl of preferences.nameLabels) {
if (!nl.enabled) continue
try {
const labelName = `EmailSorter/Team/${nl.name}`
const labelName = `MailFlow/Team/${nl.name}`
const label = await gmail.createLabel(labelName, '#4a86e8')
if (label) {
nameLabelMap[nl.id || nl.name] = label.id
@@ -1203,7 +1203,7 @@ router.post('/sort-demo', asyncHandler(async (req, res) => {
/**
* POST /api/email/cleanup
* Cleanup old EmailSorter labels from Gmail
* Cleanup old MailFlow labels from Gmail
*/
router.post('/cleanup',
validate({
@@ -1235,7 +1235,7 @@ router.post('/cleanup',
respond.success(res, {
deleted,
message: deleted > 0
? `${deleted} old "EmailSorter/..." labels were deleted`
? `${deleted} old "MailFlow/..." labels were deleted`
: 'No old labels found'
})
})
@@ -1549,8 +1549,8 @@ async function processPromotionsCleanup(account, action, deleteAfterDays, matchC
const gmail = await getGmailService(account.accessToken, account.refreshToken)
// Find emails with matching categories/labels older than deleteAfterDays
// Look for emails with EmailSorter labels matching the categories
const labelQueries = matchCategories.map(cat => `label:EmailSorter/${cat}`).join(' OR ')
// Look for emails with MailFlow labels matching the categories
const labelQueries = matchCategories.map(cat => `label:MailFlow/${cat}`).join(' OR ')
const query = `(${labelQueries}) before:${cutoffDate.getFullYear()}/${String(cutoffDate.getMonth() + 1).padStart(2, '0')}/${String(cutoffDate.getDate()).padStart(2, '0')}`
const response = await gmail.gmail.users.messages.list({

View File

@@ -107,7 +107,7 @@ export class GmailService {
/**
* Create or get a label
* @param {string} name - Label name (e.g., "EmailSorter/VIP")
* @param {string} name - Label name (e.g., "MailFlow/VIP")
* @param {string} color - Optional label color (must be from Gmail's palette)
*/
async createLabel(name, color = null) {
@@ -272,14 +272,14 @@ export class GmailService {
}
/**
* Cleanup old EmailSorter labels
* Removes all labels starting with "EmailSorter/" and old German labels
* Cleanup old MailFlow labels
* Removes all labels starting with "MailFlow/" and old German labels
*/
async cleanupOldLabels() {
// Old labels to remove (German and old format)
const OLD_LABELS = [
// Old "EmailSorter/" prefix labels
'EmailSorter/',
// Old "MailFlow/" prefix labels
'MailFlow/',
// Old German labels
'Wichtig', 'Kunden', 'Rechnungen', 'Sicherheit', 'Termine', 'Prüfen', 'Werbung',
'VIP / Wichtig', 'Kunden / Projekte', 'Rechnungen / Belege',
@@ -293,8 +293,8 @@ export class GmailService {
// Filter labels that match old patterns
const labelsToDelete = labels.filter(l => {
if (!l.name) return false
// Check for EmailSorter/ prefix
if (l.name.startsWith('EmailSorter/')) return true
// Check for MailFlow/ prefix
if (l.name.startsWith('MailFlow/')) return true
// Check for exact matches with old labels
if (OLD_LABELS.includes(l.name)) return true
return false

View File

@@ -7,7 +7,7 @@ import { ImapFlow } from 'imapflow'
import { log } from '../middleware/logger.mjs'
const INBOX = 'INBOX'
const FOLDER_PREFIX = 'EmailSorter'
const FOLDER_PREFIX = 'MailFlow'
/** Map category key to IMAP folder name */
export function getFolderNameForCategory(category) {
@@ -134,7 +134,7 @@ export class ImapService {
}
/**
* Ensure folder exists (create if not). Use subfolder under EmailSorter to avoid clutter.
* Ensure folder exists (create if not). Use subfolder under MailFlow to avoid clutter.
*/
async ensureFolder(folderName) {
const path = `${FOLDER_PREFIX}/${folderName}`
@@ -150,7 +150,7 @@ export class ImapService {
}
/**
* Move message (by UID) from INBOX to folder name (under EmailSorter/)
* Move message (by UID) from INBOX to folder name (under MailFlow/)
*/
async moveToFolder(messageId, folderName) {
const path = `${FOLDER_PREFIX}/${folderName}`

View File

@@ -302,7 +302,7 @@ export class OutlookService {
notificationUrl: webhookUrl,
resource: 'me/mailFolders(\'inbox\')/messages',
expirationDateTime,
clientState: 'email-sorter-webhook',
clientState: 'mailflow-webhook',
}),
})
}