# Share a project, and nothing else

**A member sees everything in the project and nothing outside it — enforced by the query, not by a check somebody has to remember.**

Membership is not a permission checked before a read: it is the set of projects every query is built from. A project you are not in is not refused, it is absent — there is no query that can return a task from it. And a member is a full member: read-only invitees are a billing failure waiting to land on somebody's write path, so what a role decides is who else gets in, never what the work looks like. Sharing refuses nothing either: an address with no Flow account is invited by mail rather than turned away, because the address is the credential and there is nothing to sign up for. Nobody is put in a project without saying yes, though: an invitation reaches nothing until the person it names accepts it.

Driven by a person. Every step below is a step in
`packages/server/tests/e2e`, run against a listening server on every pull
request; the calls under each one are what that run executed.

The same flow is playable at https://flow.ttoss.dev/docs/examples/sharing-a-project.

## 1. Ana has a project with work in it

- `POST /api/v1/projects` → `201`
- `POST /api/v1/tasks/batch` → `200`

## 2. Bruno, who is not in it, cannot see that it exists

- `GET /api/v1/projects` → `200`
- `GET /api/v1/projects/proj_dfb539q5ze` → `404`

## 3. Nor can he reach the work inside it, even by id

- `GET /api/v1/tasks/task_3vt0nzawrh` → `404`
- `GET /api/v1/tasks` → `200`

## 4. Ana invites him by the address he signs in with

- `POST /api/v1/projects/proj_dfb539q5ze/members` → `200`

## 5. Until he accepts, the project is still not his

- `GET /api/v1/projects/proj_dfb539q5ze` → `404`
- `GET /api/v1/invitations` → `200`

## 6. He accepts the invitation

- `POST /api/v1/invitations/proj_dfb539q5ze/accept` → `200`

## 7. He now reads the work

- `GET /api/v1/tasks` → `200`

## 8. And writes to it, because a member is a full member

- `POST /api/v1/tasks/batch` → `200`
- `GET /api/v1/tasks/task_v94q21kpyn` → `200`

## 9. But he does not decide who else gets in

- `POST /api/v1/projects/proj_dfb539q5ze/members` → `403`

## 10. Carla is still outside, and still sees nothing

- `GET /api/v1/tasks` → `200`

## 11. Ana invites Carla, and Carla declines

- `POST /api/v1/projects/proj_dfb539q5ze/members` → `200`
- `DELETE /api/v1/invitations/proj_dfb539q5ze` → `200`
- `GET /api/v1/projects/proj_dfb539q5ze` → `200`

## 12. Ana shares it with an address that has never signed in, and Flow invites it

- `POST /api/v1/projects/proj_dfb539q5ze/members` → `200`

## 13. Until she accepts, the project says so beside her name

- `GET /api/v1/projects/proj_dfb539q5ze` → `200`

## 14. She signs in with that address, accepts, and the work is hers

- `POST /api/v1/invitations/proj_dfb539q5ze/accept` → `200`
- `GET /api/v1/tasks` → `200`

## 15. And a caller with no token gets nowhere at all

- `GET /api/v1/tasks` → `401`
