page.tsx
This commit is contained in:
parent
a5715aa1ca
commit
a896e96ebf
1 changed files with 211 additions and 17 deletions
|
|
@ -1,57 +1,251 @@
|
||||||
// app/page.tsx
|
// 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 you’re reading this months later: hi 👋
|
||||||
|
// The product is the automation, not the UI.
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<main className="max-w-3xl mx-auto p-8 space-y-12">
|
<main className="max-w-3xl mx-auto p-8 space-y-16">
|
||||||
|
|
||||||
{/* What this is */}
|
{/* --------------------------------------------------
|
||||||
|
Intro
|
||||||
|
-------------------------------------------------- */}
|
||||||
<section>
|
<section>
|
||||||
<h1 className="text-2xl font-semibold">
|
<h1 className="text-2xl font-semibold">
|
||||||
Stripe → Xero automation
|
Stripe → Xero automation
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p className="mt-2 text-gray-600">
|
<p className="mt-2 text-gray-600">
|
||||||
Automatically create and mark Xero invoices as paid when a Stripe payment succeeds.
|
Automatically create and mark Xero invoices as paid when a Stripe payment succeeds.
|
||||||
|
<br />
|
||||||
Built for people who value time more than pressing buttons.
|
Built for people who value time more than pressing buttons.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Steps */}
|
{/* --------------------------------------------------
|
||||||
|
High-level flow (human readable)
|
||||||
|
-------------------------------------------------- */}
|
||||||
<section>
|
<section>
|
||||||
<h2 className="text-xl font-medium">How it works</h2>
|
<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">
|
<ol className="mt-4 space-y-3 list-decimal list-inside text-gray-700">
|
||||||
<li>Log in ( Set up magic link, db has been set up)</li>
|
<li>Log in via magic link (passwordless)</li>
|
||||||
<li>Connect Stripe</li>
|
<li>Connect your Stripe account</li>
|
||||||
<li>Connect Xero</li>
|
<li>Connect your Xero organisation</li>
|
||||||
<li>Make a payment</li>
|
<li>A Stripe payment succeeds</li>
|
||||||
<li>Invoice appears in Xero as paid</li>
|
<li>An invoice appears in Xero as paid</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Proof */}
|
{/* --------------------------------------------------
|
||||||
|
Magic link auth – detailed flow
|
||||||
|
-------------------------------------------------- */}
|
||||||
<section>
|
<section>
|
||||||
<h2 className="text-xl font-medium">Proof, not promises</h2>
|
<h2 className="text-xl font-medium">Login flow (magic link)</h2>
|
||||||
|
|
||||||
<p className="mt-2 text-gray-600">
|
<p className="mt-2 text-gray-600">
|
||||||
Your next Stripe payment will automatically reconcile in Xero.
|
Authentication is passwordless. We only store intent and proof of login.
|
||||||
No manual matching. No “awaiting payment”.
|
</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>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Pricing */}
|
{/* --------------------------------------------------
|
||||||
|
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>
|
<section>
|
||||||
<h2 className="text-xl font-medium">Pricing</h2>
|
<h2 className="text-xl font-medium">Pricing</h2>
|
||||||
|
|
||||||
<p className="mt-2 text-gray-700">
|
<p className="mt-2 text-gray-700">
|
||||||
£200 / month — unlimited invoices.
|
£200 / month — unlimited invoices.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* CTA */}
|
{/* --------------------------------------------------
|
||||||
|
Footer / reminder
|
||||||
|
-------------------------------------------------- */}
|
||||||
<section className="pt-8 border-t">
|
<section className="pt-8 border-t">
|
||||||
<p className="text-gray-500 text-sm">
|
<p className="text-gray-500 text-sm">
|
||||||
This page is a placeholder. The product is the automation.
|
This page is intentionally simple.
|
||||||
|
<br />
|
||||||
|
The product is the automation, not the UI.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</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>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue