Following is an outline of the design process used for the web backed for Ananias Roguelike
Step 1 – Rough Draft
Make a rough draft including the features intended to be supported in the game and the potential integration points to be required.
Step 2 – Architecture
Decide on the architecture and the technology stack.
Step 3 – API Blueprint
Clean up and design an API blueprint.
Anon Services These require no auth token POST /player Creates a new player and starts a session Request { "name": "slash", "email": "slash@slashware.net", "password": "password" } Response { "pin": 54544 "t": "5496876546873" } GET /authToken/:name Obtains a token (starting a session) Returns a 401 if there's no player with than name or the password doesn't match the player with the given name Request { "password": "password" } Response { "t": "5496876546873" } DELETE /authToken/:t Deletes a token, expiring a session Returns a 404 if there's no such token POST /authToken/isAlive/:t Prolongs the life time of a session Returns a 404 if there's no such token GET /player/:pin Obtains info about a player Returns a 404 if there's no player with than PIN Response { "name": "slash", "pin": 54544 "games": 330, "victories": 1, "groups": 0, "friends": 4 } Auth Services These require an auth token passed as "t" via parameter All services returns a 401 if the token is not valid or expired GET /friends/scores Obtains the scores of a player friends combined with own, sorted by depth and kills Response { "scores": [ { "name": "deekatax", "class": "Paladin", "sex": "Male", "depth": 14, "kills": 85 "won": false } ] } GET /messages Consumes the messages queue for the player. Response { "messages": [ { "type": "newLevel", "from": "deekatax", "time": "2015-01-02T13:45:22Z", "text": "Deekatax's Arcane reached Level 3" } ] } POST /event/:type Generates messages for all of a player friends Request { "text": "Deekatax's Arcane reached Level 3" } POST /score Saves a score for the player Returns 400 Bad request if the hash doesn't validate the score. Request { "class": "Paladin", "sex": "Male", "depth": 14, "kills": 85 "won": false, "hash": "51468768743asdasdasda8s7da6sd787678" } GET /scores Obtains the personal scores for the player { "scores": [ { "name": "slash", "class": "Paladin", "sex": "Male", "depth": 14, "kills": 85 "won": false } ] } POST /friendship/:friendPIN Creates a friendship link between the current user and the user identified with the PIN Returns a 404 error if user doesn't exist
Step 4 – Functional Analysis
Functional analysis for all API operations, describing in general terms how each one would work in terms of data and “business logic” operations.
POST /player * Verify no player with same name exists, else return 400 * Verify password complies with required features, else return 400 * Encrypt password * Generate PIN * Insert a new player * Forward to GET /authToken/:name GET /authToken/:name * Get player by name. If not found return 401 * Encrypt password * Compare password with player password. If doesn't match return 401 * Generate auth token * Validate no session with such token exists, else regenerate * Calculate expiry time * Insert new session * Return token DELETE /authToken/:t * Get session by token. If none return 404 * Delete session by token POST /authToken/isAlive/:t * Get session by token. If none return 404 * Calculate new expiry time * Update session by token with new expiry time GET /player/:pin * Get player facts by pin (without friendNames). If none return 404 * Return player facts (General validation for all Auth Services) * Validate authToken, if invalid return 401 * Extend session expiry time * Get the username related to the token GET /friends/scores * Get friendNames list for player from playerFacts * Get the top 10 scores for each friend on the list (+ the auth player) and add to a master list) * Get the scores for the player sorted by depth and kills, first 10 * Sort list by depth and kills * Trim list to first 10 results * Return list GET /messages * Get the unconsumed messages for the player, and mark them as consumed * Return messages POST /event/:type * Get the friendNames list from playerFacts * Create a message for each friend POST /score * Regenerate hash using provided data, if it doesn't match provided hash return 400 * Insert a score document with given data * Update playerFacts for authPlayer * Increase games * If won, increase victories GET /scores * Obtain data from scores by authPlayer sorted by depth and kills, trim result by 10 POST /friendship/:friendPIN * Get player with given PIN, return 404 if not found * Get friendship from authPlayer to givenPlayer, if found return. * Get friendship from givenPlayer to authPlayer, if found return. * Create friendship from authPlayer to givenPlayer * Update playerFacts for authPlayer, adding givenPlayer to friendNames and increasing the friendsCount * Update playerFacts for givenPlayer, adding authPlayer to friendNames and increasing the friendsCount
Step 5 – Document Model
Define the document model (master documents, transactional and facts) based on the blueprint and the functional model.
Masters ======= players playerName String, email String, password String, pin Number friendships fromPlayer String, toPlayer String, friendshipTime String scores playerName String, characterClass String, characterSex String, depth Number, kills Number, won Boolean, scoreTime String Transactional ============= sessions playerName String, token String, expiryTime String messages messageTime String messageType String, fromPlayerName String, toPlayerName String, messageText String, consumed Boolean Facts ===== playerFacts playerName String, pin Number, games Number, victories Number, friendsCount Number, friendNames Array< String >
Step 6 – Component Prototypes
Design the prototypes for the Data Access and “Business Logic” components based mainly on the functional analysis.
Business Logic Prototype { verifyPassword: function(plainPassword){}, encryptPassword: function(plainPassword){}, generatePIN: function(){}, generateAuthToken: function(){}, getNewExpiryTime: function(){}, isTokenValid: function(expiryTime){}, generateScoreHash: function(score){} } Data Access Prototype { getPlayer: function(name){}, getPlayerByPIN: function(pin){}, insertPlayer: function(player){}, getSession: function(token){}, insertSession: function(session){}, deleteSession: function(token){}, updateSessionExpiry: function(token, expiry){}, getPlayerFactsWithoutFriendNames: function(pin){}, getFriendNames: function(playerName){}, getTop10Scores: function(playerName){}, getAndConsumeUnconsumedMessages: function(playerName){}, insertMessage: function(message){}, insertScore: function(score){}, updatePlayerFactsByScore: function(score){}, getFriendship: function(fromPlayer, toPlayer){}, insertFriendship: function(fromPlayer, toPlayer){}, updatePlayerFriendFacts: function (player, newFriend){} }
One thought on “Ananias Web Backend Designs”