Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# .env is gitignored.

CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_DATABASE_ID=
CLOUDFLARE_PRODUCTION_DATABASE_ID=
CLOUDFLARE_STAGING_DATABASE_ID=
CLOUDFLARE_D1_TOKEN=
52 changes: 52 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,55 @@ jobs:
run: bun run lint:types
- name: build
run: bun run build
deploy-production:
needs: lint
if: github.ref == 'refs/heads/production' && github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: bun
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3
with:
bun-version: 1.3.8
- name: install
run: bun install
- name: migrate
run: bun run db:migrate:prod
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: build
run: bun run build
- name: deploy
run: bun run wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
deploy-staging:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/staging' && github.event_name == 'push'
steps:
Comment on lines +52 to +55
Copy link

Copilot AI Feb 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deploy-staging does not depend on the lint job, so it can deploy even when lint/typecheck/build fails (jobs run in parallel by default). Add needs: lint (and/or gate with if: success()) to prevent deploying broken commits to staging.

Copilot uses AI. Check for mistakes.
- name: checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: bun
uses: oven-sh/setup-bun@3d267786b128fe76c2f16a390aa2448b815359f3
with:
bun-version: 1.3.8
- name: install
run: bun install
- name: migrate
run: bun run db:migrate:staging
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
- name: build
run: bun run build
- name: deploy
run: bun run wrangler deploy --env staging
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
6 changes: 0 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,3 @@ logs
# Gemini
.gemini/

# AI context
AGENTS.md
CLAUDE.md
GEMINI.md
WARP.md
.github/copilot-instructions.md
2 changes: 1 addition & 1 deletion .trunk/trunk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ lint:
- markdownlint@0.47.0
- prettier@3.8.1
- taplo@0.10.0
- trufflehog@3.92.5
- trufflehog@3.93.1
- yamllint@1.38.0
ignore:
- linters:
Expand Down
94 changes: 94 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Agent Guide for Affirm

This document outlines the development workflow, commands, and patterns for working in this codebase.

## Project Overview

- **Framework**: Nuxt 4 (Vue 3)
- **Runtime**: Cloudflare Workers (Compatibility Date: 2026-02-01)
- **Database**: Cloudflare D1 (SQLite) with Drizzle ORM
- **Package Manager**: Bun
- **Styling**: Tailwind CSS v4 + DaisyUI
- **Tooling**: Trunk (lint/format), Vitest (testing), Playwright (e2e)

## Essential Commands

### Development

- **Start Dev Server**: `bun run dev` (Runs Nuxt dev server with Cloudflare binding proxies)
- **Lint & Fix**: `bun run lint:fix` (Runs ESLint and Trunk)
- **Format**: `bun run format` (Runs Prettier and Trunk)
- **Type Check**: `bun run lint:types`

### Database (Drizzle & D1)

- **Generate Migrations**: `bun run db:generate` (Run after changing `server/database/schema.ts`)
- **Migrate Local**: `bun run db:migrate` (Applies migrations to local D1 instance)
- **Migrate Staging**: `bun run db:migrate:staging` (Applies to `affirm-staging` DB)
- **Migrate Production**: `bun run db:migrate:prod` (Applies to `affirm` DB)
- **Drizzle Studio**:
- Staging: `bun run db:studio:staging`
- Production: `bun run db:studio:prod`

### Testing

- **Run All Tests**: `bun run test`
- **Unit Tests**: `bun run test:unit`
- **Nuxt Tests**: `bun run test:nuxt`
- **E2E Tests**: `bun run test:e2e` (Playwright)

### Deployment

- **Deploy to Production**: `bun run deploy`
- **Deploy to Staging**: `bun run deploy:nonprod` (Uploads versions without immediate promotion)

## Code Structure

- **`app/`**: Nuxt 4 application source (pages, components, composables).
- **`server/`**: Server-side logic (Nitro).
- **`server/database/`**: Drizzle schema and migrations.
- **`server/utils/db.ts`**: Database connection utility (`useDB`).
- **`server/api/`**: API event handlers.
- **`shared/`**: Shared utilities between client and server.
- **`.trunk/`**: Configuration for Trunk (linter/formatter manager).

## Database Patterns

### Schema Definition

Define tables in `server/database/schema.ts` using `drizzle-orm/sqlite-core`.

```typescript
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";

export const users = sqliteTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
});
```

### Accessing Database

Use the `useDB` utility in server routes. It uses the `DB` binding from the request context.

```typescript
import { useDB } from "../utils/db";

export default defineEventHandler(async (event) => {
const db = useDB(event);
return await db.query.users.findMany();
});
```

## Configuration

- **`nuxt.config.ts`**: Main Nuxt configuration.
- **`wrangler.jsonc`**: Cloudflare Workers configuration. Defines `DB` bindings for `prod` and `staging` environments.
- **`drizzle.config.ts`**: Drizzle Kit configuration.

## Gotchas & Guidelines

1. **Environment Variables**: Managed via `wrangler.jsonc` bindings for runtime. For local dev, `.dev.vars` is used.
2. **Migrations**: Always run `bun run db:generate` after modifying schema. Do not modify SQL files manually.
3. **Bindings**: The application relies on Cloudflare bindings (`DB`, `ASSETS`). Ensure `bun run dev` is used to properly proxy these during development.
4. **Imports**: Use `~` alias for project root (e.g., `~/server/utils/db`).
1 change: 1 addition & 0 deletions CLAUDE.md
23 changes: 23 additions & 0 deletions PROMPTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Prompts

---

## Database Workflows

We need to use Drizzle affixed to the Cloudflare Workers `DB` binding instead of connecting separately, so we can benefit from automatic environment mocking and set up a staging environment.

Currently, we set up an authentication token, configure the account ID, and other related settings in `.env`, but instead, we want to use the Cloudflare Workers binding. We also want to set up a staging database. The staging branch doesn't currently exist, but it will be `staging`. We will also have a staging database at `affirm-staging`. We also need to handle the `MiniFlare` environment, which is mocked locally.

We need to come up with a system of keeping these environments separate and providing developer tooling to access them while defaulting to the locally mocked `MiniFlare` environment, which should be automatically provided by Wrangler if we use the binding rather than manual configuration.

Come up with a way of doing this and implement it.

You can use the Cloudflare Documentation tool for Cloudflare information. Also use the Context7 tool to research Drizzle.

Also implement a GitHub Action which will take the migrations through from local (no CI), staging on the `staging` branch which does not exist yet, to staging db, and production on the `main` branch.

Set up scripts in `package.json` to make things smoother. Include a script for Drizzle Studio.

Document it in `README.md`, including Mermaid diagrams where appropriate, and then implement it. Include step-by-step guides to creating a migration, applying it, following through the lifecycle, and troubleshooting. No need to maintain any agent-facing documentation, just human-facing.

---
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ This project follows the **Nuxt 4** directory structure (source in `app/`).
- **`assets/`**: CSS and static assets (Tailwind entry point).
- **`server/`**: Nitro server backend.
- **`api/`**: API endpoints (e.g., `/api/hello`).
- **`database/`**: Drizzle schema and migrations.
- **`utils/`**: Auto-imported server utilities (e.g., `useDB`).
- **`shared/`**: Code shared between client and server.
- **`public/`**: Static files served at root (favicon, robots.txt).

Expand Down
Loading
Loading