juntekim.com/stripe_to_invoice/app/page.tsx
2025-12-28 16:59:41 +00:00

251 lines
6.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// app/page.tsx
// This page doubles as:
// 1. A landing page
// 2. A product spec
// 3. A reminder to future-me what the hell I was building
//
// If youre reading this months later: hi 👋
// The product is the automation, not the UI.
export default function Home() {
return (
<main className="max-w-3xl mx-auto p-8 space-y-16">
{/* --------------------------------------------------
Intro
-------------------------------------------------- */}
<section>
<h1 className="text-2xl font-semibold">
Stripe Xero automation
</h1>
<p className="mt-2 text-gray-600">
Automatically create and mark Xero invoices as paid when a Stripe payment succeeds.
<br />
Built for people who value time more than pressing buttons.
</p>
</section>
{/* --------------------------------------------------
High-level flow (human readable)
-------------------------------------------------- */}
<section>
<h2 className="text-xl font-medium">How it works (high level)</h2>
<ol className="mt-4 space-y-3 list-decimal list-inside text-gray-700">
<li>Log in via magic link (passwordless)</li>
<li>Connect your Stripe account</li>
<li>Connect your Xero organisation</li>
<li>A Stripe payment succeeds</li>
<li>An invoice appears in Xero as paid</li>
</ol>
</section>
{/* --------------------------------------------------
Magic link auth detailed flow
-------------------------------------------------- */}
<section>
<h2 className="text-xl font-medium">Login flow (magic link)</h2>
<p className="mt-2 text-gray-600">
Authentication is passwordless. We only store intent and proof of login.
</p>
{/* Text-based flow diagram (easy to read + copy) */}
<pre className="mt-4 p-4 bg-gray-50 border rounded text-sm overflow-x-auto">
{`Browser
|
| POST /auth/login (email)
v
Backend
- find or create user
- generate token
- hash token
- store login_tokens row
- send email (SES)
|
v
Email (magic link)
|
| GET /auth/callback?token=XYZ
v
Backend
- hash token
- validate token (unused + not expired)
- mark token as used
- create session
|
v
Set session cookie
`}
</pre>
{/* Step-by-step breakdown */}
<ol className="mt-6 space-y-4 list-decimal list-inside text-gray-700">
<li>
User enters their email address.
</li>
<li>
Backend creates (or finds) a user record and stores a one-time login token
in <code className="px-1 bg-gray-100 rounded">login_tokens</code>.
</li>
<li>
An email is sent containing a short-lived magic link.
</li>
<li>
When the link is clicked, the token is validated, marked as used,
and a session is created.
</li>
<li>
A secure session cookie is set. No passwords. No OAuth popups.
</li>
</ol>
</section>
{/* --------------------------------------------------
Stripe → Xero automation flow
-------------------------------------------------- */}
<section>
<h2 className="text-xl font-medium">Stripe Xero automation flow</h2>
<pre className="mt-4 p-4 bg-gray-50 border rounded text-sm overflow-x-auto">
{`Stripe payment succeeds
|
| Webhook
v
Backend
- verify Stripe event
- map payment to customer
- create Xero invoice
- mark invoice as paid
|
v
Xero (reconciled automatically)
`}
</pre>
<p className="mt-4 text-gray-600">
Once connected, everything runs automatically.
No manual reconciliation. No awaiting payment state.
</p>
</section>
{/* --------------------------------------------------
Proof
-------------------------------------------------- */}
<section>
<h2 className="text-xl font-medium">Proof, not promises</h2>
<p className="mt-2 text-gray-600">
Your next Stripe payment will automatically reconcile in Xero.
<br />
No manual matching. No bookkeeping busywork.
</p>
</section>
{/* --------------------------------------------------
Pricing
-------------------------------------------------- */}
<section>
<h2 className="text-xl font-medium">Pricing</h2>
<p className="mt-2 text-gray-700">
£200 / month unlimited invoices.
</p>
</section>
{/* --------------------------------------------------
Footer / reminder
-------------------------------------------------- */}
<section className="pt-8 border-t">
<p className="text-gray-500 text-sm">
This page is intentionally simple.
<br />
The product is the automation, not the UI.
</p>
</section>
<section>
<h2 className="text-xl font-medium">Implementation notes (for future me)</h2>
<p className="mt-2 text-gray-600">
These are the only docs needed to implement magic-link auth with Next.js + AWS SES.
</p>
<ul className="mt-4 space-y-2 list-disc list-inside text-gray-700">
<li>
Next.js Route Handlers (auth endpoints):{" "}
<a
href="https://nextjs.org/docs/app/building-your-application/routing/route-handlers"
className="text-blue-600 underline"
target="_blank"
>
nextjs.org/docs/app/.../route-handlers
</a>
</li>
<li>
Next.js Server Actions (optional):{" "}
<a
href="https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions"
className="text-blue-600 underline"
target="_blank"
>
nextjs.org/docs/app/.../server-actions
</a>
</li>
<li>
AWS SES sending email (Node.js):{" "}
<a
href="https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/sesv2/"
className="text-blue-600 underline"
target="_blank"
>
AWS SDK SESv2
</a>
</li>
<li>
AWS SES sandbox production access:{" "}
<a
href="https://docs.aws.amazon.com/ses/latest/dg/request-production-access.html"
className="text-blue-600 underline"
target="_blank"
>
Request production access
</a>
</li>
<li>
Node.js crypto (token generation + hashing):{" "}
<a
href="https://nodejs.org/api/crypto.html"
className="text-blue-600 underline"
target="_blank"
>
nodejs.org/api/crypto
</a>
</li>
<li>
Cookies & sessions:{" "}
<a
href="https://nextjs.org/docs/app/api-reference/functions/cookies"
className="text-blue-600 underline"
target="_blank"
>
Next.js cookies API
</a>
</li>
</ul>
</section>
</main>
)
}