Companies and users

Running more than one company on an install, letting more than one person sign in, and using the activity log to see who changed what.

View Markdown
Browse documentation
On this page

These are two separate settings. Multi-company means one person keeping several companies on a private install, and says nothing about sharing it or putting it on a network. Multi-user means several people signing in to the same self-hosted install, and each of them can work in all of its companies.

More than one company

Each company is walled off from the others. Evidence, journals, knowledge documents, calculations, and conversations all belong to one company, and none of it is copied between them. A new company starts empty: no documents, knowledge, mappings, accounts, journals, assumptions, forecasts, or conversations.

Switching companies

The account menu lists the companies you can open, with the current one marked. Pick another and everything company-specific reloads: conversations, documents, knowledge, accounting, calculations, usage, and settings.

Your current company is remembered in an HTTP-only, same-site cookie. The cookie only records a preference; it doesn't grant access. Access is checked on every request, and if the cookie points at a company you can't open (or one that no longer exists), you land on the first company you can.

Adding a company

Choose New company in the account menu and enter a name and base currency. Balsa creates the company and your membership in a single transaction, switches to it, and opens its empty onboarding screen.

COMPANIES

You can also list companies ahead of time in COMPANIES, as comma-separated Name or Name:CUR entries:

COMPANIES=Acme Holdings:USD,Beta GmbH:EUR

They're created for the install's owner on first sign-in, and the first one becomes the default. If you add names later, they're created at the next sign-in. Editing or removing an entry won't rename or delete an existing company; changing the list only ever adds.

How companies are kept apart

There are two layers. First, the application checks that any record id sent in a request belongs to the current company before using it. Second, PostgreSQL row level security enforces the company scope when a transaction sets it. The current policies permit unscoped access when no scope is set, so application ownership checks remain necessary. Database enforcement also requires a non-superuser role without BYPASSRLS. See Security.

More than one person

Set AUTH_MODE=better-auth and choose an AUTH_SIGN_UP_CODE. Share the code with the people who should have access, turn on AUTH_ALLOW_SIGN_UP while they register, then turn it off again.

Be clear about what signing up gets someone. On a self-hosted install, every registered user can open every company, including ones created later, and can create new companies. There's no step where you add someone to a company; a second user sees the same list as the first. There are no invitations and no way to give someone narrower access.

So letting someone register means giving them every company's financial data on that server. If that's not what you want, run separate installs.

Balsa doesn't send email. The sign-up code controls who can register, and anyone registered can work in the install.

Roles

Each membership has a role, owner or member. Owner-only routes are checked on the server and return 403; they aren't just hidden in the UI.

Right Owner Member
All financial work: evidence, chat, knowledge, journals, close, forecasts yes yes
Company settings (name, currency, favicon) yes no
Reset (delete) the company yes no
Create a new company yes yes

On a self-hosted install today, every membership is an owner membership, so the member column doesn't come into play. The server-side check is there so that hiding a button isn't the only protection, and so it's ready if membership ever becomes per-company.

Activity log

Since everyone on an install has the same access, the log is how you tell who did what. Each meaningful change records who made it, how it came in, what the action was, which record it touched, a summary, and the before and after values. When the change runs in a transaction, the log entry is written in that same transaction, so both are saved or neither is.

The via field shows how a change came in:

  • ui: someone did it directly.
  • agent: the agent did it at someone's request, and it's attributed to that person.
  • worker: a background job did it, with no person attached.

Logged actions include approving or rejecting evidence, applying or rejecting a decision, answering a review question, posting and reversing journals, closing and reopening periods, creating or changing a policy, changing company settings, creating a company, and editing knowledge.

Activity in the account menu shows the current company's log, newest first, with each person's name and email. Only members of that company can see it.

Records also store their own author, separate from the log. Decisions, resolved review items, economic items, closed periods, and knowledge documents each note who acted, and traces that show an approval or decision show that person's name.

Resetting a company deletes its log along with everything else.

Review ownership is separate from access

A financial work review records its preparer, assigned reviewer and exception owners. Only the assigned reviewer can sign a submitted report, even on an installation where users have owner memberships. The preparer or a company owner can manage assignments. Self-review requires explicit acknowledgement.

These assignments organize accountability; they do not hide company data from other admitted users. See Reviews and sign-off.