happiness is an open-source donation page platform. It was initially built to power donation pages for Slingshot Giving and Hack+.
happiness runs on the Next.js nodejs runtime and uses PlanetScale's serverless driver by default. Any standard MySQL database can be used instead by setting DATABASE_DRIVER=mysql2, which switches Drizzle over to the mysql2 driver; this path is exercised by the E2E test suite.
To get started, create a clone of this repository:
git clone --mirror https://github.com/heysanil/happiness
# or, click "Use this template" on GitHubTool versions (Node, Bun, and lefthook) are pinned in mise.toml. Install mise, then let it provision the toolchain — this also installs the git hooks defined in lefthook.yml:
mise install
If you cloned this repository back when it used husky, clear the stale hooks path first — otherwise git keeps looking for hooks in a .husky directory that no longer exists, and the checks below silently never run:
git config --unset core.hooksPath
Install dependencies using bun:
bun install
Copy .env.example to .env.local and set the required environmental variables. At minimum you'll need to sign up for Stripe (for payment processing). The donor portal additionally requires BETTER_AUTH_SECRET, an Upstash Redis instance, and SMTP credentials for sending one-time login codes.
You can also directly modify the configuration in happiness.config.ts and replace icons/logos in public.
Push the database schema to your database:
bun db:push
This will create the required tables with a happiness_ prefix, so you can use an existing database (all future schema pushes will also be scoped to happiness_-prefixed tables).
Then, run the development server using bun dev (or the production server using bun start). The dev server port can be set with HP_DEV_PORT and defaults to 3000.
You can also open a Drizzle Studio UI using bun db:gui, or run both the development server and Drizzle Studio UI using bun dev:db. Drizzle Studio runs on port 3100 by default, but this behavior can be changed in package.json.
NOTE: To complete setup, you also need to set up the correct webhooks on the Stripe Dashboard. Using a service like Zeplo as a proxy to forward webhooks to your app is recommended, which will give you more control over logging and retries, but you can also point Stripe directly to the /v1/external/stripe endpoint.
Happiness exposes a REST API for managing pages, donations, and donors. The API documentation can be found at /api when running the server, and a JSON OpenAPI spec can be downloaded at /api/openapi.json.
For now, there are two main ways to use a non-MySQL database with Happiness:
- Update the Drizzle schema & configuration to use a different database driver. You will need to manually update each
XXColumnsdefinition to use the correct Drizzlecoretypes. - Update the operations functions in
src/db/ops. You will need to manually rewrite each function to adapt to your database. This will essentially disable the Drizzle ORM, but will allow you to use any database (including NoSQL databases). You should still use the types and Zod schemas exported from the Drizzle schema and ensure all functions maintain the same return formats.
You only need to do one of these; if you update the Drizzle schema & configuration, you can leave the operations functions as-is, and vice versa.
If you proceed with either of these routes, we ask that you open-source your work so that others can benefit from it. We are also open to accepting pull requests that add support for other databases, as well as promoting community-maintained forks that adapt Happiness to other databases.
Any number of Pages can be set up, which are either a simple donation page or a 'story' style page with more customization.
Every Donation is linked to both a Page and a Donor.
Donors begin their donation on the page. Upon selecting their amount and preferences, they are redirected to a Stripe Checkout page to complete their donation. Once the donation is complete, they are redirected back to the page. Donations are only recorded to the database after payments are successfully processed and the donor is redirected back to the page.
Recurring donations are handled fully through Stripe; incoming donation webhooks are used to update the database.
All API routes currently exist under src/app/(api)/v1.
Each route is defined in a directory's route.ts file. Every route.ts should be colocated with a schemas.ts file that defines the OpenAPI schemas for each operation in the route.
The OpenAPI spec is generated in src/app/(api)/api/oas/index.ts. Components can be defined there, and then shared across paths via $ref.
The API docs are generated using Stoplight Elements, and live in src/app/(api)/api.
- Administrator portal and dashboard
- Stripe Connect support (
STRIPE_ACCOUNT_ID), with per-deployment webhook isolation for instances sharing a Stripe account (HAPPINESS_INSTANCE_ID) - API key management
- Updater for smooth upgrades instead of relying on Git cloning