Start repository

This commit is contained in:
Francisco Pessano
2025-06-06 21:14:10 -03:00
commit 1bb5fcd022
72 changed files with 14106 additions and 0 deletions

98
src/pages/api/postmark.ts Normal file
View File

@@ -0,0 +1,98 @@
import type { APIRoute } from 'astro';
import { supabase } from '../../lib/supabase';
export const POST: APIRoute = async ({ request }) => {
try {
const data = await request.json();
// Check for opt-out keywords
const optOutKeywords = ['STOP', 'UNSUBSCRIBE', 'OPT-OUT', 'REMOVE'];
const textBody = data.TextBody || '';
const hasOptOut = optOutKeywords.some(keyword =>
textBody.toUpperCase().includes(keyword)
);
if (hasOptOut) {
// Log opt-out and don't process further
const { error } = await supabase.from('debts').insert({
vendor: data.FromFull?.Email || 'unknown',
amount: 0,
raw_email: textBody,
status: 'opted_out'
});
if (error) {
console.error('Error logging opt-out:', error);
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Opt-out processed', { status: 200 });
}
// Extract debt amount using regex
const amountMatch = textBody.match(/\$(\d+(?:,\d{3})*(?:\.\d{2})?)/);
const amount = amountMatch ? parseFloat(amountMatch[1].replace(/,/g, '')) : 0;
// Insert debt record
const { data: insertedDebt, error: insertError } = await supabase
.from('debts')
.insert({
vendor: data.FromFull?.Email || 'unknown',
amount: amount,
raw_email: textBody,
status: 'received'
})
.select()
.single();
if (insertError) {
console.error('Error inserting debt:', insertError);
return new Response(JSON.stringify({ error: insertError.message }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
// Log the email receipt
await supabase.from('audit_logs').insert({
debt_id: insertedDebt.id,
action: 'email_received',
details: {
vendor: data.FromFull?.Email,
amount: amount,
subject: data.Subject
}
});
// Trigger negotiation function
if (amount > 0) {
const negotiateUrl = `${import.meta.env.SUPABASE_URL}/functions/v1/negotiate`;
try {
await fetch(negotiateUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${import.meta.env.SUPABASE_ANON_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ record: insertedDebt })
});
} catch (negotiateError) {
console.error('Error triggering negotiation:', negotiateError);
// Don't fail the webhook if negotiation fails
}
}
return new Response('OK', { status: 200 });
} catch (error) {
console.error('Postmark webhook error:', error);
return new Response(JSON.stringify({ error: 'Internal server error' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
};

9
src/pages/index.astro Normal file
View File

@@ -0,0 +1,9 @@
---
import '@/styles/globals.css'
import Layout from '../layouts/Layout.astro';
import { Dashboard } from '../components/Dashboard';
---
<Layout title="InboxNegotiator - AI-Powered Debt Resolution">
<Dashboard client:load />
</Layout>