Provision Neon, R2 and Better Auth
1. The database — Neon
- Create a Neon project. Pick the region nearest to where you will deploy.
- Copy the pooled connection string. It starts with
postgresql://and ends with?sslmode=require. - Put it in
.envasDATABASE_URL.
Create the tables, then the reference data:
bun run db:migrate
bun run db:seed
The seed can run as often as you like. It inserts six categories and the 230 countries, and it never duplicates a row.
2. Receipt storage — Cloudflare R2
- In Cloudflare, open R2 and create a bucket, for example
travole-receipts. Keep it private. - Create an R2 API token with Object Read & Write on that bucket.
- Cloudflare shows the token’s credentials once. Copy them now.
Two traps here, both seen in real installs:
R2_ACCESS_KEY_IDis the token’s Access Key ID — 32 hexadecimal characters. It is not the long token value. With the wrong one, every call fails withCredential access key has length 53, should be 32.- A read-only token lists the bucket fine and then refuses every upload with
403 AccessDenied. Check the permission before you debug the code.
R2_ACCOUNT_ID=<your Cloudflare account id>
R2_ACCESS_KEY_ID=<32 hex characters>
R2_SECRET_ACCESS_KEY=<the secret shown with it>
R2_BUCKET=travole-receipts
3. Authentication — Better Auth
Better Auth needs a secret to sign sessions. Generate one:
openssl rand -base64 32
BETTER_AUTH_SECRET=<the output>
BETTER_AUTH_URL=http://localhost:3000
4. Who may create an account
Travole is closed by default. The first account is created through a bootstrap door, and that door closes by itself the moment it is used. Everyone after that needs an invitation.
AUTH_ALLOW_FIRST_USER=true
AUTH_ALLOW_SIGNUP=false
AUTH_ALLOW_INVITATIONS=true
AUTH_ALLOWED_EMAIL=<your email>
Only the exact string true means true. 1, yes and TRUE all mean false. A lenient parser
would turn a typo into an open registration page.
5. Check it locally
bun run dev
Open http://localhost:3000/signup and create your account with the address you put in
AUTH_ALLOWED_EMAIL. You are now the admin. Create a trip, add one expense with a PDF receipt,
and download it again. If all three work, every service is wired correctly.
Check what you read in “Provision Neon, R2 and Better Auth”
The questions are public; scoring them needs an account. They were generated once for this step, and the key never leaves the server.
Loading the check…