# How to Add Team Accounts to a Product Built for One User
> How to add team accounts to a one-user product: workspaces, memberships, migration, invites, three roles, ownership, data isolation and a 7-day plan.

```yaml
url: "https://makerhunt.io/studio/how-to-add-team-accounts-to-a-product-built-for-one-user"
markdown: "https://makerhunt.io/studio/how-to-add-team-accounts-to-a-product-built-for-one-user.md"
title: How to Add Team Accounts to a Product Built for One User
type: studio_article
category: Growth
tags: "team accounts, multi-user accounts, SaaS workspaces, invite teammates, roles and permissions, multi-tenant data model, access control, data isolation, makers, Growth"
featured_image: "https://txmhk1zrnc.ufs.sh/f/xSkWTCqmKWx9qTPFxATydfDnaYRZuIMoALgyEwj7cr2xOmXW"
published_at: "2026-10-21T09:49:27.596Z"
updated_at: "2026-10-21T09:49:28.188Z"
```

## About this studio article

How to add team accounts to a one-user product: workspaces, memberships, migration, invites, three roles, ownership, data isolation and a 7-day plan.

## Article

To add team accounts to a product built for one user, stop treating the person as the owner of the data and introduce a workspace that owns it instead. Every user gets a membership in one or more workspaces, every record carries a workspace_id, every query is scoped to the workspace the person is currently in, and every existing user is moved into a personal workspace of one so nothing breaks on day one. Then add three small pieces on top: email invites that expire, a tiny set of roles (owner, admin, member), and a clear rule for who owns the workspace when people come and go. That's the whole job. The hard part isn't the invite screen. It's the one query you forget to scope.

Below: when it's time, the data model, migration, invites, roles, ownership, data isolation, removals, a made-up example and a 7-day plan.

## When is it time to add team accounts?

Most solo products start with one email, one password, one pile of data. That's the right call. Building multi-user accounts into a SaaS before anyone needs them is a great way to spend a month on plumbing nobody asked for. But the signs do show up:

Signs it's time

Signs to wait

Customers share one login and tell you so ("my assistant uses my account")

One person asked once, in passing

Support requests like "can I give my colleague access without my password?"

Your users are mostly individuals using it for personal work

Buyers say they can't sign up until more than one person can use it

You haven't found people who pay for the single-user version yet

People export data just to send it to a teammate

Sharing one read-only link would answer every request you've had

