From cdd067fdf4d1f46d190801c1c923d557e678c6aa Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:13:10 +0100 Subject: [PATCH 01/16] Add CLAUDE.md guidance and Claude skills documentation Added CLAUDE.md files to the root and template/app directories to provide guidance for Claude Code when working with the Open SaaS template. Introduced new Claude skills for migrating the database and starting the Wasp dev server, including troubleshooting docs. Updated wasp-overview.mdc with an Open SaaS overview section. --- CLAUDE.md | 259 ++++++++++++++++++ template/.claude/skills/migrating-db/SKILL.md | 24 ++ .../skills/migrating-db/troubleshooting.md | 17 ++ .../.claude/skills/starting-wasp/SKILL.md | 27 ++ .../skills/starting-wasp/troubleshooting.md | 20 ++ template/app/.cursor/rules/wasp-overview.mdc | 19 ++ template/app/CLAUDE.md | 235 ++++++++++++++++ 7 files changed, 601 insertions(+) create mode 100644 CLAUDE.md create mode 100644 template/.claude/skills/migrating-db/SKILL.md create mode 100644 template/.claude/skills/migrating-db/troubleshooting.md create mode 100644 template/.claude/skills/starting-wasp/SKILL.md create mode 100644 template/.claude/skills/starting-wasp/troubleshooting.md create mode 100644 template/app/CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..a7faa3096 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,259 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What is Open SaaS? + +**Open SaaS** is a free, open-source SaaS starter template built on top of the Wasp framework. It provides a production-ready foundation for building SaaS applications with essential features already implemented: + +- **Authentication** - Email verification + OAuth (Google, GitHub, Discord) +- **Payments** - Stripe and Lemon Squeezy integration with subscription management +- **Admin Dashboard** - User management and analytics +- **Email** - SendGrid, Mailgun, or SMTP support +- **File Uploads** - AWS S3 integration +- **Analytics** - Plausible or Google Analytics +- **AI Ready** - Example OpenAI integration with function calling +- **Documentation** - Astro Starlight blog and docs site +- **Testing** - Playwright E2E tests +- **Deployment** - One-command deploy to Railway or Fly.io + +Open SaaS follows best practices and conventions specific to building SaaS applications on Wasp. The template is designed to be customized and extended for your specific product needs. + +**Documentation:** +- Human-readable: https://docs.opensaas.sh +- LLM-optimized: https://docs.opensaas.sh/llms-full.txt + +## Repository Structure + +This is the **Open SaaS** monorepo, a full-stack SaaS template built with Wasp, React, Node.js, and Prisma. + +The repository is organized into three main directories: + +- **`template/`** - The core Open SaaS template distributed via `wasp new -t saas` + - `template/app/` - The main Wasp application + - `template/blog/` - Astro-based documentation and blog + - `template/e2e-tests/` - Playwright end-to-end tests + +- **`opensaas-sh/`** - Production deployment at https://opensaas.sh (built with Open SaaS itself) + - `opensaas-sh/app/` - Generated via `dope.sh` from template + diffs + - `opensaas-sh/app_diff/` - Versioned diffs applied to template + - `opensaas-sh/blog/` - Production docs and landing page + +- **`tools/`** - Development tooling including `dope.sh` for managing derived projects + +### Derived Project Management + +The `opensaas-sh` app is not directly versioned. Instead, only the **diffs** from the template are stored in `opensaas-sh/app_diff/`. Use `tools/dope.sh` to manage this: + +```bash +# Regenerate opensaas-sh/app/ from template + diffs (after template changes): +./tools/dope.sh template/app opensaas-sh/app patch + +# Update diffs after modifying opensaas-sh/app/: +./tools/dope.sh template/app opensaas-sh/app diff +``` + +## Working with the Wasp App + +Remember: LLM-optimized docs are always up-to-date at: https://wasp.sh/llms-full.txt +and: https://docs.opensaas.sh/llms-full.txt + +### Project Structure + +Wasp uses a declarative configuration file (`main.wasp`) to generate a full-stack application: + +- **`main.wasp`** - App configuration defining routes, pages, auth, operations, and more +- **`schema.prisma`** - Prisma database schema (defines entities) +- **`src/`** - Custom application code organized by feature: + - `src/auth/` - Authentication logic and pages + - `src/client/` - Shared client components and layout + - `src/payment/` - Stripe/Lemon Squeezy integration + - `src/user/` - User profile and settings + - `src/demo-ai-app/` - Example OpenAI integration + - `src/file-upload/` - AWS S3 file upload example + - `src/landing-page/` - Marketing landing page components + - `src/admin/` - Admin dashboard + - `src/server/` - Server utilities and scripts + - `src/shared/` - Code shared between client and server + +### Essential Commands + +```bash +# Development +wasp start # Start dev server (runs DB, server, and client) +wasp start db # Start only the managed development database +wasp db migrate-dev # Create and apply database migrations +wasp db studio # Open Prisma Studio to inspect database +wasp db seed # Run seed functions defined in main.wasp + +# Testing & Quality +wasp test # Run tests +npm run prettier:check # Check code formatting (root level) +npm run prettier:format # Format code (root level) + +# Production +wasp build # Generate production build +wasp deploy # Deploy to Railway or Fly.io + +# Maintenance +wasp clean # Delete generated code and caches (fixes most issues) +``` + +### Import Conventions (CRITICAL) + +**In TypeScript/TSX files (`.ts`/`.tsx`):** +- ✅ Wasp imports: `import { User } from 'wasp/entities'` +- ✅ Wasp operations: `import { useQuery } from 'wasp/client/operations'` +- ✅ Wasp types: `import type { GetTasks } from 'wasp/server/operations'` +- ✅ Prisma enum values: `import { SubscriptionStatus } from '@prisma/client'` +- ✅ Local code: Use relative paths like `import { Component } from './Component'` +- ❌ NEVER use `@wasp/...` prefix +- ❌ NEVER use `@src/...` in TypeScript files + +**In main.wasp file:** +- ✅ Your code: `fn: import { getTasks } from "@src/tasks/operations.ts"` +- ❌ NEVER use relative paths like `"../src/..."` + +### Wasp Operations Pattern + +Wasp operations (queries and actions) are the primary way to communicate between client and server. + +**Define in main.wasp:** +```wasp +query getTasks { + fn: import { getTasks } from "@src/tasks/operations.ts", + entities: [Task] // Grants access to Task entity +} + +action createTask { + fn: import { createTask } from "@src/tasks/operations.ts", + entities: [Task] +} +``` + +**Implement in `src/{feature}/operations.ts`:** +```typescript +import { HttpError } from 'wasp/server' +import type { GetTasks, CreateTask } from 'wasp/server/operations' +import type { Task } from 'wasp/entities' + +export const getTasks: GetTasks = async (_args, context) => { + if (!context.user) throw new HttpError(401) + return context.entities.Task.findMany({ where: { userId: context.user.id } }) +} + +export const createTask: CreateTask<{ description: string }, Task> = async (args, context) => { + if (!context.user) throw new HttpError(401) + return context.entities.Task.create({ + data: { description: args.description, userId: context.user.id } + }) +} +``` + +**Use on client:** +```typescript +// Queries: use useQuery hook +import { getTasks, useQuery } from 'wasp/client/operations' +const { data: tasks, isLoading } = useQuery(getTasks) + +// Actions: call directly with async/await (DO NOT use useAction unless optimistic updates needed) +import { createTask } from 'wasp/client/operations' +await createTask({ description: 'New task' }) +``` + +### Database Workflow + +1. Modify `schema.prisma` to add/change models +2. Run `wasp db migrate-dev` to generate and apply migrations +3. Wasp automatically generates TypeScript types in `wasp/entities` +4. Reference entities in operations via `context.entities.ModelName` + +### AI-Assisted Development + +The template includes comprehensive Cursor rules in `template/app/.cursor/rules/`: +- `wasp-overview.mdc` - Wasp framework fundamentals +- `project-conventions.mdc` - Import rules and common patterns +- `database-operations.mdc` - Database and operations patterns +- `authentication.mdc` - Auth setup and customization +- `ui-components.mdc` - ShadCN UI component usage +- `deployment.mdc` - Production deployment guides +- `advanced-troubleshooting.mdc` - Custom API endpoints, background jobs + +Wasp documentation is available at: +- LLM-optimized: https://wasp.sh/llms-full.txt +- Human-readable: https://wasp.sh/docs + +## Tech Stack + +- **Framework:** Wasp 0.19+ (React + Node.js + Prisma) +- **Frontend:** React, TypeScript, TailwindCSS, ShadCN UI +- **Backend:** Node.js, Express +- **Database:** PostgreSQL (production) / SQLite (local dev) +- **Auth:** Email + OAuth (Google, GitHub, Discord) +- **Payments:** Stripe or Lemon Squeezy +- **Email:** SendGrid, Mailgun, or SMTP +- **Storage:** AWS S3 +- **Testing:** Playwright (E2E) +- **Docs:** Astro Starlight + +## Common Development Patterns + +### Feature Organization +Group related code by feature in `src/{featureName}/`: +- `operations.ts` - Wasp queries and actions +- `{FeatureName}Page.tsx` - Page components +- Components, utilities, and types as needed + +Group feature config in `main.wasp` using regions: +```wasp +// #region Tasks Feature +route TasksRoute { path: "/tasks", to: TasksPage } +page TasksPage { component: import { TasksPage } from "@src/tasks/TasksPage" } +query getTasks { ... } +action createTask { ... } +// #endregion +``` + +### Error Handling +Use `HttpError` from `wasp/server` for structured errors: +```typescript +import { HttpError } from 'wasp/server' +throw new HttpError(404, 'Resource not found') +``` + +### Testing +E2E tests live in `template/e2e-tests/` and use Playwright: +```bash +cd template/e2e-tests +npm install +npm run test +``` + +## Contributing + +1. Work in the `template/` directory (changes auto-flow to derived projects) +2. Update `template/e2e-tests/` if adding/changing features +3. Update `opensaas-sh/blog/src/content/docs/` if changing documented behavior +4. Run `npm run prettier:format` before committing +5. Test changes work with `wasp clean && wasp start` + +## Troubleshooting + +**"Cannot find module 'wasp/...'"** +- Check import prefix is `wasp/`, not `@wasp/` +- Restart Wasp dev server: `wasp clean && wasp start` + +**"Cannot find module '@src/...'" in TypeScript** +- Use relative imports in `.ts`/`.tsx` files +- Only use `@src/...` in `main.wasp` file + +**Database changes not applied** +- Run `wasp db migrate-dev` after changing `schema.prisma` +- Check PostgreSQL is running if using `postgresql` provider + +**Generated code out of sync** +- Run `wasp clean` to delete all generated code and caches +- Restart with `wasp start` + +**macOS dope.sh errors** +- Install: `brew install coreutils gpatch diffutils` diff --git a/template/.claude/skills/migrating-db/SKILL.md b/template/.claude/skills/migrating-db/SKILL.md new file mode 100644 index 000000000..92b375418 --- /dev/null +++ b/template/.claude/skills/migrating-db/SKILL.md @@ -0,0 +1,24 @@ +--- +name: migrating-db +description: migrate the database after making changes to `schema.prisma`. +--- + +# migrating-db + +## Migrating the Database + +1. read the status of [`./app/migrations`](../../../app/migrations) directory +2. read [`./app/schema.prisma`](../../../app/schema.prisma) and compare to the current database schema. +3. if there are no pending migrations, exit. +4. choose a migration name that describes what changed. +5. run `npx prisma migrate dev --name ` to create a new migration. + +## Viewing the Database GUI + +1. ask the user if they want to view the database GUI. +2. if they do, run `wasp db studio` in a separate terminal. +3. open [http://localhost:5555](http://localhost:5555) in the browser. + +## Troubleshooting + +see [troubleshooting](../troubleshooting.md) \ No newline at end of file diff --git a/template/.claude/skills/migrating-db/troubleshooting.md b/template/.claude/skills/migrating-db/troubleshooting.md new file mode 100644 index 000000000..4b909f608 --- /dev/null +++ b/template/.claude/skills/migrating-db/troubleshooting.md @@ -0,0 +1,17 @@ +# Troubleshooting Database Migrations + +## Connecting to a Database + +If you are using PostgreSQL, Wasp supports two ways of connecting to a database: + +1. Using the Dev Database provided by Wasp with `wasp start db`. +2. Using an existing database by specifying a database URL in `.env.server` + +## Using the Dev Database provided by Wasp with `wasp start db` + +The command `wasp start db` will start a default PostgreSQL dev database for you. + +Your Wasp app will automatically connect to it, just keep `wasp start db` running in the background. Also, make sure that: + +- You have Docker installed and it's available in your PATH or Docker Desktop is running. +- The port `5432` isn't taken. diff --git a/template/.claude/skills/starting-wasp/SKILL.md b/template/.claude/skills/starting-wasp/SKILL.md new file mode 100644 index 000000000..ebc631aca --- /dev/null +++ b/template/.claude/skills/starting-wasp/SKILL.md @@ -0,0 +1,27 @@ +--- +name: starting-wasp +description: start the Wasp development server correctly with all required services. +--- + +# starting-wasp + +## Starting the Development Server + +1. check if the user has Wasp installed by running `wasp version`. +2. if Wasp is not installed, instruct them to install it with: `curl -sSL https://get.wasp.sh/installer.sh | sh` +3. check if PostgreSQL is needed by reading [`./app/schema.prisma`](../../../app/schema.prisma) to see if the database provider is `postgresql`. +4. if PostgreSQL is required: + - ask if they have PostgreSQL running locally or want to use Wasp's managed database. + - if they want Wasp's managed database, run `wasp start db` in the `template/app` directory first (in the background or instruct to run in separate terminal). + - if they have their own database running, inform them that they need to set the correct `DATABASE_URL` in [`./app/.env.server`](../../../app/.env.server). +5. run `wasp start` in the `template/app` directory in a separate terminal to start the development server. + +## Viewing Server Logs + +1. the Wasp dev server shows combined client and server logs. +2. server logs will show database queries, API calls, and errors. +3. client logs will show React component renders and frontend errors. + +## Troubleshooting + +see [troubleshooting](../troubleshooting.md) diff --git a/template/.claude/skills/starting-wasp/troubleshooting.md b/template/.claude/skills/starting-wasp/troubleshooting.md new file mode 100644 index 000000000..7512eb92e --- /dev/null +++ b/template/.claude/skills/starting-wasp/troubleshooting.md @@ -0,0 +1,20 @@ +# Troubleshooting Starting Wasp + +## Using Wasp's Managed Database + +The command `wasp start db` will start a default PostgreSQL dev database for you. + +Your Wasp app will automatically connect to it, just keep `wasp start db` running in the background. Also, make sure that: + +- You have Docker installed and it's available in your PATH or Docker Desktop is running. +- The port `5432` isn't taken. + +## Using an Existing Database + +- if the user has their own database running, inform them that they need to set the correct `DATABASE_URL` in [`./app/.env.server`](../../../app/.env.server). +- if they do not have a `.env.server` file, inform them that they can create it by copying the contents of [`./app/.env.server.example`](../../../app/.env.server.example). + +## Starting with a Clean State + +1. if the user is experiencing issues, suggest running `wasp clean` first to clear generated code and caches. +2. then follow the normal starting procedure above. \ No newline at end of file diff --git a/template/app/.cursor/rules/wasp-overview.mdc b/template/app/.cursor/rules/wasp-overview.mdc index bd9ee942e..17484b0a9 100644 --- a/template/app/.cursor/rules/wasp-overview.mdc +++ b/template/app/.cursor/rules/wasp-overview.mdc @@ -9,6 +9,25 @@ This document covers the fundamental concepts of the Wasp framework and the basi ## Background Information +### What is Open SaaS + +- Open SaaS is a free, open-source SaaS starter template built on top of the Wasp framework. +- It provides a production-ready foundation for building SaaS applications with essential features already implemented: + - Full-stack authentication (email + OAuth providers: Google, GitHub, Discord) + - Stripe and Lemon Squeezy payment integration with subscription management + - Admin dashboard with user management + - Email sending (SendGrid, Mailgun, or SMTP) + - File uploads with AWS S3 + - Analytics integration (Plausible or Google Analytics) + - Landing page and documentation site (Astro Starlight) + - Example AI integration with OpenAI + - End-to-end testing with Playwright + - One-command deployment to Railway or Fly.io +- Open SaaS follows best practices and conventions specific to building SaaS applications on Wasp. +- The template is designed to be customized and extended for your specific SaaS product needs. +- Documentation: https://docs.opensaas.sh +- LLM-optimized Open SaaS docs: https://docs.opensaas.sh/llms-full.txt + ### What is Wasp - Wasp (Web Application SPecification language) is a declarative, statically typed, domain-specific language (DSL) for building modern, full-stack web applications. diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md new file mode 100644 index 000000000..840f2fd9f --- /dev/null +++ b/template/app/CLAUDE.md @@ -0,0 +1,235 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What is This Project? + +This is the **Open SaaS template** - a free, open-source SaaS starter boilerplate built on the Wasp framework. Users get this template when they run `wasp new -t saas` and customize it to build their own SaaS applications. + +**This template comes with production-ready features:** +- **Authentication** - Email verification + OAuth (Google, GitHub, Discord) +- **Payments** - Stripe and Lemon Squeezy integration with subscription management +- **Admin Dashboard** - User management and analytics +- **Email** - SendGrid, Mailgun, or SMTP support +- **File Uploads** - AWS S3 integration +- **Analytics** - Plausible or Google Analytics +- **AI Ready** - Example OpenAI integration with function calling +- **Demo App** - Example task management app to demonstrate features +- **Testing** - Playwright E2E tests included +- **Deployment** - One-command deploy to Railway or Fly.io + +Users will customize this template by: +- Removing the demo app features they don't need +- Adding their own data models to `schema.prisma` +- Building their own pages and features in `src/` +- Configuring their branding, payments, and integrations + +**Documentation:** +- Open SaaS Docs: https://docs.opensaas.sh +- LLM-optimized: https://docs.opensaas.sh/llms-full.txt +- Wasp Docs: https://wasp.sh/docs +- Wasp LLM-optimized: https://wasp.sh/llms-full.txt + +## Project Structure + +This is a Wasp application. Wasp uses a declarative configuration file to generate a full-stack app: + +- **`main.wasp`** - App configuration defining routes, pages, auth, operations, and more +- **`schema.prisma`** - Prisma database schema (defines data models) +- **`src/`** - Application code organized by feature: + - `src/auth/` - Authentication logic and pages + - `src/client/` - Shared client components and layout + - `src/payment/` - Stripe/Lemon Squeezy integration + - `src/user/` - User profile and settings + - `src/demo-ai-app/` - Example OpenAI integration (demo feature) + - `src/file-upload/` - AWS S3 file upload example (demo feature) + - `src/landing-page/` - Marketing landing page components + - `src/admin/` - Admin dashboard + - `src/server/` - Server utilities and scripts + - `src/shared/` - Code shared between client and server + +**Note:** The demo app features (`demo-ai-app`, `file-upload`, etc.) are examples users can reference and remove when building their own SaaS. + +## Essential Commands + +```bash +# Development +wasp start # Start dev server (runs DB, server, and client) +wasp start db # Start only the managed development database +wasp db migrate-dev # Create and apply database migrations +wasp db studio # Open Prisma Studio to inspect database +wasp db seed # Run seed functions defined in main.wasp + +# Testing +wasp test # Run tests + +# Production +wasp build # Generate production build +wasp deploy # Deploy to Railway or Fly.io + +# Maintenance +wasp clean # Delete generated code and caches (fixes most issues) +``` + +## Import Conventions (CRITICAL) + +**In TypeScript/TSX files (`.ts`/`.tsx`):** +- ✅ Wasp imports: `import { User } from 'wasp/entities'` +- ✅ Wasp operations: `import { useQuery } from 'wasp/client/operations'` +- ✅ Wasp types: `import type { GetTasks } from 'wasp/server/operations'` +- ✅ Prisma enum values: `import { SubscriptionStatus } from '@prisma/client'` +- ✅ Local code: Use relative paths like `import { Component } from './Component'` +- ❌ NEVER use `@wasp/...` prefix +- ❌ NEVER use `@src/...` in TypeScript files + +**In main.wasp file:** +- ✅ Your code: `fn: import { getTasks } from "@src/tasks/operations.ts"` +- ❌ NEVER use relative paths like `"../src/..."` + +## Wasp Operations Pattern + +Wasp operations (queries and actions) are the primary way to communicate between client and server. + +**Define in main.wasp:** +```wasp +query getTasks { + fn: import { getTasks } from "@src/tasks/operations.ts", + entities: [Task] // Grants access to Task entity +} + +action createTask { + fn: import { createTask } from "@src/tasks/operations.ts", + entities: [Task] +} +``` + +**Implement in `src/{feature}/operations.ts`:** +```typescript +import { HttpError } from 'wasp/server' +import type { GetTasks, CreateTask } from 'wasp/server/operations' +import type { Task } from 'wasp/entities' + +export const getTasks: GetTasks = async (_args, context) => { + if (!context.user) throw new HttpError(401) + return context.entities.Task.findMany({ where: { userId: context.user.id } }) +} + +export const createTask: CreateTask<{ description: string }, Task> = async (args, context) => { + if (!context.user) throw new HttpError(401) + return context.entities.Task.create({ + data: { description: args.description, userId: context.user.id } + }) +} +``` + +**Use on client:** +```typescript +// Queries: use useQuery hook +import { getTasks, useQuery } from 'wasp/client/operations' +const { data: tasks, isLoading } = useQuery(getTasks) + +// Actions: call directly with async/await (DO NOT use useAction unless optimistic updates needed) +import { createTask } from 'wasp/client/operations' +await createTask({ description: 'New task' }) +``` + +## Database Workflow + +1. Modify `schema.prisma` to add/change models +2. Run `wasp db migrate-dev` to generate and apply migrations +3. Wasp automatically generates TypeScript types in `wasp/entities` +4. Reference entities in operations via `context.entities.ModelName` + +**Note:** The default database is PostgreSQL. For local development, run `wasp start db` to start a managed PostgreSQL instance, or configure your own in `.env.server`. + +## Development Patterns + +### Feature Organization +Group related code by feature in `src/{featureName}/`: +- `operations.ts` - Wasp queries and actions +- `{FeatureName}Page.tsx` - Page components +- Components, utilities, and types as needed + +Group feature config in `main.wasp` using regions: +```wasp +// #region Tasks Feature +route TasksRoute { path: "/tasks", to: TasksPage } +page TasksPage { component: import { TasksPage } from "@src/tasks/TasksPage" } +query getTasks { ... } +action createTask { ... } +// #endregion +``` + +### Error Handling +Use `HttpError` from `wasp/server` for structured errors: +```typescript +import { HttpError } from 'wasp/server' +throw new HttpError(404, 'Resource not found') +``` + +### AI-Assisted Development + +This template includes Cursor rules in `.cursor/rules/` to help AI assistants understand Wasp and Open SaaS conventions: +- `wasp-overview.mdc` - Wasp framework fundamentals and Open SaaS overview +- `project-conventions.mdc` - Import rules and common patterns +- `database-operations.mdc` - Database and operations patterns +- `authentication.mdc` - Auth setup and customization +- `ui-components.mdc` - ShadCN UI component usage +- `deployment.mdc` - Production deployment guides +- `advanced-troubleshooting.mdc` - Custom API endpoints, background jobs + +## Common Issues & Solutions + +**"Cannot find module 'wasp/...'"** +- Check import prefix is `wasp/`, not `@wasp/` +- Restart Wasp dev server: `wasp clean && wasp start` + +**"Cannot find module '@src/...'" in TypeScript** +- Use relative imports in `.ts`/`.tsx` files +- Only use `@src/...` in `main.wasp` file + +**Database changes not applied** +- Run `wasp db migrate-dev` after changing `schema.prisma` +- Check PostgreSQL is running with `wasp start db` + +**Generated code out of sync** +- Run `wasp clean` to delete all generated code and caches +- Restart with `wasp start` + +**Type errors after changing operations** +- Restart Wasp dev server to regenerate types +- Check that entities are listed in operation definitions in `main.wasp` + +## Tech Stack + +- **Framework:** Wasp (React + Node.js + Prisma) +- **Frontend:** React, TypeScript, TailwindCSS, ShadCN UI +- **Backend:** Node.js, Express +- **Database:** PostgreSQL +- **Auth:** Email verification + OAuth (Google, GitHub, Discord) +- **Payments:** Stripe or Lemon Squeezy +- **Email:** SendGrid, Mailgun, or SMTP +- **Storage:** AWS S3 +- **Testing:** Playwright (E2E) + +## Customizing This Template + +When building your SaaS app with this template: + +1. **Configure branding:** Update `main.wasp` with your app name, title, description, and metadata +2. **Choose auth methods:** Enable/disable OAuth providers in `main.wasp` auth section +3. **Set up payments:** Configure Stripe or Lemon Squeezy (see https://docs.opensaas.sh/guides/stripe-integration/) +4. **Customize landing page:** Edit components in `src/landing-page/` +5. **Remove demo features:** Delete demo app code you don't need (`demo-ai-app`, example tasks, etc.) +6. **Add your data models:** Define your entities in `schema.prisma` +7. **Build your features:** Create your own pages, operations, and components in `src/` +8. **Configure services:** Set up email, analytics, file storage in `.env.server` +9. **Update tests:** Modify e2e tests to match your features +10. **Deploy:** Run `wasp deploy` when ready for production + +## Getting Help + +- **Open SaaS Docs:** https://docs.opensaas.sh +- **Wasp Docs:** https://wasp.sh/docs +- **Wasp Discord:** https://discord.gg/aCamt5wCpS (use #🙋questions channel) +- **Open SaaS GitHub:** https://github.com/wasp-lang/open-saas/issues From 9d3a999f4bf0f59a8d47d901c454f885817ad78c Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:17:30 +0100 Subject: [PATCH 02/16] Add SKILLS for feature scaffolding and E2E testing Introduced documentation under template/.claude/skills for adding new features to the Open SaaS app, covering planning, database setup, backend operations, frontend pages, navigation, Wasp config, and troubleshooting. Also added guides for running Playwright end-to-end tests and related troubleshooting steps. --- .../.claude/skills/adding-feature/SKILL.md | 43 +++++++++++++++++++ .../.claude/skills/adding-feature/database.md | 39 +++++++++++++++++ .../skills/adding-feature/navigation.md | 20 +++++++++ .../skills/adding-feature/operations.md | 38 ++++++++++++++++ .../.claude/skills/adding-feature/pages.md | 34 +++++++++++++++ .../skills/adding-feature/troubleshooting.md | 43 +++++++++++++++++++ .../skills/adding-feature/wasp-config.md | 38 ++++++++++++++++ .../.claude/skills/running-e2e-tests/SKILL.md | 25 +++++++++++ .../running-e2e-tests/troubleshooting.md | 11 +++++ 9 files changed, 291 insertions(+) create mode 100644 template/.claude/skills/adding-feature/SKILL.md create mode 100644 template/.claude/skills/adding-feature/database.md create mode 100644 template/.claude/skills/adding-feature/navigation.md create mode 100644 template/.claude/skills/adding-feature/operations.md create mode 100644 template/.claude/skills/adding-feature/pages.md create mode 100644 template/.claude/skills/adding-feature/troubleshooting.md create mode 100644 template/.claude/skills/adding-feature/wasp-config.md create mode 100644 template/.claude/skills/running-e2e-tests/SKILL.md create mode 100644 template/.claude/skills/running-e2e-tests/troubleshooting.md diff --git a/template/.claude/skills/adding-feature/SKILL.md b/template/.claude/skills/adding-feature/SKILL.md new file mode 100644 index 000000000..ea76d1a9a --- /dev/null +++ b/template/.claude/skills/adding-feature/SKILL.md @@ -0,0 +1,43 @@ +--- +name: adding-feature +description: plan and scaffold a new feature for the Open SaaS app following Wasp conventions. +--- + +# adding-feature + +## Feature Planning + +1. ask the user what feature they want to add +2. gather requirements: + - does it need authentication? + - does it need database models (entities)? + - is it a public or private feature? + - does it need admin access? + - what are the main user actions? (create, read, update, delete, etc.) +3. determine feature name in kebab-case (e.g., `todo-list`, `user-notes`) +4. identify which components are needed: + - database models → see [database.md](./database.md) + - backend operations (queries/actions) → see [operations.md](./operations.md) + - frontend pages → see [pages.md](./pages.md) + - navigation links → see [navigation.md](./navigation.md) + +## Implementation Steps + +Follow these guides in order: + +1. **[Database Setup](./database.md)** - if feature needs entities +2. **[Operations](./operations.md)** - backend queries and actions +3. **[Wasp Configuration](./wasp-config.md)** - register in main.wasp +4. **[Pages](./pages.md)** - frontend components +5. **[Navigation](./navigation.md)** - add to navbar (optional) + +## Verification + +1. ensure Wasp dev server is running (`wasp start`) +2. if type errors occur, run `cd app && wasp clean && wasp start` +3. test all operations work correctly +4. verify authentication works as expected + +## Troubleshooting + +see [troubleshooting](./troubleshooting.md) diff --git a/template/.claude/skills/adding-feature/database.md b/template/.claude/skills/adding-feature/database.md new file mode 100644 index 000000000..9609e67ce --- /dev/null +++ b/template/.claude/skills/adding-feature/database.md @@ -0,0 +1,39 @@ +# Database Setup + +## Adding Entities to schema.prisma + +1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) to understand existing models +2. add new Prisma model following the pattern: + - use `String @id @default(uuid())` for IDs + - include `createdAt` and `updatedAt` timestamps + - add user relation if feature is user-specific +3. if adding relation to User model, update User model with the relation field +4. reference existing models in schema.prisma as examples + +## Running Migrations + +1. run `cd app && wasp db migrate-dev --name add-feature-name` +2. verify migration completed successfully +3. Wasp automatically generates TypeScript types in `wasp/entities` + +## Common Patterns + +**User-owned resource:** +```prisma +model FeatureName { + id String @id @default(uuid()) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id]) + userId String +} +``` + +**Update User model:** +```prisma +model User { + // ... existing fields + featureNames FeatureName[] +} +``` diff --git a/template/.claude/skills/adding-feature/navigation.md b/template/.claude/skills/adding-feature/navigation.md new file mode 100644 index 000000000..e01316af3 --- /dev/null +++ b/template/.claude/skills/adding-feature/navigation.md @@ -0,0 +1,20 @@ +# Navigation + +## Adding to Navbar + +1. read [`../../../app/src/client/components/AppNavBar.tsx`](../../../app/src/client/components/AppNavBar.tsx) +2. find the appropriate section (authenticated vs. public links) +3. add link using `Link` component from react-router-dom +4. follow existing patterns for styling and structure + +## Example + +```tsx +Feature Name +``` + +## Notes + +- only add to navbar if feature should be easily accessible +- consider whether link should be public or authenticated-only +- follow existing styling patterns diff --git a/template/.claude/skills/adding-feature/operations.md b/template/.claude/skills/adding-feature/operations.md new file mode 100644 index 000000000..5aca15fd4 --- /dev/null +++ b/template/.claude/skills/adding-feature/operations.md @@ -0,0 +1,38 @@ +# Operations (Backend Logic) + +## Creating operations.ts + +1. create directory: `mkdir -p app/src/{feature-name}/` +2. create `app/src/{feature-name}/operations.ts` +3. reference [`../../../app/src/demo-ai-app/operations.ts`](../../../app/src/demo-ai-app/operations.ts) as example + +## Implementation Guidelines + +**Queries (reading data):** +- use for fetching data +- return data from database via `context.entities.EntityName` +- always check `if (!context.user)` for authenticated operations + +**Actions (writing data):** +- use for create, update, delete operations +- always verify ownership before modifying resources +- validate input data before processing + +**Error Handling:** +- use `HttpError` from `wasp/server` +- common status codes: 401 (unauthorized), 403 (forbidden), 404 (not found) + +**Database Access:** +- access via `context.entities.EntityName` +- use Prisma methods: `findMany`, `findUnique`, `create`, `update`, `delete` +- filter by `userId` for user-specific data + +## Import Conventions + +✅ Correct: +- `import { HttpError } from 'wasp/server'` +- `import type { GetItems } from 'wasp/server/operations'` +- `import type { EntityName } from 'wasp/entities'` + +❌ Wrong: +- `import { HttpError } from '@wasp/server'` diff --git a/template/.claude/skills/adding-feature/pages.md b/template/.claude/skills/adding-feature/pages.md new file mode 100644 index 000000000..13f9d4cce --- /dev/null +++ b/template/.claude/skills/adding-feature/pages.md @@ -0,0 +1,34 @@ +# Pages (Frontend Components) + +## Creating Page Component + +1. create `app/src/{feature-name}/{FeatureName}Page.tsx` +2. reference [`../../../app/src/demo-ai-app/DemoAppPage.tsx`](../../../app/src/demo-ai-app/DemoAppPage.tsx) as example + +## Implementation Guidelines + +**Using Queries:** +- import and use `useQuery` hook for reading data +- handle `isLoading` and `error` states +- data automatically refetches after actions + +**Using Actions:** +- import action directly from `wasp/client/operations` +- call with `await` (do NOT use `useAction` unless optimistic updates needed) +- wrap in try/catch for error handling + +**Layout:** +- follow existing page structure from demo-ai-app +- use Tailwind CSS classes for styling +- include proper dark mode support (`dark:` classes) + +## Import Conventions + +✅ Correct: +- `import { useQuery } from 'wasp/client/operations'` +- `import { getItems, createItem } from 'wasp/client/operations'` +- `import type { EntityName } from 'wasp/entities'` + +❌ Wrong: +- `import { useQuery } from '@wasp/client/operations'` +- `import { getItems } from '@src/feature-name/operations'` (use relative path in TypeScript) diff --git a/template/.claude/skills/adding-feature/troubleshooting.md b/template/.claude/skills/adding-feature/troubleshooting.md new file mode 100644 index 000000000..7f22c5a05 --- /dev/null +++ b/template/.claude/skills/adding-feature/troubleshooting.md @@ -0,0 +1,43 @@ +# Troubleshooting - Adding Features + +## Type Errors After Adding Operations + +Run `cd app && wasp clean && wasp start` to regenerate types. + +## "Cannot find module 'wasp/...'" + +Use `wasp/` prefix, NOT `@wasp/`. Example: `import { User } from 'wasp/entities'` + +## Entity Not Found in Context + +Add entity to operation's `entities` array in `main.wasp`: +```wasp +query getItems { + fn: import { getItems } from "@src/feature-name/operations", + entities: [EntityName] // ← Must list all entities used +} +``` + +## Migration Fails + +- check `schema.prisma` syntax is valid +- ensure PostgreSQL is running (`wasp start db` if using managed DB) +- delete failed migration in `app/migrations/` directory and retry + +## 401 Unauthorized Errors + +- verify page has `authRequired: true` in `main.wasp` +- ensure testing on `localhost:3000` (correct port) +- check cookies are enabled in browser + +## Page Not Found (404) + +- verify route is defined in `main.wasp` +- check path matches what you're navigating to +- restart Wasp dev server + +## Data Not Updating in UI + +- queries auto-refetch after actions complete +- check browser console for errors +- verify action completed successfully (no errors thrown) diff --git a/template/.claude/skills/adding-feature/wasp-config.md b/template/.claude/skills/adding-feature/wasp-config.md new file mode 100644 index 000000000..3f6e8c9c8 --- /dev/null +++ b/template/.claude/skills/adding-feature/wasp-config.md @@ -0,0 +1,38 @@ +# Wasp Configuration (main.wasp) + +## Registering Feature in main.wasp + +1. read [`../../../app/main.wasp`](../../../app/main.wasp) to see existing patterns +2. add feature section with region comments for organization + +## Structure + +```wasp +// #region FeatureName + +route FeatureNameRoute { path: "/feature-path", to: FeatureNamePage } + +page FeatureNamePage { + authRequired: true, // if authentication required + component: import { FeatureNamePage } from "@src/feature-name/FeatureNamePage" +} + +query getItems { + fn: import { getItems } from "@src/feature-name/operations", + entities: [EntityName, User] // list ALL entities accessed +} + +action createItem { + fn: import { createItem } from "@src/feature-name/operations", + entities: [EntityName] +} + +// #endregion +``` + +## Key Points + +- use `@src/feature-name/...` for imports in main.wasp +- list ALL entities accessed in `entities: [...]` array +- set `authRequired: true` for authenticated pages +- queries are for reading, actions are for writing diff --git a/template/.claude/skills/running-e2e-tests/SKILL.md b/template/.claude/skills/running-e2e-tests/SKILL.md new file mode 100644 index 000000000..3d2213ab0 --- /dev/null +++ b/template/.claude/skills/running-e2e-tests/SKILL.md @@ -0,0 +1,25 @@ +--- +name: running-e2e-tests +description: run Playwright end-to-end tests for the Open SaaS app. +--- + +# running-e2e-tests + +## Running E2E Tests + +1. check if the user is in the correct directory by verifying [`./e2e-tests/package.json`](../../../e2e-tests/package.json) exists. +2. check if dependencies are installed by verifying [`./e2e-tests/node_modules`](../../../e2e-tests/node_modules) exists. +3. if not installed, run `cd e2e-tests && npm install`. +4. check if the Wasp app is running by checking if localhost:3000 and localhost:3001 are accessible. +5. if not running, inform the user they need to start the app first with `wasp start` in a separate terminal with `SKIP_EMAIL_VERIFICATION_IN_DEV=true` environment variable set. +6. check if Stripe CLI is needed by asking the user if they want to test payment flows. +7. if Stripe is needed: + - check if Stripe CLI is installed by running `stripe --version`. + - if not installed, provide instructions: https://docs.stripe.com/stripe-cli + - check to make sure the user is logged in to Stripe CLI by running `stripe login`. +8. run the tests with `npm run local:e2e:start`. +9. inform the user that the playwright UI will open and allow them to select and run tests. + +## Troubleshooting + +see [troubleshooting](../troubleshooting.md) diff --git a/template/.claude/skills/running-e2e-tests/troubleshooting.md b/template/.claude/skills/running-e2e-tests/troubleshooting.md new file mode 100644 index 000000000..29689eb19 --- /dev/null +++ b/template/.claude/skills/running-e2e-tests/troubleshooting.md @@ -0,0 +1,11 @@ +# Troubleshooting E2E Tests + +## Running E2E Tests + +- **Email Verification:** Tests require `SKIP_EMAIL_VERIFICATION_IN_DEV=true` when starting the Wasp app, otherwise they will hang. + - if the user doesn't want to skip email verification in dev mode, they must click the email verification link in the server console to continue the test (undesirable). +- **Stripe Webhooks:** Payment tests require Stripe CLI running with webhook forwarding. + - if the user is not logged in to Stripe CLI, they can run `stripe login` to login. + - it the api key is expired, inform the user to quit the process, and run `stripe login` again to refresh the keys. +- **Other Payment Provider Webhooks:** Payment tests require the payment provider's webhook listener running with webhook forwarding via Ngrok. See [llms.txt](https://docs.opensaas.sh/llms.txt) for the provider specific guide URL. +- **Database:** Tests use the development database, so ensure `wasp db start` is running. \ No newline at end of file From 884332390b4e91a321a36998b0e9dbbdd6dd3216 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 1 Dec 2025 11:49:30 +0100 Subject: [PATCH 03/16] Update CLAUDE.md --- template/app/CLAUDE.md | 127 +++++++---------------------------------- 1 file changed, 21 insertions(+), 106 deletions(-) diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index 840f2fd9f..d42c6755e 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -7,8 +7,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co This is the **Open SaaS template** - a free, open-source SaaS starter boilerplate built on the Wasp framework. Users get this template when they run `wasp new -t saas` and customize it to build their own SaaS applications. **This template comes with production-ready features:** -- **Authentication** - Email verification + OAuth (Google, GitHub, Discord) -- **Payments** - Stripe and Lemon Squeezy integration with subscription management +- **Authentication** - Email verification + OAuth (Google, GitHub, Discord, Slack) +- **Payments** - Stripe, Polar.sh, and Lemon Squeezy integration with subscription management - **Admin Dashboard** - User management and analytics - **Email** - SendGrid, Mailgun, or SMTP support - **File Uploads** - AWS S3 integration @@ -18,12 +18,6 @@ This is the **Open SaaS template** - a free, open-source SaaS starter boilerplat - **Testing** - Playwright E2E tests included - **Deployment** - One-command deploy to Railway or Fly.io -Users will customize this template by: -- Removing the demo app features they don't need -- Adding their own data models to `schema.prisma` -- Building their own pages and features in `src/` -- Configuring their branding, payments, and integrations - **Documentation:** - Open SaaS Docs: https://docs.opensaas.sh - LLM-optimized: https://docs.opensaas.sh/llms-full.txt @@ -35,6 +29,7 @@ Users will customize this template by: This is a Wasp application. Wasp uses a declarative configuration file to generate a full-stack app: - **`main.wasp`** - App configuration defining routes, pages, auth, operations, and more + - note: users can also use `main.wasp.ts` instead of `main.wasp` for TypeScript support. - **`schema.prisma`** - Prisma database schema (defines data models) - **`src/`** - Application code organized by feature: - `src/auth/` - Authentication logic and pages @@ -60,9 +55,6 @@ wasp db migrate-dev # Create and apply database migrations wasp db studio # Open Prisma Studio to inspect database wasp db seed # Run seed functions defined in main.wasp -# Testing -wasp test # Run tests - # Production wasp build # Generate production build wasp deploy # Deploy to Railway or Fly.io @@ -90,82 +82,20 @@ wasp clean # Delete generated code and caches (fixes most issues) Wasp operations (queries and actions) are the primary way to communicate between client and server. -**Define in main.wasp:** -```wasp -query getTasks { - fn: import { getTasks } from "@src/tasks/operations.ts", - entities: [Task] // Grants access to Task entity -} - -action createTask { - fn: import { createTask } from "@src/tasks/operations.ts", - entities: [Task] -} -``` - -**Implement in `src/{feature}/operations.ts`:** -```typescript -import { HttpError } from 'wasp/server' -import type { GetTasks, CreateTask } from 'wasp/server/operations' -import type { Task } from 'wasp/entities' - -export const getTasks: GetTasks = async (_args, context) => { - if (!context.user) throw new HttpError(401) - return context.entities.Task.findMany({ where: { userId: context.user.id } }) -} - -export const createTask: CreateTask<{ description: string }, Task> = async (args, context) => { - if (!context.user) throw new HttpError(401) - return context.entities.Task.create({ - data: { description: args.description, userId: context.user.id } - }) -} -``` - -**Use on client:** -```typescript -// Queries: use useQuery hook -import { getTasks, useQuery } from 'wasp/client/operations' -const { data: tasks, isLoading } = useQuery(getTasks) - -// Actions: call directly with async/await (DO NOT use useAction unless optimistic updates needed) -import { createTask } from 'wasp/client/operations' -await createTask({ description: 'New task' }) -``` +Refer to the following skills for more information: +- [operations.md](../.claude/skills/adding-feature/operations.md) ## Database Workflow -1. Modify `schema.prisma` to add/change models -2. Run `wasp db migrate-dev` to generate and apply migrations -3. Wasp automatically generates TypeScript types in `wasp/entities` -4. Reference entities in operations via `context.entities.ModelName` - -**Note:** The default database is PostgreSQL. For local development, run `wasp start db` to start a managed PostgreSQL instance, or configure your own in `.env.server`. +refer to the following skills: +- [database.md](../.claude/skills/adding-feature/database.md) +- [starting-wasp SKILL.md](../.claude/skills/starting-wasp/SKILL.md) +- [migrating-db SKILL.md](../.claude/skills/migrating-db/SKILL.md) ## Development Patterns ### Feature Organization -Group related code by feature in `src/{featureName}/`: -- `operations.ts` - Wasp queries and actions -- `{FeatureName}Page.tsx` - Page components -- Components, utilities, and types as needed - -Group feature config in `main.wasp` using regions: -```wasp -// #region Tasks Feature -route TasksRoute { path: "/tasks", to: TasksPage } -page TasksPage { component: import { TasksPage } from "@src/tasks/TasksPage" } -query getTasks { ... } -action createTask { ... } -// #endregion -``` - -### Error Handling -Use `HttpError` from `wasp/server` for structured errors: -```typescript -import { HttpError } from 'wasp/server' -throw new HttpError(404, 'Resource not found') -``` +Refer to [adding-feature SKILL.md](../.claude/skills/adding-feature/SKILL.md) for more information. ### AI-Assisted Development @@ -188,48 +118,33 @@ This template includes Cursor rules in `.cursor/rules/` to help AI assistants un - Use relative imports in `.ts`/`.tsx` files - Only use `@src/...` in `main.wasp` file -**Database changes not applied** -- Run `wasp db migrate-dev` after changing `schema.prisma` -- Check PostgreSQL is running with `wasp start db` - -**Generated code out of sync** -- Run `wasp clean` to delete all generated code and caches -- Restart with `wasp start` - **Type errors after changing operations** - Restart Wasp dev server to regenerate types - Check that entities are listed in operation definitions in `main.wasp` -## Tech Stack - -- **Framework:** Wasp (React + Node.js + Prisma) -- **Frontend:** React, TypeScript, TailwindCSS, ShadCN UI -- **Backend:** Node.js, Express -- **Database:** PostgreSQL -- **Auth:** Email verification + OAuth (Google, GitHub, Discord) -- **Payments:** Stripe or Lemon Squeezy -- **Email:** SendGrid, Mailgun, or SMTP -- **Storage:** AWS S3 -- **Testing:** Playwright (E2E) - ## Customizing This Template When building your SaaS app with this template: 1. **Configure branding:** Update `main.wasp` with your app name, title, description, and metadata 2. **Choose auth methods:** Enable/disable OAuth providers in `main.wasp` auth section -3. **Set up payments:** Configure Stripe or Lemon Squeezy (see https://docs.opensaas.sh/guides/stripe-integration/) +3. **Set up payments:** Configure Stripe, Polar.sh or Lemon Squeezy (see https://docs.opensaas.sh/guides/payment-integrations/) 4. **Customize landing page:** Edit components in `src/landing-page/` -5. **Remove demo features:** Delete demo app code you don't need (`demo-ai-app`, example tasks, etc.) +5. **Reference demo features:** Demo app code shows how to use the features of the template (`demo-ai-app`, example tasks, etc.) 6. **Add your data models:** Define your entities in `schema.prisma` 7. **Build your features:** Create your own pages, operations, and components in `src/` 8. **Configure services:** Set up email, analytics, file storage in `.env.server` 9. **Update tests:** Modify e2e tests to match your features 10. **Deploy:** Run `wasp deploy` when ready for production +Reference the skills in [.claude/skills/](../.claude/skills/) for more information. + ## Getting Help -- **Open SaaS Docs:** https://docs.opensaas.sh -- **Wasp Docs:** https://wasp.sh/docs -- **Wasp Discord:** https://discord.gg/aCamt5wCpS (use #🙋questions channel) -- **Open SaaS GitHub:** https://github.com/wasp-lang/open-saas/issues +**Wasp Discord:** https://discord.gg/aCamt5wCpS (use #🙋questions channel) + +**Documentation:** +- Open SaaS Docs: https://docs.opensaas.sh +- LLM-optimized: https://docs.opensaas.sh/llms-full.txt +- Wasp Docs: https://wasp.sh/docs +- Wasp LLM-optimized: https://wasp.sh/llms-full.txt \ No newline at end of file From 55405c553c29ea38a5dfee0d976f7b7e5f7d0513 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:45:39 +0100 Subject: [PATCH 04/16] Refactor feature addition guides and remove navigation doc Updated skill documentation for adding features to clarify requirements gathering, database setup, operations, pages, troubleshooting, and Wasp config. Removed the navigation.md guide and referenced existing code for organization. Improved instructions for using Wasp hooks, ShadCN UI components, and clarified migration and error handling steps. --- .../.claude/skills/adding-feature/SKILL.md | 21 +++++------ .../.claude/skills/adding-feature/database.md | 36 +++---------------- .../skills/adding-feature/navigation.md | 20 ----------- .../skills/adding-feature/operations.md | 4 +-- .../.claude/skills/adding-feature/pages.md | 9 +++-- .../skills/adding-feature/troubleshooting.md | 3 +- .../skills/adding-feature/wasp-config.md | 26 -------------- template/app/CLAUDE.md | 17 +++------ 8 files changed, 26 insertions(+), 110 deletions(-) delete mode 100644 template/.claude/skills/adding-feature/navigation.md diff --git a/template/.claude/skills/adding-feature/SKILL.md b/template/.claude/skills/adding-feature/SKILL.md index ea76d1a9a..31a991809 100644 --- a/template/.claude/skills/adding-feature/SKILL.md +++ b/template/.claude/skills/adding-feature/SKILL.md @@ -10,31 +10,28 @@ description: plan and scaffold a new feature for the Open SaaS app following Was 1. ask the user what feature they want to add 2. gather requirements: - does it need authentication? - - does it need database models (entities)? - - is it a public or private feature? - - does it need admin access? + - what kind of database models (entities) may be needed? - what are the main user actions? (create, read, update, delete, etc.) + - what dependencies may be needed? + - what integrations may be needed? + - what types of UI components may be needed? + - might this feature make use of wasp's jobs feature? + - etc. 3. determine feature name in kebab-case (e.g., `todo-list`, `user-notes`) -4. identify which components are needed: - - database models → see [database.md](./database.md) - - backend operations (queries/actions) → see [operations.md](./operations.md) - - frontend pages → see [pages.md](./pages.md) - - navigation links → see [navigation.md](./navigation.md) ## Implementation Steps -Follow these guides in order: +Follow these guide: 1. **[Database Setup](./database.md)** - if feature needs entities 2. **[Operations](./operations.md)** - backend queries and actions -3. **[Wasp Configuration](./wasp-config.md)** - register in main.wasp +3. **[Wasp Configuration](./wasp-config.md)** - register in wasp config file 4. **[Pages](./pages.md)** - frontend components -5. **[Navigation](./navigation.md)** - add to navbar (optional) ## Verification 1. ensure Wasp dev server is running (`wasp start`) -2. if type errors occur, run `cd app && wasp clean && wasp start` +2. if type errors occur, restart the Wasp dev server 3. test all operations work correctly 4. verify authentication works as expected diff --git a/template/.claude/skills/adding-feature/database.md b/template/.claude/skills/adding-feature/database.md index 9609e67ce..bd380d0b8 100644 --- a/template/.claude/skills/adding-feature/database.md +++ b/template/.claude/skills/adding-feature/database.md @@ -2,38 +2,10 @@ ## Adding Entities to schema.prisma -1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) to understand existing models -2. add new Prisma model following the pattern: - - use `String @id @default(uuid())` for IDs - - include `createdAt` and `updatedAt` timestamps - - add user relation if feature is user-specific -3. if adding relation to User model, update User model with the relation field -4. reference existing models in schema.prisma as examples +1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) to understand existing models and common patterns. +2. add new Prisma model. ## Running Migrations -1. run `cd app && wasp db migrate-dev --name add-feature-name` -2. verify migration completed successfully -3. Wasp automatically generates TypeScript types in `wasp/entities` - -## Common Patterns - -**User-owned resource:** -```prisma -model FeatureName { - id String @id @default(uuid()) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - user User @relation(fields: [userId], references: [id]) - userId String -} -``` - -**Update User model:** -```prisma -model User { - // ... existing fields - featureNames FeatureName[] -} -``` +Refer to [migrating-db SKILL.md](../.claude/skills/migrating-db/SKILL.md) for more information. +Note: Wasp automatically generates TypeScript types in `wasp/entities` diff --git a/template/.claude/skills/adding-feature/navigation.md b/template/.claude/skills/adding-feature/navigation.md deleted file mode 100644 index e01316af3..000000000 --- a/template/.claude/skills/adding-feature/navigation.md +++ /dev/null @@ -1,20 +0,0 @@ -# Navigation - -## Adding to Navbar - -1. read [`../../../app/src/client/components/AppNavBar.tsx`](../../../app/src/client/components/AppNavBar.tsx) -2. find the appropriate section (authenticated vs. public links) -3. add link using `Link` component from react-router-dom -4. follow existing patterns for styling and structure - -## Example - -```tsx -Feature Name -``` - -## Notes - -- only add to navbar if feature should be easily accessible -- consider whether link should be public or authenticated-only -- follow existing styling patterns diff --git a/template/.claude/skills/adding-feature/operations.md b/template/.claude/skills/adding-feature/operations.md index 5aca15fd4..be781e46b 100644 --- a/template/.claude/skills/adding-feature/operations.md +++ b/template/.claude/skills/adding-feature/operations.md @@ -20,12 +20,10 @@ **Error Handling:** - use `HttpError` from `wasp/server` -- common status codes: 401 (unauthorized), 403 (forbidden), 404 (not found) **Database Access:** - access via `context.entities.EntityName` -- use Prisma methods: `findMany`, `findUnique`, `create`, `update`, `delete` -- filter by `userId` for user-specific data +- use Prisma methods on these entities ## Import Conventions diff --git a/template/.claude/skills/adding-feature/pages.md b/template/.claude/skills/adding-feature/pages.md index 13f9d4cce..821600858 100644 --- a/template/.claude/skills/adding-feature/pages.md +++ b/template/.claude/skills/adding-feature/pages.md @@ -8,7 +8,7 @@ ## Implementation Guidelines **Using Queries:** -- import and use `useQuery` hook for reading data +- import and use Wasp's `useQuery` hook for reading data - handle `isLoading` and `error` states - data automatically refetches after actions @@ -17,10 +17,13 @@ - call with `await` (do NOT use `useAction` unless optimistic updates needed) - wrap in try/catch for error handling +**Using Auth:** +- import and use Wasp's `useAuth` hook for authentication +- or pass Wasp's `AuthUser` object to the page component using props if it is protected by authentication via `authRequired: true` in the wasp config file + **Layout:** -- follow existing page structure from demo-ai-app - use Tailwind CSS classes for styling -- include proper dark mode support (`dark:` classes) +- prefer the use of ShadCN UI components for styling (some already exist in the template under [`src/client/components/ui`](../../../app/src/client/components/ui/)) ## Import Conventions diff --git a/template/.claude/skills/adding-feature/troubleshooting.md b/template/.claude/skills/adding-feature/troubleshooting.md index 7f22c5a05..63e26c5e6 100644 --- a/template/.claude/skills/adding-feature/troubleshooting.md +++ b/template/.claude/skills/adding-feature/troubleshooting.md @@ -2,7 +2,7 @@ ## Type Errors After Adding Operations -Run `cd app && wasp clean && wasp start` to regenerate types. +Re-run `wasp start` and inform the user to restart the typescript server to regenerate types. ## "Cannot find module 'wasp/...'" @@ -39,5 +39,4 @@ query getItems { ## Data Not Updating in UI - queries auto-refetch after actions complete -- check browser console for errors - verify action completed successfully (no errors thrown) diff --git a/template/.claude/skills/adding-feature/wasp-config.md b/template/.claude/skills/adding-feature/wasp-config.md index 3f6e8c9c8..645c8ba04 100644 --- a/template/.claude/skills/adding-feature/wasp-config.md +++ b/template/.claude/skills/adding-feature/wasp-config.md @@ -5,34 +5,8 @@ 1. read [`../../../app/main.wasp`](../../../app/main.wasp) to see existing patterns 2. add feature section with region comments for organization -## Structure - -```wasp -// #region FeatureName - -route FeatureNameRoute { path: "/feature-path", to: FeatureNamePage } - -page FeatureNamePage { - authRequired: true, // if authentication required - component: import { FeatureNamePage } from "@src/feature-name/FeatureNamePage" -} - -query getItems { - fn: import { getItems } from "@src/feature-name/operations", - entities: [EntityName, User] // list ALL entities accessed -} - -action createItem { - fn: import { createItem } from "@src/feature-name/operations", - entities: [EntityName] -} - -// #endregion -``` - ## Key Points -- use `@src/feature-name/...` for imports in main.wasp - list ALL entities accessed in `entities: [...]` array - set `authRequired: true` for authenticated pages - queries are for reading, actions are for writing diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index d42c6755e..416b8059f 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -94,19 +94,12 @@ refer to the following skills: ## Development Patterns -### Feature Organization -Refer to [adding-feature SKILL.md](../.claude/skills/adding-feature/SKILL.md) for more information. +Wasp abstracts and adds layers on top of the tools it uses to make development more productive. The codebase is your source of truth for how to use Wasp effectively. -### AI-Assisted Development +### Feature Organization -This template includes Cursor rules in `.cursor/rules/` to help AI assistants understand Wasp and Open SaaS conventions: -- `wasp-overview.mdc` - Wasp framework fundamentals and Open SaaS overview -- `project-conventions.mdc` - Import rules and common patterns -- `database-operations.mdc` - Database and operations patterns -- `authentication.mdc` - Auth setup and customization -- `ui-components.mdc` - ShadCN UI component usage -- `deployment.mdc` - Production deployment guides -- `advanced-troubleshooting.mdc` - Custom API endpoints, background jobs +Use the current features as a guide to understand how code is organized. +When adding new features, refer to [adding-feature SKILL.md](../.claude/skills/adding-feature/SKILL.md) for more information. ## Common Issues & Solutions @@ -127,7 +120,7 @@ This template includes Cursor rules in `.cursor/rules/` to help AI assistants un When building your SaaS app with this template: 1. **Configure branding:** Update `main.wasp` with your app name, title, description, and metadata -2. **Choose auth methods:** Enable/disable OAuth providers in `main.wasp` auth section +2. **Choose auth methods:** Enable/disable different auth methods (email, Google, GitHub, Discord, Slack, etc.) in `main.wasp` auth section 3. **Set up payments:** Configure Stripe, Polar.sh or Lemon Squeezy (see https://docs.opensaas.sh/guides/payment-integrations/) 4. **Customize landing page:** Edit components in `src/landing-page/` 5. **Reference demo features:** Demo app code shows how to use the features of the template (`demo-ai-app`, example tasks, etc.) From 61a32e0dbee4331a7911aa10ddc399b1b5cb270b Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:14:22 +0100 Subject: [PATCH 05/16] Add and update skills for auth, payments, debugging, deployment Added new skill files for configuring authentication, payments, debugging Wasp, and deploying the app. Updated existing feature scaffolding skills for improved clarity and consistency. Added commands for reviewing and removing AI-generated code slop. --- template/.claude/commands/review-ai-slop.md | 15 ++++ .../.claude/skills/adding-feature/SKILL.md | 16 ++-- .../.claude/skills/adding-feature/database.md | 12 +-- .../skills/adding-feature/operations.md | 41 +++-------- .../.claude/skills/adding-feature/pages.md | 36 ++------- .../skills/adding-feature/troubleshooting.md | 41 ++--------- .../skills/adding-feature/wasp-config.md | 14 ++-- .../.claude/skills/configuring-auth/SKILL.md | 39 ++++++++++ .../configuring-auth/troubleshooting.md | 33 +++++++++ .../skills/configuring-payments/SKILL.md | 56 ++++++++++++++ .../skills/configuring-payments/cleanup.md | 19 +++++ .../configuring-payments/troubleshooting.md | 34 +++++++++ .../.claude/skills/debugging-wasp/SKILL.md | 73 +++++++++++++++++++ .../skills/debugging-wasp/troubleshooting.md | 42 +++++++++++ .../.claude/skills/deploying-app/SKILL.md | 37 ++++++++++ .../skills/deploying-app/troubleshooting.md | 36 +++++++++ template/app/.cursor/commands/deslop.md | 11 +++ 17 files changed, 436 insertions(+), 119 deletions(-) create mode 100644 template/.claude/commands/review-ai-slop.md create mode 100644 template/.claude/skills/configuring-auth/SKILL.md create mode 100644 template/.claude/skills/configuring-auth/troubleshooting.md create mode 100644 template/.claude/skills/configuring-payments/SKILL.md create mode 100644 template/.claude/skills/configuring-payments/cleanup.md create mode 100644 template/.claude/skills/configuring-payments/troubleshooting.md create mode 100644 template/.claude/skills/debugging-wasp/SKILL.md create mode 100644 template/.claude/skills/debugging-wasp/troubleshooting.md create mode 100644 template/.claude/skills/deploying-app/SKILL.md create mode 100644 template/.claude/skills/deploying-app/troubleshooting.md create mode 100644 template/app/.cursor/commands/deslop.md diff --git a/template/.claude/commands/review-ai-slop.md b/template/.claude/commands/review-ai-slop.md new file mode 100644 index 000000000..74ba9e315 --- /dev/null +++ b/template/.claude/commands/review-ai-slop.md @@ -0,0 +1,15 @@ +--- +description: Review current code changes for AI generated +--- + +# Remove AI slop + +Check the diff against main, and remove all AI generated slop introduced in this branch. + +This includes: +- Extra comments that a human wouldn't add or is inconsistent with the rest of the file +- Extra defensive checks or try/catch blocks that are abnormal for that area of the codebase (especially if called by trusted / validated codepaths) +- Casts to any (or as) to get around type issues +- Any other style that is inconsistent with the file + +Report at the end with only a 1-3 sentence summary of what you changed. \ No newline at end of file diff --git a/template/.claude/skills/adding-feature/SKILL.md b/template/.claude/skills/adding-feature/SKILL.md index 31a991809..0a0c7d960 100644 --- a/template/.claude/skills/adding-feature/SKILL.md +++ b/template/.claude/skills/adding-feature/SKILL.md @@ -9,14 +9,14 @@ description: plan and scaffold a new feature for the Open SaaS app following Was 1. ask the user what feature they want to add 2. gather requirements: - - does it need authentication? - - what kind of database models (entities) may be needed? - - what are the main user actions? (create, read, update, delete, etc.) - - what dependencies may be needed? - - what integrations may be needed? - - what types of UI components may be needed? - - might this feature make use of wasp's jobs feature? - - etc. + - **Access:** public, authenticated, or admin-only? + - **Subscription tier:** available to all users or gated by plan (hobby/pro)? + - **Usage limits:** should it consume credits or have rate limits? + - **Data model:** what entities are needed? relate to User? + - **Operations:** what can users do? (CRUD, custom actions) + - **Admin visibility:** should admins see this data in the dashboard? + - **Background work:** needs scheduled jobs or async processing? + - **External APIs:** any third-party integrations? 3. determine feature name in kebab-case (e.g., `todo-list`, `user-notes`) ## Implementation Steps diff --git a/template/.claude/skills/adding-feature/database.md b/template/.claude/skills/adding-feature/database.md index bd380d0b8..4f7935208 100644 --- a/template/.claude/skills/adding-feature/database.md +++ b/template/.claude/skills/adding-feature/database.md @@ -1,11 +1,7 @@ # Database Setup -## Adding Entities to schema.prisma +1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) for existing patterns +2. add new Prisma model +3. run `wasp db migrate-dev --name describe-change` -1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) to understand existing models and common patterns. -2. add new Prisma model. - -## Running Migrations - -Refer to [migrating-db SKILL.md](../.claude/skills/migrating-db/SKILL.md) for more information. -Note: Wasp automatically generates TypeScript types in `wasp/entities` +Wasp automatically generates TypeScript types in `wasp/entities`. diff --git a/template/.claude/skills/adding-feature/operations.md b/template/.claude/skills/adding-feature/operations.md index be781e46b..b3ef856a6 100644 --- a/template/.claude/skills/adding-feature/operations.md +++ b/template/.claude/skills/adding-feature/operations.md @@ -1,36 +1,17 @@ # Operations (Backend Logic) -## Creating operations.ts +## Setup -1. create directory: `mkdir -p app/src/{feature-name}/` -2. create `app/src/{feature-name}/operations.ts` -3. reference [`../../../app/src/demo-ai-app/operations.ts`](../../../app/src/demo-ai-app/operations.ts) as example +1. create `app/src/{feature-name}/operations.ts` +2. reference [`../../../app/src/demo-ai-app/operations.ts`](../../../app/src/demo-ai-app/operations.ts) as example -## Implementation Guidelines +## Guidelines -**Queries (reading data):** -- use for fetching data -- return data from database via `context.entities.EntityName` -- always check `if (!context.user)` for authenticated operations +- **Queries:** for reading data +- **Actions:** for create/update/delete +- check `if (!context.user)` for authenticated operations +- verify ownership before modifying resources +- access database via `context.entities.EntityName` +- use `HttpError` from `wasp/server` for errors -**Actions (writing data):** -- use for create, update, delete operations -- always verify ownership before modifying resources -- validate input data before processing - -**Error Handling:** -- use `HttpError` from `wasp/server` - -**Database Access:** -- access via `context.entities.EntityName` -- use Prisma methods on these entities - -## Import Conventions - -✅ Correct: -- `import { HttpError } from 'wasp/server'` -- `import type { GetItems } from 'wasp/server/operations'` -- `import type { EntityName } from 'wasp/entities'` - -❌ Wrong: -- `import { HttpError } from '@wasp/server'` +Import conventions are in project CLAUDE.md. diff --git a/template/.claude/skills/adding-feature/pages.md b/template/.claude/skills/adding-feature/pages.md index 821600858..f92b9bbee 100644 --- a/template/.claude/skills/adding-feature/pages.md +++ b/template/.claude/skills/adding-feature/pages.md @@ -1,37 +1,15 @@ # Pages (Frontend Components) -## Creating Page Component +## Setup 1. create `app/src/{feature-name}/{FeatureName}Page.tsx` 2. reference [`../../../app/src/demo-ai-app/DemoAppPage.tsx`](../../../app/src/demo-ai-app/DemoAppPage.tsx) as example -## Implementation Guidelines +## Guidelines -**Using Queries:** -- import and use Wasp's `useQuery` hook for reading data -- handle `isLoading` and `error` states -- data automatically refetches after actions +- **Queries:** use `useQuery` hook, handle `isLoading`/`error` states +- **Actions:** call directly with `await` (no `useAction` unless optimistic updates needed) +- **Auth:** use `useAuth` hook, or receive `AuthUser` via props on protected pages +- **Styling:** use Tailwind + ShadCN components from [`src/client/components/ui`](../../../app/src/client/components/ui/) -**Using Actions:** -- import action directly from `wasp/client/operations` -- call with `await` (do NOT use `useAction` unless optimistic updates needed) -- wrap in try/catch for error handling - -**Using Auth:** -- import and use Wasp's `useAuth` hook for authentication -- or pass Wasp's `AuthUser` object to the page component using props if it is protected by authentication via `authRequired: true` in the wasp config file - -**Layout:** -- use Tailwind CSS classes for styling -- prefer the use of ShadCN UI components for styling (some already exist in the template under [`src/client/components/ui`](../../../app/src/client/components/ui/)) - -## Import Conventions - -✅ Correct: -- `import { useQuery } from 'wasp/client/operations'` -- `import { getItems, createItem } from 'wasp/client/operations'` -- `import type { EntityName } from 'wasp/entities'` - -❌ Wrong: -- `import { useQuery } from '@wasp/client/operations'` -- `import { getItems } from '@src/feature-name/operations'` (use relative path in TypeScript) +Import conventions are in project CLAUDE.md. diff --git a/template/.claude/skills/adding-feature/troubleshooting.md b/template/.claude/skills/adding-feature/troubleshooting.md index 63e26c5e6..06b396f72 100644 --- a/template/.claude/skills/adding-feature/troubleshooting.md +++ b/template/.claude/skills/adding-feature/troubleshooting.md @@ -1,42 +1,13 @@ # Troubleshooting - Adding Features -## Type Errors After Adding Operations +**Type errors after adding operations:** re-run `wasp start`, restart TypeScript server -Re-run `wasp start` and inform the user to restart the typescript server to regenerate types. +**Entity not in context:** add to `entities: [...]` array in main.wasp -## "Cannot find module 'wasp/...'" +**Migration fails:** check schema.prisma syntax, ensure DB running (`wasp start db`) -Use `wasp/` prefix, NOT `@wasp/`. Example: `import { User } from 'wasp/entities'` +**401 errors:** verify `authRequired: true` in main.wasp -## Entity Not Found in Context +**Page 404:** verify route defined in main.wasp, restart Wasp server -Add entity to operation's `entities` array in `main.wasp`: -```wasp -query getItems { - fn: import { getItems } from "@src/feature-name/operations", - entities: [EntityName] // ← Must list all entities used -} -``` - -## Migration Fails - -- check `schema.prisma` syntax is valid -- ensure PostgreSQL is running (`wasp start db` if using managed DB) -- delete failed migration in `app/migrations/` directory and retry - -## 401 Unauthorized Errors - -- verify page has `authRequired: true` in `main.wasp` -- ensure testing on `localhost:3000` (correct port) -- check cookies are enabled in browser - -## Page Not Found (404) - -- verify route is defined in `main.wasp` -- check path matches what you're navigating to -- restart Wasp dev server - -## Data Not Updating in UI - -- queries auto-refetch after actions complete -- verify action completed successfully (no errors thrown) +For more issues, see [debugging-wasp skill](../debugging-wasp/SKILL.md). diff --git a/template/.claude/skills/adding-feature/wasp-config.md b/template/.claude/skills/adding-feature/wasp-config.md index 645c8ba04..5aa7df338 100644 --- a/template/.claude/skills/adding-feature/wasp-config.md +++ b/template/.claude/skills/adding-feature/wasp-config.md @@ -1,12 +1,8 @@ -# Wasp Configuration (main.wasp) +# Wasp Configuration -## Registering Feature in main.wasp +1. read [`../../../app/main.wasp`](../../../app/main.wasp) for existing patterns +2. add feature section with region comments -1. read [`../../../app/main.wasp`](../../../app/main.wasp) to see existing patterns -2. add feature section with region comments for organization - -## Key Points - -- list ALL entities accessed in `entities: [...]` array +Key points: +- list ALL entities in `entities: [...]` array - set `authRequired: true` for authenticated pages -- queries are for reading, actions are for writing diff --git a/template/.claude/skills/configuring-auth/SKILL.md b/template/.claude/skills/configuring-auth/SKILL.md new file mode 100644 index 000000000..5964ccd00 --- /dev/null +++ b/template/.claude/skills/configuring-auth/SKILL.md @@ -0,0 +1,39 @@ +--- +name: configuring-auth +description: configure authentication for Open SaaS (email/password and OAuth providers). +--- + +# configuring-auth + +All authentication guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt) + +## Check Current Status + +1. read [`../../../app/main.wasp`](../../../app/main.wasp) auth section +2. report enabled methods to user (email is enabled by default) + +## Email Authentication + +Email auth is enabled by default. For production: +1. configure email provider in main.wasp (SendGrid, Mailgun, or SMTP) +2. set provider env vars in `.env.server` +3. customize templates in `src/auth/email-and-pass/emails.ts` if needed + +**Dev testing:** use `Dummy` provider, find verification URLs in server console, or set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` + +## OAuth Providers + +1. **Enable:** uncomment provider in main.wasp auth methods. Note: Additional providers can be found in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). +2. **Credentials:** set `_CLIENT_ID` and `_CLIENT_SECRET` in `.env.server` +3. **Redirect URL:** configure in provider dashboard: + - Dev: `http://localhost:3001/auth//callback` + - Prod: `https://your-domain.com/auth//callback` +4. **Verify:** restart wasp, test login flow, check `wasp db studio` + +## Disabling Auth + +Comment out method in main.wasp, restart server. + +## Troubleshooting + +see [troubleshooting](./troubleshooting.md) diff --git a/template/.claude/skills/configuring-auth/troubleshooting.md b/template/.claude/skills/configuring-auth/troubleshooting.md new file mode 100644 index 000000000..ae534d88a --- /dev/null +++ b/template/.claude/skills/configuring-auth/troubleshooting.md @@ -0,0 +1,33 @@ +# Troubleshooting - Authentication + +## Email Issues + +**No verification email (dev):** check server console for URL, or set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` + +**No verification email (prod):** verify email provider configured (not `Dummy`), check env vars, verify sender address matches provider settings + +**Password reset fails:** verify `passwordReset.clientRoute` points to valid route + +## OAuth Issues + +**Button not appearing:** uncomment provider in main.wasp, restart server + +**redirect_uri_mismatch:** URL must match exactly: +- Port is `3001` (server), not `3000` +- Provider name lowercase (e.g., `github`) +- No trailing slash + +**Missing user data:** check `userSignupFields` in `src/auth/userSignupFields.ts`, verify OAuth scopes + +**Flow hangs:** check `onAuthSucceededRedirectTo` in main.wasp, clear cookies + +## Production Issues + +- Verify production env vars are set +- Use production OAuth credentials (not dev) +- Ensure redirect URLs use production domain +- Email provider must not be `Dummy` + +## More Help + +Refer to [Wasp auth docs](https://wasp.sh/llms.txt) diff --git a/template/.claude/skills/configuring-payments/SKILL.md b/template/.claude/skills/configuring-payments/SKILL.md new file mode 100644 index 000000000..538ad5f82 --- /dev/null +++ b/template/.claude/skills/configuring-payments/SKILL.md @@ -0,0 +1,56 @@ +--- +name: configuring-payments +description: configure payment integration for Open SaaS (Stripe, Lemon Squeezy, or Polar). +--- + +# configuring-payments + +All payment integration guide URLs, including provider-specific guide URLs, are available in the [Open SaaS LLM-optimized documentation](https://docs.opensaas.sh/llms.txt) + +## Setup Steps + +### 1. Select Provider + +In [`../../../app/src/payment/paymentProcessor.ts`](../../../app/src/payment/paymentProcessor.ts), uncomment chosen provider, comment out others. + +### 2. Environment Variables + +Set in `.env.server`: + +| Provider | Variables | +|----------|-----------| +| Stripe | `STRIPE_API_KEY`, `STRIPE_WEBHOOK_SECRET` | +| Lemon Squeezy | `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_STORE_ID`, `LEMONSQUEEZY_WEBHOOK_SECRET` | +| Polar | `POLAR_ORGANIZATION_ACCESS_TOKEN`, `POLAR_WEBHOOK_SECRET`, `POLAR_SANDBOX_MODE=true` | + +### 3. Create Products + +Create in provider dashboard: 2 subscriptions (Hobby, Pro) + 1 one-time (Credits). + +Set IDs in `.env.server`: +``` +PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=... +PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=... +PAYMENTS_CREDITS_10_PLAN_ID=... +``` + +Update `src/payment/plans.ts` if changing product names. + +### 4. Configure Webhooks + +**Stripe:** `stripe listen --forward-to localhost:3001/payments-webhook` + +**Lemon Squeezy / Polar:** use ngrok (`ngrok http 3001`), set webhook URL to `https://[ngrok-url]/payments-webhook` + +### 5. Test + +1. start wasp + webhook forwarding +2. test checkout, verify `subscriptionStatus` in `wasp db studio` + +## Cleanup + +See [cleanup.md](./cleanup.md) to remove unused provider code. + +## Troubleshooting + +See [troubleshooting](./troubleshooting.md) diff --git a/template/.claude/skills/configuring-payments/cleanup.md b/template/.claude/skills/configuring-payments/cleanup.md new file mode 100644 index 000000000..f3d16c662 --- /dev/null +++ b/template/.claude/skills/configuring-payments/cleanup.md @@ -0,0 +1,19 @@ +# Cleanup Unused Providers + +Optional cleanup after selecting payment provider. + +## Remove Unused Provider Directories + +Delete directories in `app/src/payment/` for providers you're not using (e.g., `stripe/`, `lemonsqueezy/`, `polar/`). + +## Environment Variables + +Remove unused provider variables from `.env.server`. + +## Schema (Lemon Squeezy only) + +If not using Lemon Squeezy, remove `lemonSqueezyCustomerPortalUrl` from User model in schema.prisma, then run `wasp db migrate-dev`. + +## Verify + +Run `wasp clean && wasp start`, test payment flow. diff --git a/template/.claude/skills/configuring-payments/troubleshooting.md b/template/.claude/skills/configuring-payments/troubleshooting.md new file mode 100644 index 000000000..4edf7c531 --- /dev/null +++ b/template/.claude/skills/configuring-payments/troubleshooting.md @@ -0,0 +1,34 @@ +# Troubleshooting - Payments + +## Webhooks Not Working + +**Stripe:** verify `stripe listen` running, secret matches CLI output + +**Lemon Squeezy / Polar:** verify ngrok running, URL includes `/payments-webhook`, secret matches + +**ngrok expired:** restart ngrok, update webhook URL in dashboard + +## Product IDs + +ID format varies by provider: +- Stripe: `price_...` +- Lemon Squeezy: `variant_...` +- Polar: product IDs + +Ensure products active in dashboard, IDs correct in `.env.server`. + +## Subscription Not Updating + +Check webhook events enabled: +- Lemon Squeezy: `order_created`, `subscription_*` +- Polar: `order.paid`, `subscription.updated` + +## Test Payments + +**Stripe:** card `4242 4242 4242 4242`, API key starts with `sk_test_` + +**Polar:** set `POLAR_SANDBOX_MODE=true` + +## More Help + +See [Open SaaS payment docs](https://docs.opensaas.sh/llms.txt) diff --git a/template/.claude/skills/debugging-wasp/SKILL.md b/template/.claude/skills/debugging-wasp/SKILL.md new file mode 100644 index 000000000..3d421e732 --- /dev/null +++ b/template/.claude/skills/debugging-wasp/SKILL.md @@ -0,0 +1,73 @@ +--- +name: debugging-wasp +description: diagnose and fix common Wasp development issues in Open SaaS. +--- + +# debugging-wasp + +## Diagnostic Workflow + +1. identify error type from message +2. run appropriate diagnostics +3. apply fix +4. verify fix worked + +## Quick Fixes + +**Nuclear option (fixes most issues):** +```bash +cd app && wasp clean && wasp start +``` + +**Restart TypeScript server:** Cmd/Ctrl + Shift + P → "TypeScript: Restart TS Server" + +## Wasp-Specific Issues + +### Import Errors + +Import conventions are documented in project CLAUDE.md. Key points: +- TypeScript files: use `wasp/...` (not `@wasp/`) +- TypeScript files: use relative paths (not `@src/`) +- main.wasp: use `@src/...` paths + +After fixing imports, re-run `wasp start`. + +### Entity/Operation Errors + +**"context.entities.EntityName is undefined":** +1. verify entity exists in `schema.prisma` +2. check entity is in operation's `entities: [...]` array in `main.wasp` +3. restart Wasp server + +**Types not updating after adding operation:** +1. restart Wasp server to regenerate types +2. restart TypeScript server in IDE + +### Database Issues + +**Schema changes not applied:** +```bash +wasp db migrate-dev --name describe-change +``` + +**Inspect database state:** +```bash +wasp db studio +``` + +**Database out of sync (WARNING: deletes data):** +```bash +wasp db reset +``` + +### Runtime Errors + +**401 errors:** verify `if (!context.user)` guard or `authRequired: true` in page + +**Database connection:** run `wasp start db` or check `DATABASE_URL` in `.env.server` + +**Environment variables:** check `.env.server`, restart server after changes + +## Troubleshooting + +see [troubleshooting](./troubleshooting.md) for specific issues diff --git a/template/.claude/skills/debugging-wasp/troubleshooting.md b/template/.claude/skills/debugging-wasp/troubleshooting.md new file mode 100644 index 000000000..a9229db5b --- /dev/null +++ b/template/.claude/skills/debugging-wasp/troubleshooting.md @@ -0,0 +1,42 @@ +# Troubleshooting - Debugging Wasp + +## `wasp clean` Doesn't Help + +Manually clean and reinstall: +```bash +rm -rf .wasp/ node_modules/ +npm install +wasp start +``` + +## Operation Not Found at Runtime + +1. verify function is exported: `export const myOperation = ...` +2. check import path in `main.wasp` matches file location +3. check for typos in operation name + +## Port Already in Use + +```bash +pkill -f wasp +# or: lsof -i :3000 && kill +``` + +## IDE Errors But Wasp Compiles + +Trust Wasp compiler. To fix IDE: +1. restart TypeScript server +2. verify IDE isn't excluding `.wasp/out/sdk/wasp/` +3. close and reopen workspace + +## Generated Code Location + +For debugging, inspect `.wasp/out/`: +- Server: `.wasp/out/server/` +- Client: `.wasp/out/web-app/` +- SDK types: `.wasp/out/sdk/wasp/` + +## Need More Help + +- Wasp Discord: https://discord.gg/aCamt5wCpS +- Wasp Docs: https://wasp.sh/llms.txt diff --git a/template/.claude/skills/deploying-app/SKILL.md b/template/.claude/skills/deploying-app/SKILL.md new file mode 100644 index 000000000..281e8ee79 --- /dev/null +++ b/template/.claude/skills/deploying-app/SKILL.md @@ -0,0 +1,37 @@ +--- +name: deploying-app +description: deploy the Open SaaS app to Railway or Fly.io using Wasp CLI. +--- + +# deploying-app + +All deployment guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt) + +## Pre-Deployment + +1. confirm platform: Railway or Fly.io +2. verify CLI installed and logged in: + - Railway: `railway whoami` + - Fly.io: `fly auth whoami` +3. collect env vars: server secrets + client vars (prefixed `REACT_APP_`) + +## Deploy Commands + +| Platform | First Time | Subsequent | +|----------|------------|------------| +| Railway | `wasp deploy railway launch --server-secret KEY=val` | `REACT_APP_X=val wasp deploy railway deploy ` | +| Fly.io | `wasp deploy fly launch --server-secret KEY=val` | `REACT_APP_X=val wasp deploy fly deploy` | + +**Critical:** +- `launch` runs ONCE only +- Client vars required on EVERY deploy +- Don't interrupt deployment + +## Verify + +- Check logs: Railway dashboard, `wasp deploy railway variables` or `wasp deploy fly cmd logs --context=server` +- Test deployed URL + +## Troubleshooting + +See [troubleshooting](./troubleshooting.md) diff --git a/template/.claude/skills/deploying-app/troubleshooting.md b/template/.claude/skills/deploying-app/troubleshooting.md new file mode 100644 index 000000000..2f31f3b11 --- /dev/null +++ b/template/.claude/skills/deploying-app/troubleshooting.md @@ -0,0 +1,36 @@ +# Troubleshooting - Deployment + +## Client Env Vars Not Working + +Must be prefixed `REACT_APP_` and provided on EVERY deploy: +```bash +REACT_APP_X=val wasp deploy railway deploy my-app +``` + +## Deployment Interrupted + +Safe to rerun: `wasp deploy railway deploy` or `wasp deploy fly deploy` + +Do NOT rerun: `launch` commands (one-time only) + +## Add Server Secrets After Launch + +**Railway:** set in dashboard (Service > Variables) or rerun with `--server-secret` + +**Fly.io:** `wasp deploy fly cmd secrets set KEY=value --context=server` + +## Name Already Taken + +Railway names unique per account. Fly.io names globally unique. + +## Build Failures + +Test locally first: `wasp build` + +## Database Issues + +Both platforms auto-configure `DATABASE_URL`. Check database service is running in dashboard/status. + +## More Help + +See [Wasp deployment docs](https://wasp.sh/llms.txt) diff --git a/template/app/.cursor/commands/deslop.md b/template/app/.cursor/commands/deslop.md new file mode 100644 index 000000000..d82835663 --- /dev/null +++ b/template/app/.cursor/commands/deslop.md @@ -0,0 +1,11 @@ +# Remove AI code slop + +Check the diff against main, and remove all AI generated slop introduced in this branch. + +This includes: +- Extra comments that a human wouldn't add or is inconsistent with the rest of the file +- Extra defensive checks or try/catch blocks that are abnormal for that area of the codebase (especially if called by trusted / validated codepaths) +- Casts to any to get around type issues +- Any other style that is inconsistent with the file + +Report at the end with only a 1-3 sentence summary of what you changed \ No newline at end of file From aa0236f4f6c188fac7f1b044ba6ef8292ea53c3d Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:18:36 +0100 Subject: [PATCH 06/16] Add skill guide for background job integration Introduces SKILL.md for adding scheduled or async background jobs using Wasp's PgBoss integration. Includes job declaration, implementation steps, cron patterns, manual invocation, and troubleshooting tips. --- .../skills/adding-background-job/SKILL.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 template/.claude/skills/adding-background-job/SKILL.md diff --git a/template/.claude/skills/adding-background-job/SKILL.md b/template/.claude/skills/adding-background-job/SKILL.md new file mode 100644 index 000000000..3d82fa97b --- /dev/null +++ b/template/.claude/skills/adding-background-job/SKILL.md @@ -0,0 +1,71 @@ +--- +name: adding-background-job +description: add scheduled or async background jobs using Wasp's PgBoss integration. +--- + +# adding-background-job + +Complete job guide URLs are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). + +## Existing Example + +Reference the `dailyStatsJob` in this template: +- Declaration: [`../../../app/main.wasp`](../../../app/main.wasp) (search for `job dailyStatsJob`) +- Implementation: [`../../../app/src/analytics/stats.ts`](../../../app/src/analytics/stats.ts) + +## Adding a Job + +### 1. Declare in main.wasp + +```wasp +job myJob { + executor: PgBoss, + perform: { + fn: import { myJobFn } from "@src/jobs/myJob" + }, + schedule: { + cron: "0 * * * *" // hourly + }, + entities: [EntityName] // entities accessed in job +} +``` + +### 2. Implement the Job + +Create `src/jobs/myJob.ts`: + +```typescript +import type { MyJob } from 'wasp/server/jobs' + +export const myJobFn: MyJob = async (_args, context) => { + // Access entities via context.entities.EntityName + // Use try/catch and log errors +} +``` + +## Common Cron Patterns + +| Schedule | Cron | +|----------|------| +| Every minute | `* * * * *` | +| Every hour | `0 * * * *` | +| Daily at midnight | `0 0 * * *` | +| Weekly (Sunday) | `0 0 * * 0` | + +## Manual Invocation + +Jobs can be triggered manually from operations: + +```typescript +import { myJob } from 'wasp/server/jobs' + +await myJob.submit({}) // or with args +``` + +## Troubleshooting + +**Job not running:** Verify PostgreSQL is running (jobs use pg-boss queue) + +**Entities undefined:** Add to `entities: [...]` array in job declaration + +**Debugging:** Use `* * * * *` cron for every-minute execution during development From 3083c1ba21fa93a1b1e33eb9e59e5e68a5720dd4 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:53:01 +0100 Subject: [PATCH 07/16] Add deployment and setup wizard commands and skills Introduces new commands for deploying and initializing Open SaaS projects, along with detailed skills for pre-deployment validation and interactive setup. Updates deployment instructions to reference Open SaaS documentation and clarifies review command description. These changes improve onboarding and deployment reliability for Open SaaS apps. --- template/.claude/commands/deploy.md | 21 ++ .../commands/open-saas-setup-wizard.md | 9 + template/.claude/commands/review-ai-slop.md | 4 +- .../.claude/skills/deploying-app/SKILL.md | 4 +- .../.claude/skills/pre-deployment/SKILL.md | 209 ++++++++++++++++++ template/.claude/skills/setup-wizard/SKILL.md | 114 ++++++++++ 6 files changed, 358 insertions(+), 3 deletions(-) create mode 100644 template/.claude/commands/deploy.md create mode 100644 template/.claude/commands/open-saas-setup-wizard.md create mode 100644 template/.claude/skills/pre-deployment/SKILL.md create mode 100644 template/.claude/skills/setup-wizard/SKILL.md diff --git a/template/.claude/commands/deploy.md b/template/.claude/commands/deploy.md new file mode 100644 index 000000000..64033febd --- /dev/null +++ b/template/.claude/commands/deploy.md @@ -0,0 +1,21 @@ +--- +description: Run pre-deployment checks then deploy to Railway or Fly.io. +--- + +# Deploy Open SaaS App + +This command guides you through validating your app configuration and deploying to production. + +## Process + +1. **Pre-Deployment Validation** - Run the [pre-deployment skill](../skills/pre-deployment/SKILL.md) to check: + - Wasp config metadata (app name, OG tags, analytics) + - Environment variables + - Database migrations + - Optional: production build test + +2. **Deployment** - If validation passes, run the [deploying-app skill](../skills/deploying-app/SKILL.md) to deploy to Railway or Fly.io. + +Begin with: "I'll help you deploy your Open SaaS app. First, let me run some pre-deployment checks to catch any issues." + +Then execute the pre-deployment skill. After it completes successfully, ask the user if they want to proceed with deployment and execute the deploying-app skill. diff --git a/template/.claude/commands/open-saas-setup-wizard.md b/template/.claude/commands/open-saas-setup-wizard.md new file mode 100644 index 000000000..bc0f3adbf --- /dev/null +++ b/template/.claude/commands/open-saas-setup-wizard.md @@ -0,0 +1,9 @@ +--- +description: Initialize a guided setup for configuring a new Open SaaS project. +--- + +# Open SaaS Setup Wizard + +Run the [setup-wizard skill](../skills/setup-wizard/SKILL.md) to guide the user through configuring their Open SaaS project. + +Begin with: "Welcome to Open SaaS setup! I'll guide you through configuring your project. Let's start with your app branding." diff --git a/template/.claude/commands/review-ai-slop.md b/template/.claude/commands/review-ai-slop.md index 74ba9e315..02811cb96 100644 --- a/template/.claude/commands/review-ai-slop.md +++ b/template/.claude/commands/review-ai-slop.md @@ -1,8 +1,8 @@ --- -description: Review current code changes for AI generated +description: Review current code changes for poorly generated code. --- -# Remove AI slop +# Review AI Slop Check the diff against main, and remove all AI generated slop introduced in this branch. diff --git a/template/.claude/skills/deploying-app/SKILL.md b/template/.claude/skills/deploying-app/SKILL.md index 281e8ee79..9c2be6754 100644 --- a/template/.claude/skills/deploying-app/SKILL.md +++ b/template/.claude/skills/deploying-app/SKILL.md @@ -5,7 +5,9 @@ description: deploy the Open SaaS app to Railway or Fly.io using Wasp CLI. # deploying-app -All deployment guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt) +Complete deployment guide URLs are available in the [Open SaaS Deployment Guide](https://docs.opensaas.sh/llms.txt) and the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). + +Run [pre-deployment skill](../pre-deployment/SKILL.md) first to validate configuration. ## Pre-Deployment diff --git a/template/.claude/skills/pre-deployment/SKILL.md b/template/.claude/skills/pre-deployment/SKILL.md new file mode 100644 index 000000000..8e746cbc0 --- /dev/null +++ b/template/.claude/skills/pre-deployment/SKILL.md @@ -0,0 +1,209 @@ +--- +name: pre-deployment +description: validate configuration and test production build before deploying. +--- + +# pre-deployment + +Pre-deployment validation checks that catch common issues before deploying with the [deploying-app skill](../deploying-app/SKILL.md). + +## Before Starting + +1. verify user is in the app directory (check for `main.wasp` or `main.wasp.ts`) +2. ask: "Would you like me to run pre-deployment checks on your Open SaaS app?" + +## Validation Steps + +Run these checks in order. Report all issues found, then ask the user if they want to proceed or fix issues first. + +### Step 1: Wasp Config Metadata + +Check the wasp config file (`main.wasp` or `main.wasp.ts`) `app` block for placeholder values: + +**App Identity:** +- `app.title` - should NOT be "My Open SaaS App" or contain "Open SaaS" +- `app.name` - should be customized (PascalCase identifier) + +**Head Meta Tags (in `app.head`):** +- ``) +- OR scripts should be removed/commented if not using Plausible + +**Email Configuration:** +- `auth.methods.email.fromField.email` - should NOT be "me@example.com" +- `emailSender.defaultFrom.email` - should NOT be "me@example.com" +- `emailSender.provider` - should NOT be "Dummy" for production + +Report format: +``` +## Configuration Issues Found + +### Critical (must fix): +- [ ] issue description + +### Warnings (recommended to fix): +- [ ] issue description + +### Passed: +- [x] check that passed +``` + +### Step 2: Environment Variables + +Based on the wasp config, generate a checklist of required env vars for the user to verify. **Do NOT read .env files** - ask the user to confirm they have the required variables set. + +Present the checklist based on what's configured: + +``` +## Environment Variables Checklist + +Please verify you have these variables ready for deployment: + +### Server Variables (.env.server) +- [ ] DATABASE_URL - auto-set by Railway/Fly, no action needed +- [ ] JWT_SECRET - auto-generated by Wasp CLI deploy + +### Based on Your Config: +[Generate this list by checking main.wasp for enabled features] +``` + +**If OAuth providers enabled:** +- Google: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET` +- GitHub: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET` +- Discord: `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET` +- etc. + +**If email provider is SendGrid/Mailgun/SMTP:** +- SendGrid: `SENDGRID_API_KEY` +- Mailgun: `MAILGUN_API_KEY`, `MAILGUN_DOMAIN` +- SMTP: `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD` + +**If file uploads configured:** +- `AWS_S3_REGION`, `AWS_S3_FILES_BUCKET`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` + +**If OpenAI integration used:** +- `OPENAI_API_KEY` + +**If payment provider configured:** +- Remind user to switch from test/sandbox keys to **production keys** +- Stripe: `STRIPE_API_KEY` (live key), `STRIPE_WEBHOOK_SECRET` +- Lemon Squeezy: `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_WEBHOOK_SECRET` +- Polar: `POLAR_ACCESS_TOKEN`, `POLAR_WEBHOOK_SECRET`, set `POLAR_SANDBOX_MODE=false` +- See [configuring-payments skill](../configuring-payments/SKILL.md) for full setup + +**Client Variables:** +- List any `REACT_APP_*` vars needed +- Remind user: "Client env vars must be passed at deploy time, not set in hosting dashboards." + +Ask user: "Do you have all the required environment variables ready? (yes/no)" + +### Step 3: Production Configuration Reminders + +Based on enabled features, remind user of production setup tasks: + +**If OAuth providers enabled:** +- Remind user: "Add your production domain to OAuth redirect URLs in each provider's dashboard" +- Format: `https://your-domain.com/auth//callback` + +**If payment provider configured:** +- Stripe: Create production webhook endpoint at `https://your-domain.com/payments-webhook` +- Lemon Squeezy: Configure webhook with events: `order_created`, `subscription_created`, `subscription_updated`, `subscription_cancelled` +- Polar: Create webhook endpoint, disable sandbox mode + +**If AWS S3 file uploads used:** +- Remind user: "Add your production domain to S3 bucket CORS `AllowedOrigins`" + +### Step 4: Database Migrations + +Check for pending migrations: +```bash +# List migration files +ls -la migrations/ +``` + +Remind user: +- Production automatically applies pending migrations on server start +- Ensure migrations are committed to version control +- Test migrations work locally before deploying + +### Step 5: Production Build Test + +Ask user: "Would you like to test the production build locally? This catches environment-specific issues." + +If yes, guide through: + +1. Start database (if not running): + ```bash + wasp start db + ``` + +2. Run production build test: + ```bash + wasp build start --server-env DATABASE_URL= --server-env JWT_SECRET=test-secret-for-local + ``` + + Or with env file: + ```bash + wasp build start --server-env-file .env.server + ``` + +3. Verify app loads at `http://localhost:3000` + +4. Check for: + - Build compilation errors + - Runtime errors in console + - Missing env var errors + +If issues found, help debug before proceeding. + +### Step 6: Final Checklist + +Present summary: + +``` +## Pre-Deployment Summary + +### Configuration Status: +- App Name: [name] +- App Title: [title] +- Email Provider: [provider] +- Auth Methods: [list] +- Payment Provider: [if configured] + +### Issues to Resolve: +[list any issues from steps 1-4] + +### Before Deploying: +- [ ] All configuration placeholders replaced +- [ ] Production email provider configured +- [ ] Required env vars ready for deployment +- [ ] Production build tested locally (optional but recommended) +- [ ] Database migrations committed + +### Ready to Deploy? +``` + +## Completion + +If all checks pass or user chooses to proceed: +- Summarize what was validated +- Ask: "Would you like to proceed with deployment? I can guide you through deploying to Railway or Fly.io." +- If yes, transition to [deploying-app skill](../deploying-app/SKILL.md) + +## Reference + +For deployment details not covered here, see: +- [Open SaaS Deployment Guide](https://docs.opensaas.sh/guides/deploying/) - Open SaaS-specific deployment instructions +- [Wasp Deployment Intro](https://wasp.sh/docs/deployment/intro) +- [Environment Variables](https://wasp.sh/docs/deployment/env-vars) +- [Database Setup](https://wasp.sh/docs/deployment/database) +- [Local Build Testing](https://wasp.sh/docs/deployment/local-testing) diff --git a/template/.claude/skills/setup-wizard/SKILL.md b/template/.claude/skills/setup-wizard/SKILL.md new file mode 100644 index 000000000..ce23c5556 --- /dev/null +++ b/template/.claude/skills/setup-wizard/SKILL.md @@ -0,0 +1,114 @@ +--- +name: setup-wizard +description: interactive guided setup for configuring a new Open SaaS project. +--- + +# setup-wizard + +This wizard walks through essential Open SaaS configuration. Run each step in order, asking the user for decisions at each stage. + +## Before Starting + +1. verify user is in the app directory (check for wasp config file: `main.wasp` or `main.wasp.ts`) +2. ask: "Would you like me to guide you through setting up your Open SaaS project?" + +## Setup Steps + +Guide the user through these steps in order. At each step, ask for their preferences before making changes. + +### Step 1: App Branding + +Ask the user: +- What is your app name? +- What is a one-line description? + +Then update in [`../../../app/main.wasp`](../../../app/main.wasp): +- `app.name` +- `app.title` +- `app.head` meta tags + +### Step 2: Authentication + +Ask the user which auth methods they want: +- Email/password (enabled by default) +- Google OAuth +- GitHub OAuth +- Discord OAuth +- Slack OAuth +- Keycloak OAuth + +For each OAuth provider selected: +1. uncomment or add the provider in wasp config file auth methods +2. inform user they'll need to set env vars later (Step 6) + +Refer to [configuring-auth skill](../configuring-auth/SKILL.md) for details. + +### Step 3: Payment Provider + +Ask the user: +- Which payment provider? (Stripe / Lemon Squeezy / Polar / Skip for now) + +If they choose one: +1. update `src/payment/paymentProcessor.ts` to select their provider +2. note they'll configure credentials in Step 6 + +Refer to [configuring-payments skill](../configuring-payments/SKILL.md) for details. + +### Step 4: Email Provider + +Ask the user: +- Which email provider for production? (SendGrid / Mailgun / SMTP / Skip for now) + +If they choose one: +1. update `emailSender.provider` in wasp config file +2. note they'll configure credentials in Step 6 + +For development, explain `Dummy` provider shows emails in console. + +### Step 5: Analytics (Optional) + +Ask the user: +- Want to set up analytics? (Plausible / Google Analytics / Skip) + +If yes, note they'll add tracking ID in Step 6. + +### Step 6: Environment Variables + +Generate a checklist of required env vars based on their selections: + +``` +# Based on your setup, you need these in .env.server: + +# Database (required) +DATABASE_URL= + +# Auth - OAuth (if selected) +GOOGLE_CLIENT_ID= +GOOGLE_CLIENT_SECRET= +# ... etc based on selections + +# Payments (if selected) +STRIPE_API_KEY= +# ... etc based on selection + +# Email (if selected) +SENDGRID_API_KEY= +# ... etc based on selection +``` + +Ask: "Would you like me to create a .env.server template with these variables?" + +### Step 7: Verify Setup + +Refer to [starting-wasp skill](../starting-wasp/SKILL.md) for details on how to start the development server. +1. after starting the development server, verify configuration compiles +2. check for any errors +3. summarize what was configured and what still needs credentials + +## Completion + +Provide a summary: +- What was configured +- What env vars still need to be filled in +- Links to provider dashboards for obtaining credentials +- Suggest running e2e tests after adding credentials From 72f61df8b5c2e54bb2a178116b6e75c4a3afd640 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Tue, 2 Dec 2025 13:56:19 +0100 Subject: [PATCH 08/16] Update CLAUDE.md --- template/app/CLAUDE.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index 416b8059f..94128c265 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -2,6 +2,12 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## New Project Detection + +On first interaction, check if this is an unconfigured Open SaaS project by reading `main.wasp` (or `main.wasp.ts`). If `app.title` is still "My Open SaaS App" or contains placeholder values like "your-saas-app.com", suggest: + +> "It looks like you haven't customized your Open SaaS project yet. Would you like me to run the setup wizard to configure your app? Just say 'yes' or run `/open-saas-setup-wizard`." + ## What is This Project? This is the **Open SaaS template** - a free, open-source SaaS starter boilerplate built on the Wasp framework. Users get this template when they run `wasp new -t saas` and customize it to build their own SaaS applications. From 7f315e717b4e7afc355bd526c0ac7cf3d94cb062 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:33:41 +0100 Subject: [PATCH 09/16] Add Stripe CLI automation scripts and docs Introduced scripts for automated Stripe setup and configuration checking, and added a guide for Stripe CLI-based setup. Updated payment and auth skill docs to reference new automation options and improved guidance. Enhanced troubleshooting and setup wizard documentation for better user onboarding. --- .../.claude/skills/configuring-auth/SKILL.md | 4 +- .../skills/configuring-payments/SKILL.md | 16 +-- .../scripts/check-stripe-config.sh | 110 ++++++++++++++++++ .../scripts/setup-stripe-products.sh | 102 ++++++++++++++++ .../stripe-automated-setup.md | 109 +++++++++++++++++ .../configuring-payments/troubleshooting.md | 5 +- template/.claude/skills/setup-wizard/SKILL.md | 9 +- 7 files changed, 344 insertions(+), 11 deletions(-) create mode 100644 template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh create mode 100644 template/.claude/skills/configuring-payments/scripts/setup-stripe-products.sh create mode 100644 template/.claude/skills/configuring-payments/stripe-automated-setup.md diff --git a/template/.claude/skills/configuring-auth/SKILL.md b/template/.claude/skills/configuring-auth/SKILL.md index 5964ccd00..32b9487e4 100644 --- a/template/.claude/skills/configuring-auth/SKILL.md +++ b/template/.claude/skills/configuring-auth/SKILL.md @@ -5,7 +5,9 @@ description: configure authentication for Open SaaS (email/password and OAuth pr # configuring-auth -All authentication guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt) +All authentication guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). + +Inform the user that guides found on https://wasp.sh/docs have full walkthroughs with screenshots and examples, if preferred. ## Check Current Status diff --git a/template/.claude/skills/configuring-payments/SKILL.md b/template/.claude/skills/configuring-payments/SKILL.md index 538ad5f82..284ada11a 100644 --- a/template/.claude/skills/configuring-payments/SKILL.md +++ b/template/.claude/skills/configuring-payments/SKILL.md @@ -7,7 +7,13 @@ description: configure payment integration for Open SaaS (Stripe, Lemon Squeezy, All payment integration guide URLs, including provider-specific guide URLs, are available in the [Open SaaS LLM-optimized documentation](https://docs.opensaas.sh/llms.txt) -## Setup Steps +## Setup Methods + +**Automated Stripe Setup via CLI:** For faster Stripe setup via command line, see [stripe-automated-setup.md](./stripe-automated-setup.md) + +**Manual Setup:** Follow steps below for any provider. + +## Manual Setup Steps ### 1. Select Provider @@ -42,15 +48,11 @@ Update `src/payment/plans.ts` if changing product names. **Lemon Squeezy / Polar:** use ngrok (`ngrok http 3001`), set webhook URL to `https://[ngrok-url]/payments-webhook` -### 5. Test +## Testing Payments and Troubleshooting -1. start wasp + webhook forwarding -2. test checkout, verify `subscriptionStatus` in `wasp db studio` +See [troubleshooting](./troubleshooting.md) ## Cleanup See [cleanup.md](./cleanup.md) to remove unused provider code. -## Troubleshooting - -See [troubleshooting](./troubleshooting.md) diff --git a/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh b/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh new file mode 100644 index 000000000..075c6d024 --- /dev/null +++ b/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Check Stripe configuration status for Open SaaS +# Usage: ./check-stripe-config.sh [path-to-env-file] + +set -e + +ENV_FILE="${1:-.env.server}" + +echo "🔍 Checking Stripe Configuration" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Check Stripe CLI +echo "1. Stripe CLI" +if command -v stripe &> /dev/null; then + echo " ✅ Stripe CLI installed" + + if stripe config --list &> /dev/null 2>&1; then + echo " ✅ Authenticated" + ACCOUNT=$(stripe config --list 2>/dev/null | grep "account_id" | awk '{print $2}') + echo " 📋 Account: $ACCOUNT" + else + echo " ⚠️ Not logged in. Run: stripe login" + fi +else + echo " ❌ Stripe CLI not installed" + echo " Install: brew install stripe/stripe-cli/stripe" +fi + +echo "" + +# Check .env.server file +echo "2. Environment Variables ($ENV_FILE)" +if [ -f "$ENV_FILE" ]; then + echo " ✅ File exists" + + # Check API Key + if grep -q "^STRIPE_API_KEY=sk_test_" "$ENV_FILE" 2>/dev/null; then + echo " ✅ STRIPE_API_KEY configured" + elif grep -q "^STRIPE_API_KEY=sk_live_" "$ENV_FILE" 2>/dev/null; then + echo " ⚠️ STRIPE_API_KEY is LIVE mode (use test mode for development)" + else + echo " ❌ STRIPE_API_KEY missing or invalid" + fi + + # Check Webhook Secret + if grep -q "^STRIPE_WEBHOOK_SECRET=whsec_" "$ENV_FILE" 2>/dev/null; then + echo " ✅ STRIPE_WEBHOOK_SECRET configured" + else + echo " ⚠️ STRIPE_WEBHOOK_SECRET missing" + echo " Run: stripe listen --forward-to localhost:3001/payments-webhook" + fi + + # Check Product IDs + if grep -q "^PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then + echo " ✅ PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID configured" + else + echo " ❌ PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID missing" + fi + + if grep -q "^PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then + echo " ✅ PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID configured" + else + echo " ❌ PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID missing" + fi + + if grep -q "^PAYMENTS_CREDITS_10_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then + echo " ✅ PAYMENTS_CREDITS_10_PLAN_ID configured" + else + echo " ❌ PAYMENTS_CREDITS_10_PLAN_ID missing" + fi +else + echo " ❌ $ENV_FILE not found" +fi + +echo "" + +# Check if server is running +echo "3. Webhook Endpoint" +if curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/payments-webhook 2>/dev/null | grep -q "200\|404\|405"; then + echo " ✅ Server responding on port 3001" +else + echo " ⚠️ Server not responding on port 3001" + echo " Start with: wasp start" +fi + +echo "" + +# List products if CLI is available +if command -v stripe &> /dev/null && stripe config --list &> /dev/null 2>&1; then + echo "4. Stripe Products" + echo " Fetching products..." + PRODUCTS=$(stripe products list --limit 5 2>/dev/null) + + if [ $? -eq 0 ]; then + echo "$PRODUCTS" | grep -E "id|name" | head -10 + else + echo " ⚠️ Could not fetch products" + fi +fi + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "Quick commands:" +echo " • View products: stripe products list" +echo " • View prices: stripe prices list" +echo " • Test webhook: stripe trigger checkout.session.completed" +echo " • View events: stripe events list --limit 10" +echo " • Open dashboard: stripe dashboard" +echo "" diff --git a/template/.claude/skills/configuring-payments/scripts/setup-stripe-products.sh b/template/.claude/skills/configuring-payments/scripts/setup-stripe-products.sh new file mode 100644 index 000000000..638b0dbfc --- /dev/null +++ b/template/.claude/skills/configuring-payments/scripts/setup-stripe-products.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# Setup Stripe products and prices for Open SaaS +# Usage: ./setup-stripe-products.sh [app-name] [hobby-price] [pro-price] [credits-price] +# Example: ./setup-stripe-products.sh "My SaaS" 999 1999 1499 + +set -e + +# Default values +APP_NAME="${1:-My Open SaaS App}" +HOBBY_PRICE="${2:-999}" # $9.99 in cents +PRO_PRICE="${3:-1999}" # $19.99 in cents +CREDITS_PRICE="${4:-1499}" # $14.99 in cents + +echo "🚀 Creating Stripe products for: $APP_NAME" +echo " Hobby: \$$(echo "scale=2; $HOBBY_PRICE/100" | bc)/month" +echo " Pro: \$$(echo "scale=2; $PRO_PRICE/100" | bc)/month" +echo " Credits: \$$(echo "scale=2; $CREDITS_PRICE/100" | bc)" +echo "" + +# Check if Stripe CLI is installed +if ! command -v stripe &> /dev/null; then + echo "❌ Stripe CLI not found. Install it first:" + echo " macOS: brew install stripe/stripe-cli/stripe" + echo " Other: https://stripe.com/docs/stripe-cli" + exit 1 +fi + +# Check if logged in +if ! stripe config --list &> /dev/null; then + echo "❌ Not logged in to Stripe. Run: stripe login" + exit 1 +fi + +echo "✅ Stripe CLI ready" +echo "" + +# Create Hobby subscription product +echo "Creating Hobby subscription..." +HOBBY_PRODUCT=$(stripe products create \ + --name "$APP_NAME - Hobby" \ + --description "Hobby tier subscription" \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'prod_[^"]*') + +HOBBY_PRICE_ID=$(stripe prices create \ + --product "$HOBBY_PRODUCT" \ + --currency usd \ + --unit-amount "$HOBBY_PRICE" \ + --recurring[interval]=month \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'price_[^"]*') + +echo " ✅ Hobby Plan Price ID: $HOBBY_PRICE_ID" + +# Create Pro subscription product +echo "Creating Pro subscription..." +PRO_PRODUCT=$(stripe products create \ + --name "$APP_NAME - Pro" \ + --description "Pro tier subscription with premium features" \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'prod_[^"]*') + +PRO_PRICE_ID=$(stripe prices create \ + --product "$PRO_PRODUCT" \ + --currency usd \ + --unit-amount "$PRO_PRICE" \ + --recurring[interval]=month \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'price_[^"]*') + +echo " ✅ Pro Plan Price ID: $PRO_PRICE_ID" + +# Create Credits one-time product +echo "Creating Credits package..." +CREDITS_PRODUCT=$(stripe products create \ + --name "$APP_NAME - 10 Credits" \ + --description "10 credits for one-time purchase" \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'prod_[^"]*') + +CREDITS_PRICE_ID=$(stripe prices create \ + --product "$CREDITS_PRODUCT" \ + --currency usd \ + --unit-amount "$CREDITS_PRICE" \ + --format json | grep -o '"id": *"[^"]*"' | head -1 | grep -o 'price_[^"]*') + +echo " ✅ Credits Price ID: $CREDITS_PRICE_ID" +echo "" + +# Output summary +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "✅ All products created successfully!" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo "Add these to your .env.server file:" +echo "" +echo "PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=$HOBBY_PRICE_ID" +echo "PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=$PRO_PRICE_ID" +echo "PAYMENTS_CREDITS_10_PLAN_ID=$CREDITS_PRICE_ID" +echo "" +echo "Next steps:" +echo "1. Copy the above variables to your .env.server" +echo "2. Get your API key: stripe keys list" +echo "3. Add STRIPE_API_KEY to .env.server" +echo "4. Start webhook forwarding: stripe listen --forward-to localhost:3001/payments-webhook" +echo "5. Add the webhook secret to .env.server" +echo "" diff --git a/template/.claude/skills/configuring-payments/stripe-automated-setup.md b/template/.claude/skills/configuring-payments/stripe-automated-setup.md new file mode 100644 index 000000000..66817eac1 --- /dev/null +++ b/template/.claude/skills/configuring-payments/stripe-automated-setup.md @@ -0,0 +1,109 @@ +# Stripe Automated Setup via CLI + +Use these scripts and instructions to automate Stripe setup via CLI. + +## When to Use This + +Use CLI automation when: +- User explicitly asks for CLI/automated setup +- User is comfortable with command-line tools +- Setting up Stripe for the first time +- Need to quickly create test products + +Use manual setup (dashboard) when: +- User prefers GUI +- User needs custom product configurations +- Setting up production (review each setting) + +## Prerequisites + +Check if Stripe CLI is installed: +```bash +stripe --version +``` + +If not installed: +```bash +# macOS +brew install stripe/stripe-cli/stripe + +# Linux/Windows +# Download from: https://stripe.com/docs/stripe-cli +``` + +Login to Stripe: +```bash +stripe login +``` + +## Automated Setup Process + +### Step 1: Get API Key + +Open the Stripe API keys page and get your test key (starts with `sk_test_`): +```bash +stripe open dashboard/apikeys +``` + +Help user add to `.env.server`: +```bash +STRIPE_API_KEY=sk_test_51ABC... +``` + +### Step 2: Create Products + +Run the product setup script: +```bash +cd .claude/skills/configuring-payments +chmod +x setup-stripe-products.sh + +# Basic usage - use app name from main.wasp +./setup-stripe-products.sh "App Name" + +# Custom pricing (in cents): hobby pro credits +./setup-stripe-products.sh "App Name" 999 1999 1499 +``` + +The script will output Price IDs. Help user add to `.env.server`: +```bash +PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=price_1ABC... +PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=price_1DEF... +PAYMENTS_CREDITS_10_PLAN_ID=price_1GHI... +``` + +### Step 3: Setup Webhook + +Instruct user to open a **separate terminal** and run: +```bash +stripe listen --forward-to localhost:3001/payments-webhook +``` + +This outputs a webhook secret (starts with `whsec_`). Help user add to `.env.server`: +```bash +STRIPE_WEBHOOK_SECRET=whsec_ABC123... +``` + +**Important:** This terminal must stay open during development. + +### Step 4: Verify Configuration + +Run the verification script: +```bash +cd .claude/skills/configuring-payments +chmod +x check-stripe-config.sh +./check-stripe-config.sh +``` + +Review output with user and fix any issues. + +### Step 5: Restart Wasp Server + +Server should auto-restart when `.env.server` changes. If not: +```bash +# Stop current server (Ctrl+C) and restart +wasp start +``` + +## Testing Payments and Troubleshooting + +See [troubleshooting](./troubleshooting.md) for common issues and how to fix them. diff --git a/template/.claude/skills/configuring-payments/troubleshooting.md b/template/.claude/skills/configuring-payments/troubleshooting.md index 4edf7c531..c67120860 100644 --- a/template/.claude/skills/configuring-payments/troubleshooting.md +++ b/template/.claude/skills/configuring-payments/troubleshooting.md @@ -25,10 +25,11 @@ Check webhook events enabled: ## Test Payments -**Stripe:** card `4242 4242 4242 4242`, API key starts with `sk_test_` - +**Stripe:** test card `4242 4242 4242 4242`, API key starts with `sk_test_` **Polar:** set `POLAR_SANDBOX_MODE=true` +- test checkout, verify `subscriptionStatus` in `wasp db studio` + ## More Help See [Open SaaS payment docs](https://docs.opensaas.sh/llms.txt) diff --git a/template/.claude/skills/setup-wizard/SKILL.md b/template/.claude/skills/setup-wizard/SKILL.md index ce23c5556..721e3322c 100644 --- a/template/.claude/skills/setup-wizard/SKILL.md +++ b/template/.claude/skills/setup-wizard/SKILL.md @@ -111,4 +111,11 @@ Provide a summary: - What was configured - What env vars still need to be filled in - Links to provider dashboards for obtaining credentials -- Suggest running e2e tests after adding credentials +- Links to [Open SaaS docs](https://docs.opensaas.sh) for completing integrations +- Prompt the user if they'd like help with further setup for full functionality of the features they selected. + +### Further Setup Help + +- For payments, run the [configuring-payments skill](../configuring-payments/SKILL.md) for further setup. +- For auth, run the [configuring-auth skill](../configuring-auth/SKILL.md) for further setup. +- For features, run the [adding-feature skill](../adding-feature/SKILL.md) for further setup. From 5cca6509c50d9c199aef36d1d4f5dfdea24d6fae Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:37:01 +0100 Subject: [PATCH 10/16] Update documentation references and add MCP config Standardized LLM-optimized documentation URLs across skills and main docs, clarified Stripe setup instructions, and added template/.mcp.json for MCP server configuration. Improved guidance for planning, deployment, and troubleshooting, and updated references to documentation lookup tools. --- CLAUDE.md | 20 +++--- .../.claude/skills/adding-feature/SKILL.md | 20 ++++++ .../background-jobs.md} | 7 +-- .../.claude/skills/configuring-auth/SKILL.md | 13 ++-- .../skills/configuring-payments/SKILL.md | 12 +++- .../scripts/check-stripe-config.sh | 50 +-------------- .../stripe-automated-setup.md | 62 +++++++++++++++++-- .../.claude/skills/debugging-wasp/SKILL.md | 8 +++ .../.claude/skills/deploying-app/SKILL.md | 19 +++--- template/.claude/skills/migrating-db/SKILL.md | 9 ++- .../.claude/skills/pre-deployment/SKILL.md | 14 ++--- .../.claude/skills/running-e2e-tests/SKILL.md | 7 +++ template/.claude/skills/setup-wizard/SKILL.md | 7 +++ .../.claude/skills/starting-wasp/SKILL.md | 11 +++- template/.mcp.json | 11 ++++ template/app/CLAUDE.md | 25 ++++---- 16 files changed, 190 insertions(+), 105 deletions(-) rename template/.claude/skills/{adding-background-job/SKILL.md => adding-feature/background-jobs.md} (91%) create mode 100644 template/.mcp.json diff --git a/CLAUDE.md b/CLAUDE.md index a7faa3096..939f20614 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -19,10 +19,6 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Open SaaS follows best practices and conventions specific to building SaaS applications on Wasp. The template is designed to be customized and extended for your specific product needs. -**Documentation:** -- Human-readable: https://docs.opensaas.sh -- LLM-optimized: https://docs.opensaas.sh/llms-full.txt - ## Repository Structure This is the **Open SaaS** monorepo, a full-stack SaaS template built with Wasp, React, Node.js, and Prisma. @@ -55,9 +51,6 @@ The `opensaas-sh` app is not directly versioned. Instead, only the **diffs** fro ## Working with the Wasp App -Remember: LLM-optimized docs are always up-to-date at: https://wasp.sh/llms-full.txt -and: https://docs.opensaas.sh/llms-full.txt - ### Project Structure Wasp uses a declarative configuration file (`main.wasp`) to generate a full-stack application: @@ -179,10 +172,6 @@ The template includes comprehensive Cursor rules in `template/app/.cursor/rules/ - `deployment.mdc` - Production deployment guides - `advanced-troubleshooting.mdc` - Custom API endpoints, background jobs -Wasp documentation is available at: -- LLM-optimized: https://wasp.sh/llms-full.txt -- Human-readable: https://wasp.sh/docs - ## Tech Stack - **Framework:** Wasp 0.19+ (React + Node.js + Prisma) @@ -257,3 +246,12 @@ npm run test **macOS dope.sh errors** - Install: `brew install coreutils gpatch diffutils` + +## LLM-optimized Documentation + +If needed, ground yourself using the Wasp & Open SaaS documentation: +- https://wasp.sh/llms.txt +- https://docs.opensaas.sh/llms.txt + +## MCP Documentation Lookup +- For specific lookups: Use `mcp__wasp-docs__find_docs` to search Wasp/OpenSaaS docs diff --git a/template/.claude/skills/adding-feature/SKILL.md b/template/.claude/skills/adding-feature/SKILL.md index 0a0c7d960..0c38b4e1d 100644 --- a/template/.claude/skills/adding-feature/SKILL.md +++ b/template/.claude/skills/adding-feature/SKILL.md @@ -5,8 +5,20 @@ description: plan and scaffold a new feature for the Open SaaS app following Was # adding-feature +## Planning Requirement + +**IMPORTANT:** Before implementing any feature, use the EnterPlanMode tool to: +1. Explore existing code patterns in the codebase +2. Design the implementation approach +3. Write a plan file for user approval and/or add tasks to the todo list with TodoWrite tool. + +Only proceed with implementation after the user approves the plan. + ## Feature Planning +### Requirements Gathering + +When gathering requirements (either before or during plan mode), ask about: 1. ask the user what feature they want to add 2. gather requirements: - **Access:** public, authenticated, or admin-only? @@ -27,6 +39,7 @@ Follow these guide: 2. **[Operations](./operations.md)** - backend queries and actions 3. **[Wasp Configuration](./wasp-config.md)** - register in wasp config file 4. **[Pages](./pages.md)** - frontend components +5. **[Background Jobs](./background-jobs.md)** - scheduled or async background jobs ## Verification @@ -38,3 +51,10 @@ Follow these guide: ## Troubleshooting see [troubleshooting](./troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/adding-background-job/SKILL.md b/template/.claude/skills/adding-feature/background-jobs.md similarity index 91% rename from template/.claude/skills/adding-background-job/SKILL.md rename to template/.claude/skills/adding-feature/background-jobs.md index 3d82fa97b..e13410bcd 100644 --- a/template/.claude/skills/adding-background-job/SKILL.md +++ b/template/.claude/skills/adding-feature/background-jobs.md @@ -1,9 +1,4 @@ ---- -name: adding-background-job -description: add scheduled or async background jobs using Wasp's PgBoss integration. ---- - -# adding-background-job +# Background Jobs Complete job guide URLs are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). diff --git a/template/.claude/skills/configuring-auth/SKILL.md b/template/.claude/skills/configuring-auth/SKILL.md index 32b9487e4..565c8f0bc 100644 --- a/template/.claude/skills/configuring-auth/SKILL.md +++ b/template/.claude/skills/configuring-auth/SKILL.md @@ -5,10 +5,6 @@ description: configure authentication for Open SaaS (email/password and OAuth pr # configuring-auth -All authentication guide URLs, including provider-specific guide URLs, are available in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). - -Inform the user that guides found on https://wasp.sh/docs have full walkthroughs with screenshots and examples, if preferred. - ## Check Current Status 1. read [`../../../app/main.wasp`](../../../app/main.wasp) auth section @@ -25,7 +21,7 @@ Email auth is enabled by default. For production: ## OAuth Providers -1. **Enable:** uncomment provider in main.wasp auth methods. Note: Additional providers can be found in the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). +1. **Enable:** uncomment provider in main.wasp auth methods. Note: Additional providers can be found in the [Wasp documentation](https://wasp.sh/llms.txt). 2. **Credentials:** set `_CLIENT_ID` and `_CLIENT_SECRET` in `.env.server` 3. **Redirect URL:** configure in provider dashboard: - Dev: `http://localhost:3001/auth//callback` @@ -39,3 +35,10 @@ Comment out method in main.wasp, restart server. ## Troubleshooting see [troubleshooting](./troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/configuring-payments/SKILL.md b/template/.claude/skills/configuring-payments/SKILL.md index 284ada11a..67e620f8b 100644 --- a/template/.claude/skills/configuring-payments/SKILL.md +++ b/template/.claude/skills/configuring-payments/SKILL.md @@ -5,11 +5,9 @@ description: configure payment integration for Open SaaS (Stripe, Lemon Squeezy, # configuring-payments -All payment integration guide URLs, including provider-specific guide URLs, are available in the [Open SaaS LLM-optimized documentation](https://docs.opensaas.sh/llms.txt) - ## Setup Methods -**Automated Stripe Setup via CLI:** For faster Stripe setup via command line, see [stripe-automated-setup.md](./stripe-automated-setup.md) +**Automated Stripe Setup via CLI:** For faster Stripe setup via command line, follow the instructions in [stripe-automated-setup.md](./stripe-automated-setup.md) **Manual Setup:** Follow steps below for any provider. @@ -56,3 +54,11 @@ See [troubleshooting](./troubleshooting.md) See [cleanup.md](./cleanup.md) to remove unused provider code. +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. + diff --git a/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh b/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh index 075c6d024..83a790a01 100644 --- a/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh +++ b/template/.claude/skills/configuring-payments/scripts/check-stripe-config.sh @@ -29,54 +29,8 @@ fi echo "" -# Check .env.server file -echo "2. Environment Variables ($ENV_FILE)" -if [ -f "$ENV_FILE" ]; then - echo " ✅ File exists" - - # Check API Key - if grep -q "^STRIPE_API_KEY=sk_test_" "$ENV_FILE" 2>/dev/null; then - echo " ✅ STRIPE_API_KEY configured" - elif grep -q "^STRIPE_API_KEY=sk_live_" "$ENV_FILE" 2>/dev/null; then - echo " ⚠️ STRIPE_API_KEY is LIVE mode (use test mode for development)" - else - echo " ❌ STRIPE_API_KEY missing or invalid" - fi - - # Check Webhook Secret - if grep -q "^STRIPE_WEBHOOK_SECRET=whsec_" "$ENV_FILE" 2>/dev/null; then - echo " ✅ STRIPE_WEBHOOK_SECRET configured" - else - echo " ⚠️ STRIPE_WEBHOOK_SECRET missing" - echo " Run: stripe listen --forward-to localhost:3001/payments-webhook" - fi - - # Check Product IDs - if grep -q "^PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then - echo " ✅ PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID configured" - else - echo " ❌ PAYMENTS_HOBBY_SUBSCRIPTION_PLAN_ID missing" - fi - - if grep -q "^PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then - echo " ✅ PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID configured" - else - echo " ❌ PAYMENTS_PRO_SUBSCRIPTION_PLAN_ID missing" - fi - - if grep -q "^PAYMENTS_CREDITS_10_PLAN_ID=price_" "$ENV_FILE" 2>/dev/null; then - echo " ✅ PAYMENTS_CREDITS_10_PLAN_ID configured" - else - echo " ❌ PAYMENTS_CREDITS_10_PLAN_ID missing" - fi -else - echo " ❌ $ENV_FILE not found" -fi - -echo "" - # Check if server is running -echo "3. Webhook Endpoint" +echo "2. Webhook Endpoint" if curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/payments-webhook 2>/dev/null | grep -q "200\|404\|405"; then echo " ✅ Server responding on port 3001" else @@ -88,7 +42,7 @@ echo "" # List products if CLI is available if command -v stripe &> /dev/null && stripe config --list &> /dev/null 2>&1; then - echo "4. Stripe Products" + echo "3. Stripe Products" echo " Fetching products..." PRODUCTS=$(stripe products list --limit 5 2>/dev/null) diff --git a/template/.claude/skills/configuring-payments/stripe-automated-setup.md b/template/.claude/skills/configuring-payments/stripe-automated-setup.md index 66817eac1..5fe7e39b4 100644 --- a/template/.claude/skills/configuring-payments/stripe-automated-setup.md +++ b/template/.claude/skills/configuring-payments/stripe-automated-setup.md @@ -1,6 +1,7 @@ # Stripe Automated Setup via CLI Use these scripts and instructions to automate Stripe setup via CLI. +Important: never edit any .env files, always ask the user to add the values! ## When to Use This @@ -17,6 +18,18 @@ Use manual setup (dashboard) when: ## Prerequisites +### Step 1: Select Your Stripe Account/Workspace + +**Important:** If you have multiple Stripe business accounts or workspaces, you MUST select the correct one BEFORE logging in to CLI. This ensures test products are created in the right workspace. + +1. Go to https://dashboard.stripe.com +2. Click your account name in the **top left corner** +3. Select the correct business/workspace for this project +4. (Optional) If you need a new workspace, click **"+ New account"** and set it up +5. **Stay logged in** with this account selected + +### Step 2: Install Stripe CLI + Check if Stripe CLI is installed: ```bash stripe --version @@ -31,21 +44,62 @@ brew install stripe/stripe-cli/stripe # Download from: https://stripe.com/docs/stripe-cli ``` -Login to Stripe: +### Step 3: Login to Stripe CLI + ```bash stripe login ``` +This will open your browser. Authorize the CLI with the account you selected in Step 1. + +### Step 4: Verify Correct Account is Connected + +After login, run: +```bash +stripe config --list +``` + +Prompt the user to confirm that the following are correct: +- [ ] Account ID +- [ ] Display Name +- [ ] Project Name +Prompt: "Does this match the Stripe workspace you selected in Step 1? If not, please log out and log back in with the correct project name." + +**⚠️ IMPORTANT:** The `test_mode_api_key` shown in `stripe config --list` is a **temporary CLI session key**, NOT your actual Stripe API key. Do NOT use this key in `.env.server`. You must get the real API key from the Stripe Dashboard (see Step 1 below). + +If the account is wrong, follow these steps: + +1. Log out: + ```bash + stripe logout + ``` + +2. Prompt user to go to https://dashboard.stripe.com and select the correct workspace (top left corner) + +3. Log back in: + ```bash + stripe login + ``` + +4. Verify again: + ```bash + stripe config --list + ``` + ## Automated Setup Process -### Step 1: Get API Key +### Step 1: Get API Key from Dashboard -Open the Stripe API keys page and get your test key (starts with `sk_test_`): +**⚠️ CRITICAL:** You must get the API key from the Stripe Dashboard, NOT from `stripe config --list`. The CLI's `test_mode_api_key` is a temporary session key that won't work for your application. + +Open the Stripe API keys page: ```bash stripe open dashboard/apikeys ``` -Help user add to `.env.server`: +This opens your browser to the API keys page. Look for the **Secret key** (starts with `sk_test_` for test mode). Click "Reveal test key" if needed, then copy it. + +Instruct the user to add to `.env.server`: ```bash STRIPE_API_KEY=sk_test_51ABC... ``` diff --git a/template/.claude/skills/debugging-wasp/SKILL.md b/template/.claude/skills/debugging-wasp/SKILL.md index 3d421e732..0ab599778 100644 --- a/template/.claude/skills/debugging-wasp/SKILL.md +++ b/template/.claude/skills/debugging-wasp/SKILL.md @@ -71,3 +71,11 @@ wasp db reset ## Troubleshooting see [troubleshooting](./troubleshooting.md) for specific issues + +## Documentation + +Fetch full text documentation directly: +- https://wasp.sh/llms-full.txt +- https://docs.opensaas.sh/llms-full.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/deploying-app/SKILL.md b/template/.claude/skills/deploying-app/SKILL.md index 9c2be6754..98f4a2be7 100644 --- a/template/.claude/skills/deploying-app/SKILL.md +++ b/template/.claude/skills/deploying-app/SKILL.md @@ -5,17 +5,14 @@ description: deploy the Open SaaS app to Railway or Fly.io using Wasp CLI. # deploying-app -Complete deployment guide URLs are available in the [Open SaaS Deployment Guide](https://docs.opensaas.sh/llms.txt) and the [Wasp LLM-optimized documentation](https://wasp.sh/llms.txt). - -Run [pre-deployment skill](../pre-deployment/SKILL.md) first to validate configuration. - ## Pre-Deployment -1. confirm platform: Railway or Fly.io -2. verify CLI installed and logged in: +1. Run [pre-deployment skill](../pre-deployment/SKILL.md) first to validate configuration. +2. confirm platform: Railway or Fly.io +3. verify CLI installed and logged in: - Railway: `railway whoami` - Fly.io: `fly auth whoami` -3. collect env vars: server secrets + client vars (prefixed `REACT_APP_`) +4. collect env vars: server secrets + client vars (prefixed `REACT_APP_`) ## Deploy Commands @@ -37,3 +34,11 @@ Run [pre-deployment skill](../pre-deployment/SKILL.md) first to validate configu ## Troubleshooting See [troubleshooting](./troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/migrating-db/SKILL.md b/template/.claude/skills/migrating-db/SKILL.md index 92b375418..a08235d50 100644 --- a/template/.claude/skills/migrating-db/SKILL.md +++ b/template/.claude/skills/migrating-db/SKILL.md @@ -21,4 +21,11 @@ description: migrate the database after making changes to `schema.prisma`. ## Troubleshooting -see [troubleshooting](../troubleshooting.md) \ No newline at end of file +see [troubleshooting](../troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. \ No newline at end of file diff --git a/template/.claude/skills/pre-deployment/SKILL.md b/template/.claude/skills/pre-deployment/SKILL.md index 8e746cbc0..41dd014e0 100644 --- a/template/.claude/skills/pre-deployment/SKILL.md +++ b/template/.claude/skills/pre-deployment/SKILL.md @@ -199,11 +199,9 @@ If all checks pass or user chooses to proceed: - Ask: "Would you like to proceed with deployment? I can guide you through deploying to Railway or Fly.io." - If yes, transition to [deploying-app skill](../deploying-app/SKILL.md) -## Reference - -For deployment details not covered here, see: -- [Open SaaS Deployment Guide](https://docs.opensaas.sh/guides/deploying/) - Open SaaS-specific deployment instructions -- [Wasp Deployment Intro](https://wasp.sh/docs/deployment/intro) -- [Environment Variables](https://wasp.sh/docs/deployment/env-vars) -- [Database Setup](https://wasp.sh/docs/deployment/database) -- [Local Build Testing](https://wasp.sh/docs/deployment/local-testing) +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/running-e2e-tests/SKILL.md b/template/.claude/skills/running-e2e-tests/SKILL.md index 3d2213ab0..f48c26f69 100644 --- a/template/.claude/skills/running-e2e-tests/SKILL.md +++ b/template/.claude/skills/running-e2e-tests/SKILL.md @@ -23,3 +23,10 @@ description: run Playwright end-to-end tests for the Open SaaS app. ## Troubleshooting see [troubleshooting](../troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/setup-wizard/SKILL.md b/template/.claude/skills/setup-wizard/SKILL.md index 721e3322c..0634cae66 100644 --- a/template/.claude/skills/setup-wizard/SKILL.md +++ b/template/.claude/skills/setup-wizard/SKILL.md @@ -119,3 +119,10 @@ Provide a summary: - For payments, run the [configuring-payments skill](../configuring-payments/SKILL.md) for further setup. - For auth, run the [configuring-auth skill](../configuring-auth/SKILL.md) for further setup. - For features, run the [adding-feature skill](../adding-feature/SKILL.md) for further setup. + +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/starting-wasp/SKILL.md b/template/.claude/skills/starting-wasp/SKILL.md index ebc631aca..442eec87e 100644 --- a/template/.claude/skills/starting-wasp/SKILL.md +++ b/template/.claude/skills/starting-wasp/SKILL.md @@ -5,13 +5,15 @@ description: start the Wasp development server correctly with all required servi # starting-wasp +Start the wasp app for the user as a background task, or allow the user to start it themselves in separate terminals. + ## Starting the Development Server 1. check if the user has Wasp installed by running `wasp version`. 2. if Wasp is not installed, instruct them to install it with: `curl -sSL https://get.wasp.sh/installer.sh | sh` 3. check if PostgreSQL is needed by reading [`./app/schema.prisma`](../../../app/schema.prisma) to see if the database provider is `postgresql`. 4. if PostgreSQL is required: - - ask if they have PostgreSQL running locally or want to use Wasp's managed database. + - ask if they have PostgreSQL running locally or want to use Wasp's managed database (default). - if they want Wasp's managed database, run `wasp start db` in the `template/app` directory first (in the background or instruct to run in separate terminal). - if they have their own database running, inform them that they need to set the correct `DATABASE_URL` in [`./app/.env.server`](../../../app/.env.server). 5. run `wasp start` in the `template/app` directory in a separate terminal to start the development server. @@ -25,3 +27,10 @@ description: start the Wasp development server correctly with all required servi ## Troubleshooting see [troubleshooting](../troubleshooting.md) + +## Documentation + +Fetch guide URLs directly: +- https://wasp.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.mcp.json b/template/.mcp.json new file mode 100644 index 000000000..43045c94d --- /dev/null +++ b/template/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "chrome-devtools": { + "command": "npx", + "args": ["chrome-devtools-mcp@latest"] + }, + "wasp-docs": { + "command": "wasp-mcp-docs" + } + } +} diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index 94128c265..537c2febe 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -25,10 +25,10 @@ This is the **Open SaaS template** - a free, open-source SaaS starter boilerplat - **Deployment** - One-command deploy to Railway or Fly.io **Documentation:** -- Open SaaS Docs: https://docs.opensaas.sh -- LLM-optimized: https://docs.opensaas.sh/llms-full.txt -- Wasp Docs: https://wasp.sh/docs -- Wasp LLM-optimized: https://wasp.sh/llms-full.txt +- Open SaaS Docs (human-readable): https://docs.opensaas.sh +- Open SaaS Docs (LLM-optimized): https://docs.opensaas.sh/llms.txt +- Wasp Docs (human-readable): https://wasp.sh/docs +- Wasp Docs (LLM-optimized): https://wasp.sh/llms.txt ## Project Structure @@ -138,12 +138,15 @@ When building your SaaS app with this template: Reference the skills in [.claude/skills/](../.claude/skills/) for more information. -## Getting Help +## Wasp Discord -**Wasp Discord:** https://discord.gg/aCamt5wCpS (use #🙋questions channel) +- https://discord.gg/aCamt5wCpS (use #🙋questions channel) -**Documentation:** -- Open SaaS Docs: https://docs.opensaas.sh -- LLM-optimized: https://docs.opensaas.sh/llms-full.txt -- Wasp Docs: https://wasp.sh/docs -- Wasp LLM-optimized: https://wasp.sh/llms-full.txt \ No newline at end of file +## LLM-optimized Documentation + +If needed, ground yourself using the Wasp & Open SaaS documentation: +- https://wasp.sh/llms.txt +- https://docs.opensaas.sh/llms.txt + +## MCP Documentation Lookup +- For specific lookups: Use `mcp__wasp-docs__find_docs` to search Wasp/OpenSaaS docs From 7d5aabfe206fb085e188d1cec07459fed1a027d7 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Thu, 4 Dec 2025 12:12:00 +0100 Subject: [PATCH 11/16] Remove redundant skill files and update docs Deleted unused skill and troubleshooting files for configuring auth, debugging Wasp, migrating DB, running E2E tests, and starting Wasp. Renamed pre-deployment skill to validating-pre-deployment and updated references. Improved database and troubleshooting sections in CLAUDE.md for clarity and accuracy. --- .../.claude/skills/adding-feature/database.md | 25 +++- .../.claude/skills/configuring-auth/SKILL.md | 44 ------- .../configuring-auth/troubleshooting.md | 33 ------ .../.claude/skills/debugging-wasp/SKILL.md | 81 ------------- .../skills/debugging-wasp/troubleshooting.md | 42 ------- .../.claude/skills/deploying-app/SKILL.md | 2 +- template/.claude/skills/migrating-db/SKILL.md | 31 ----- .../skills/migrating-db/troubleshooting.md | 17 --- .../.claude/skills/running-e2e-tests/SKILL.md | 32 ----- .../running-e2e-tests/troubleshooting.md | 11 -- .../.claude/skills/starting-wasp/SKILL.md | 36 ------ .../skills/starting-wasp/troubleshooting.md | 20 ---- .../SKILL.md | 4 +- template/app/CLAUDE.md | 109 +++++++++--------- 14 files changed, 80 insertions(+), 407 deletions(-) delete mode 100644 template/.claude/skills/configuring-auth/SKILL.md delete mode 100644 template/.claude/skills/configuring-auth/troubleshooting.md delete mode 100644 template/.claude/skills/debugging-wasp/SKILL.md delete mode 100644 template/.claude/skills/debugging-wasp/troubleshooting.md delete mode 100644 template/.claude/skills/migrating-db/SKILL.md delete mode 100644 template/.claude/skills/migrating-db/troubleshooting.md delete mode 100644 template/.claude/skills/running-e2e-tests/SKILL.md delete mode 100644 template/.claude/skills/running-e2e-tests/troubleshooting.md delete mode 100644 template/.claude/skills/starting-wasp/SKILL.md delete mode 100644 template/.claude/skills/starting-wasp/troubleshooting.md rename template/.claude/skills/{pre-deployment => validating-pre-deployment}/SKILL.md (99%) diff --git a/template/.claude/skills/adding-feature/database.md b/template/.claude/skills/adding-feature/database.md index 4f7935208..f225db42a 100644 --- a/template/.claude/skills/adding-feature/database.md +++ b/template/.claude/skills/adding-feature/database.md @@ -1,7 +1,26 @@ # Database Setup -1. read [`../../../app/schema.prisma`](../../../app/schema.prisma) for existing patterns -2. add new Prisma model -3. run `wasp db migrate-dev --name describe-change` +## Adding/Modifying Models + +1. Read [`../../../app/schema.prisma`](../../../app/schema.prisma) for existing patterns +2. Add or modify Prisma model +3. Run migration: `wasp db migrate-dev --name describe-change` Wasp automatically generates TypeScript types in `wasp/entities`. + +## Useful Commands + +```bash +wasp db migrate-dev --name # Create and apply migration +wasp db studio # Open GUI to inspect database +wasp db reset # Reset database (WARNING: deletes data) +wasp db seed # Run seed functions +``` + +## Troubleshooting + +**Schema changes not applied:** Run `wasp db migrate-dev --name describe-change` + +**Database out of sync:** Run `wasp db reset` (deletes all data) + +**Migration conflicts:** Check [`../../../app/migrations`](../../../app/migrations) directory for existing migrations diff --git a/template/.claude/skills/configuring-auth/SKILL.md b/template/.claude/skills/configuring-auth/SKILL.md deleted file mode 100644 index 565c8f0bc..000000000 --- a/template/.claude/skills/configuring-auth/SKILL.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: configuring-auth -description: configure authentication for Open SaaS (email/password and OAuth providers). ---- - -# configuring-auth - -## Check Current Status - -1. read [`../../../app/main.wasp`](../../../app/main.wasp) auth section -2. report enabled methods to user (email is enabled by default) - -## Email Authentication - -Email auth is enabled by default. For production: -1. configure email provider in main.wasp (SendGrid, Mailgun, or SMTP) -2. set provider env vars in `.env.server` -3. customize templates in `src/auth/email-and-pass/emails.ts` if needed - -**Dev testing:** use `Dummy` provider, find verification URLs in server console, or set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` - -## OAuth Providers - -1. **Enable:** uncomment provider in main.wasp auth methods. Note: Additional providers can be found in the [Wasp documentation](https://wasp.sh/llms.txt). -2. **Credentials:** set `_CLIENT_ID` and `_CLIENT_SECRET` in `.env.server` -3. **Redirect URL:** configure in provider dashboard: - - Dev: `http://localhost:3001/auth//callback` - - Prod: `https://your-domain.com/auth//callback` -4. **Verify:** restart wasp, test login flow, check `wasp db studio` - -## Disabling Auth - -Comment out method in main.wasp, restart server. - -## Troubleshooting - -see [troubleshooting](./troubleshooting.md) - -## Documentation - -Fetch guide URLs directly: -- https://wasp.sh/llms.txt - -If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/configuring-auth/troubleshooting.md b/template/.claude/skills/configuring-auth/troubleshooting.md deleted file mode 100644 index ae534d88a..000000000 --- a/template/.claude/skills/configuring-auth/troubleshooting.md +++ /dev/null @@ -1,33 +0,0 @@ -# Troubleshooting - Authentication - -## Email Issues - -**No verification email (dev):** check server console for URL, or set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` - -**No verification email (prod):** verify email provider configured (not `Dummy`), check env vars, verify sender address matches provider settings - -**Password reset fails:** verify `passwordReset.clientRoute` points to valid route - -## OAuth Issues - -**Button not appearing:** uncomment provider in main.wasp, restart server - -**redirect_uri_mismatch:** URL must match exactly: -- Port is `3001` (server), not `3000` -- Provider name lowercase (e.g., `github`) -- No trailing slash - -**Missing user data:** check `userSignupFields` in `src/auth/userSignupFields.ts`, verify OAuth scopes - -**Flow hangs:** check `onAuthSucceededRedirectTo` in main.wasp, clear cookies - -## Production Issues - -- Verify production env vars are set -- Use production OAuth credentials (not dev) -- Ensure redirect URLs use production domain -- Email provider must not be `Dummy` - -## More Help - -Refer to [Wasp auth docs](https://wasp.sh/llms.txt) diff --git a/template/.claude/skills/debugging-wasp/SKILL.md b/template/.claude/skills/debugging-wasp/SKILL.md deleted file mode 100644 index 0ab599778..000000000 --- a/template/.claude/skills/debugging-wasp/SKILL.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -name: debugging-wasp -description: diagnose and fix common Wasp development issues in Open SaaS. ---- - -# debugging-wasp - -## Diagnostic Workflow - -1. identify error type from message -2. run appropriate diagnostics -3. apply fix -4. verify fix worked - -## Quick Fixes - -**Nuclear option (fixes most issues):** -```bash -cd app && wasp clean && wasp start -``` - -**Restart TypeScript server:** Cmd/Ctrl + Shift + P → "TypeScript: Restart TS Server" - -## Wasp-Specific Issues - -### Import Errors - -Import conventions are documented in project CLAUDE.md. Key points: -- TypeScript files: use `wasp/...` (not `@wasp/`) -- TypeScript files: use relative paths (not `@src/`) -- main.wasp: use `@src/...` paths - -After fixing imports, re-run `wasp start`. - -### Entity/Operation Errors - -**"context.entities.EntityName is undefined":** -1. verify entity exists in `schema.prisma` -2. check entity is in operation's `entities: [...]` array in `main.wasp` -3. restart Wasp server - -**Types not updating after adding operation:** -1. restart Wasp server to regenerate types -2. restart TypeScript server in IDE - -### Database Issues - -**Schema changes not applied:** -```bash -wasp db migrate-dev --name describe-change -``` - -**Inspect database state:** -```bash -wasp db studio -``` - -**Database out of sync (WARNING: deletes data):** -```bash -wasp db reset -``` - -### Runtime Errors - -**401 errors:** verify `if (!context.user)` guard or `authRequired: true` in page - -**Database connection:** run `wasp start db` or check `DATABASE_URL` in `.env.server` - -**Environment variables:** check `.env.server`, restart server after changes - -## Troubleshooting - -see [troubleshooting](./troubleshooting.md) for specific issues - -## Documentation - -Fetch full text documentation directly: -- https://wasp.sh/llms-full.txt -- https://docs.opensaas.sh/llms-full.txt - -If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/debugging-wasp/troubleshooting.md b/template/.claude/skills/debugging-wasp/troubleshooting.md deleted file mode 100644 index a9229db5b..000000000 --- a/template/.claude/skills/debugging-wasp/troubleshooting.md +++ /dev/null @@ -1,42 +0,0 @@ -# Troubleshooting - Debugging Wasp - -## `wasp clean` Doesn't Help - -Manually clean and reinstall: -```bash -rm -rf .wasp/ node_modules/ -npm install -wasp start -``` - -## Operation Not Found at Runtime - -1. verify function is exported: `export const myOperation = ...` -2. check import path in `main.wasp` matches file location -3. check for typos in operation name - -## Port Already in Use - -```bash -pkill -f wasp -# or: lsof -i :3000 && kill -``` - -## IDE Errors But Wasp Compiles - -Trust Wasp compiler. To fix IDE: -1. restart TypeScript server -2. verify IDE isn't excluding `.wasp/out/sdk/wasp/` -3. close and reopen workspace - -## Generated Code Location - -For debugging, inspect `.wasp/out/`: -- Server: `.wasp/out/server/` -- Client: `.wasp/out/web-app/` -- SDK types: `.wasp/out/sdk/wasp/` - -## Need More Help - -- Wasp Discord: https://discord.gg/aCamt5wCpS -- Wasp Docs: https://wasp.sh/llms.txt diff --git a/template/.claude/skills/deploying-app/SKILL.md b/template/.claude/skills/deploying-app/SKILL.md index 98f4a2be7..ebc730362 100644 --- a/template/.claude/skills/deploying-app/SKILL.md +++ b/template/.claude/skills/deploying-app/SKILL.md @@ -7,7 +7,7 @@ description: deploy the Open SaaS app to Railway or Fly.io using Wasp CLI. ## Pre-Deployment -1. Run [pre-deployment skill](../pre-deployment/SKILL.md) first to validate configuration. +1. Run the [validating-pre-deployment skill](../validating-pre-deployment/SKILL.md) first to validate configuration. 2. confirm platform: Railway or Fly.io 3. verify CLI installed and logged in: - Railway: `railway whoami` diff --git a/template/.claude/skills/migrating-db/SKILL.md b/template/.claude/skills/migrating-db/SKILL.md deleted file mode 100644 index a08235d50..000000000 --- a/template/.claude/skills/migrating-db/SKILL.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: migrating-db -description: migrate the database after making changes to `schema.prisma`. ---- - -# migrating-db - -## Migrating the Database - -1. read the status of [`./app/migrations`](../../../app/migrations) directory -2. read [`./app/schema.prisma`](../../../app/schema.prisma) and compare to the current database schema. -3. if there are no pending migrations, exit. -4. choose a migration name that describes what changed. -5. run `npx prisma migrate dev --name ` to create a new migration. - -## Viewing the Database GUI - -1. ask the user if they want to view the database GUI. -2. if they do, run `wasp db studio` in a separate terminal. -3. open [http://localhost:5555](http://localhost:5555) in the browser. - -## Troubleshooting - -see [troubleshooting](../troubleshooting.md) - -## Documentation - -Fetch guide URLs directly: -- https://wasp.sh/llms.txt - -If you need more specific info, use mcp__wasp-docs__find_docs to search. \ No newline at end of file diff --git a/template/.claude/skills/migrating-db/troubleshooting.md b/template/.claude/skills/migrating-db/troubleshooting.md deleted file mode 100644 index 4b909f608..000000000 --- a/template/.claude/skills/migrating-db/troubleshooting.md +++ /dev/null @@ -1,17 +0,0 @@ -# Troubleshooting Database Migrations - -## Connecting to a Database - -If you are using PostgreSQL, Wasp supports two ways of connecting to a database: - -1. Using the Dev Database provided by Wasp with `wasp start db`. -2. Using an existing database by specifying a database URL in `.env.server` - -## Using the Dev Database provided by Wasp with `wasp start db` - -The command `wasp start db` will start a default PostgreSQL dev database for you. - -Your Wasp app will automatically connect to it, just keep `wasp start db` running in the background. Also, make sure that: - -- You have Docker installed and it's available in your PATH or Docker Desktop is running. -- The port `5432` isn't taken. diff --git a/template/.claude/skills/running-e2e-tests/SKILL.md b/template/.claude/skills/running-e2e-tests/SKILL.md deleted file mode 100644 index f48c26f69..000000000 --- a/template/.claude/skills/running-e2e-tests/SKILL.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -name: running-e2e-tests -description: run Playwright end-to-end tests for the Open SaaS app. ---- - -# running-e2e-tests - -## Running E2E Tests - -1. check if the user is in the correct directory by verifying [`./e2e-tests/package.json`](../../../e2e-tests/package.json) exists. -2. check if dependencies are installed by verifying [`./e2e-tests/node_modules`](../../../e2e-tests/node_modules) exists. -3. if not installed, run `cd e2e-tests && npm install`. -4. check if the Wasp app is running by checking if localhost:3000 and localhost:3001 are accessible. -5. if not running, inform the user they need to start the app first with `wasp start` in a separate terminal with `SKIP_EMAIL_VERIFICATION_IN_DEV=true` environment variable set. -6. check if Stripe CLI is needed by asking the user if they want to test payment flows. -7. if Stripe is needed: - - check if Stripe CLI is installed by running `stripe --version`. - - if not installed, provide instructions: https://docs.stripe.com/stripe-cli - - check to make sure the user is logged in to Stripe CLI by running `stripe login`. -8. run the tests with `npm run local:e2e:start`. -9. inform the user that the playwright UI will open and allow them to select and run tests. - -## Troubleshooting - -see [troubleshooting](../troubleshooting.md) - -## Documentation - -Fetch guide URLs directly: -- https://docs.opensaas.sh/llms.txt - -If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/running-e2e-tests/troubleshooting.md b/template/.claude/skills/running-e2e-tests/troubleshooting.md deleted file mode 100644 index 29689eb19..000000000 --- a/template/.claude/skills/running-e2e-tests/troubleshooting.md +++ /dev/null @@ -1,11 +0,0 @@ -# Troubleshooting E2E Tests - -## Running E2E Tests - -- **Email Verification:** Tests require `SKIP_EMAIL_VERIFICATION_IN_DEV=true` when starting the Wasp app, otherwise they will hang. - - if the user doesn't want to skip email verification in dev mode, they must click the email verification link in the server console to continue the test (undesirable). -- **Stripe Webhooks:** Payment tests require Stripe CLI running with webhook forwarding. - - if the user is not logged in to Stripe CLI, they can run `stripe login` to login. - - it the api key is expired, inform the user to quit the process, and run `stripe login` again to refresh the keys. -- **Other Payment Provider Webhooks:** Payment tests require the payment provider's webhook listener running with webhook forwarding via Ngrok. See [llms.txt](https://docs.opensaas.sh/llms.txt) for the provider specific guide URL. -- **Database:** Tests use the development database, so ensure `wasp db start` is running. \ No newline at end of file diff --git a/template/.claude/skills/starting-wasp/SKILL.md b/template/.claude/skills/starting-wasp/SKILL.md deleted file mode 100644 index 442eec87e..000000000 --- a/template/.claude/skills/starting-wasp/SKILL.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: starting-wasp -description: start the Wasp development server correctly with all required services. ---- - -# starting-wasp - -Start the wasp app for the user as a background task, or allow the user to start it themselves in separate terminals. - -## Starting the Development Server - -1. check if the user has Wasp installed by running `wasp version`. -2. if Wasp is not installed, instruct them to install it with: `curl -sSL https://get.wasp.sh/installer.sh | sh` -3. check if PostgreSQL is needed by reading [`./app/schema.prisma`](../../../app/schema.prisma) to see if the database provider is `postgresql`. -4. if PostgreSQL is required: - - ask if they have PostgreSQL running locally or want to use Wasp's managed database (default). - - if they want Wasp's managed database, run `wasp start db` in the `template/app` directory first (in the background or instruct to run in separate terminal). - - if they have their own database running, inform them that they need to set the correct `DATABASE_URL` in [`./app/.env.server`](../../../app/.env.server). -5. run `wasp start` in the `template/app` directory in a separate terminal to start the development server. - -## Viewing Server Logs - -1. the Wasp dev server shows combined client and server logs. -2. server logs will show database queries, API calls, and errors. -3. client logs will show React component renders and frontend errors. - -## Troubleshooting - -see [troubleshooting](../troubleshooting.md) - -## Documentation - -Fetch guide URLs directly: -- https://wasp.sh/llms.txt - -If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/starting-wasp/troubleshooting.md b/template/.claude/skills/starting-wasp/troubleshooting.md deleted file mode 100644 index 7512eb92e..000000000 --- a/template/.claude/skills/starting-wasp/troubleshooting.md +++ /dev/null @@ -1,20 +0,0 @@ -# Troubleshooting Starting Wasp - -## Using Wasp's Managed Database - -The command `wasp start db` will start a default PostgreSQL dev database for you. - -Your Wasp app will automatically connect to it, just keep `wasp start db` running in the background. Also, make sure that: - -- You have Docker installed and it's available in your PATH or Docker Desktop is running. -- The port `5432` isn't taken. - -## Using an Existing Database - -- if the user has their own database running, inform them that they need to set the correct `DATABASE_URL` in [`./app/.env.server`](../../../app/.env.server). -- if they do not have a `.env.server` file, inform them that they can create it by copying the contents of [`./app/.env.server.example`](../../../app/.env.server.example). - -## Starting with a Clean State - -1. if the user is experiencing issues, suggest running `wasp clean` first to clear generated code and caches. -2. then follow the normal starting procedure above. \ No newline at end of file diff --git a/template/.claude/skills/pre-deployment/SKILL.md b/template/.claude/skills/validating-pre-deployment/SKILL.md similarity index 99% rename from template/.claude/skills/pre-deployment/SKILL.md rename to template/.claude/skills/validating-pre-deployment/SKILL.md index 41dd014e0..dd9d129b6 100644 --- a/template/.claude/skills/pre-deployment/SKILL.md +++ b/template/.claude/skills/validating-pre-deployment/SKILL.md @@ -1,9 +1,9 @@ --- -name: pre-deployment +name: validating-pre-deployment description: validate configuration and test production build before deploying. --- -# pre-deployment +# validating-pre-deployment Pre-deployment validation checks that catch common issues before deploying with the [deploying-app skill](../deploying-app/SKILL.md). diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index 537c2febe..9b9f841f1 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -1,13 +1,5 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## New Project Detection - -On first interaction, check if this is an unconfigured Open SaaS project by reading `main.wasp` (or `main.wasp.ts`). If `app.title` is still "My Open SaaS App" or contains placeholder values like "your-saas-app.com", suggest: - -> "It looks like you haven't customized your Open SaaS project yet. Would you like me to run the setup wizard to configure your app? Just say 'yes' or run `/open-saas-setup-wizard`." - ## What is This Project? This is the **Open SaaS template** - a free, open-source SaaS starter boilerplate built on the Wasp framework. Users get this template when they run `wasp new -t saas` and customize it to build their own SaaS applications. @@ -24,11 +16,11 @@ This is the **Open SaaS template** - a free, open-source SaaS starter boilerplat - **Testing** - Playwright E2E tests included - **Deployment** - One-command deploy to Railway or Fly.io -**Documentation:** -- Open SaaS Docs (human-readable): https://docs.opensaas.sh -- Open SaaS Docs (LLM-optimized): https://docs.opensaas.sh/llms.txt -- Wasp Docs (human-readable): https://wasp.sh/docs -- Wasp Docs (LLM-optimized): https://wasp.sh/llms.txt +## New Project Detection + +On first interaction, check if this is an unconfigured Open SaaS project by reading `main.wasp` (or `main.wasp.ts`). If `app.title` is still "My Open SaaS App" or contains placeholder values like "your-saas-app.com", suggest: + +> "It looks like you haven't customized your Open SaaS project yet. Would you like me to run the setup wizard to configure your app? Just say 'yes' or run `/open-saas-setup-wizard`." ## Project Structure @@ -37,17 +29,13 @@ This is a Wasp application. Wasp uses a declarative configuration file to genera - **`main.wasp`** - App configuration defining routes, pages, auth, operations, and more - note: users can also use `main.wasp.ts` instead of `main.wasp` for TypeScript support. - **`schema.prisma`** - Prisma database schema (defines data models) -- **`src/`** - Application code organized by feature: - - `src/auth/` - Authentication logic and pages - - `src/client/` - Shared client components and layout - - `src/payment/` - Stripe/Lemon Squeezy integration - - `src/user/` - User profile and settings - - `src/demo-ai-app/` - Example OpenAI integration (demo feature) - - `src/file-upload/` - AWS S3 file upload example (demo feature) - - `src/landing-page/` - Marketing landing page components - - `src/admin/` - Admin dashboard - - `src/server/` - Server utilities and scripts - - `src/shared/` - Code shared between client and server +- **`src/{featureName}/`** - Application code organized by feature: + - `operations.ts` - Wasp queries and actions + - `{FeatureName}Page.tsx` - Page components + - Components, utilities, and types as needed +- **`src/client/components/ui`** - predefined ShadCN UI components +- **`src/shared/`** - Code shared between client and server +- **`e2e-tests/`** - Playwright end-to-end tests **Note:** The demo app features (`demo-ai-app`, `file-upload`, etc.) are examples users can reference and remove when building their own SaaS. @@ -63,6 +51,7 @@ wasp db seed # Run seed functions defined in main.wasp # Production wasp build # Generate production build +wasp build start # Generate production build and start server to test locally wasp deploy # Deploy to Railway or Fly.io # Maintenance @@ -88,15 +77,18 @@ wasp clean # Delete generated code and caches (fixes most issues) Wasp operations (queries and actions) are the primary way to communicate between client and server. -Refer to the following skills for more information: -- [operations.md](../.claude/skills/adding-feature/operations.md) - ## Database Workflow -refer to the following skills: -- [database.md](../.claude/skills/adding-feature/database.md) -- [starting-wasp SKILL.md](../.claude/skills/starting-wasp/SKILL.md) -- [migrating-db SKILL.md](../.claude/skills/migrating-db/SKILL.md) +1. Edit `schema.prisma` to add/modify models +2. Run `wasp db migrate-dev --name describe-change` +3. Wasp auto-generates TypeScript types in `wasp/entities` +4. Access via `context.entities.ModelName` in operations + +**Useful commands:** +```bash +wasp db studio # GUI to inspect database +wasp db reset # Reset database (WARNING: deletes data) +``` ## Development Patterns @@ -107,36 +99,45 @@ Wasp abstracts and adds layers on top of the tools it uses to make development m Use the current features as a guide to understand how code is organized. When adding new features, refer to [adding-feature SKILL.md](../.claude/skills/adding-feature/SKILL.md) for more information. -## Common Issues & Solutions +## Troubleshooting + +**Nuclear option (fixes most issues):** +```bash +wasp clean && wasp start +``` + +**Restart TypeScript server:** `Cmd/Ctrl + Shift + P` → "TypeScript: Restart TS Server" + +### Import Errors +- `"Cannot find module 'wasp/...'"` → Use `wasp/`, not `@wasp/` +- `"Cannot find module '@src/...'"` in TypeScript → Use relative paths, `@src/` is only for main.wasp -**"Cannot find module 'wasp/...'"** -- Check import prefix is `wasp/`, not `@wasp/` -- Restart Wasp dev server: `wasp clean && wasp start` +### Entity/Operation Errors +- `"context.entities.X is undefined"` → Check entity is in `entities: [...]` array in main.wasp +- Types not updating → Restart Wasp server, then restart TS server -**"Cannot find module '@src/...'" in TypeScript** -- Use relative imports in `.ts`/`.tsx` files -- Only use `@src/...` in `main.wasp` file +### Database Issues +- Schema changes not applied → `wasp db migrate-dev --name describe-change` +- Database out of sync → `wasp db reset` (WARNING: deletes data) -**Type errors after changing operations** -- Restart Wasp dev server to regenerate types -- Check that entities are listed in operation definitions in `main.wasp` +### Runtime Errors +- 401 errors → Check `if (!context.user)` guard or `authRequired: true` on page +- DB connection issues → Run `wasp start db` or check `DATABASE_URL` +- Env var changes not working → Restart server after `.env.server` changes -## Customizing This Template +## Authentication Quick Reference -When building your SaaS app with this template: +**Email auth** is enabled by default. For production, switch from `Dummy` to a real email provider. -1. **Configure branding:** Update `main.wasp` with your app name, title, description, and metadata -2. **Choose auth methods:** Enable/disable different auth methods (email, Google, GitHub, Discord, Slack, etc.) in `main.wasp` auth section -3. **Set up payments:** Configure Stripe, Polar.sh or Lemon Squeezy (see https://docs.opensaas.sh/guides/payment-integrations/) -4. **Customize landing page:** Edit components in `src/landing-page/` -5. **Reference demo features:** Demo app code shows how to use the features of the template (`demo-ai-app`, example tasks, etc.) -6. **Add your data models:** Define your entities in `schema.prisma` -7. **Build your features:** Create your own pages, operations, and components in `src/` -8. **Configure services:** Set up email, analytics, file storage in `.env.server` -9. **Update tests:** Modify e2e tests to match your features -10. **Deploy:** Run `wasp deploy` when ready for production +**Dev testing:** Set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` or find verification URLs in server console. -Reference the skills in [.claude/skills/](../.claude/skills/) for more information. +## E2E Testing + +With the Wasp app running in a separate terminal, run the following commands: +```bash +cd e2e-tests && npm install # First time only +npm run local:e2e:start # Run tests (opens Playwright UI) +``` ## Wasp Discord From f28f3f37e6b9e8f896933dccdeee582e7ad081d8 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Thu, 4 Dec 2025 12:39:45 +0100 Subject: [PATCH 12/16] Add Kaizen approach guide and update feature skill Introduces a comprehensive Kaizen approach guide for continuous improvement in feature development. Updates SKILL.md to reference the Kaizen approach and clarifies implementation steps. Removes wasp-config.md and integrates its guidance into SKILL.md. Refines operations and pages documentation to improve best practices and remove unnecessary references. --- .../.claude/skills/adding-feature/SKILL.md | 6 +- .../skills/adding-feature/kaizen-approach.md | 719 ++++++++++++++++++ .../skills/adding-feature/operations.md | 2 +- .../.claude/skills/adding-feature/pages.md | 1 - .../skills/adding-feature/wasp-config.md | 8 - 5 files changed, 724 insertions(+), 12 deletions(-) create mode 100644 template/.claude/skills/adding-feature/kaizen-approach.md delete mode 100644 template/.claude/skills/adding-feature/wasp-config.md diff --git a/template/.claude/skills/adding-feature/SKILL.md b/template/.claude/skills/adding-feature/SKILL.md index 0c38b4e1d..400b78354 100644 --- a/template/.claude/skills/adding-feature/SKILL.md +++ b/template/.claude/skills/adding-feature/SKILL.md @@ -33,11 +33,13 @@ When gathering requirements (either before or during plan mode), ask about: ## Implementation Steps -Follow these guide: +Prompt the user if they'd like to follow the [Kaizen approach](./kaizen-approach.md) when implementing a feature, especially for complex ones. + +Here is an example process for implementing a feature: 1. **[Database Setup](./database.md)** - if feature needs entities 2. **[Operations](./operations.md)** - backend queries and actions -3. **[Wasp Configuration](./wasp-config.md)** - register in wasp config file +3. **Wasp Configuration** - define feature in wasp config file 4. **[Pages](./pages.md)** - frontend components 5. **[Background Jobs](./background-jobs.md)** - scheduled or async background jobs diff --git a/template/.claude/skills/adding-feature/kaizen-approach.md b/template/.claude/skills/adding-feature/kaizen-approach.md new file mode 100644 index 000000000..35cec92f3 --- /dev/null +++ b/template/.claude/skills/adding-feature/kaizen-approach.md @@ -0,0 +1,719 @@ +# Kaizen: Continuous Improvement + +Apply a continuous improvement mindset - suggest small iterative improvements, error-proof designs, follow established patterns, avoid over-engineering; automatically applied to guide quality and simplicity + +## Overview + +Small improvements, continuously. Error-proof by design. Follow what works. Build only what's needed. + +**Core principle:** Many small improvements beat one big change. Prevent errors at design time, not with fixes. + +**Philosophy:** Quality through incremental progress and prevention, not perfection through massive effort. + +## The Four Pillars + +### 1. Continuous Improvement (Kaizen) + +Small, frequent improvements compound into major gains. + +#### Principles + +**Incremental over revolutionary:** + +- Make smallest viable change that improves quality +- One improvement at a time +- Verify each change before next +- Build momentum through small wins + +**Always leave code better:** + +- Fix small issues as you encounter them +- Refactor while you work (within scope) +- Update outdated comments +- Remove dead code when you see it + +**Iterative refinement:** + +- First version: make it work +- Second pass: make it clear +- Third pass: make it efficient +- Don't try all three at once + + +```typescript +// Iteration 1: Make it work +const calculateTotal = (items: Item[]) => { + let total = 0; + for (let i = 0; i < items.length; i++) { + total += items[i].price * items[i].quantity; + } + return total; +}; + +// Iteration 2: Make it clear (refactor) +const calculateTotal = (items: Item[]): number => { + return items.reduce((total, item) => { + return total + (item.price * item.quantity); + }, 0); +}; + +// Iteration 3: Make it robust (add validation) +const calculateTotal = (items: Item[]): number => { + if (!items?.length) return 0; + + return items.reduce((total, item) => { + if (item.price < 0 || item.quantity < 0) { + throw new Error('Price and quantity must be non-negative'); + } + return total + (item.price * item.quantity); + }, 0); +}; + +``` +Each step is complete, tested, and working + + + +```typescript +// Trying to do everything at once +const calculateTotal = (items: Item[]): number => { + // Validate, optimize, add features, handle edge cases all together + if (!items?.length) return 0; + const validItems = items.filter(item => { + if (item.price < 0) throw new Error('Negative price'); + if (item.quantity < 0) throw new Error('Negative quantity'); + return item.quantity > 0; // Also filtering zero quantities + }); + // Plus caching, plus logging, plus currency conversion... + return validItems.reduce(...); // Too many concerns at once +}; +``` + +Overwhelming, error-prone, hard to verify + + +#### In Practice + +**When implementing features:** + +1. Start with simplest version that works +2. Add one improvement (error handling, validation, etc.) +3. Test and verify +4. Repeat if time permits +5. Don't try to make it perfect immediately + +**When refactoring:** + +- Fix one smell at a time +- Commit after each improvement +- Keep tests passing throughout +- Stop when "good enough" (diminishing returns) + +**When reviewing code:** + +- Suggest incremental improvements (not rewrites) +- Prioritize: critical → important → nice-to-have +- Focus on highest-impact changes first +- Accept "better than before" even if not perfect + +### 2. Poka-Yoke (Error Proofing) + +Design systems that prevent errors at compile/design time, not runtime. + +#### Principles + +**Make errors impossible:** + +- Type system catches mistakes +- Compiler enforces contracts +- Invalid states unrepresentable +- Errors caught early (left of production) + +**Design for safety:** + +- Fail fast and loudly +- Provide helpful error messages +- Make correct path obvious +- Make incorrect path difficult + +**Defense in layers:** + +1. Type system (compile time) +2. Validation (runtime, early) +3. Guards (preconditions) +4. Error boundaries (graceful degradation) + +#### Type System Error Proofing + + +```typescript +// Error: string status can be any value +type OrderBad = { + status: string; // Can be "pending", "PENDING", "pnding", anything! + total: number; +}; + +// Good: Only valid states possible +type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered'; +type Order = { + status: OrderStatus; + total: number; +}; + +// Better: States with associated data +type Order = + | { status: 'pending'; createdAt: Date } + | { status: 'processing'; startedAt: Date; estimatedCompletion: Date } + | { status: 'shipped'; trackingNumber: string; shippedAt: Date } + | { status: 'delivered'; deliveredAt: Date; signature: string }; + +// Now impossible to have shipped without trackingNumber + +``` +Type system prevents entire classes of errors + + + +```typescript +// Make invalid states unrepresentable +type NonEmptyArray = [T, ...T[]]; + +const firstItem = (items: NonEmptyArray): T => { + return items[0]; // Always safe, never undefined! +}; + +// Caller must prove array is non-empty +const items: number[] = [1, 2, 3]; +if (items.length > 0) { + firstItem(items as NonEmptyArray); // Safe +} +``` + +Function signature guarantees safety + + +#### Validation Error Proofing + + +```typescript +// Error: Validation after use +const processPayment = (amount: number) => { + const fee = amount * 0.03; // Used before validation! + if (amount <= 0) throw new Error('Invalid amount'); + // ... +}; + +// Good: Validate immediately +const processPayment = (amount: number) => { + if (amount <= 0) { + throw new Error('Payment amount must be positive'); + } + if (amount > 10000) { + throw new Error('Payment exceeds maximum allowed'); + } + + const fee = amount * 0.03; + // ... now safe to use +}; + +// Better: Validation at boundary with branded type +type PositiveNumber = number & { readonly __brand: 'PositiveNumber' }; + +const validatePositive = (n: number): PositiveNumber => { + if (n <= 0) throw new Error('Must be positive'); + return n as PositiveNumber; +}; + +const processPayment = (amount: PositiveNumber) => { + // amount is guaranteed positive, no need to check + const fee = amount * 0.03; +}; + +// Validate at system boundary +const handlePaymentRequest = (req: Request) => { + const amount = validatePositive(req.body.amount); // Validate once + processPayment(amount); // Use everywhere safely +}; + +``` +Validate once at boundary, safe everywhere else + + +#### Guards and Preconditions + + +```typescript +// Early returns prevent deeply nested code +const processUser = (user: User | null) => { + if (!user) { + logger.error('User not found'); + return; + } + + if (!user.email) { + logger.error('User email missing'); + return; + } + + if (!user.isActive) { + logger.info('User inactive, skipping'); + return; + } + + // Main logic here, guaranteed user is valid and active + sendEmail(user.email, 'Welcome!'); +}; +``` + +Guards make assumptions explicit and enforced + + +#### Configuration Error Proofing + + +```typescript +// Error: Optional config with unsafe defaults +type ConfigBad = { + apiKey?: string; + timeout?: number; +}; + +const client = new APIClient({ timeout: 5000 }); // apiKey missing! + +// Good: Required config, fails early +type Config = { + apiKey: string; + timeout: number; +}; + +const loadConfig = (): Config => { + const apiKey = process.env.API_KEY; + if (!apiKey) { + throw new Error('API_KEY environment variable required'); + } + + return { + apiKey, + timeout: 5000, + }; +}; + +// App fails at startup if config invalid, not during request +const config = loadConfig(); +const client = new APIClient(config); + +``` +Fail at startup, not in production + + +#### In Practice + +**When designing APIs:** +- Use types to constrain inputs +- Make invalid states unrepresentable +- Return Result instead of throwing +- Document preconditions in types + +**When handling errors:** +- Validate at system boundaries +- Use guards for preconditions +- Fail fast with clear messages +- Log context for debugging + +**When configuring:** +- Required over optional with defaults +- Validate all config at startup +- Fail deployment if config invalid +- Don't allow partial configurations + +### 3. Standardized Work + +Follow established patterns. Document what works. Make good practices easy to follow. + +#### Principles + +**Consistency over cleverness:** +- Follow existing codebase patterns +- Don't reinvent solved problems +- New pattern only if significantly better +- Team agreement on new patterns + +**Documentation lives with code:** +- README for setup and architecture +- CLAUDE.md for AI coding conventions +- Comments for "why", not "what" +- Examples for complex patterns + +**Automate standards:** +- Linters enforce style +- Type checks enforce contracts +- Tests verify behavior +- CI/CD enforces quality gates + +#### Following Patterns + + +```typescript +// Existing codebase pattern for API clients +class UserAPIClient { + async getUser(id: string): Promise { + return this.fetch(`/users/${id}`); + } +} + +// New code follows the same pattern +class OrderAPIClient { + async getOrder(id: string): Promise { + return this.fetch(`/orders/${id}`); + } +} +``` + +Consistency makes codebase predictable + + + +```typescript +// Existing pattern uses classes +class UserAPIClient { /* ... */ } + +// New code introduces different pattern without discussion +const getOrder = async (id: string): Promise => { + // Breaking consistency "because I prefer functions" +}; + +``` +Inconsistency creates confusion + + +#### Error Handling Patterns + + +```typescript +// Project standard: Result type for recoverable errors +type Result = { ok: true; value: T } | { ok: false; error: E }; + +// All services follow this pattern +const fetchUser = async (id: string): Promise> => { + try { + const user = await db.users.findById(id); + if (!user) { + return { ok: false, error: new Error('User not found') }; + } + return { ok: true, value: user }; + } catch (err) { + return { ok: false, error: err as Error }; + } +}; + +// Callers use consistent pattern +const result = await fetchUser('123'); +if (!result.ok) { + logger.error('Failed to fetch user', result.error); + return; +} +const user = result.value; // Type-safe! +``` + +Standard pattern across codebase + + +#### Documentation Standards + + +```typescript +/** + * Retries an async operation with exponential backoff. + * + * Why: Network requests fail temporarily; retrying improves reliability + * When to use: External API calls, database operations + * When not to use: User input validation, internal function calls + * + * @example + * const result = await retry( + * () => fetch('https://api.example.com/data'), + * { maxAttempts: 3, baseDelay: 1000 } + * ); + */ +const retry = async ( + operation: () => Promise, + options: RetryOptions +): Promise => { + // Implementation... +}; +``` +Documents why, when, and how + + +#### In Practice + +**Before adding new patterns:** + +- Search codebase for similar problems solved +- Check CLAUDE.md for project conventions +- Discuss with team if breaking from pattern +- Update docs when introducing new pattern + +**When writing code:** + +- Match existing file structure +- Use same naming conventions +- Follow same error handling approach +- Import from same locations + +**When reviewing:** + +- Check consistency with existing code +- Point to examples in codebase +- Suggest aligning with standards +- Update CLAUDE.md if new standard emerges + +### 4. Just-In-Time (JIT) + +Build what's needed now. No more, no less. Avoid premature optimization and over-engineering. + +#### Principles + +**YAGNI (You Aren't Gonna Need It):** + +- Implement only current requirements +- No "just in case" features +- No "we might need this later" code +- Delete speculation + +**Simplest thing that works:** + +- Start with straightforward solution +- Add complexity only when needed +- Refactor when requirements change +- Don't anticipate future needs + +**Optimize when measured:** + +- No premature optimization +- Profile before optimizing +- Measure impact of changes +- Accept "good enough" performance + +#### YAGNI in Action + + +```typescript +// Current requirement: Log errors to console +const logError = (error: Error) => { + console.error(error.message); +}; +``` +Simple, meets current need + + + +```typescript +// Over-engineered for "future needs" +interface LogTransport { + write(level: LogLevel, message: string, meta?: LogMetadata): Promise; +} + +class ConsoleTransport implements LogTransport { /*... */ } +class FileTransport implements LogTransport { /* ... */ } +class RemoteTransport implements LogTransport { /* ...*/ } + +class Logger { + private transports: LogTransport[] = []; + private queue: LogEntry[] = []; + private rateLimiter: RateLimiter; + private formatter: LogFormatter; + + // 200 lines of code for "maybe we'll need it" +} + +const logError = (error: Error) => { + Logger.getInstance().log('error', error.message); +}; + +``` +Building for imaginary future requirements + + +**When to add complexity:** +- Current requirement demands it +- Pain points identified through use +- Measured performance issues +- Multiple use cases emerged + + +```typescript +// Start simple +const formatCurrency = (amount: number): string => { + return `$${amount.toFixed(2)}`; +}; + +// Requirement evolves: support multiple currencies +const formatCurrency = (amount: number, currency: string): string => { + const symbols = { USD: '$', EUR: '€', GBP: '£' }; + return `${symbols[currency]}${amount.toFixed(2)}`; +}; + +// Requirement evolves: support localization +const formatCurrency = (amount: number, locale: string): string => { + return new Intl.NumberFormat(locale, { + style: 'currency', + currency: locale === 'en-US' ? 'USD' : 'EUR', + }).format(amount); +}; +``` + +Complexity added only when needed + + +#### Premature Abstraction + + +```typescript +// One use case, but building generic framework +abstract class BaseCRUDService { + abstract getAll(): Promise; + abstract getById(id: string): Promise; + abstract create(data: Partial): Promise; + abstract update(id: string, data: Partial): Promise; + abstract delete(id: string): Promise; +} + +class GenericRepository { /*300 lines */ } +class QueryBuilder { /* 200 lines*/ } +// ... building entire ORM for single table + +``` +Massive abstraction for uncertain future + + + +```typescript +// Simple functions for current needs +const getUsers = async (): Promise => { + return db.query('SELECT * FROM users'); +}; + +const getUserById = async (id: string): Promise => { + return db.query('SELECT * FROM users WHERE id = $1', [id]); +}; + +// When pattern emerges across multiple entities, then abstract +``` + +Abstract only when pattern proven across 3+ cases + + +#### Performance Optimization + + +```typescript +// Current: Simple approach +const filterActiveUsers = (users: User[]): User[] => { + return users.filter(user => user.isActive); +}; + +// Benchmark shows: 50ms for 1000 users (acceptable) +// ✓ Ship it, no optimization needed + +// Later: After profiling shows this is bottleneck +// Then optimize with indexed lookup or caching + +``` +Optimize based on measurement, not assumptions + + + +```typescript +// Premature optimization +const filterActiveUsers = (users: User[]): User[] => { + // "This might be slow, so let's cache and index" + const cache = new WeakMap(); + const indexed = buildBTreeIndex(users, 'isActive'); + // 100 lines of optimization code + // Adds complexity, harder to maintain + // No evidence it was needed +}; +``` + +Complex solution for unmeasured problem + + +#### In Practice + +**When implementing:** + +- Solve the immediate problem +- Use straightforward approach +- Resist "what if" thinking +- Delete speculative code + +**When optimizing:** + +- Profile first, optimize second +- Measure before and after +- Document why optimization needed +- Keep simple version in tests + +**When abstracting:** + +- Wait for 3+ similar cases (Rule of Three) +- Make abstraction as simple as possible +- Prefer duplication over wrong abstraction +- Refactor when pattern clear + +## Integration with Commands + +The Kaizen skill guides how you work. The commands provide structured analysis: + +- **`/why`**: Root cause analysis (5 Whys) +- **`/cause-and-effect`**: Multi-factor analysis (Fishbone) +- **`/plan-do-check-act`**: Iterative improvement cycles +- **`/analyse-problem`**: Comprehensive documentation (A3) +- **`/analyse`**: Smart method selection (Gemba/VSM/Muda) + +Use commands for structured problem-solving. Apply skill for day-to-day development. + +## Red Flags + +**Violating Continuous Improvement:** + +- "I'll refactor it later" (never happens) +- Leaving code worse than you found it +- Big bang rewrites instead of incremental + +**Violating Poka-Yoke:** + +- "Users should just be careful" +- Validation after use instead of before +- Optional config with no validation + +**Violating Standardized Work:** + +- "I prefer to do it my way" +- Not checking existing patterns +- Ignoring project conventions + +**Violating Just-In-Time:** + +- "We might need this someday" +- Building frameworks before using them +- Optimizing without measuring + +## Remember + +**Kaizen is about:** + +- Small improvements continuously +- Preventing errors by design +- Following proven patterns +- Building only what's needed + +**Not about:** + +- Perfection on first try +- Massive refactoring projects +- Clever abstractions +- Premature optimization + +**Mindset:** Good enough today, better tomorrow. Repeat. diff --git a/template/.claude/skills/adding-feature/operations.md b/template/.claude/skills/adding-feature/operations.md index b3ef856a6..0997afe1f 100644 --- a/template/.claude/skills/adding-feature/operations.md +++ b/template/.claude/skills/adding-feature/operations.md @@ -3,13 +3,13 @@ ## Setup 1. create `app/src/{feature-name}/operations.ts` -2. reference [`../../../app/src/demo-ai-app/operations.ts`](../../../app/src/demo-ai-app/operations.ts) as example ## Guidelines - **Queries:** for reading data - **Actions:** for create/update/delete - check `if (!context.user)` for authenticated operations +- check user subscription status before granting access to premium features - verify ownership before modifying resources - access database via `context.entities.EntityName` - use `HttpError` from `wasp/server` for errors diff --git a/template/.claude/skills/adding-feature/pages.md b/template/.claude/skills/adding-feature/pages.md index f92b9bbee..7db2b17bf 100644 --- a/template/.claude/skills/adding-feature/pages.md +++ b/template/.claude/skills/adding-feature/pages.md @@ -3,7 +3,6 @@ ## Setup 1. create `app/src/{feature-name}/{FeatureName}Page.tsx` -2. reference [`../../../app/src/demo-ai-app/DemoAppPage.tsx`](../../../app/src/demo-ai-app/DemoAppPage.tsx) as example ## Guidelines diff --git a/template/.claude/skills/adding-feature/wasp-config.md b/template/.claude/skills/adding-feature/wasp-config.md deleted file mode 100644 index 5aa7df338..000000000 --- a/template/.claude/skills/adding-feature/wasp-config.md +++ /dev/null @@ -1,8 +0,0 @@ -# Wasp Configuration - -1. read [`../../../app/main.wasp`](../../../app/main.wasp) for existing patterns -2. add feature section with region comments - -Key points: -- list ALL entities in `entities: [...]` array -- set `authRequired: true` for authenticated pages From 1f1bf80a1b6089113ad4c87acc5228099ece91a2 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Thu, 4 Dec 2025 16:55:15 +0100 Subject: [PATCH 13/16] improve setup skill & add seo optimizer skill --- .../skills/adding-feature/kaizen-approach.md | 35 +++-- .../stripe-automated-setup.md | 7 +- .../.claude/skills/seo-optimizer/SKILL.md | 97 +++++++++++++ .../.claude/skills/seo-optimizer/meta-tags.md | 80 +++++++++++ .../skills/seo-optimizer/robots-txt.md | 88 ++++++++++++ .../skills/seo-optimizer/structured-data.md | 127 ++++++++++++++++++ template/.claude/skills/setup-wizard/SKILL.md | 101 ++++++-------- 7 files changed, 459 insertions(+), 76 deletions(-) create mode 100644 template/.claude/skills/seo-optimizer/SKILL.md create mode 100644 template/.claude/skills/seo-optimizer/meta-tags.md create mode 100644 template/.claude/skills/seo-optimizer/robots-txt.md create mode 100644 template/.claude/skills/seo-optimizer/structured-data.md diff --git a/template/.claude/skills/adding-feature/kaizen-approach.md b/template/.claude/skills/adding-feature/kaizen-approach.md index 35cec92f3..602eddf14 100644 --- a/template/.claude/skills/adding-feature/kaizen-approach.md +++ b/template/.claude/skills/adding-feature/kaizen-approach.md @@ -40,6 +40,7 @@ Small, frequent improvements compound into major gains. - Don't try all three at once + ```typescript // Iteration 1: Make it work const calculateTotal = (items: Item[]) => { @@ -70,10 +71,12 @@ const calculateTotal = (items: Item[]): number => { }; ``` + Each step is complete, tested, and working + ```typescript // Trying to do everything at once const calculateTotal = (items: Item[]): number => { @@ -146,6 +149,7 @@ Design systems that prevent errors at compile/design time, not runtime. #### Type System Error Proofing + ```typescript // Error: string status can be any value type OrderBad = { @@ -174,6 +178,7 @@ Type system prevents entire classes of errors + ```typescript // Make invalid states unrepresentable type NonEmptyArray = [T, ...T[]]; @@ -195,6 +200,7 @@ Function signature guarantees safety #### Validation Error Proofing + ```typescript // Error: Validation after use const processPayment = (amount: number) => { @@ -242,6 +248,7 @@ Validate once at boundary, safe everywhere else #### Guards and Preconditions + ```typescript // Early returns prevent deeply nested code const processUser = (user: User | null) => { @@ -263,6 +270,7 @@ const processUser = (user: User | null) => { // Main logic here, guaranteed user is valid and active sendEmail(user.email, 'Welcome!'); }; + ``` Guards make assumptions explicit and enforced @@ -271,6 +279,7 @@ Guards make assumptions explicit and enforced #### Configuration Error Proofing + ```typescript // Error: Optional config with unsafe defaults type ConfigBad = { @@ -302,8 +311,9 @@ const loadConfig = (): Config => { const config = loadConfig(); const client = new APIClient(config); -``` Fail at startup, not in production + +``` #### In Practice @@ -353,6 +363,7 @@ Follow established patterns. Document what works. Make good practices easy to fo #### Following Patterns + ```typescript // Existing codebase pattern for API clients class UserAPIClient { @@ -373,6 +384,7 @@ Consistency makes codebase predictable + ```typescript // Existing pattern uses classes class UserAPIClient { /* ... */ } @@ -389,6 +401,7 @@ Inconsistency creates confusion #### Error Handling Patterns + ```typescript // Project standard: Result type for recoverable errors type Result = { ok: true; value: T } | { ok: false; error: E }; @@ -421,6 +434,7 @@ Standard pattern across codebase #### Documentation Standards + ```typescript /** * Retries an async operation with exponential backoff. @@ -498,6 +512,7 @@ Build what's needed now. No more, no less. Avoid premature optimization and over #### YAGNI in Action + ```typescript // Current requirement: Log errors to console const logError = (error: Error) => { @@ -508,6 +523,7 @@ Simple, meets current need + ```typescript // Over-engineered for "future needs" interface LogTransport { @@ -542,6 +558,7 @@ Building for imaginary future requirements - Multiple use cases emerged + ```typescript // Start simple const formatCurrency = (amount: number): string => { @@ -569,6 +586,7 @@ Complexity added only when needed #### Premature Abstraction + ```typescript // One use case, but building generic framework abstract class BaseCRUDService { @@ -588,6 +606,7 @@ Massive abstraction for uncertain future + ```typescript // Simple functions for current needs const getUsers = async (): Promise => { @@ -607,6 +626,7 @@ Abstract only when pattern proven across 3+ cases #### Performance Optimization + ```typescript // Current: Simple approach const filterActiveUsers = (users: User[]): User[] => { @@ -624,6 +644,7 @@ Optimize based on measurement, not assumptions + ```typescript // Premature optimization const filterActiveUsers = (users: User[]): User[] => { @@ -662,18 +683,6 @@ Complex solution for unmeasured problem - Prefer duplication over wrong abstraction - Refactor when pattern clear -## Integration with Commands - -The Kaizen skill guides how you work. The commands provide structured analysis: - -- **`/why`**: Root cause analysis (5 Whys) -- **`/cause-and-effect`**: Multi-factor analysis (Fishbone) -- **`/plan-do-check-act`**: Iterative improvement cycles -- **`/analyse-problem`**: Comprehensive documentation (A3) -- **`/analyse`**: Smart method selection (Gemba/VSM/Muda) - -Use commands for structured problem-solving. Apply skill for day-to-day development. - ## Red Flags **Violating Continuous Improvement:** diff --git a/template/.claude/skills/configuring-payments/stripe-automated-setup.md b/template/.claude/skills/configuring-payments/stripe-automated-setup.md index 5fe7e39b4..baf48d06f 100644 --- a/template/.claude/skills/configuring-payments/stripe-automated-setup.md +++ b/template/.claude/skills/configuring-payments/stripe-automated-setup.md @@ -150,7 +150,12 @@ chmod +x check-stripe-config.sh Review output with user and fix any issues. -### Step 5: Restart Wasp Server +### Step 5: Cleanup + +- Remove the unused payment processor code from the `src/payment/` directory. +- Prompt the user to remove the unused provider variables from the `.env.server` file. + +### Step 6: Restart Wasp Server Server should auto-restart when `.env.server` changes. If not: ```bash diff --git a/template/.claude/skills/seo-optimizer/SKILL.md b/template/.claude/skills/seo-optimizer/SKILL.md new file mode 100644 index 000000000..98624b79f --- /dev/null +++ b/template/.claude/skills/seo-optimizer/SKILL.md @@ -0,0 +1,97 @@ +--- +name: seo-optimizer +description: interactive SEO audit and fixes for your Open SaaS app. +--- + +# seo-optimizer + +Interactive SEO audit for your Open SaaS app. Finds issues and offers fixes one at a time. + +## Before Starting + +1. Read the wasp config file (`main.wasp` or `main.wasp.ts`) to check current meta tag configuration +2. If placeholders detected, ask user for their app name and production domain + +## Audit Sequence + +Run these checks in order. For each issue found: explain → ask user for input → generate fix → apply → move to next. + +### Step 1: Critical Meta Tags + +Check the wasp config file `app.head` for placeholder values: + +| Placeholder | Field | +|-------------|-------| +| "My Open SaaS App" or contains "Open SaaS" | title, og:title | +| "your-saas-app.com" | og:url | +| "Your (App) Name" | author | +| "me@example.com" | author email | +| Generic descriptions | description, og:description | + +For each placeholder found: +1. Ask user: "What should [field] be?" +2. Generate the corrected meta tag +3. Apply the fix to main.wasp +4. Move to next issue + +### Step 2: Open Graph Validation + +Verify Open Graph tags are complete and consistent: + +**Required OG tags:** +- `og:type` (should be "website") +- `og:title` (should match app title) +- `og:description` (should match meta description) +- `og:url` (should be production domain) +- `og:image` (should point to actual banner image) +- `og:site_name` + +**Twitter Card tags:** +- `twitter:card` (summary_large_image recommended) +- `twitter:image` + +If any are missing or inconsistent → offer to fix. + +### Step 3: Technical SEO + +Check [`../../../app/public/`](../../../app/public/) for: + +**robots.txt:** +- If missing → offer to create using [robots-txt.md](./robots-txt.md) template +- If exists → verify it allows search engine crawling + +**favicon:** +- Verify favicon.ico exists +- If missing → warn user + +### Step 4: Structured Data (Optional) + +Ask: "Would you like to add structured data (JSON-LD) for better search results?" + +If yes, offer to generate: +1. **Organization schema** - Company/app info +2. **FAQPage schema** - If FAQ section exists (reads from contentSections.tsx) + +See [structured-data.md](./structured-data.md) for templates. + +## File Paths + +| File | What to Check | +|------|---------------| +| the wasp config file (`main.wasp` or `main.wasp.ts`) | `app.head` meta tags | +| `app/public/` | robots.txt, favicon.ico | +| `src/landing-page/contentSections.tsx` | FAQ data for schema generation | + +## Completion + +After all fixes applied, summarize: +- What was fixed +- What user should verify manually (e.g., OG image looks correct) +- Recommend testing with [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) and [Twitter Card Validator](https://cards-dev.twitter.com/validator) + +## Documentation + +Fetch guide URLs directly: +- https://docs.opensaas.sh/llms.txt + +If you need more specific info, use mcp__wasp-docs__find_docs to search. diff --git a/template/.claude/skills/seo-optimizer/meta-tags.md b/template/.claude/skills/seo-optimizer/meta-tags.md new file mode 100644 index 000000000..8473dfa1d --- /dev/null +++ b/template/.claude/skills/seo-optimizer/meta-tags.md @@ -0,0 +1,80 @@ +# Meta Tags Reference + +## Required Meta Tags + +These must be in the wasp config file (`main.wasp` or `main.wasp.ts`) under `app.head`: + +```html + + +Your App Name - Tagline + + + + + + + + + + + + + + + + +``` + +## Open Graph Image Requirements + +- **Dimensions:** 1200 x 630 pixels (recommended) +- **Format:** PNG, JPG, or WebP +- **File size:** Under 1MB +- **Location:** `app/public/` directory +- **URL:** Must be absolute URL in production + +## Placeholder Detection + +Watch for these common placeholder values in Open SaaS: + +| Placeholder | Replace With | +|-------------|--------------| +| `"My Open SaaS App"` | Your actual app name | +| `"Open SaaS"` | Your actual app name | +| `"your-saas-app.com"` | Your production domain | +| `"Your (App) Name"` | Your name or company | +| `"me@example.com"` | Your actual email | +| `"/public-banner.webp"` | Your custom OG image path | +app MyApp { + wasp: { version: "^0.15.0" }, + title: "Acme SaaS - Project Management Made Simple", + head: [ + "", + "", + "", + "", + + "", + "", + "", + "", + "", + "", + + "", + "", + + "" + ], + // ... +} +``` + +## Testing Tools + +After making changes, verify with: +- [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) +- [Twitter Card Validator](https://cards-dev.twitter.com/validator) +- [LinkedIn Post Inspector](https://www.linkedin.com/post-inspector/) +- [OpenGraph.xyz](https://www.opengraph.xyz/) diff --git a/template/.claude/skills/seo-optimizer/robots-txt.md b/template/.claude/skills/seo-optimizer/robots-txt.md new file mode 100644 index 000000000..8435029f1 --- /dev/null +++ b/template/.claude/skills/seo-optimizer/robots-txt.md @@ -0,0 +1,88 @@ +# robots.txt Template + +## Location + +Create at: `app/public/robots.txt` + +This file tells search engine crawlers which pages to index and which to ignore. + +## Standard Template for SaaS Apps + +```txt +# robots.txt for SaaS Application + +User-agent: * +Allow: / + +# Disallow authenticated app routes +Disallow: /demo-app +Disallow: /account +Disallow: /admin +Disallow: /checkout + +# Disallow API routes (if exposed) +Disallow: /api/ +Disallow: /operations/ + +# Sitemap (if you have one) +Sitemap: https://yourdomain.com/sitemap.xml +``` + +## What to Allow + +**Allow crawling:** +- `/` - Landing page +- `/pricing` - Pricing page +- `/login` - Login page (for SEO, users searching "yourapp login") +- `/signup` - Signup page +- Blog pages (if on same domain) + +## What to Disallow + +**Block crawling:** +- `/demo-app` - Authenticated app pages +- `/account` - User account pages +- `/admin` - Admin dashboard +- `/checkout` - Payment/checkout flows +- `/api/` - API endpoints +- `/operations/` - Wasp operations + +## Sitemap Reference + +If your app has a sitemap (Astro blog generates one automatically): +```txt +Sitemap: https://yourdomain.com/sitemap.xml +``` + +For the main Wasp app, you may need to generate a sitemap separately or use a service. + +## Important Notes + +1. **robots.txt is public** - Don't use it to hide sensitive URLs (they can still be discovered) +2. **Not a security measure** - It's a suggestion to crawlers, not enforcement +3. **Crawl-delay** - Avoid unless you have server capacity issues +4. **Test changes** - Use [Google's robots.txt Tester](https://support.google.com/webmasters/answer/6062598) + +## Common Mistakes + +**Too restrictive:** +```txt +# BAD - blocks everything +User-agent: * +Disallow: / +``` + +**Missing trailing slashes:** +```txt +# This blocks /admin but not /administrator +Disallow: /admin + +# Use this to block all paths starting with /admin +Disallow: /admin +``` + +## After Creating + +1. Verify file is accessible at `https://yourdomain.com/robots.txt` +2. Check in [Google Search Console](https://search.google.com/search-console) for crawl errors +3. Submit sitemap if you have one diff --git a/template/.claude/skills/seo-optimizer/structured-data.md b/template/.claude/skills/seo-optimizer/structured-data.md new file mode 100644 index 000000000..c5a7ba96c --- /dev/null +++ b/template/.claude/skills/seo-optimizer/structured-data.md @@ -0,0 +1,127 @@ +# Structured Data (JSON-LD) Templates + +Structured data helps search engines understand your content and can enable rich results in search. + +## How to Add JSON-LD to Open SaaS + +Add as a ` +``` + +**Note:** JSON must be on a single line or escaped properly in the wasp string. + +## Organization Schema + +Use this for your company/app info. Helps with knowledge panel in search results. + +```json +{ + "@context": "https://schema.org", + "@type": "Organization", + "name": "Your App Name", + "url": "https://yourdomain.com", + "logo": "https://yourdomain.com/logo.png", + "description": "Brief description of your company/app", + "sameAs": [ + "https://twitter.com/yourhandle", + "https://github.com/yourorg", + "https://linkedin.com/company/yourcompany" + ] +} +``` + +## WebSite Schema + +Enables sitelinks search box in Google results. + +```json +{ + "@context": "https://schema.org", + "@type": "WebSite", + "name": "Your App Name", + "url": "https://yourdomain.com" +} +``` + +## FAQPage Schema + +If your landing page has an FAQ section, this can show FAQ rich results in Google. + +**Template:** +```json +{ + "@context": "https://schema.org", + "@type": "FAQPage", + "mainEntity": [ + { + "@type": "Question", + "name": "What is Your App?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Your App is a SaaS platform that..." + } + }, + { + "@type": "Question", + "name": "How much does it cost?", + "acceptedAnswer": { + "@type": "Answer", + "text": "We offer plans starting at..." + } + } + ] +} +``` + +**Generating from contentSections.tsx:** + +Read the FAQs array from [`../../../app/src/landing-page/contentSections.tsx`](../../../app/src/landing-page/contentSections.tsx) and generate the schema: + +```typescript +// contentSections.tsx has: +export const faqs = [ + { id: 1, question: '...', answer: '...' }, + // ... +] +``` + +Transform to JSON-LD `mainEntity` array. + +## SoftwareApplication Schema + +Good for SaaS products, can show ratings and pricing in search. + +```json +{ + "@context": "https://schema.org", + "@type": "SoftwareApplication", + "name": "Your App Name", + "applicationCategory": "BusinessApplication", + "operatingSystem": "Web", + "offers": { + "@type": "Offer", + "price": "0", + "priceCurrency": "USD" + } +} +``` + +## Testing Structured Data + +After adding, verify with: +- [Google Rich Results Test](https://search.google.com/test/rich-results) +- [Schema Markup Validator](https://validator.schema.org/) + +## Common Issues + +**JSON parsing errors:** +- Escape quotes properly: `\"` not `"` +- No trailing commas in arrays/objects +- Must be valid JSON on single line in wasp string + +**Schema not detected:** +- Ensure `type="application/ld+json"` is set +- Check JSON is valid +- Wait for Google to recrawl (can take days) diff --git a/template/.claude/skills/setup-wizard/SKILL.md b/template/.claude/skills/setup-wizard/SKILL.md index 0634cae66..df6c2254c 100644 --- a/template/.claude/skills/setup-wizard/SKILL.md +++ b/template/.claude/skills/setup-wizard/SKILL.md @@ -30,99 +30,76 @@ Then update in [`../../../app/main.wasp`](../../../app/main.wasp): ### Step 2: Authentication Ask the user which auth methods they want: -- Email/password (enabled by default) -- Google OAuth -- GitHub OAuth -- Discord OAuth -- Slack OAuth -- Keycloak OAuth +- Email/password (enabled by default with `Dummy` email sender for local development) +- Google OAuth (requires API keys) +- GitHub OAuth (requires API keys) +- Discord OAuth (requires API keys) +- Slack OAuth (requires API keys) +- Keycloak OAuth (requires API keys) For each OAuth provider selected: 1. uncomment or add the provider in wasp config file auth methods 2. inform user they'll need to set env vars later (Step 6) -Refer to [configuring-auth skill](../configuring-auth/SKILL.md) for details. - ### Step 3: Payment Provider -Ask the user: -- Which payment provider? (Stripe / Lemon Squeezy / Polar / Skip for now) +Ask the user which payment provider they'd like to use: + - Stripe (industry standard, most configurable, lower fees per transaction) + - Polar (Merchant of Record, great DX, higher fees per transaction) + - Lemon Squeezy (Merchant of Record, higher fees per transaction) + - Skip for now (no payments) If they choose one: 1. update `src/payment/paymentProcessor.ts` to select their provider -2. note they'll configure credentials in Step 6 - -Refer to [configuring-payments skill](../configuring-payments/SKILL.md) for details. +2. remove the unused payment processor code from the `src/payment/` directory +3. remove unused payment provider code and clients from `src/analytics/stats.ts` +4. prompt the user to remove the unused provider variables from the `.env.server` file +5. note they'll configure their provider's credentials in Step 6 ### Step 4: Email Provider -Ask the user: -- Which email provider for production? (SendGrid / Mailgun / SMTP / Skip for now) +Ask the user which email provider they'd like to use: + - SendGrid (requires API key) + - Mailgun (requires API key) + - SMTP (requires SMTP server credentials) + - Skip for now (default provider is `Dummy`, which logs emails to console for local development) If they choose one: 1. update `emailSender.provider` in wasp config file 2. note they'll configure credentials in Step 6 -For development, explain `Dummy` provider shows emails in console. - ### Step 5: Analytics (Optional) -Ask the user: -- Want to set up analytics? (Plausible / Google Analytics / Skip) - -If yes, note they'll add tracking ID in Step 6. - -### Step 6: Environment Variables - -Generate a checklist of required env vars based on their selections: - -``` -# Based on your setup, you need these in .env.server: +Ask the user if they want to set up analytics: + - Plausible (requires API key) + - Google Analytics (requires API key) + - Skip for now (no analytics) -# Database (required) -DATABASE_URL= +If yes, note they'll configure the analytics provider in Step 6. -# Auth - OAuth (if selected) -GOOGLE_CLIENT_ID= -GOOGLE_CLIENT_SECRET= -# ... etc based on selections +### Step 6: Completing Integrations & Environment Variables -# Payments (if selected) -STRIPE_API_KEY= -# ... etc based on selection +For each integration selected: follow the guide or skill → generate checklist of required env vars → give user instructions to apply → move to next. -# Email (if selected) -SENDGRID_API_KEY= -# ... etc based on selection -``` - -Ask: "Would you like me to create a .env.server template with these variables?" +- OAuth providers: find the correct provider guide URL at https://wasp.sh/llms.txt +- Email providers: find the sending emails guide URL at https://wasp.sh/llms.txt +- Analytics providers: find the correct guide URL at https://docs.opensaas.sh/llms.txt +- Payment providers: invoke the [configuring-payments skill](../configuring-payments/SKILL.md) ### Step 7: Verify Setup -Refer to [starting-wasp skill](../starting-wasp/SKILL.md) for details on how to start the development server. -1. after starting the development server, verify configuration compiles -2. check for any errors -3. summarize what was configured and what still needs credentials - -## Completion - -Provide a summary: -- What was configured -- What env vars still need to be filled in -- Links to provider dashboards for obtaining credentials -- Links to [Open SaaS docs](https://docs.opensaas.sh) for completing integrations -- Prompt the user if they'd like help with further setup for full functionality of the features they selected. +1. "Would you like to start your Wasp app in a new terminal yourself or would you like me to start it for you as a background task?" +2. after starting the development server, verify configuration compiles +3. check for any errors. -### Further Setup Help +## Step 8: Completion -- For payments, run the [configuring-payments skill](../configuring-payments/SKILL.md) for further setup. -- For auth, run the [configuring-auth skill](../configuring-auth/SKILL.md) for further setup. -- For features, run the [adding-feature skill](../adding-feature/SKILL.md) for further setup. +Provide a summary of the setup process and what other skills and commands are available to help with further setup. ## Documentation -Fetch guide URLs directly: -- https://docs.opensaas.sh/llms.txt +Fetch guide URLs directly from the Wasp and Open SaaS docs: +- https://wasp.sh/llms.txt +- https://docs.opensaas.sh/llms.txt If you need more specific info, use mcp__wasp-docs__find_docs to search. From ca21e99c08098a50b145f13116beeafe72282a5b Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:33:02 +0100 Subject: [PATCH 14/16] refine setup-wizard --- template/.claude/skills/setup-wizard/SKILL.md | 15 ++++++++++++--- .../skills/validating-pre-deployment/SKILL.md | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/template/.claude/skills/setup-wizard/SKILL.md b/template/.claude/skills/setup-wizard/SKILL.md index df6c2254c..61161d8e2 100644 --- a/template/.claude/skills/setup-wizard/SKILL.md +++ b/template/.claude/skills/setup-wizard/SKILL.md @@ -27,10 +27,12 @@ Then update in [`../../../app/main.wasp`](../../../app/main.wasp): - `app.title` - `app.head` meta tags +DO NOT change URLs in the `app.head` meta tags. Leave these as they are until the user has a production domain and is ready to deploy. + ### Step 2: Authentication Ask the user which auth methods they want: -- Email/password (enabled by default with `Dummy` email sender for local development) +- Email/password (works right away with `Dummy` email sender in local development) - Google OAuth (requires API keys) - GitHub OAuth (requires API keys) - Discord OAuth (requires API keys) @@ -79,8 +81,15 @@ If yes, note they'll configure the analytics provider in Step 6. ### Step 6: Completing Integrations & Environment Variables -For each integration selected: follow the guide or skill → generate checklist of required env vars → give user instructions to apply → move to next. +For each integration selected in Steps 2-5: +1. fetch the guide or skill from the list below to guide the user through the integration +2. generate checklist of required env vars +3. give user instructions for retrieving and adding env vars to `.env.server` +4. follow steps/run commands in the guide or skill to complete the integration for the user where applicable +5. prompt the user to confirm they're ready to move to the next integration +6. move to next integration +Skills and guides to fetch for each integration: - OAuth providers: find the correct provider guide URL at https://wasp.sh/llms.txt - Email providers: find the sending emails guide URL at https://wasp.sh/llms.txt - Analytics providers: find the correct guide URL at https://docs.opensaas.sh/llms.txt @@ -88,7 +97,7 @@ For each integration selected: follow the guide or skill → generate checklist ### Step 7: Verify Setup -1. "Would you like to start your Wasp app in a new terminal yourself or would you like me to start it for you as a background task?" +1. start the wasp app processes in new terminals as background tasks in the current Claude Code session: `wasp start db` and `wasp start`. 2. after starting the development server, verify configuration compiles 3. check for any errors. diff --git a/template/.claude/skills/validating-pre-deployment/SKILL.md b/template/.claude/skills/validating-pre-deployment/SKILL.md index dd9d129b6..145bb4b39 100644 --- a/template/.claude/skills/validating-pre-deployment/SKILL.md +++ b/template/.claude/skills/validating-pre-deployment/SKILL.md @@ -29,11 +29,13 @@ Check the wasp config file (`main.wasp` or `main.wasp.ts`) `app` block for place - ``) - OR scripts should be removed/commented if not using Plausible From d7ff8a77b21c169c0d39a0d8758c3bb2f6850d75 Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:35:23 +0100 Subject: [PATCH 15/16] Clarify payment provider setup and cleanup steps Added instructions to include provider-specific details from guide URLs during setup. Expanded cleanup steps to specify additional files and directories to remove for unused payment providers. --- .../.claude/skills/configuring-payments/SKILL.md | 12 ++++++++---- .../.claude/skills/configuring-payments/cleanup.md | 6 +++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/template/.claude/skills/configuring-payments/SKILL.md b/template/.claude/skills/configuring-payments/SKILL.md index 67e620f8b..f301eb733 100644 --- a/template/.claude/skills/configuring-payments/SKILL.md +++ b/template/.claude/skills/configuring-payments/SKILL.md @@ -27,6 +27,8 @@ Set in `.env.server`: | Lemon Squeezy | `LEMONSQUEEZY_API_KEY`, `LEMONSQUEEZY_STORE_ID`, `LEMONSQUEEZY_WEBHOOK_SECRET` | | Polar | `POLAR_ORGANIZATION_ACCESS_TOKEN`, `POLAR_WEBHOOK_SECRET`, `POLAR_SANDBOX_MODE=true` | +Include specifics, e.g. scopes, from the guide URLs for the chosen provider: https://docs.opensaas.sh/llms.txt + ### 3. Create Products Create in provider dashboard: 2 subscriptions (Hobby, Pro) + 1 one-time (Credits). @@ -46,13 +48,15 @@ Update `src/payment/plans.ts` if changing product names. **Lemon Squeezy / Polar:** use ngrok (`ngrok http 3001`), set webhook URL to `https://[ngrok-url]/payments-webhook` -## Testing Payments and Troubleshooting +Include specifics, e.g. events, secrets, etc., from the guide URLs for the chosen provider: https://docs.opensaas.sh/llms.txt -See [troubleshooting](./troubleshooting.md) +### 5. Cleanup -## Cleanup +Remove unused provider code by following [cleanup.md](./cleanup.md) -See [cleanup.md](./cleanup.md) to remove unused provider code. +## Testing Payments and Troubleshooting + +See [troubleshooting](./troubleshooting.md) ## Documentation diff --git a/template/.claude/skills/configuring-payments/cleanup.md b/template/.claude/skills/configuring-payments/cleanup.md index f3d16c662..625793e61 100644 --- a/template/.claude/skills/configuring-payments/cleanup.md +++ b/template/.claude/skills/configuring-payments/cleanup.md @@ -4,7 +4,11 @@ Optional cleanup after selecting payment provider. ## Remove Unused Provider Directories -Delete directories in `app/src/payment/` for providers you're not using (e.g., `stripe/`, `lemonsqueezy/`, `polar/`). +Delete code for providers you're not using (e.g., `stripe/`, `lemonsqueezy/`, `polar/`) in the following directories: +- `app/src/payment//` +- `app/src/payment/paymentProcessor.ts` +- `app/src/server/scripts/dbSeeds.ts` +- `app/src/analytics/stats.ts` ## Environment Variables From 11f563949540864c80abaedc4a09b8e4bcad3fcb Mon Sep 17 00:00:00 2001 From: vincanger <70215737+vincanger@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:18:34 +0100 Subject: [PATCH 16/16] Update CLAUDE.md --- template/app/CLAUDE.md | 170 +++++++++++++---------------------------- 1 file changed, 53 insertions(+), 117 deletions(-) diff --git a/template/app/CLAUDE.md b/template/app/CLAUDE.md index 9b9f841f1..b6651771e 100644 --- a/template/app/CLAUDE.md +++ b/template/app/CLAUDE.md @@ -1,153 +1,89 @@ # CLAUDE.md -## What is This Project? +## What is Open SaaS? -This is the **Open SaaS template** - a free, open-source SaaS starter boilerplate built on the Wasp framework. Users get this template when they run `wasp new -t saas` and customize it to build their own SaaS applications. +Open SaaS is a free, open-source SaaS starter built on Wasp (React + Node.js + Prisma). It includes auth, payments, admin dashboard, email, file uploads, and analytics out of the box. Users customize this template to build their own SaaS applications. -**This template comes with production-ready features:** -- **Authentication** - Email verification + OAuth (Google, GitHub, Discord, Slack) -- **Payments** - Stripe, Polar.sh, and Lemon Squeezy integration with subscription management -- **Admin Dashboard** - User management and analytics -- **Email** - SendGrid, Mailgun, or SMTP support -- **File Uploads** - AWS S3 integration -- **Analytics** - Plausible or Google Analytics -- **AI Ready** - Example OpenAI integration with function calling -- **Demo App** - Example task management app to demonstrate features -- **Testing** - Playwright E2E tests included -- **Deployment** - One-command deploy to Railway or Fly.io +**Tech stack:** Wasp, React, TypeScript, Node.js, Prisma, PostgreSQL, TailwindCSS, ShadCN UI -## New Project Detection +## Critical Files -On first interaction, check if this is an unconfigured Open SaaS project by reading `main.wasp` (or `main.wasp.ts`). If `app.title` is still "My Open SaaS App" or contains placeholder values like "your-saas-app.com", suggest: +Read these first to understand the app: -> "It looks like you haven't customized your Open SaaS project yet. Would you like me to run the setup wizard to configure your app? Just say 'yes' or run `/open-saas-setup-wizard`." +- [main.wasp](main.wasp) - App config: routes, pages, auth, operations, jobs + - note: users can also use `main.wasp.ts` instead of `main.wasp` +- [schema.prisma](schema.prisma) - Database models and relationships +- [src/payment/](src/payment/) - Payment processor integration & great example of Wasp's feature set in action. +- [src/auth/](src/auth/) - Authentication logic and pages -## Project Structure - -This is a Wasp application. Wasp uses a declarative configuration file to generate a full-stack app: - -- **`main.wasp`** - App configuration defining routes, pages, auth, operations, and more - - note: users can also use `main.wasp.ts` instead of `main.wasp` for TypeScript support. -- **`schema.prisma`** - Prisma database schema (defines data models) -- **`src/{featureName}/`** - Application code organized by feature: - - `operations.ts` - Wasp queries and actions - - `{FeatureName}Page.tsx` - Page components - - Components, utilities, and types as needed -- **`src/client/components/ui`** - predefined ShadCN UI components -- **`src/shared/`** - Code shared between client and server -- **`e2e-tests/`** - Playwright end-to-end tests - -**Note:** The demo app features (`demo-ai-app`, `file-upload`, etc.) are examples users can reference and remove when building their own SaaS. - -## Essential Commands +## Commands ```bash # Development -wasp start # Start dev server (runs DB, server, and client) -wasp start db # Start only the managed development database -wasp db migrate-dev # Create and apply database migrations -wasp db studio # Open Prisma Studio to inspect database -wasp db seed # Run seed functions defined in main.wasp +wasp start # Start dev server (DB + server + client) +wasp start db # Start only the database +wasp db migrate-dev # Apply schema changes +wasp db studio # Inspect database GUI # Production wasp build # Generate production build -wasp build start # Generate production build and start server to test locally wasp deploy # Deploy to Railway or Fly.io # Maintenance -wasp clean # Delete generated code and caches (fixes most issues) +wasp clean # Delete generated code (fixes most issues) ``` -## Import Conventions (CRITICAL) - -**In TypeScript/TSX files (`.ts`/`.tsx`):** -- ✅ Wasp imports: `import { User } from 'wasp/entities'` -- ✅ Wasp operations: `import { useQuery } from 'wasp/client/operations'` -- ✅ Wasp types: `import type { GetTasks } from 'wasp/server/operations'` -- ✅ Prisma enum values: `import { SubscriptionStatus } from '@prisma/client'` -- ✅ Local code: Use relative paths like `import { Component } from './Component'` -- ❌ NEVER use `@wasp/...` prefix -- ❌ NEVER use `@src/...` in TypeScript files - -**In main.wasp file:** -- ✅ Your code: `fn: import { getTasks } from "@src/tasks/operations.ts"` -- ❌ NEVER use relative paths like `"../src/..."` - -## Wasp Operations Pattern - -Wasp operations (queries and actions) are the primary way to communicate between client and server. - -## Database Workflow - -1. Edit `schema.prisma` to add/modify models -2. Run `wasp db migrate-dev --name describe-change` -3. Wasp auto-generates TypeScript types in `wasp/entities` -4. Access via `context.entities.ModelName` in operations +## Project Structure -**Useful commands:** -```bash -wasp db studio # GUI to inspect database -wasp db reset # Reset database (WARNING: deletes data) ``` - -## Development Patterns - -Wasp abstracts and adds layers on top of the tools it uses to make development more productive. The codebase is your source of truth for how to use Wasp effectively. - -### Feature Organization - -Use the current features as a guide to understand how code is organized. -When adding new features, refer to [adding-feature SKILL.md](../.claude/skills/adding-feature/SKILL.md) for more information. - -## Troubleshooting - -**Nuclear option (fixes most issues):** -```bash -wasp clean && wasp start +src/ +├── {feature}/ # Feature modules (auth, payment, user, admin, etc.) +│ ├── operations.ts # Wasp queries and actions +│ └── *Page.tsx # Page components +├── client/components/ # Shared UI components (ShadCN) +└── shared/ # Code shared between client and server ``` -**Restart TypeScript server:** `Cmd/Ctrl + Shift + P` → "TypeScript: Restart TS Server" +Features are organized by domain. Use existing features as patterns when adding new ones. -### Import Errors -- `"Cannot find module 'wasp/...'"` → Use `wasp/`, not `@wasp/` -- `"Cannot find module '@src/...'"` in TypeScript → Use relative paths, `@src/` is only for main.wasp +## Coding Standards -### Entity/Operation Errors -- `"context.entities.X is undefined"` → Check entity is in `entities: [...]` array in main.wasp -- Types not updating → Restart Wasp server, then restart TS server +- **Comment the "why", not the "what"** - Explain non-obvious decisions and edge cases +- Use descriptive names over comments where possible +- Follow existing patterns in the codebase -### Database Issues -- Schema changes not applied → `wasp db migrate-dev --name describe-change` -- Database out of sync → `wasp db reset` (WARNING: deletes data) +## Import Conventions (Critical) -### Runtime Errors -- 401 errors → Check `if (!context.user)` guard or `authRequired: true` on page -- DB connection issues → Run `wasp start db` or check `DATABASE_URL` -- Env var changes not working → Restart server after `.env.server` changes +**In TypeScript files:** +- ✅ `import type { User } from 'wasp/entities'` +- ✅ `import type { GetTasks } from 'wasp/server/operations'` +- ✅ `import { getTasks,useQuery } from 'wasp/client/operations'` +- ✅ `import { SubscriptionStatus } from '@prisma/client'` +- ✅ Local code: relative paths `import { X } from './X'` +- ❌ Never `@wasp/...` or `@src/...` +- ⚠️ Call actions directly using `async/await`. DO NOT use Wasp's `useAction` hook unless optimistic updates are needed. -## Authentication Quick Reference +**In main.wasp:** +- ✅ `fn: import { getTasks } from "@src/tasks/operations.ts"` +- ❌ Never relative paths -**Email auth** is enabled by default. For production, switch from `Dummy` to a real email provider. - -**Dev testing:** Set `SKIP_EMAIL_VERIFICATION_IN_DEV=true` or find verification URLs in server console. - -## E2E Testing +## Troubleshooting -With the Wasp app running in a separate terminal, run the following commands: -```bash -cd e2e-tests && npm install # First time only -npm run local:e2e:start # Run tests (opens Playwright UI) -``` +| Error | Fix | +|-------|-----| +| `Cannot find module 'wasp/...'` | Use `wasp/`, not `@wasp/` | +| `Cannot find module '@src/...'` in TS | Use relative paths; `@src/` is only for main.wasp | +| `context.entities.X undefined` | Add entity to `entities: [...]` in main.wasp | +| Types not updating | Restart Wasp server, then TS server | +| Schema changes not applied | `wasp db migrate-dev --name change-name` | +| General weirdness | `wasp clean && wasp start` | -## Wasp Discord +## Resources -- https://discord.gg/aCamt5wCpS (use #🙋questions channel) +**Help:** https://discord.gg/aCamt5wCpS (#🙋questions channel) -## LLM-optimized Documentation +**MCP Tools:** Use `mcp__wasp-docs` to search Wasp/OpenSaaS docs -If needed, ground yourself using the Wasp & Open SaaS documentation: +**Documentation:** - https://wasp.sh/llms.txt - https://docs.opensaas.sh/llms.txt - -## MCP Documentation Lookup -- For specific lookups: Use `mcp__wasp-docs__find_docs` to search Wasp/OpenSaaS docs