Difference between revisions of "IS480 Team wiki: 2016T1 Stark Final Wiki"

From IS480
Jump to navigation Jump to search
Line 85: Line 85:
! style="background: #D80E0E; color: white; font-weight: bold; width: 50%" | Actual
! style="background: #D80E0E; color: white; font-weight: bold; width: 50%" | Actual

Revision as of 14:34, 30 October 2016

Team Stark Logo.png

Team Stark Home.png   HOME


Team Stark About Us.png   ABOUT US


Team Stark Project Overview.png   PROJECT OVERVIEW


Team Stark Project Management.png   PROJECT MANAGEMENT


Team Stark Documentation.png   DOCUMENTATION


Project Progress Summary

Final Slides: [ Download Here]

MaiMai is deployed for production at
MaiMai is deployed for testing purpose at
Learn more about us at http://www.maitwo.com

Current Iteration:
Total Iterations: 16
Iteration Dates (Current):
Iteration Dates (Final):

Project Highlights

Project Challenges

Project Achievements

Project Management

Project Scope

Stark Scope midterm wiki.png
Stark Scope final.png

Scope Changes The following changes has been made to our project scope and reflected in our schedule.

Project Timeline

Stark schedule after.png
Stark schedule final.png

Schedule Highlights The following changes has been made to our project scope and reflected in our schedule.

  • iBanking was shifted from iteration 12 to iteration 13 as we need to replan the business process as there is no way for savings account to be automated
  • Added "Web Push Notification" into "Good-To-Have" feature in iteration 13 as to integrate the user's experience with the notification function in MaiMai
  • Altered "Location Check-In" to "Agreement fields (Location, Date and Time)" as check-In process requires much more planning and considerations. As there is limited time, the team has decided to focus on providing as much structured agreements as possible to show future plan of using such structured agreements as a mean to automate the dispute management process.
  • Shifted UT3 from 24 Oct to 31 Oct as additional features were being modified and added into scope, UT3 will focus on all additional features.

Refer to our Change Management for more!

Project Metrics

Schedule Metrics


Iteration Planned Duration (Days) Actual Duration (Days) Schedule Metric Score Action Taken Status
8 14 16 0.88 More time needed to fix bugs from UT1 and after the integration of Dispute Management.

Follow up action: Informed supervisor and mentor about the delay. More hours put in for debugging. No major delay to overall schedule.


View our Schedule Metrics Here!

Bug Metrics


Iteration Bug Score Bug Summary Action Taken
6 43

3 low
8 high
0 critical

The spike in bug count is due to the integration of dispute management system together with previous completed features. Resolve bugs immediately. No major delay was caused.
8 179

44 low
21 high
3 critical

The spike in bug count is because of the integration of many new features together for UT1. Resolve bugs immediately. Iteration 8 was scheduled for post UT1 debugging. PM scheduled the Lead Backend developer to focus on debugging while the rest of the developers focus on development.
9 42

7 low
3 high
2 critical

The first critical bug was system crashed when a dispute for review is filed. The second critical bug was images is not updated when listing image name is being edited. Resolve bugs immediately. No major delay was caused. Critical bug did not occur again. Similar action was performed but bug did not replicate.

Viewed our Bug Metrics Here!

Project Risks

Risk Description Likelihood Impact Mitigation Strategy
Mismatch of product against market. High High
Developed product may not be what our target users or anyone in the market wants.
1. Gather more feedbacks during testing to validate market needs against project idea.

2. Transact with more real user and conduct interview with them to understand the problems and needs of the market.

Quick rise of direct competition Low Low
Existing application like Caurosell can easily implement payment services that we are providing.
We provide user with dispute management service which is something that is unique to us and we are investing our resources into defining a stringent and reliable process of micro management. As such we have the upper hand because that is our prime feature. However, it still remain as a risk.

Technical Complexity

Complexities arise due to the following needs:

  • User Experience
  • Performance (Client and Server)
  • Compatibility across devices and browsers
  • Mobile vs Desktop

Processing of Users’ Uploaded Images