Shared logins are the loudest signal. People already work as a team inside your product, just badly: no idea who changed what, and a password passed around in chat. If you're weighing team accounts against five other feature requests, the same scoring you'd use when [choosing your first integration when users ask for everything](https://makerhunt.io/studio/how-to-choose-your-first-integration-when-users-ask-for-everything) works here too: count who asked, how much they pay, and what they do today instead.

## Could sharing a single item be enough for now?

Check whether people want a team or just want to show one thing to one person. Sharing a single item (a project, a report, a board) with one email address is much smaller to build:

- A shares table with item_id, the invited email, and an access level like view or edit.
- A check on that one item's page: are you the owner, or is your email on the share list?

If requests sound like "my client needs to see this report", ship item sharing and watch. If they sound like "my whole team works in this every day", go straight to workspaces. Rule of thumb: when people keep sharing items with the same three people, they're a team.

## What changes in the data model?

Do this before you touch any screens. In a single-user product, data hangs off the user: a projects table with a user_id column, and every query says "projects where user_id is me". In a team product, the user and the data owner are no longer the same thing.

The common multi-tenant data model has three pieces:

- **Users** are people who can sign in. A user has an email and a login. That's it.
- **Workspaces** (some products say organizations, teams or accounts) own the data and, later, the subscription.
- **Memberships** connect the two: this user belongs to this workspace with this role.

Here's a sketch in plain SQL. It's an illustration, not a finished schema:

`create table workspaces (id uuid primary key, name text not null, created_at timestamptz not null);`

`create table memberships (workspace_id uuid not null references workspaces, user_id uuid not null references users, role text not null, primary key (workspace_id, user_id));`

`alter table projects add column workspace_id uuid references workspaces;`

Keep the old user_id on records, but it now means "created by", not "owned by". That saves you when someone leaves and their projects need to stay with the team.

This is the same shape most auth providers use. Clerk's [documentation on Organizations](https://clerk.com/docs/organizations/overview) describes users who can belong to multiple organizations, with roles and permissions, and an "Active Organization" that decides which organization's data the user can see and which role they have in it. Provider or not, the current workspace is part of every request.

## How do you move existing users into workspaces?

You already have users with data. They can't wake up to an empty app. The safe move is to give every existing user a personal workspace of one and put all their data in it:

1. Create one workspace per existing user, named after them or their company field if you have one.
2. Create a membership for that user in that workspace with the owner role.
3. Backfill workspace_id on every table that holds their data, matching on the old user_id.
4. Check counts: rows with a null workspace_id should be zero before you go further.
5. Only then make workspace_id required (not null) and switch queries over to it.

Do it in that order and you can ship the migration before any team feature exists, and nobody notices. Run it on a copy of production first. Don't forget the tables you rarely think about: uploaded files, API keys, saved filters, webhooks.

## How should invites work?

Invites are how a workspace grows from one person to two, so they're worth getting right. The basic flow to invite teammates:

1. An admin types an email address and picks a role.
2. You create an invite record: workspace, email, role, who invited them, a random single-use token, and an expiry date.
3. You send an email with a link containing the token.
4. When the link is opened, you check the token is valid, unused and not expired, then create the membership and mark the invite accepted.

Details that save support tickets:

- **Existing user vs new user.** If the invited email already has an account, the link should add the workspace to that account after sign-in. If not, it should lead to sign-up with the email filled in. Don't create a second account for the same email.
- **Expiry.** Pick an expiry and show it in the email. A week is a common rule of thumb.
- **Pending invites list.** Admins see who hasn't joined yet, with resend and revoke buttons. Revoking kills the old link.
- **Domain-based joining comes later.** "Anyone with our company email can join" is a second step, not a launch feature.

How people sign in is a separate decision from how they join a workspace. If you haven't settled it yet, that's covered in [choosing a login method for your indie SaaS](https://indiehunt.io/studio/how-to-choose-a-login-method-for-your-indie-saas). Teammate invites can also become a modest growth channel, but treat that as a side effect, not the reason to build them.

![image](https://txmhk1zrnc.ufs.sh/f/xSkWTCqmKWx9NJJlKX81aJoSiVHmxAvYheq4GpKsXtBd8l92)

## Which roles and permissions do you actually need?

Fewer than you think. Most small products can launch team accounts with three roles and live with them for a long time:

Role

Can do

Can't do

Owner

Everything, including billing, deleting the workspace and transferring ownership

Leave without handing ownership to someone else

Admin

Invite and remove members, change roles of members, manage workspace settings

Delete the workspace, change billing, remove the owner

Member

Create, edit and delete the normal things your product is for

Invite people, change roles, touch settings or billing

Write permission checks against actions, not role names. A canInviteMembers(membership) check is easier to change later than "if role equals admin" scattered across forty files.

Resist custom roles until a paying customer needs one. The OWASP [Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) warns about "role explosion" when a system defines too many roles, and notes it's easier to grant users more permissions later than to take away ones they already have. Start tight. If someone asks for a "viewer" role, add exactly that, not a role builder.

## Who owns the workspace when people come and go?

Every workspace needs at least one owner at all times, or the day the owner leaves, nobody can change anything. A few rules:

- **Last-owner rule.** The last owner can't leave, be removed, or be downgraded. They have to make someone else owner first.
- **Transfer ownership.** An owner can promote another member to owner. Make it a deliberate action with a confirmation step, because it hands over control.
- **Billing follows the workspace.** The subscription belongs to the workspace, not to the person who first typed in a card, so it survives people leaving.
- **A support path for orphaned workspaces.** If the only owner is gone, have a written manual process to verify who's asking and reassign ownership.

Team accounts usually change how you charge, often per seat. That's a pricing decision in its own right, so keep it separate and don't let it block the plumbing.

![image](https://txmhk1zrnc.ufs.sh/f/xSkWTCqmKWx9A7xt8ZKZ8WgHXza4tSvnxGRNErpmbcI92y0h)

## How do people know which workspace they're in?

Once one person belongs to two workspaces, someone will create a project in the wrong one. Make the current workspace impossible to miss:

- Show the workspace name in the top corner of every page, not just in settings.
- Put a switcher right there, listing every workspace the person belongs to.
- Include the workspace in the URL (a path segment like /w/acme-studio/projects) so links shared between teammates open in the right place.
- With only one workspace, keep the switcher quiet so solo users don't notice.

Watch out for multiple browser tabs. Clerk's docs note that each tab can keep its own active organization, while the session cookie only reflects one of them, so background requests shouldn't rely on the cookie alone to know which workspace they're for. Whatever you build, pass the workspace explicitly in each request (in the URL or a header) and check it on the server.

## How do you stop one workspace from seeing another's data?

This is the bug that turns a launch into an apology email. Every query now has to say "where workspace_id is the current workspace, and I'm a member of it". Miss one, and someone can read another team's data by changing an ID in a URL.

That's not a rare mistake. The OWASP Top 10:2025 page on [Broken Access Control](https://owasp.org/Top10/2025/A01_2025-Broken_Access_Control/) keeps it at number one and lists "permitting viewing or editing someone else's account by providing its unique identifier (insecure direct object references)" among the common problems. Its prevention advice fits team accounts well: deny by default, implement access control once and reuse it everywhere, enforce record ownership, check on the server rather than in the front end, and include access control in unit and integration tests.

In practice, for a small product:

- **One way to load records.** Route every read and write through a helper that refuses to run without the current workspace.
- **Check membership on every request.** Resolve the workspace from the URL, confirm the signed-in user has a membership, then load data. The OWASP cheat sheet's line is that validating permissions on just the majority of requests is not enough.
- **Write the cross-workspace test.** Create two workspaces with one user each. Log in as the first and request every endpoint with the second workspace's record IDs. Every request should fail. Add each new endpoint to it.
- **Consider the database as a second lock.** If you use Postgres, [row security policies](https://www.postgresql.org/docs/current/ddl-rowsecurity.html) can restrict which rows a query can see or change, and when row security is enabled on a table with no policy, the default is deny. Note that table owners and superusers normally bypass these policies, so test with the same database role your app uses.
- **Don't forget files and exports.** Uploads, exports, search and background jobs are where scoping goes missing.

Once teams are in, bigger buyers will start asking how you keep their data apart. Having this work done makes it much easier to write [a security page that unblocks your first B2B deals](https://makerhunt.io/studio/how-to-write-a-security-page-for-first-b2b-deals).

## What happens when you remove a member?

Removing someone should be quick, and it should leave the team's work exactly where it was:

- **Their work stays with the workspace.** Projects they created belong to the workspace. Show "created by" as their name with a "former member" label rather than deleting anything.
- **Reassign what needs an owner.** If records have an assignee, offer to move them to someone else during removal.
- **Access ends now.** Delete the membership, and revoke anything that grants access to that workspace: active sessions scoped to it, personal API tokens, pending invites they sent.
- **Their account survives.** Removing a membership isn't deleting the user; they may belong to other workspaces.
- **Emails stop.** Anything that was being sent to them about that workspace should stop with the membership.

## Do you need an audit log?

Not a full one. But a small record of membership changes answers the most common team question you'll get: "who added this person?" Log a handful of events with who did it, to whom, and when:

Event

What to record

Invite sent

Inviter, invited email, role

Invite accepted or revoked

Who accepted, or who revoked it

Member removed

Who removed whom

Role changed

Who changed it, old role, new role

Ownership transferred

From whom, to whom

One append-only table is enough, shown to owners and admins in settings.

## A made-up example: Plankfold adds team accounts

Everything in this example is made up: the product, the maker and every number.

Plankfold is a cut-list and job planner for one-person furniture workshops. Its maker, Maren, built it for solo woodworkers: one login, one list of jobs. Over a few months, about a dozen paying workshops told her they'd hired a second person and shared the password. One owner found a deleted job and couldn't tell who did it.

Maren skipped item sharing, because every request was about daily work, not showing one job to a client. She spent a weekend on the migration, then a week on the rest:

Area

Before

After

Data ownership

Jobs and cut lists owned by user_id

Owned by workspace_id; user_id kept as "created by"

Existing users

One account each

Each moved into a personal workspace of one, as owner

Access for helpers

Shared password

Email invites that expire after 7 days, with resend and revoke

Roles

None

Owner, admin, member

Who did what

Unknown

Membership changes logged; jobs show who created them

Isolation checks

None needed

Cross-workspace test run against every endpoint

Someone leaves

Change the password and tell everyone

Remove the member; their jobs stay with the workshop

The cross-workspace test failed twice on the first run, on the cut-list export and on sketch thumbnails. Both were fixed before launch. In this made-up story, the shared-password emails stopped once invites shipped, which was the point.

## What traps should you avoid?

- **Copying the account into a team.** Cloning data per teammate gives you diverging copies. One workspace, many members.
- **Roles explosion.** Five roles on day one means five sets of rules to test. Three is plenty.
- **Forgetting the existing data migration.** Every old record needs a workspace_id before you make it required. Check the rarely used tables.
- **Emails still going to the original user.** Anything that used to go to "the account" (scheduled reports, exports, anything about the workspace) should go to the right members now, not just whoever signed up first.
- **Leaking data across workspaces.** The unscoped query. Write the cross-workspace test before launch, not after the support email.
- **Enterprise features too early.** Single sign-on and automated user provisioning (SSO and SCIM) are later asks from bigger customers, so leave them out until someone actually needs them to buy.

## A 7-day plan to add team accounts

Times are rough rules of thumb for a small codebase, not a benchmark.

Day

Do this

Done when

1

List every table and file store that holds user data; decide workspace vs item sharing

You have the list and a decision

2

Add workspaces and memberships tables; add workspace_id to data tables

Schema change runs on a copy of production

3

Migrate every user into a personal workspace; backfill workspace_id; make it required

Zero rows with no workspace; counts match per user

4

Scope every query through one helper; write the cross-workspace test

Test passes for every endpoint, exports and files included

5

Invites: create, email, accept, expire, resend, revoke, pending list

You can invite yourself on a second email and join

6

Roles, last-owner rule, ownership transfer, member removal

A member can't invite; the last owner can't leave

7

Workspace name and switcher in the header; membership audit log; invite three real customers who asked

Three teams using it, and you're watching for confusion

## FAQ

### Should every new signup get a workspace automatically?

Yes. Create a workspace at sign-up and make the new user its owner. Then there's only one code path, and solo users never have to think about workspaces until they invite someone.

### Can one person belong to more than one workspace?

Plan for it from the start. Freelancers and agencies often work in several clients' workspaces. The memberships table handles this for free, as long as the current workspace comes from the request and not from the user record.

### Should I build this myself or use an auth provider's organizations feature?

Either works. A provider gives you invites, roles and switching screens quickly; building it keeps everything in your database. Scoping your own queries is your job either way.

## Give the second person their own key

Team accounts aren't a big feature, just a careful one. Do the data model first and the screens get easy. If you're building this now, share what you're working on with other makers on [MakerHunt](https://makerhunt.io/) and ask how they handled their first shared login. Someone there has already found the query you're about to forget.

## Links

- Article (HTML): https://makerhunt.io/studio/how-to-add-team-accounts-to-a-product-built-for-one-user
- AI-friendly Markdown: https://makerhunt.io/studio/how-to-add-team-accounts-to-a-product-built-for-one-user.md

## Explore

- [Studio index](https://makerhunt.io/studio)
- [Blog](https://makerhunt.io/blog)
- [Browse projects](https://makerhunt.io/projects)

_HTML version: https://makerhunt.io/studio/how-to-add-team-accounts-to-a-product-built-for-one-user_