import 'dotenv/config'; import express from 'express'; import { Client, Databases, Query } from 'node-appwrite'; import Stripe from 'stripe'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const requiredEnvVars = [ 'APPWRITE_ENDPOINT', 'APPWRITE_PROJECT_ID', 'APPWRITE_API_KEY', 'APPWRITE_DATABASE_ID', 'STRIPE_SECRET_KEY', 'STRIPE_WEBHOOK_SECRET' ]; for (const envVar of requiredEnvVars) { if (!process.env[envVar]) { console.error(`Error: Missing required environment variable: ${envVar}`); process.exit(1); } } const app = express(); const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); const client = new Client() .setEndpoint(process.env.APPWRITE_ENDPOINT) .setProject(process.env.APPWRITE_PROJECT_ID) .setKey(process.env.APPWRITE_API_KEY); const databases = new Databases(client); app.use(express.static(join(__dirname, '..', 'public'))); app.use('/api', express.json()); app.post('/stripe/webhook', express.raw({ type: 'application/json' }), async (req, res) => { const sig = req.headers['stripe-signature']; try { const event = stripe.webhooks.constructEvent( req.body, sig, process.env.STRIPE_WEBHOOK_SECRET ); if (event.type === 'checkout.session.completed') { const session = event.data.object; const submissionId = session.metadata.submissionId; if (submissionId) { await databases.updateDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', submissionId, { status: 'paid' } ); await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'orders', 'unique()', { submissionId: submissionId, orderDataJson: JSON.stringify(session) } ); } } res.json({ received: true }); } catch (err) { console.error('Webhook error:', err.message); res.status(400).send(`Webhook Error: ${err.message}`); } }); app.get('/api/questions', async (req, res) => { try { const { productSlug } = req.query; const productsResponse = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'products', [Query.equal('slug', productSlug), Query.equal('isActive', true)] ); if (productsResponse.documents.length === 0) { return res.status(404).json({ error: 'Product not found' }); } const product = productsResponse.documents[0]; const questionsResponse = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'questions', [ Query.equal('productId', product.$id), Query.equal('isActive', true), Query.orderAsc('step'), Query.orderAsc('order') ] ); res.json(questionsResponse.documents); } catch (error) { console.error('Error fetching questions:', error); res.status(500).json({ error: 'Failed to fetch questions' }); } }); app.post('/api/submissions', async (req, res) => { try { const { productSlug, answers } = req.body; const productsResponse = await databases.listDocuments( process.env.APPWRITE_DATABASE_ID, 'products', [Query.equal('slug', productSlug)] ); if (productsResponse.documents.length === 0) { return res.status(404).json({ error: 'Product not found' }); } const product = productsResponse.documents[0]; const submission = await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', 'unique()', { productId: product.$id, status: 'draft', customerEmail: answers.email || null, customerName: answers.name || null, finalSummaryJson: JSON.stringify(answers), priceCents: product.priceCents, currency: product.currency } ); await databases.createDocument( process.env.APPWRITE_DATABASE_ID, 'answers', 'unique()', { submissionId: submission.$id, answersJson: JSON.stringify(answers) } ); res.json({ submissionId: submission.$id }); } catch (error) { console.error('Error creating submission:', error); res.status(500).json({ error: 'Failed to create submission' }); } }); app.post('/api/checkout', async (req, res) => { try { const { submissionId } = req.body; if (!submissionId) { return res.status(400).json({ error: 'Missing submissionId' }); } const submission = await databases.getDocument( process.env.APPWRITE_DATABASE_ID, 'submissions', submissionId ); const session = await stripe.checkout.sessions.create({ payment_method_types: ['card'], line_items: [ { price_data: { currency: submission.currency, product_data: { name: 'Email Sortierer Service', }, unit_amount: submission.priceCents, }, quantity: 1, }, ], mode: 'payment', success_url: `${process.env.BASE_URL || 'http://localhost:3000'}/success.html`, cancel_url: `${process.env.BASE_URL || 'http://localhost:3000'}/cancel.html`, metadata: { submissionId: submissionId } }); res.json({ url: session.url }); } catch (error) { console.error('Error creating checkout session:', error); res.status(500).json({ error: 'Failed to create checkout session' }); } }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });