Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e42f0e9
Onboarding: ask where people heard about OpenProfit
lobbystack Oct 19, 2026
a5a8379
Move GitHub and GHCR links to morencyr/openprofit
lobbystack Oct 19, 2026
dd4c05b
Onboarding: ask where people heard about OpenProfit
lobbystack Oct 19, 2026
762e960
Move GitHub and GHCR links to morencyr/openprofit
lobbystack Oct 19, 2026
859e39f
Login: Google logo on its button. Onboarding: drop the currency and i…
lobbystack Oct 19, 2026
2099899
Login: link the terms and privacy policy under the buttons on the hos…
lobbystack Oct 19, 2026
ac9e04d
Merge pull request #1 from morencyr/feature/login-onboarding-polish-6…
morencyr Oct 19, 2026
b4a831e
Onboarding: add TikTok to where people heard about OpenProfit
lobbystack Oct 19, 2026
0a85a58
Blog: four posts on profit, TrustMRR, AI token costs and payment fees
lobbystack Oct 19, 2026
5b42113
Blog: US spelling in the TrustMRR table
lobbystack Oct 19, 2026
a197c33
Blog: stop-slop pass on the four new posts
lobbystack Oct 19, 2026
4b8c318
Blog: SaaS running costs, and spend limits vs budget alerts
lobbystack Oct 19, 2026
584f38a
Login: use the flat Google G from SVG Logos, SVGL's blurs at 14 px
lobbystack Oct 19, 2026
0d0e74c
Onboarding: add TikTok to where people heard about OpenProfit
lobbystack Oct 19, 2026
7ab6b12
SEO: profit in the homepage title, WebSite schema, llms.txt
lobbystack Oct 19, 2026
ef3cd27
GitHub social preview image, 1280x640, from the banner's mark, wordma…
lobbystack Oct 19, 2026
cfa4f25
SEO: cross-links, searched post titles, breadcrumb and FAQ schema, ll…
lobbystack Oct 19, 2026
2d69f4d
Integrations: fuller Cloudflare, DigitalOcean, Twilio and Vercel pages
lobbystack Oct 19, 2026
51b3862
Vercel and Cloudflare: fix backfill and reread ranges
lobbystack Oct 19, 2026
796bd57
Vercel and Cloudflare: fix backfill and reread ranges
lobbystack Oct 19, 2026
134ad0b
Run on Bun: package manager, dev server, scripts and production
lobbystack Oct 20, 2026
7cadbcb
Books: fee math, POST exports and a re-sync migration
lobbystack Oct 20, 2026
312513e
Merge origin/main into books
lobbystack Oct 20, 2026
b22ad1e
Docs: base currency changes reopen exported months; image runs on Bun
lobbystack Oct 20, 2026
b4e8c93
Move hosting from Railway to Dokploy behind Cloudflare
lobbystack Oct 22, 2026
68f25e8
CLAUDE.md: openprofit.dev is registered through Railway Domains
lobbystack Oct 22, 2026
3e7b48f
Add a script that re-encrypts stored secrets under a new SECRET_KEY
lobbystack Oct 23, 2026
4b5ef5d
Run on Bun 1.4.4 for CVE-2026-111497
lobbystack Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"configurations": [
{
"name": "dev",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["dev"],
"runtimeExecutable": "bun",
"runtimeArgs": ["run", "dev"],
"port": 3000
}
]
Expand Down
2 changes: 1 addition & 1 deletion .cta.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"mode": "file-router",
"typescript": true,
"tailwind": true,
"packageManager": "pnpm",
"packageManager": "bun",
"git": false,
"install": true,
"intent": false,
Expand Down
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ data
design
.env
.git
packages
packages/*/*
!packages/*/package.json
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
blank_issues_enabled: true
contact_links:
- name: Security issue
url: https://github.com/lobbystack/openprofit/blob/main/CONTRIBUTING.md#report-a-security-issue
url: https://github.com/morencyr/openprofit/blob/main/CONTRIBUTING.md#report-a-security-issue
about: Email hello@openprofit.dev. Don't report security problems in a public issue.
- name: Setup questions
url: https://openprofit.dev/docs
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/connector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: "Connector: "
body:
- type: markdown
attributes:
value: A connector needs an API that returns billing or usage data with a key. Links to the provider's own docs help most. To build it yourself, see [CONTRIBUTING.md](https://github.com/lobbystack/openprofit/blob/main/CONTRIBUTING.md#build-a-connector).
value: A connector needs an API that returns billing or usage data with a key. Links to the provider's own docs help most. To build it yourself, see [CONTRIBUTING.md](https://github.com/morencyr/openprofit/blob/main/CONTRIBUTING.md#build-a-connector).
- type: input
id: provider
attributes:
Expand Down
Binary file added .github/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 9 additions & 11 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
name: Check

