Ananias Web Backend Designs

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.

backendDraft

Step 2 – Architecture

Decide on the architecture and the technology stack.

ananiasweb

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s