Problem: Beforehand we had a “limit” on the size of images to 1MB

  • Server resources
  • Faster loading for users

Causes: Poor user experience

  • Users complain why other “apps” out there that can accept all images from their phones (main basis of benchmarking).

Uploadimage1.png Uploadimage2.png

Benchmark max file size to accept:

  • Two “best” phones (iPhone 7s and Samsung Galaxy 7 camera captured photos (12 MP 3-6 MB)

Keep file sizes after processing below 1MB

  • Maintaining sufficient quality for the web

Processing to be done client side

  • If image processing is to be at server side there is an additional two way transfer of the user uploading to the server and downloading the processed image
  • Heavy on server resources

What we did:

  • Used HTML’s Canvas for resizing
  • Client-side library Pica for reducing image quality

1. Retrieve images from form
2. Create HTML Image object
3. Load uploaded image into Image object

  //Goes through the images ( might have multiple images at one go)
  let images = this.state.image;
  for (let i = 0; i < images.length; i++) {
    let image = images[i];
    let img = new Image();
    img.src = window.URL.createObjectURL(image);
    img.onload = () => {

4. Create a HTML Canvas object
5. Draw Image object onto Canvas

  img.onload = () => {
   let src = document.createElement('canvas');
   src.width = img.width;
   src.height = img.height;
   let ctx = src.getContext('2d');
   ctx.drawImage(img, 0, 0);

6. Determine processed Canvas size while maintaining ratio

   let dest = document.createElement('canvas');
   let longerLength = 1536;
   let shorterLength = 1180;
   let ratio;
   if ((src.width > src.height || src.width === src.height) &&
       (src.width > longerLength || src.height > shorterLength)) {
       if (src.width / longerLength > 1) {
           ratio = longerLength / src.width;
           dest.width = Math.round(ratio * src.width);
           dest.height = Math.round(ratio * src.height);
       } else {
           ratio = src.width / longerLength;
           dest.height = Math.round(ratio * src.height);
           dest.width = Math.round(ratio * src.width);

7. Use Pica to do image optimization from source Canvas to destination Canvas

  pica.resizeCanvas(src, dest, (err) => {
    if (err) {
     dest.toBlob(processImage, 'image/jpeg', 0.8);

8. With processed Canvas ready, we convert it into a blob and then into a Buffer Object to transfer to backend later

  const processImage = (blob) => {
    const data = (file) => {
       let reader = new FileReader();
       let name = file.name;
       reader.onloadend = (e) => {
           let results = this.state.uploadData;
           let sha1 = this.state.sha1;
           let image = reader.result;
           let buffer = new Buffer(image.byteLength);
           let view = new Uint8Array(image);
           for (let i = 0; i < buffer.length; ++i) {
               buffer[i] = view[i];

9. We later realized that iOS browsers do not support the Canvas function “toBlob”

  export const addToBlobFunction = function () {
   // add toBlob functionality for browsers that do not support it.
   if( !HTMLCanvasElement.prototype.toBlob ) {
       Object.defineProperty( HTMLCanvasElement.prototype, 'toBlob', {
           value: function( callback, type, quality ) {
               const bin = atob( this.toDataURL( type, quality ).split(',')[1] ),
                   len = bin.length,
                   len32 = len >> 2,
                   a8 = new Uint8Array( len ),
                   a32 = new Uint32Array( a8.buffer, 0, len32 );
               for( var i=0, j=0; i < len32; i++ ) {
                   a32[i] = bin.charCodeAt(j++)  |
                       bin.charCodeAt(j++) << 8  |
                       bin.charCodeAt(j++) << 16 |
                       bin.charCodeAt(j++) << 24;
               let tailLength = len & 3;
               while( tailLength-- ) {
                   a8[ j ] = bin.charCodeAt(j++);

End Result: Image sizes reduced from (5.5MB to 0.4MB, 8% of original image size)


Reactive and Real-time Chat

The chat serves as the core foundation to the transaction process for buyers and sellers Its’ main purpose is to facilitate efficient and effective communication and transaction between users. It needed to be reactive and real-time:

  • Needs to respond to changes by either user especially when building up the initial agreements
  • Needs to reflect proper status and relevant information according to the stage in the transaction

Reactivity and Real-Time achieved with Meteor and React:

  • Meteor provide the real time syncing
  • React allows us to react to changes in data
Real time.png

Designing of the data “schemas” is especially important Required to allow for changes to be properly reflected Caters to a publish-subscribe methodology

 let toInsert = {
   "_id": chatId,
   "listing": listingId,
   "listingOwner": listingOwner,
   "otherUser": otherUser,
   "status": "open",
   "price": listing.price,
   "agreements": agreements,
   "privateImages": {},
   createdAt: new Date()
   "chat": chatId,
   "owner": username,
   "type": "user",
   "message": message,
   "createdAt": new Date()
 case 'add':
   if (currentAgreement) throw new Meteor.Error('agreement already exists');
   agreements[agreement] = {
       agreement: agreement,
       owner: username,
       status: 'add'

Using Meteor for data subscription, data changes are continuously pushed to the React Component

  export default createContainer(({params}) => {   
     // …
     const chatHandle = Meteor.subscribe('getChat', chatId, {
        // …
     // …
  }, Conversation);
  componentWillReceiveProps(nextProps) {
     let {user, chat, transaction, payment} = nextProps;

Using React’s lifecycle management (componentWillReceiveProps), we respond to changes whenever it receives new data

  componentWillReceiveProps(nextProps) {
     let chat = nextProps.chat;
     let listing = nextProps.listing;
     if (Object.keys(chat).length > 0) {
     } else if (Object.keys(listing).length > 0) {

For example rendering the agreements and the available actions

  agreements.forEach((val) => {
     let agreement = val.agreement;
     let owner = val.owner;
     let status = val.status;
     switch (status) {
        case 'confirmed':
        case 'edit':
           contentEdited.push(pendingAgreement(agreement, 'edit', owner === myUser));
        case 'delete':
           contentEdited.push(pendingAgreement(agreement, 'delete', owner === myUser));

Or showing new chat messages immediately

  getMessage(messageArr) {
    let user = this.props.myUser;
    let messages = [];
    messageArr.map((message) => {
       let {_id: id, owner, type, message: content, createdAt: date} = message;
       switch (type) {
           case 'user':
                   <UserMessage key={id} message={content} date={date} owner={owner === user} username={user}/>
           case 'system':
                   <SystemMessage key={id} message={content} date={date}

Quality of Product

Intermediate Deliverables

Stage Specification Modules
Project Requirements Market Research Market Research
Project Management Minutes Minutes
Metrics Schedule Metrics
Bug Metrics
Risk Risks
Change Management Change Management
Diagrams Use Diagrams
Architecture Diagram
Design Low-Fi Prototype
High-Fi Prototype
UI Prototype
Testing User Testing 1 User Test 1
User Test 2
User Test 3


User Testing

User Testing Date Venue Users Link
User Testing 1 1st August 2016 - 8th August 2016 Off-Site (At respective members' discretion) 22 User Testing 1
User Testing 2 12th September 2016 - 26th September 2016 SIS GSR 2-7 & Off-Site (At respective members' discretion) 38 User Testing 2
User Testing 3 User Testing 3


Team Reflection The journey so far has been tough but enjoyable learning experience for Team Stark. As a self-proposed IS480 project, we learnt how to make use of this opportunity to learn about running a start-up. For example, the importance of gathering feedbacks from actual users, validating ideas and features, followed by developing an application that caters to market needs. We have learnt about individual's strengths and weaknesses and worked towards complementing each other to produce quality work. Furthermore, given the guidance of our supervisor, mentor, and reviewers helps the team to overcome obstacles and stretch us to our maximum capability.

Individual Reflection

Name Reflections
Stark Ivy.png

Lee Chian Yee

Stark Hem.png

Raji Hemanth Kumar

Stark Qx.png

Lee Qixian

STARK Josh.png

Phua Xue Yong

Stark Qp.png

Lin Qianpin

Stark Darren.png

Darren Tay Kuang Yong