> For the complete documentation index, see [llms.txt](https://swu-forge.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://swu-forge.gitbook.io/docs/teams/team-folders.md).

# Team Folders

Team folders are a shared workspace for everyone on a team. When a folder is marked as a team folder, every team member gets visibility (and, depending on their role, edit rights) on the decks inside it. Subfolders inherit the team scope from their parent.

## What team members can do with team decks

Team members can operate on decks that live in their team's folders, with limits scaled to their role:

| Action                                                          | OWNER | ADMIN | EDITOR | VIEWER |
| --------------------------------------------------------------- | :---: | :---: | :----: | :----: |
| Read the deck (view, export, JSON, proxy PDF, share image)      |   ✓   |   ✓   |    ✓   |    ✓   |
| Edit the deck (rename, change cards, change format, edit notes) |   ✓   |   ✓   |    ✓   |    ✗   |
| Manage versions and branches                                    |   ✓   |   ✓   |    ✓   |    ✗   |
| Move the deck between folders the member can write on           |   ✓   |   ✓   |    ✓   |    ✗   |
| Make the deck linkable (enable/disable its public link)         |   ✓   |   ✓   |    ✓   |    ✗   |
| Delete the deck (removes **all** members' recordings on it)     |   ✓   |   ✓   |    ✓   |    ✗   |
| Add the deck to public browse/search lists                      |   ✓   |   ✓   |    ✗   |    ✗   |
| Create a team folder (or promote your own folder into the team) |   ✓   |   ✓   |    ✓   |    ✗   |
| Rename / move a team folder                                     |   ✓   |   ✓   |    ✓   |    ✗   |
| Delete a team folder                                            |   ✓   |   ✓   |    ✗   |    ✗   |
| Demote a team folder back to personal                           |   ✓   |   ✗   |    ✗   |    ✗   |

A per-folder VIEWER override locks a member to read-only on that one folder, regardless of their team-wide role.

Battle Log access on a team deck doesn't require the viewer to have `karabastEnabled` — being a team member is enough.

## Linking and recording on a team deck

Team decks **are** linkable. Any EDITOR (or above) can enable a team deck's public link; once it's on, the **decklist** is viewable and importable by anyone with the URL — that's how teammates pull a shared deck into Karabast to record against it. What stays private is the *battle log*: a team deck's matches and replays are **never** world-public (the "make match public" control is hidden for team decks), so your team's games and tech don't leak through a shared replay link. Team decks also stay out of public browse/search directories — the link shares the list by URL only.

Recording on a shared team deck is **membership-gated, not ownership-gated**: once the deck is linkable, *any* team member — including a VIEWER — can record games against it directly, without copying it into their own collection. Every member's games attach to the same team deck and show up under that deck's Battle Log, attributed to whoever recorded them (see the per-user tabs in [Battle Log](/docs/battle-log/battle-log.md)). They also roll up into the [team battle log](/docs/teams/team-battle-log.md) archetype stats.

> Deleting a team deck removes **every** member's recordings on it, not just yours. EDITOR and above can delete, behind a type-the-deck-name confirmation.

## On the /decks page

Once you're a member of at least one team, the **My Decks** page grows a scope filter strip at the top with chips for **All**, **Personal**, and each team you belong to. The strip is hidden if you're not on any teams.

* **Team folders** in the sidebar display the team's photo (or first-letter avatar) next to the name. A lock icon appears next to the name if your role on that folder is VIEWER.
* **Team decks** in the deck list show a small team badge after the format badge.
* **Rename folder** appears on folders you can write to (EDITOR or above on a team folder, or any personal folder you own); a VIEWER role — including a per-folder VIEWER override — hides it. **Delete folder** is more restricted — it only appears for OWNER/ADMIN (or any personal folder you own).
* **Folder right-click menu**: right-click (or long-press) a folder for its actions — **Rename**, **Delete**, and the scope moves below. The available items depend on your role and the folder's scope.
  * **Move to …** (promote) shows on a **top-level personal folder you own**, with one entry per team where you're EDITOR or above. It moves the folder and everything inside it into that team.
  * **Make personal** (demote) shows on a **top-level team folder** when you're the team **OWNER**. It pulls the folder's whole subtree back into your personal decks and clears per-folder overrides.
  * Promote/demote are offered only on **top-level** folders so a moved folder never ends up parented under a folder in the other scope.
* **Drag-and-drop**: you can drag your own decks into any team folder you have write access on. Folders with a VIEWER role refuse drops with a red border. Cross-scope folder moves (e.g. dragging a personal folder onto a team folder) are blocked — use the right-click **Move to** / **Make personal** actions instead.
* **Reordering folders**: drag a folder onto the thin line *between* two sibling folders to set a custom order (dropping a folder *onto* another folder still re-parents it). **Personal and team folders never intermingle** — you can reorder within the Personal group and within each team's group, but a folder can't be dropped into the other group's order. Reordering needs write access (a VIEWER can't reorder), and is paused while a search/filter is active. **A team's folder order is shared** — one canonical order every member sees; your personal folder order is your own.
* **Sections (Created by me view)**: the **Created by me** scope is the only one that shows personal and team folders together, so it groups them under labeled section headers — **Personal** first, then one per team (header = the team name, with the team photo and a lock if you're a VIEWER). Headers aren't folders: you can't rename or delete them, and a team section is renamed only by renaming the team. The Personal / single-team scopes show one group with no header.
* **New folder** input creates a folder under the active scope: in a team scope, it hits the team folder endpoint; in Personal, the regular folder endpoint. New folders land at the end of their group.

## On a team's Decks page

The team Decks page (`/teams/{teamId}/decks`) lists every deck filed in that team's folders as a tree. Each folder with contents has a **chevron** to collapse or expand it (folders start expanded), and the header has **Expand all** / **Collapse all** buttons to toggle the whole tree at once.

A **trophy** next to a deck's name marks it as the **top performing version of its archetype** — the deck with the best win rate (min 10 decided games) among every team deck sharing that leader + base. If two members keep separate lists of the same archetype, the trophy points to the one that's actually winning. See [Top decks](https://github.com/acousineau/swu-deck-visualizer/blob/main/docs/howto/team-top-decks.md) for how the ranking works.

> Promote / Demote actions are currently API-only and don't have a button in the UI yet. Use the endpoints below.

## Concepts

* **Promote**: turn a personal folder into a team folder. The folder and every descendant become team-scoped. Only the folder's current owner can promote it.
* **Demote**: pull a team folder (and its descendants) back into personal scope. The whole subtree gets re-homed under the team owner's personal tree, and any per-folder overrides on the subtree are deleted. Only the team **OWNER** can demote.
* **Per-folder override**: replaces a member's team-wide role for one specific folder. Lateral or downward only — you cannot give an EDITOR an ADMIN override.

## Promoting a folder

The folder you promote must currently be one of your own personal folders. A team OWNER cannot grab another member's folder; the member has to promote it themselves.

```
POST /api/teams/{teamId}/folders
Content-Type: application/json

{ "folderId": "<your folder id>" }
```

Re-running the same call against a folder that already belongs to this team is a no-op (200), so the call is retry-safe.

If the folder already belongs to a **different** team, you'll get a 409. Demote it from that team first.

## Creating a new team folder

Same endpoint, with `name` instead of `folderId`. `parentId` is optional, but if provided the parent must already be a team folder on the same team.

```
POST /api/teams/{teamId}/folders
Content-Type: application/json

{ "name": "Tournament Decks", "parentId": "<optional team folder id>" }
```

## Reordering folders

Set a custom order for one sibling group (folders sharing the same parent and the same owner scope). Send the **full** ordered list of folder ids for that group; the server assigns `position = index` to each.

```
POST /api/folders/reorder
Content-Type: application/json

{
  "parentId": "<parent folder id or null for top level>",
  "scope": { "teamId": "<team id>" },   // or { "personal": true }
  "orderedIds": ["<folder id>", "<folder id>", ...]
}
```

Rules:

* Every id must belong to the same parent and the same scope — mixing personal and team folders, or folders from different parents, is a `400`. This is what keeps the two groups from intermingling.
* `orderedIds` must be the **complete** group; if it's stale (a sibling was added concurrently) you get a `409` — refetch and retry.
* Needs `write` on the folders (EDITOR+; a per-folder VIEWER override blocks it) → `403` otherwise. Order is stored on the folder row, so a team's order is shared by all members.

## Demoting

```
DELETE /api/teams/{teamId}/folders/{folderId}
```

The whole subtree becomes personal and gets re-homed under the team owner. Overrides on the subtree are cleared. Decks inside the folders are untouched — only the folder rows change.

## Per-folder member overrides

An override locks in a specific role for one member on one folder, regardless of their team-wide role.

### Set / update an override

```
POST /api/teams/{teamId}/folders/{folderId}/overrides
Content-Type: application/json

{ "teamMemberId": "<TeamMember id>", "role": "VIEWER" }
```

Rules:

* `role` must be `ADMIN`, `EDITOR`, or `VIEWER`. `OWNER` is rejected.
* The override role's rank must be `<=` the member's team role rank (`VIEWER < EDITOR < ADMIN`). So an EDITOR can be given a VIEWER override but not an ADMIN one — overrides cannot upgrade a member.
* You cannot override the team OWNER (they always have full access).
* ADMINs cannot set or clear overrides targeting another ADMIN. Only the team OWNER can.

### Clear an override

```
DELETE /api/teams/{teamId}/folders/{folderId}/overrides/{overrideId}
```

## Auth

All four endpoints require the calling user to have the **Teams** feature flag enabled (`User.teamsEnabled = true`) and be a member of the team in question. App admins (`role === 'APP_ADMIN'`) pass with synthetic OWNER privileges.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://swu-forge.gitbook.io/docs/teams/team-folders.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