# Pushes to main run this through docker.yml, which deploys only when it passes.
on:
push:
branches: [main]
pull_request:
workflow_call:

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
- uses: oven-sh/setup-bun@v2
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm check
- run: npx tsc --noEmit
- run: pnpm build
- run: pnpm --dir packages/cli build && pnpm --dir packages/cli test
bun-version-file: package.json
- run: bun install --frozen-lockfile
- run: bun run check
- run: bunx --bun tsc --noEmit
- run: bun run build
- run: cd packages/cli && bun run build && bun run test
16 changes: 16 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
tags: ["v*"]

jobs:
check:
uses: ./.github/workflows/check.yml

build:
needs: check
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -35,3 +39,15 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

# openprofit.dev runs this image on Dokploy. Its deploy webhook pulls :latest.
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- env:
DOKPLOY_DEPLOY_WEBHOOK: ${{ secrets.DOKPLOY_DEPLOY_WEBHOOK }}
run: |
if [ -z "$DOKPLOY_DEPLOY_WEBHOOK" ]; then echo "DOKPLOY_DEPLOY_WEBHOOK is not set; skipping"; exit 0; fi
curl -fsS -X POST "$DOKPLOY_DEPLOY_WEBHOOK"
56 changes: 33 additions & 23 deletions CLAUDE.md

Large diffs are not rendered by default.

30 changes: 15 additions & 15 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# Contributing to OpenProfit

