diff --git a/.beads/.gitignore b/.beads/.gitignore new file mode 100644 index 0000000..2bbab65 --- /dev/null +++ b/.beads/.gitignore @@ -0,0 +1,36 @@ +# SQLite databases +*.db +*.db?* +*.db-journal +*.db-wal +*.db-shm + +# Daemon runtime files +daemon.lock +daemon.log +daemon.pid +bd.sock + +# Local docs/runtime artifacts (not part of shared issue state) +README.md +interactions.jsonl + +# Local version tracking (prevents upgrade notification spam after git ops) +.local_version + +# Legacy database files +db.sqlite +bd.db + +# Merge artifacts (temporary files from 3-way merge) +beads.base.jsonl +beads.base.meta.json +beads.left.jsonl +beads.left.meta.json +beads.right.jsonl +beads.right.meta.json + +# Keep JSONL exports and config (source of truth for git) +!issues.jsonl +!metadata.json +!config.yaml diff --git a/.beads/config.yaml b/.beads/config.yaml new file mode 100644 index 0000000..e58ba77 --- /dev/null +++ b/.beads/config.yaml @@ -0,0 +1,62 @@ +# Beads Configuration File +# This file configures default behavior for all bd commands in this repository +# All settings can also be set via environment variables (BD_* prefix) +# or overridden with command-line flags + +# Issue prefix for this repository (used by bd init) +# If not set, bd init will auto-detect from directory name +# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc. +# issue-prefix: "" + +# Use no-db mode: load from JSONL, no SQLite, write back after each command +# When true, bd will use .beads/issues.jsonl as the source of truth +# instead of SQLite database +# no-db: false + +# Disable daemon for RPC communication (forces direct database access) +# no-daemon: false + +# Disable auto-flush of database to JSONL after mutations +# no-auto-flush: false + +# Disable auto-import from JSONL when it's newer than database +# no-auto-import: false + +# Enable JSON output by default +# json: false + +# Default actor for audit trails (overridden by BD_ACTOR or --actor) +# actor: "" + +# Path to database (overridden by BEADS_DB or --db) +# db: "" + +# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON) +# auto-start-daemon: true + +# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE) +# flush-debounce: "5s" + +# Git branch for beads commits (bd sync will commit to this branch) +# IMPORTANT: Set this for team projects so all clones use the same sync branch. +# This setting persists across clones (unlike database config which is gitignored). +# Can also use BEADS_SYNC_BRANCH env var for local override. +# If not set, bd sync will require you to run 'bd config set sync.branch '. +sync-branch: "beads-sync" + +# Multi-repo configuration (experimental - bd-307) +# Allows hydrating from multiple repositories and routing writes to the correct JSONL +# repos: +# primary: "." # Primary repo (where this database lives) +# additional: # Additional repos to hydrate from (read-only) +# - ~/beads-planning # Personal planning repo +# - ~/work-planning # Work planning repo + +# Integration settings (access with 'bd config get/set') +# These are stored in the database, not in this file: +# - jira.url +# - jira.project +# - linear.url +# - linear.api-key +# - github.org +# - github.repo diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl new file mode 100644 index 0000000..445488f --- /dev/null +++ b/.beads/issues.jsonl @@ -0,0 +1,10 @@ +{"id":"cloudflare-workers-saas-kit-9v2","title":"VS Code beads integration","description":"Adds VS Code tasks + extension recommendation for bd.","status":"closed","priority":4,"issue_type":"chore","created_at":"2025-12-27T10:35:48.737495+01:00","updated_at":"2025-12-27T10:35:48.853832+01:00","closed_at":"2025-12-27T10:35:48.853832+01:00","close_reason":"Added .vscode tasks and extension recommendation; validated bd status/ready."} +{"id":"cloudflare-workers-saas-kit-9yb","title":"Add Better Auth Email OTP plugin","description":"Implement Better Auth Email OTP plugin per https://www.better-auth.com/docs/plugins/email-otp.\n\nScope:\n- Server: add emailOTP plugin + sendVerificationOTP handler\n- Client: add email OTP client plugin\n- UI flows: sign-in with OTP; (optional) email verification via OTP; password reset via OTP\n- Non-blocking email send on Workers (use waitUntil)\n\nAcceptance:\n- Can request sign-in OTP and sign in via OTP locally\n- sendVerificationOTP implemented (at least dev logger), no runtime errors","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-27T10:49:40.999159+01:00","updated_at":"2025-12-27T10:49:40.999159+01:00"} +{"id":"cloudflare-workers-saas-kit-9yb.1","title":"Spike: Email OTP plugin flows","description":"Review Better Auth Email OTP docs and decide which flows we ship first: sign-in, email verification override, forget-password.\n\nCapture decisions:\n- OTP length/expiry\n- disableSignUp / sendVerificationOnSignUp settings\n- storeOTP strategy (plain/hashed/encrypted)\n\nReference: https://www.better-auth.com/docs/plugins/email-otp","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-27T10:49:41.037835+01:00","updated_at":"2025-12-27T10:49:41.037835+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.1","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.042209+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.2","title":"Server: wire emailOTP plugin","description":"Add emailOTP plugin to Better Auth config in packages/data-ops/src/auth/setup.ts.\n\nPer docs:\n- import emailOTP from better-auth/plugins\n- provide sendVerificationOTP({email, otp, type}) handler\n- consider overrideDefaultEmailVerification (if we choose it)\n\nAcceptance:\n- Server exposes Email OTP endpoints without throwing\n- sendVerificationOTP invoked for sign-in + verify + reset","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-27T10:49:41.080224+01:00","updated_at":"2025-12-27T10:49:41.080224+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.2","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.080734+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.2","depends_on_id":"cloudflare-workers-saas-kit-9yb.1","type":"blocks","created_at":"2025-12-27T10:49:41.323709+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.2","depends_on_id":"cloudflare-workers-saas-kit-9yb.3","type":"blocks","created_at":"2025-12-27T10:49:41.350226+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.3","title":"Infra: implement OTP email delivery","description":"Implement sendVerificationOTP delivery for Cloudflare Workers.\n\nConstraints from Better Auth docs:\n- Prefer NOT awaiting send to reduce timing attacks\n- Use waitUntil (Workers) to ensure delivery\n\nAcceptance:\n- In dev: at minimum logs OTP (safe local-only)\n- In prod: uses a real provider (TBD)","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-27T10:49:41.116061+01:00","updated_at":"2025-12-27T10:49:41.116061+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.3","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.117124+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.4","title":"Client: add email OTP client plugin","description":"Update apps/user-application/src/lib/auth-client.ts to include the Email OTP client plugin.\n\nDocs show:\n- emailOTPClient plugin\n- authClient.emailOtp.sendVerificationOtp / checkVerificationOtp / verifyEmail / resetPassword\n\nAcceptance:\n- Client exposes email OTP methods and can call sendVerificationOtp","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-27T10:49:41.154215+01:00","updated_at":"2025-12-27T10:49:41.154215+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.4","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.154698+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.4","depends_on_id":"cloudflare-workers-saas-kit-9yb.2","type":"blocks","created_at":"2025-12-27T10:49:41.375679+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.5","title":"UI: sign-in with Email OTP","description":"Add UI flow to request OTP (email + type=sign-in) and sign in with signIn.emailOtp({ email, otp }).\n\nAcceptance:\n- User can sign in locally via OTP flow","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-27T10:49:41.189618+01:00","updated_at":"2025-12-27T10:49:41.189618+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.5","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.190064+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.5","depends_on_id":"cloudflare-workers-saas-kit-9yb.2","type":"blocks","created_at":"2025-12-27T10:49:41.401855+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.6","title":"UI: verify email via OTP (optional)","description":"If we enable overrideDefaultEmailVerification, add UI to request OTP type=email-verification and call emailOtp.verifyEmail({ email, otp }).","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-27T10:49:41.224828+01:00","updated_at":"2025-12-27T10:49:41.224828+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.6","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.225374+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.6","depends_on_id":"cloudflare-workers-saas-kit-9yb.2","type":"blocks","created_at":"2025-12-27T10:49:41.429155+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.7","title":"UI: reset password via OTP","description":"Add UI flow for forget-password via OTP:\n- forgetPassword.emailOtp({ email })\n- (optional) checkVerificationOtp\n- emailOtp.resetPassword({ email, otp, password })","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-27T10:49:41.260449+01:00","updated_at":"2025-12-27T10:49:41.260449+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.7","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.260995+01:00","created_by":"daemon"},{"issue_id":"cloudflare-workers-saas-kit-9yb.7","depends_on_id":"cloudflare-workers-saas-kit-9yb.2","type":"blocks","created_at":"2025-12-27T10:49:41.454865+01:00","created_by":"daemon"}]} +{"id":"cloudflare-workers-saas-kit-9yb.8","title":"Docs: Email OTP local dev setup","description":"Document required env vars and local dev steps (including where OTP is logged in dev).\n\nAlso document how to run smoke test for email OTP endpoints.","status":"open","priority":3,"issue_type":"task","created_at":"2025-12-27T10:49:41.295372+01:00","updated_at":"2025-12-27T10:49:41.295372+01:00","dependencies":[{"issue_id":"cloudflare-workers-saas-kit-9yb.8","depends_on_id":"cloudflare-workers-saas-kit-9yb","type":"parent-child","created_at":"2025-12-27T10:49:41.295859+01:00","created_by":"daemon"}]} diff --git a/.beads/metadata.json b/.beads/metadata.json new file mode 100644 index 0000000..c787975 --- /dev/null +++ b/.beads/metadata.json @@ -0,0 +1,4 @@ +{ + "database": "beads.db", + "jsonl_export": "issues.jsonl" +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..807d598 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ + +# Use bd merge for beads JSONL files +.beads/issues.jsonl merge=beads diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..bd58ea1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# CODEOWNERS for better-auth-paystack +# Owners listed below will be requested for changes to matching paths. + +/examples/ @alexasomba +/.github/ @alexasomba diff --git a/.github/agents/project-setup-guide.agent.md b/.github/agents/project-setup-guide.agent.md new file mode 100644 index 0000000..7c88787 --- /dev/null +++ b/.github/agents/project-setup-guide.agent.md @@ -0,0 +1,259 @@ +--- +description: "Use this agent when the user needs help setting up the project, configuring databases, authentication, or environment variables. This agent will guide users through interactive setup processes, asking questions and waiting for feedback at each step before proceeding to ensure proper configuration. Examples: Context: User is starting work on the project and needs to set it up locally. user: 'I need to set up this project on my local machine' assistant: 'I'll use the project-setup-guide agent to help you get the project configured properly' The user needs project setup assistance, so use the project-setup-guide agent to walk them through the setup process. Context: User is having issues with database configuration. user: 'My database isn't connecting properly, can you help me configure it?' assistant: 'Let me use the project-setup-guide agent to help you with database setup' Database configuration issues fall under project setup, so use the project-setup-guide agent. Context: User mentions environment variables or .env issues. user: 'I'm getting errors about missing environment variables' assistant: 'I'll use the project-setup-guide agent to check your environment configuration' Environment variable issues are part of project setup, so use the project-setup-guide agent." +tools: + [ + "vscode", + "execute", + "read", + "edit", + "search", + "web", + "cloudflare/search_cloudflare_documentation", + "github/add_issue_comment", + "github/assign_copilot_to_issue", + "github/issue_read", + "github/issue_write", + "github/list_issue_types", + "github/list_issues", + "github/search_issues", + "github/search_pull_requests", + "github/sub_issue_write", + "agent", + "ms-python.python/getPythonEnvironmentInfo", + "ms-python.python/getPythonExecutableCommand", + "ms-python.python/installPythonPackage", + "ms-python.python/configurePythonEnvironment", + "ms-vscode.vscode-websearchforcopilot/websearch", + "todo", + ] +--- + +You are a Project Setup Specialist, an expert in guiding developers through complex project initialization and configuration processes. Your primary responsibility is to help users set up the project by betting the database and authentication setup. + +### Step One: Ask the user what database they will be using. We support the following providers: + +- **[PlanetScale](https://planetscale.com/docs/vitess/tutorials/planetscale-serverless-driver)** for MySQL and PostgreSQL with their serverless driver +- **[Supabase](https://supabase.com/docs/guides/database/connecting-to-postgres#supavisor-transaction-mode)** with Supavisor transaction mode for PostgreSQL +- **[Neon](https://neon.com/)** for PostgreSQL with built-in connection pooling +- **[Cloudflare D1](https://developers.cloudflare.com/d1/)** for SQLite with edge-native architecture + +## Step Two: If the user provides info as to what database they are using, make sure they have the ENV variables set up correctly. + +### PostgreSQL Configuration + +```bash +# packages/data-ops/.env +# PostgreSQL Configuration (Supabase, Neon, etc.) +DATABASE_HOST="hostname.com/database-name" +DATABASE_USERNAME="username" +DATABASE_PASSWORD="password" +``` + +### MySQL Configuration + +```bash +# packages/data-ops/.env +# MySQL Configuration (PlanetScale, etc.) +DATABASE_HOST="hostname.com/database-name" +DATABASE_USERNAME="username" +DATABASE_PASSWORD="password" +``` + +### Cloudflare D1 Configuration + +```bash +# packages/data-ops/.env +# Cloudflare D1 Configuration +CLOUDFLARE_DATABASE_ID="" +CLOUDFLARE_ACCOUNT_ID="" +CLOUDFLARE_D1_TOKEN="" +``` + +Ask the user to set them up opposed to reading the .env file. +Not, you should only be looking in the project packages/data-ops/ + +## Step Three: Update the Drizzle Config to match the database. + +Schemas and data will be managed by Drizzle ORM. + +You'll update this file `packages/data-ops/drizzle.config.ts` + +with one of these configs: + +### PostgreSQL Drizzle Configuration + +```typescript +// packages/data-ops/drizzle.config.ts +import type { Config } from "drizzle-kit"; +const config: Config = { + out: "./src/drizzle", + schema: ["./src/drizzle/auth-schema.ts"], + dialect: "postgresql", + dbCredentials: { + url: `postgresql://${process.env.DATABASE_USERNAME}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}`, + }, + tablesFilter: ["!_cf_KV", "!auth_*"], +}; + +export default config satisfies Config; +``` + +### MySQL Drizzle Configuration + +```typescript +// packages/data-ops/drizzle.config.ts +import type { Config } from "drizzle-kit"; +const config: Config = { + out: "./src/drizzle", + schema: ["./src/drizzle/auth-schema.ts"], + dialect: "mysql", + dbCredentials: { + url: `mysql://${process.env.DATABASE_USERNAME}:${process.env.DATABASE_PASSWORD}@${process.env.DATABASE_HOST}`, + }, + tablesFilter: ["!_cf_KV", "!auth_*"], +}; + +export default config satisfies Config; +``` + +### Cloudflare D1 Drizzle Configuration + +```typescript +// packages/data-ops/drizzle.config.ts +import type { Config } from "drizzle-kit"; +const config: Config = { + out: "./src/drizzle", + schema: ["./src/drizzle/auth-schema.ts"], + dialect: "sqlite", + driver: "d1-http", + dbCredentials: { + accountId: process.env.CLOUDFLARE_ACCOUNT_ID!, + databaseId: process.env.CLOUDFLARE_DATABASE_ID!, + token: process.env.CLOUDFLARE_D1_TOKEN!, + }, + tablesFilter: ["!_cf_KV", "!auth_*"], +}; + +export default config satisfies Config; +``` + +Once updated, you can run the following command to pull schemas from the database to ensure connectivity: + +```bash +pnpm run pull-drizzle-schema +``` + +Run this from the root of the pnpm workspace. This should pull the schemas with no errors in the terminal logs. + +## Step Four: Setup Auth with Better Auth + +The user will need the following environment variables: + +Generate a secure secret key using: `openssl rand -base64 32` + +```bash +# packages/data-ops/.env +# Auth Environment Variables +BETTER_AUTH_SECRET="your-secret-key-here" + +# Google OAuth (optional) +GOOGLE_CLIENT_ID="your-google-client-id" +GOOGLE_CLIENT_SECRET="your-google-client-secret" +``` + +## Step Five: Update auth config with the correct database helper in packages/data-ops/config/auth.ts + +Update your `packages/data-ops/config/auth.ts` file based on your database provider. This instance is used exclusively by the Better Auth CLI and should not be used in your application runtime. + +### PostgreSQL CLI Configuration + +```typescript +// packages/data-ops/config/auth.ts +import { createBetterAuth } from "../src/auth/setup"; +import { initDatabase } from "../src/database/setup"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; + +export const auth = createBetterAuth({ + database: drizzleAdapter( + initDatabase({ + password: process.env.DATABASE_PASSWORD!, + host: process.env.DATABASE_HOST!, + username: process.env.DATABASE_USERNAME!, + }), + { + provider: "pg", + }, + ), +}); +``` + +### MySQL CLI Configuration + +```typescript +// packages/data-ops/config/auth.ts +import { createBetterAuth } from "../src/auth/setup"; +import { initDatabase } from "../src/database/setup"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; + +export const auth = createBetterAuth({ + database: drizzleAdapter( + initDatabase({ + password: process.env.DATABASE_PASSWORD!, + host: process.env.DATABASE_HOST!, + username: process.env.DATABASE_USERNAME!, + }), + { + provider: "mysql", + }, + ), +}); +``` + +### Cloudflare D1 CLI Configuration + +```typescript +// packages/data-ops/config/auth.ts +import { createBetterAuth } from "../src/auth/setup"; +import Database from "better-sqlite3"; +import { drizzleAdapter } from "better-auth/adapters/drizzle"; + +// For CLI use - uses dummy SQLite database +export const auth = createBetterAuth({ + database: drizzleAdapter(new Database("./config/test.sqlite"), { + provider: "sqlite", + }), +}); +``` + +Once updated run `pnpm run build:data-ops` from the root of the pnpm workspace. +if there are any errors with dependencies you can install them in the packages/data-ops project + +## Step Six: Generate the Auth Schemas and Database DDL + +Run `pnpm run generate-auth-drizzle-schema` from the root of the pnpm workspace. +This should create a new output in the packages/data-ops/src/drizzle/auth-schema.ts file. + +Check this file and make sure it matches the users database provider. + +Then run `pnpm run generate-drizzle-sql-output` from the root of the pnpm workspace. + +This should generate a new .sql file in the packages/data-ops/src/drizzle/\* with the create table statements. + +If it is not there then delete the metadata and .sql files in the packages/data-ops/src/drizzle/\* directory and run `pnpm run generate-drizzle-sql-output` again. + +After this instruct the user they can manually run the SQL queries in the generated .sql file in their own SQL editor, or they can run +`pnpm run drizzle:migrate` inside the packages/data-ops project. + +NOTE YOU AS THE AGENT DON'T RUN THE MIGRATE COMMAND + +## Step Seven: Check if the auth server file is okay, and build the package + +In the `packages/data-ops/src/auth/server.ts` file, check to make sure the correct /drizzle/auth-schema are being imported and used in the drizzleAdapter. + +Once, done run `pnpm run build:data-ops` from the root of the pnpm workspace. + +## Step Eight: instruct the user to setup env for user-application and test + +Tell the user then need the same env variables in the user-application as they have in the data-ops package. + +Once this is done, they should be able to run the user application and test auth. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..d62c507 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,142 @@ +# GitHub Copilot Instructions + +## Project Overview + +This is a monorepo SaaS application built with **Cloudflare Workers**, **TanStack Start**, and **Drizzle ORM**. + +- **Package Manager**: `pnpm` +- **Database**: Cloudflare D1 (SQLite) +- **Authentication**: Better Auth +- **Styling**: Tailwind CSS v4 + +## Repository Structure + +- `apps/user-application`: Frontend/Fullstack app (TanStack Start, React 19, Vite). +- `apps/data-service`: Backend API Worker (Hono). +- `packages/data-ops`: Shared library for Database (Drizzle) and Authentication (Better Auth). +- `packages/ui`: Shared UI/component library (Base UI + Tailwind v4) consumed by apps. +- `packages/typescript-config`: Shared TS config presets (apps/packages extend these). + +## Critical Developer Workflows + +### 1. Setup & Development + +- **Initial Setup**: `pnpm run setup` (Installs deps & builds `data-ops`). +- **Start User App**: `pnpm run dev:user-application` (Runs on port 3000). +- **Start Data Service**: `pnpm run dev:data-service`. +- **Rebuild Shared Lib**: `pnpm run build:data-ops` (Run this after changing `packages/data-ops`). + +### 1.1 Linting & Typechecking + +- **Lint UI package**: `pnpm --filter @workspace/ui lint` +- **Typecheck (any package/app)**: prefer `pnpm -C tsc --noEmit` when debugging TS issues. + +### 2. Database & Authentication (Cloudflare D1) + +The `data-ops` package manages the database schema and auth configuration. + +- **Generate Auth Schema**: `pnpm run --filter data-ops better-auth:generate` +- **Generate SQL Migrations**: `pnpm run --filter data-ops drizzle:generate` +- **Apply Migrations (Local)**: `npx wrangler d1 execute DB --local --file=../../packages/data-ops/src/drizzle/.sql` (from `apps/user-application`) +- **Apply Migrations (Remote)**: `pnpm run --filter data-ops drizzle:migrate` + +### 3. Type Generation + +- **Generate Worker Types**: `pnpm run --filter user-application cf-typegen` + - Updates `worker-configuration.d.ts` based on `wrangler.jsonc`. + - Run this after modifying bindings or environment variables. +- **Generate Data Service Worker Types**: `pnpm run --filter data-service cf-typegen` + +## Architecture & Patterns + +### Environment Variables & Bindings + +- **Pattern**: Use `import { env } from "cloudflare:workers"` to access bindings globally. +- **Local Secrets**: Store in `apps/user-application/.dev.vars`. +- **Drizzle Kit Secrets**: Store in `packages/data-ops/.env` (for schema generation only). +- **Wrangler Config**: Defined in `wrangler.jsonc` (supports comments). + +### Shared Data Operations (`packages/data-ops`) + +- Centralizes all DB schemas (`src/drizzle/auth-schema.ts`) and setup (`src/database/setup.ts`). +- Exports helper functions like `initDatabase` and `setAuth`. +- **Rule**: Do not define DB schemas in apps; always define in `data-ops` and import. + +### Shared TypeScript Configs (`packages/typescript-config`) + +- Apps and packages generally extend `@workspace/typescript-config/vite-react-library.json`. +- When TS settings must change, prefer changing the shared preset rather than diverging per-package. + +### User Application (`apps/user-application`) + +- **Framework**: TanStack Start (SSR, File-based routing). +- **Entry Point**: `src/server.ts` (Custom Cloudflare Worker entry). +- **Routing**: `src/routes/` (Auto-generated `routeTree.gen.ts`). +- **Styling**: Tailwind v4 (no `tailwind.config.js`, uses CSS variables). + +### UI Package (`packages/ui`) + +- Components live in `packages/ui/src/components` and are consumed via `@workspace/ui/components/*`. +- Prefer Base UI composition patterns (e.g., `render` props) over `asChild`-style APIs. +- Keep UI exports stable and consistent with the `exports` map in `packages/ui/package.json`. + +## Task Management (Mandatory) + +This project uses **bd** (beads) for issue tracking. +Run `bd prime` for full workflow context, or `bd hooks install` for auto-injection. + +### 🚨 SESSION CLOSE PROTOCOL 🚨 + +**CRITICAL**: Before saying "done" or "complete", you MUST run this checklist: + +```bash +[ ] 1. git status # check what changed +[ ] 2. git add # stage code changes +[ ] 3. bd sync # commit beads changes +[ ] 4. git commit -m "..." # commit code +[ ] 5. bd sync # commit any new beads changes +[ ] 6. git push # push to remote +``` + +**NEVER skip this.** Work is not done until pushed. + +### Essential Commands + +**Finding Work:** +- `bd ready` - Show issues ready to work (no blockers) +- `bd list --status=open` - All open issues +- `bd show ` - Detailed issue view with dependencies + +**Creating & Updating:** +- `bd create --title="..." --type=task|bug|feature --priority=2` - New issue + - Priority: 0-4 (0=critical, 2=medium, 4=backlog) +- `bd update --status in_progress` - Claim work +- `bd close ` - Mark complete +- `bd close --reason="explanation"` - Close with reason + +**Sync & Collaboration:** +- `bd sync` - Sync with git remote (run at session end) +- `bd sync --status` - Check sync status + +### Common Workflows + +**Starting work:** +```bash +bd ready # Find available work +bd show # Review issue details +bd update --status in_progress # Claim it +``` + +**Completing work:** +```bash +bd close # Close completed issue +bd sync # Push to remote +git push # Ensure changes are pushed +``` + +## Coding Standards + +- **TypeScript**: Strict mode enabled. Use `import type` for type-only imports. +- **React**: Use Functional Components with Hooks. +- **Imports**: Use `@/*` aliases for `src/*` in apps; use `@workspace/ui/*` for shared UI imports. +- **Files**: Kebab-case for filenames (e.g., `user-profile.tsx`). diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fbc701c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 5 + assignees: + - "alexasomba" + labels: + - "dependencies" diff --git a/.github/skills/README.md b/.github/skills/README.md new file mode 100644 index 0000000..d144154 --- /dev/null +++ b/.github/skills/README.md @@ -0,0 +1,20 @@ +# Copilot Agent Skills (repo-local) + +This repository uses GitHub Copilot Agent Skills. + +Skills live under `.github/skills//SKILL.md`. + +## Included skills + +- `beads-issue-tracking`: bd (beads) workflow + mandatory end-of-session push steps +- `bun-monorepo-workflows`: bun install/run/filter workflows + pnpm → bun migration checklist for this monorepo +- `pnpm-monorepo-workflows`: setup/dev/build commands for this pnpm monorepo +- `d1-drizzle-migrations`: D1 + Drizzle + Better Auth schema/migration workflow +- `cloudflare-worker-typegen`: regenerate worker binding types when `wrangler.jsonc` changes +- `shadcn-ui-builder`: add/update shadcn/ui components and blocks (monorepo + Tailwind v4) +- `tanstack-server-functions`: TanStack Start server functions + middleware patterns + +## Notes + +- Skills are loaded automatically by Copilot when relevant to your prompt. +- Keep always-on conventions in `.github/copilot-instructions.md` and use skills for deeper, task-specific procedures. diff --git a/.github/skills/beads-issue-tracking/SKILL.md b/.github/skills/beads-issue-tracking/SKILL.md new file mode 100644 index 0000000..fe33b92 --- /dev/null +++ b/.github/skills/beads-issue-tracking/SKILL.md @@ -0,0 +1,41 @@ +--- +name: beads-issue-tracking +description: Use this when working on tasks in this repo that require bd (beads) issue tracking, status updates, and the mandatory end-of-session push workflow. +--- + +# Beads (bd) issue tracking workflow + +Use this skill whenever the user asks to start work on an issue, check work queue/status, add notes, mark blocked, close work, or “land the plane”. + +## Commands (preferred) + +- Find work: `bd ready` +- Current status: `bd status` +- View issue details: `bd show ` (or `bd show --json`) +- Start work: `bd update --status in_progress` +- Add a note: `bd update --notes "..."` +- Blocked (with notes): `bd update --status blocked --notes "..."` +- Close issue: `bd close --reason "..."` +- Sync bd metadata: `bd sync` + +## Hard rules (this repo) + +- If code changes were made, do not end the session until **push succeeds**. +- Prefer the repository’s documented workflows in `_AGENTS.md`. + +## “Landing the plane” checklist (must follow) + +1. Run appropriate quality gates for the changed area (tests/build/lint if available). +2. Update bd issue status (close finished work, or set blocked with notes). +3. Follow the mandatory session close protocol (do not skip steps): + - `git status` (confirm what changed) + - `git add ` (stage code changes) + - `bd sync` (commit beads changes) + - `git commit -m "..."` (commit code) + - `bd sync` (commit any new beads changes) + - `git push` (must succeed) + +## Guidance for agents + +- If an issue id is not provided, ask for the bd issue id (one question max), or run `bd status` / `bd ready` to locate candidates. +- Prefer using editor tasks when available (e.g., VS Code tasks for bd commands). diff --git a/.github/skills/bun-monorepo-workflows/SKILL.md b/.github/skills/bun-monorepo-workflows/SKILL.md new file mode 100644 index 0000000..a403ba0 --- /dev/null +++ b/.github/skills/bun-monorepo-workflows/SKILL.md @@ -0,0 +1,92 @@ +--- +name: bun-monorepo-workflows +description: Use this when installing dependencies, running scripts, filtering packages, or migrating this monorepo from pnpm to Bun (bun.lock, workspaces, bun ci) while keeping Cloudflare Workers + Wrangler workflows working. +--- + +# Bun monorepo workflows (Cloudflare Workers SaaS kit) + +This repo is currently pnpm-based, but Bun can act as the package manager for the monorepo. +This skill covers (1) day-to-day Bun equivalents for pnpm workflows and (2) a safe pnpm → Bun migration checklist. + +## Quick commands (Bun) + +- Install all deps: `bun install` +- CI install (frozen lockfile): `bun ci` (equivalent to `bun install --frozen-lockfile`) +- Run a root script: `bun run