Teams - BevvyTech/BrewskiDocs GitHub Wiki
| Method | Path | Description |
|---|---|---|
POST |
/teams |
Create a new team and assign the caller as owner. |
POST |
/teams/:teamId/logo |
Upload (replace) a team logo (multipart/form-data). |
GET |
/teams/:teamId/logo |
Fetch the stored team logo file. |
DELETE |
/teams/:teamId/logo |
Remove the current team logo. |
DELETE |
/teams/:teamId/members/:userId |
Soft-deactivate a team member (non-owner). |
POST |
/teams/:teamId/members/:userId/owner |
Promote a member to owner (confirmation required). |
- Auth: Bearer token (any authenticated user).
-
Body (application/json):
{ "name": "Lantern Brewery", "currencySymbol": "£", "locale": "en-GB", "temperatureUnit": "celsius", "brewhouseCapacity": 1200, "obscureBatchCode": true, "obscureOrderNumber": true, "billingName": "Lantern Brewery Ltd", "defaultPaymentTermsAmount": 30, "defaultPaymentTermsUnit": "days" } -
Response 201:
{ "team": { "id": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7", "name": "Lantern Brewery", "logoUrl": null, "currencySymbol": "£", "temperatureUnit": "celsius", "locale": "en-GB", "obscureBatchCode": true, "obscureOrderNumber": true, "brewhouseCapacity": 1200, "billingName": "Lantern Brewery Ltd", "billingAddress": null, "vatNumber": null, "paymentDetails": null, "invoiceTerms": null, "defaultPaymentTermsAmount": 30, "defaultPaymentTermsUnit": "days", "defaultContainers": [ { "id": "a90c...", "selected": true }, { "id": "f31a...", "selected": true } ], "createdAt": "2025-02-12T11:45:00.000Z", "updatedAt": "2025-02-12T11:45:00.000Z" }, "membership": { "id": "0fdb...", "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7", "userId": "3f3fdd2e-1bab-49e3-9d24-8a2d0b307d1d", "role": "owner", "deactivated": false, "createdAt": "2025-02-12T11:45:00.000Z", "updatedAt": "2025-02-12T11:45:00.000Z" } } - Behavior:
- Seeds default containers (30 L keg, 9 g cask, 440 ml can, 500 ml bottle) and marks them as selected.
- Creates a default pricebook for the team when none exists.
- Enables
obscureBatchCodeandobscureOrderNumberso new teams start with anonymised identifiers. - Returns
409if a team with the same name already exists.
- Auth: Bearer token. Caller must be member of the team.
-
Body:
multipart/form-datawith a single file field (logo). PNG, JPEG, and SVG accepted. Max 3 MB; larger uploads return413. The original upload is not stored—Brewski generates a 500 px-tall logo and a 100 px icon automatically (aspect ratio preserved). -
Response 200:
{ "logoUrl": "/assets/logos/d43c046a.png", "logoIconUrl": "/assets/logos/d43c046a-icon.png" } - Errors: 400 (missing file), 413 (file too large), 415 (unsupported type), 404 (team missing).
- Auth: Bearer token required.
-
Response 200: Binary image stream with proper
Content-Type. - Errors: 404 when logo absent.
- Auth: Bearer token required.
- Response 204: Logo deleted if present.
- Auth: Bearer token.
- Rules: Owners can remove any non-owner; members can remove themselves.
- Response 204
- Auth: Bearer token, acting user must be an existing owner.
-
Body:
{ "confirmation": "AGREE" } -
Response 200:
{ "membership": { "id": "1b2c...", "userId": "8d7e...", "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7", "role": "owner", "deactivated": false, "updatedAt": "2025-02-04T12:10:54.321Z" } } - Errors: 403 (caller not owner), 404 (member not found), 400 (missing confirmation).
- Auth: Bearer token. Caller must belong to the team and hold a super/support membership.
-
Query params
-
size(optional,small|medium|large— defaultmedium): Controls how many records are generated. -
intent(optional,seed-demo|fix-beer-categories— defaultseed-demo): Switch between the legacy demo seeding flow and the BJCP category maintenance task.
-
-
Body (application/json, optional):
{ "styleNames": [ "1A American Light Lager", "21B Specialty IPA" ] }- Only honoured when
intent=seed-demo. Omit the body to let the platform use its internal style list.
- Only honoured when
-
Response 200 (
intent=seed-demo):{ "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7", "teamRole": "demo", "intent": "seed-demo", "migrations": [ { "id": "20250201_seed_clients", "applied": true }, { "id": "20250201_seed_orders", "applied": true } ], "appliedCount": 2, "counts": { "randomBeers": 24, "randomClients": 30, "randomOrders": 62, "randomBatches": 48 }, "randomSeed": { "size": "medium", "beersCreated": 24, "clientsCreated": 30, "ordersCreated": 62, "batchesCreated": 48 } } -
Response 200 (
intent=fix-beer-categories):{ "teamId": "d43c046a-10a1-4f52-bd0a-9bf16f828ab7", "teamRole": "demo", "intent": "fix-beer-categories", "updatedBeers": 42, "assignments": [ { "code": "21B", "name": "Specialty IPA", "categoryId": "21", "categoryName": "IPA", "count": 8 } ] } -
Behaviour
- Seeds demo migrations, then generates random data sized to the requested volume.
- When
styleNamesare supplied the generator preferentially pulls beer styles from that list; duplicates are ignored. - Marks the team as
demoonce seeding succeeds. - With
intent=fix-beer-categories, every beer in the team is reassigned to a random BJCP substyle and the update summary is logged to team activity; no demo data is created.
-
Errors:
401unauthenticated,403missing membership or super/support role,404team missing,400malformed payload or no active members.
List support tickets visible to the caller with the shared pagination envelope so Admin surfaces stay consistent.
Bearer token required.
-
scope=my(default) returns tickets the caller raised. -
scope=teamreturns tickets for the suppliedteamId(caller must be an owner/admin of that team or a support operator). -
scope=allrequires a support/super-user membership.
-
scope(optional,my|team|all, defaultmy) -
teamId(UUID, required whenscope=team, optional otherwise) -
status(optional, repeatablepending|open|resolved|cancelledstrings) — filters tickets by status. -
priority(optional,low|normal|high|urgent) -
assigned(optional, user UUID) — filter by assigned support user. -
search(optional, string) — case-insensitive match against subject, description, requester name/email, and client name. -
page(int ≥ 1, default 1) andpageSize(int ≥ 1, default 25, max 200). -
limit(int ≤ 50, optional) — when supplied, returns the most recentlimittickets without pagination metadata (legacy behaviour used by the support menu). -
includeMessages(optional, boolean) — when true, returns the most recent message for each ticket.
200 OK
{
"page": 1,
"pageSize": 25,
"total": 8,
"pages": 1,
"results": [
{
"id": "aaaa4444-bbbb-4ccc-8ddd-eeeeffff1111",
"team": { "id": "team-1", "name": "Lantern Brewery", "role": "brewery" },
"requester": { "id": "user-1", "name": "Alex", "email": "[email protected]" },
"subject": "Need delivery labels",
"status": "open",
"priority": "high",
"lastMessageAt": "2025-02-10T11:24:00.000Z",
"messageCount": 3,
"metadata": {},
"messages": []
}
],
"tickets": [
"...same array for backwards compatibility..."
]
}When limit is provided the endpoint still returns page=1, pages=1, and pageSize=limit, with total equal to the number of returned records. New clients should omit limit and rely on page / pageSize.
401 Unauthorized — bearer token missing or invalid.
403 Forbidden — caller lacks the required scope/team permissions.
404 Not Found — supplied teamId is not visible to the caller.