Issues and pull requests are welcome. Connectors are the most useful contribution. Most of this guide covers how to build one: the files to touch, the data to return, and how to test against a real account. To ask for a connector without building it, [open a connector request](https://github.com/lobbystack/openprofit/issues/new?template=connector.yml).
Issues and pull requests are welcome. Connectors are the most useful contribution. Most of this guide covers how to build one: the files to touch, the data to return, and how to test against a real account. To ask for a connector without building it, [open a connector request](https://github.com/morencyr/openprofit/issues/new?template=connector.yml).

## Set up a development environment

You need Node 22 and pnpm. Install the dependencies, copy `.env.example`, and generate a key with the `node` line:
You need [Bun](https://bun.com) 1.3 or later. Install the dependencies, copy `.env.example`, and generate a key with the `bun -e` line:

```bash
pnpm install
bun install
cp .env.example .env
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
pnpm dev
bun -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
bun run dev
```

Paste the key into `SECRET_KEY` in `.env` before you start the server. It encrypts provider credentials, and saving a connection fails without it. The app runs at http://localhost:3000.

To sign in without an email provider, enter any address on `/login`. With `RESEND_API_KEY` unset, the server prints the sign-in link to the `pnpm dev` output. Open it, then create a workspace on the onboarding page.
To sign in without an email provider, enter any address on `/login`. With `RESEND_API_KEY` unset, the server prints the sign-in link to the `bun run dev` output. Open it, then create a workspace on the onboarding page.

For a workspace with a year of demo numbers, stop `pnpm dev` and run `pnpm db:seed`. After you sign in once, `pnpm db:seed --owner=you@example.com` adds your user to it.
For a workspace with a year of demo numbers, stop `bun run dev` and run `bun run db:seed`. After you sign in once, `bun run db:seed --owner=you@example.com` adds your user to it.

### The local database

Local development uses PGlite, an embedded Postgres stored in `./data/openprofit`. Only one process can open that directory at a time:

- Stop `pnpm dev` before you run `pnpm db:seed` or any script that imports `src/db`, or the script hangs
- Stop `bun run dev` before you run `bun run db:seed` or any script that imports `src/db`, or the script hangs
- Stop processes with Ctrl+C. A `kill -9` during a write can corrupt the directory
- End one-off scripts with `process.exit(0)`, or PGlite keeps them running
- Delete `./data/openprofit` to start over
Expand All @@ -33,12 +33,12 @@ Local development uses PGlite, an embedded Postgres stored in `./data/openprofit
CI runs three commands on every pull request. Run them before you push:

```bash
pnpm check # Biome lint and format
npx tsc --noEmit # typecheck
pnpm build # production build
bun run check # Biome lint and format
bunx --bun tsc --noEmit # typecheck
bun run build # production build
```

`npx biome check --write src` fixes formatting. Biome uses tabs and double quotes. The repository has no test suite, so check your change in the browser as well.
`bunx biome check --write src` fixes formatting. Biome uses tabs and double quotes. The repository has no test suite, so check your change in the browser as well.

## Build a connector

Expand Down Expand Up @@ -246,7 +246,7 @@ Never log credentials, put them in a URL, or include them in an error message. S

### Test against a real account

Call the connector from a one-off script before you try the UI. Importing `#/connectors` doesn't open the database, so the script runs alongside `pnpm dev`. Save it as `check.ts` at the repository root and keep it out of your commit:
Call the connector from a one-off script before you try the UI. Importing `#/connectors` doesn't open the database, so the script runs alongside `bun run dev`. Save it as `check.ts` at the repository root and keep it out of your commit:

```ts
import { connector } from "#/connectors";
Expand All @@ -265,12 +265,12 @@ console.log(lines?.length, "lines");
Run it with `EXAMPLE_TOKEN` in `.env`:

```bash
npx tsx --env-file=.env check.ts
bun check.ts
```

Compare the totals with the provider's billing page for the same month. Run it twice and check that both runs return the same `externalId` values.

Then test the full flow in `pnpm dev`:
Then test the full flow in `bun run dev`:

1. Open **Connections**, pick your provider, paste the key and click **Test**. Check the label.
2. Click **Connect**. The first sync runs before the page returns. If it fails, the dev server log shows `[sync] first sync example:` with the error.
Expand Down
20 changes: 10 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
# Single-container self-host. PGlite data lives on the /app/data volume.
FROM node:22-alpine AS build
FROM oven/bun:1.4.4-alpine AS build
WORKDIR /app
RUN corepack enable
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
COPY package.json bun.lock ./
COPY packages/cli/package.json packages/cli/
RUN bun install --frozen-lockfile
COPY . .
RUN pnpm build
RUN bun run build

FROM node:22-alpine
FROM oven/bun:1.4.4-alpine
WORKDIR /app
ENV NODE_ENV=production
ENV DATABASE_URL=/app/data/openprofit
ENV PORT=3000
RUN corepack enable
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile --prod
COPY package.json bun.lock ./
COPY packages/cli/package.json packages/cli/
RUN bun install --frozen-lockfile --production --ignore-scripts
COPY drizzle ./drizzle
COPY --from=build /app/.output ./.output
EXPOSE 3000
CMD ["node", ".output/server/index.mjs"]
CMD ["bun", ".output/server/index.mjs"]
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

### Finance for developers

[Website](https://openprofit.dev) · [Docs](https://openprofit.dev/docs) · [Self-host](https://openprofit.dev/docs/self-host) · [Connectors](https://openprofit.dev/docs/connectors) · [Security](https://openprofit.dev/security) · [Issues](https://github.com/lobbystack/openprofit/issues)
[Website](https://openprofit.dev) · [Docs](https://openprofit.dev/docs) · [Self-host](https://openprofit.dev/docs/self-host) · [Connectors](https://openprofit.dev/docs/connectors) · [Security](https://openprofit.dev/security) · [Issues](https://github.com/morencyr/openprofit/issues)

[![Check](https://github.com/lobbystack/openprofit/actions/workflows/check.yml/badge.svg)](https://github.com/lobbystack/openprofit/actions/workflows/check.yml)
[![Check](https://github.com/morencyr/openprofit/actions/workflows/check.yml/badge.svg)](https://github.com/morencyr/openprofit/actions/workflows/check.yml)
[![License](https://img.shields.io/badge/license-MIT-black.svg)](LICENSE)
[![Container](https://img.shields.io/badge/ghcr.io-lobbystack%2Fopenprofit-black)](https://github.com/lobbystack/openprofit/pkgs/container/openprofit)
[![GitHub stars](https://img.shields.io/github/stars/lobbystack/openprofit?style=social)](https://github.com/lobbystack/openprofit)
[![Container](https://img.shields.io/badge/ghcr.io-morencyr%2Fopenprofit-black)](https://github.com/morencyr/openprofit/pkgs/container/openprofit)
[![GitHub stars](https://img.shields.io/github/stars/morencyr/openprofit?style=social)](https://github.com/morencyr/openprofit)

</div>

Expand Down Expand Up @@ -96,7 +96,7 @@ MIT licensed. One Docker image with Postgres inside, or point it at your own. Yo
| MongoDB Atlas | Cost | Daily invoice line items per project |
| Flat costs | Cost | Any monthly, yearly or one-time amount, typed in |

App Store, Google Play and Supabase are next. A connector is one file in [`src/connectors`](src/connectors) that implements `verify` and `fetchRevenue` or `fetchCosts`. If you want one that is not here, [open an issue](https://github.com/lobbystack/openprofit/issues) with a link to the provider's billing API, or send a pull request.
App Store, Google Play and Supabase are next. A connector is one file in [`src/connectors`](src/connectors) that implements `verify` and `fetchRevenue` or `fetchCosts`. If you want one that is not here, [open an issue](https://github.com/morencyr/openprofit/issues) with a link to the provider's billing API, or send a pull request.

## Getting started

Expand All @@ -115,12 +115,12 @@ docker run -d \
-v openprofit_data:/app/data \
-e SECRET_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('base64'))") \
-e APP_URL=http://localhost:3000 \
ghcr.io/lobbystack/openprofit:latest
ghcr.io/morencyr/openprofit:latest
```

Open http://localhost:3000/login and enter your email. Without an email provider the sign-in link prints in `docker logs openprofit`. Set `RESEND_API_KEY` and `EMAIL_FROM` to send it by mail. Point `DATABASE_URL` at a `postgres://` server to use your own database.

The [self-host guide](https://openprofit.dev/docs/self-host) covers updates and Railway. The [environment reference](https://openprofit.dev/docs/environment) lists every variable.
The [self-host guide](https://openprofit.dev/docs/self-host) covers updates, Dokploy and Railway. The [environment reference](https://openprofit.dev/docs/environment) lists every variable.

## How it works

Expand All @@ -137,22 +137,22 @@ Postgres everywhere: PGlite embedded for self-host and local development, a Post

## Development

Node 22 and pnpm.
[Bun](https://bun.com) 1.3 or later.

```bash
pnpm install
bun install
cp .env.example .env # set SECRET_KEY
pnpm db:seed # a demo workspace with a year of numbers
pnpm dev
bun run db:seed # a demo workspace with a year of numbers
bun run dev
```

Sign in once at http://localhost:3000/login, then attach the demo workspace to your user:

```bash
pnpm db:seed --owner=you@example.com
bun run db:seed --owner=you@example.com
```

Checks: `pnpm check` (Biome), `npx tsc --noEmit`, `pnpm build`. After a schema change, `pnpm db:generate` writes a migration; migrations run when the server starts.
Checks: `bun run check` (Biome), `bunx --bun tsc --noEmit`, `bun run build`. After a schema change, `bun run db:generate` writes a migration; migrations run when the server starts.

## Contributing

Expand Down
Loading
Loading