This is the backend companion for Mamba iOS
The Mamba project allows a user to host or join a Story Point Planning session and vote on a story.
To get a local copy up and running follow these simple example steps.
- XCode 12 Development Tools
- Install Vapor using brew.
brew install vapor
- Clone the repo
git clone https://github.com/Operation-Winter/mamba-ios.git
- Open in XCode
Build package:
swift build
Test package:
swift test
Update or resolve package dependencies:
swift package update
To run the container:
docker-compose up
Commands are sent between the backend and any front-end application using WebSockets. A command is sent in the following structure:
{
"uuid": "<Front-End UUID>",
"type": "<Command identifier>",
"message": {} //Contains the message body structure as specified below or null
}
Type | Description | Message |
---|---|---|
START_SESSION |
Send session name and available cards. |
{
"sessionName": "Example session",
"availableCards": [
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"autoCompleteVoting": true,
"tags": ["iOS", "Android"],
"password": "Bacon", // optional
} |
ADD_TICKET |
Add a new ticket. Changes state to `VOTING` |
{
"title": "DM-10000",
"description": "Blah blah",
"selectedTags":["iOS", "Android"]
} |
SKIP_VOTE |
Skip vote for a participant |
{
"participantId": ""
} |
REMOVE_PARTICIPANT |
Request to remove a participant from the session |
{
"participantId": ""
} |
END_SESSION |
Closes session and removes all participants | None |
FINISH_VOTING |
Force state from `VOTING` to `VOTING_FINISHED` | None |
REVOTE |
When in `VOTING_FINISHED` state revote the current ticket | None |
RECONNECT |
Reconnect to existing session using a UUID | None |
EDIT_TICKET |
Edit the details of the existing ticket |
{
"title": "DM-10000",
"description": "Blah blah",
"selectedTags":["iOS", "Android"]
} |
ADD_TIMER |
Add a timer to the session to end voting when the timer ends. |
{
"time":2
} |
CANCEL_TIMER |
Cancel an active timer. | None |
PREVIOUS_TICKETS |
Request previous tickets that have been voted on. | None |
REQUEST_COFFEE_BREAK |
Request coffee break break. | None |
Type | Description | Message |
---|---|---|
NONE_STATE |
State `NONE` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
}
],
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
VOTING_STATE |
State `VOTING` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE",
"tag":"iOS"
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
FINISHED_STATE |
State `VOTING_FINISHED` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE"
"tag":"iOS"
},
{
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515",
"selectedCard":null, //Indicates that this vote is skipped
"tag":null
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
INVALID_COMMAND |
Inform client that command sent is invalid |
{
"code":"0000",
"description":"No session code has been specified"
} |
PREVIOUS_TICKETS |
Response that contains previous tickets that have been voted on. |
{
"previousTickets":[
{
"title":"Test",
"ticketVotes":[
{
"participantId":"D520EFDD-C4BD-450B-9531-30E404B77D0F",
"selectedCard":"FIVE",
"tag":"iOS"
}
],
"description":""
}
]
} |
SESSION_IDLE_TIMEOUT |
Response that indicates that the session has timed out because it was idle. |
Type | Description | Message |
---|---|---|
JOIN_SESSION |
Join session with specified sessionCode, user name, and password. |
{
"participantName":"Armand",
"sessionCode":"545544",
"password":"Bacon" //optional
} |
VOTE |
Send vote value for a ticket |
{
"selectedCard":"ONE",
"tag":"iOS"
} |
LEAVE_SESSION |
Inform server client is disconnecting | None |
RECONNECT |
Reconnect to existing session using a UUID | None |
CHANGE_NAME |
Change participant's name. Will fail if not the matching participant UUID. |
{
"name":"TestName"
} |
REQUEST_COFFEE_BREAK |
Request coffee break break. | None |
Type | Description | Message |
---|---|---|
NONE_STATE |
State `NONE` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
}
],
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
VOTING_STATE |
State `VOTING` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE",
"tag":"iOS"
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
FINISHED_STATE |
State `VOTING_FINISHED` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE",
"tag":"iOS"
},
{
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515",
"selectedCard":null, //Indicates that this vote is skipped
"tag": null
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
INVALID_COMMAND |
Inform client that command sent is invalid |
{
"code":"0000",
"description":"No session code has been specified"
} |
INVALID_SESSION |
Inform client that session is invalid | None |
REMOVE_PARTICIPANT |
Inform client that they have been removed from the session | None |
END_SESSION |
Inform client that session had been ended | None |
SESSION_IDLE_TIMEOUT |
Response that indicates that the session has timed out because it was idle. |
Type | Description | Message |
---|---|---|
JOIN_SESSION |
Send session code and password |
{
"password":"Bacon",
"sessionCode":"545544"
} |
LEAVE_SESSION |
Inform server client is disconnecting | None |
RECONNECT |
Reconnect to existing session using a UUID | None |
Type | Description | Message |
---|---|---|
NONE_STATE |
State `NONE` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
}
],
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
VOTING_STATE |
State `VOTING` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE",
"tag":"iOS"
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
FINISHED_STATE |
State `VOTING_FINISHED` command containing current state of session |
{
"participants":[
{
"name":"Armand",
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9"
},
{
"name":"Piet",
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515"
}
],
"ticket":{
"title":"Test",
"ticketVotes":[
{
"participantId":"852ACB12-4B40-4BC2-B72B-17057A1A5AE9",
"selectedCard":"FIVE",
"tag":"iOS"
},
{
"participantId":"34ED510B-B21D-423E-83D0-B85747F4D515",
"selectedCard":null, //Indicates that this vote is skipped
"tag":null
}
],
"description":"Test"
},
"availableCards":[
"ZERO", "ONE", "TWO", "THREE", "FIVE", "EIGHT", "THIRTEEN", "TWENTY", "FOURTY", "HUNDRED", "QUESTION"
],
"sessionCode":"000000",
"sessionName":"Test"
} |
INVALID_COMMAND |
Inform client that command sent is invalid |
{
"code":"0000",
"description":"No session code has been specified"
} |
INVALID_SESSION |
Inform client that session is invalid | None |
END_SESSION |
Inform client that session had been ended | None |
SESSION_IDLE_TIMEOUT |
Response that indicates that the session has timed out because it was idle. |
0001
: The specified session code doesn't exist or the password provided is invalid.
0000
: No session code has been specified.0002
: The command doesn't exist.0003
: The server has run out of capacity, could not create a new planning session.0004
: Invalid identifier.0005
: Invalid parameters.0006
: Invalid state.
0007
: Session idle timeout
White lines indicate completed features.
Distributed under the MIT License. See LICENSE
for more information.
Armand Kamffer - @Armgame - [email protected]