Skip to content

Onboarding Guide

This onboarding guide assumes that you have already completed the TheM>Getting Started>Quick Start guide and are familiar with TheM class, TheM submodule initialization, and creating/listening for custom events. This guide also assumes that you have already installed the amplifi_mobile_sdk package into your project and placed the following minified libraries in the /lib folder of your project: axios.min.js (Optional - fetch will be used if axios is not present), crypto-js.min.js, lz-string.min.js, moment.min.js, and socket.io.min.js.

1. In the src folder of your project (from the Quick Start guide of the TheM Getting Started section), create a new file called onboarding.js with the following code.

onboarding.js

import ClassTheM from "../node_modules/@PayGearsCorp/amplifi_mobile_sdk/TheM/them.mjs";

import AMPLIFI_IMAGE_B64 from "./image-b64.js"; //sample b64 image for testing onboarding
import { sampleClient } from "./sample-client.js"; //sample client for testing onboarding
import { thisDevice } from "./android-demo-device.js"; //android device emulator for testing onboarding

const AMPLIFI_BASE_URL = "PUT_YOUR_INSTANCE_URL_HERE"; //Speak to a PayGears representative to be issued a sandbox instance URL
const AMPLIFI_CORE_URL = `${AMPLIFI_BASE_URL}core/`;

//need AMPLIFI_FACE_IMAGE_B64, AMPLIFI_DL_FRONT_B64, AMPLIFI_DL_BACK_B64 for onboarding
AMPLIFI_FACE_IMAGE_B64 = AMPLIFI_IMAGE_B64; //declared in onboarding.html
AMPLIFI_DL_FRONT_B64 = AMPLIFI_IMAGE_B64; //declared in onboarding.html
AMPLIFI_DL_BACK_B64 = AMPLIFI_IMAGE_B64; //declared in onboarding.html


const subClassesToInit = [
    //"accounts",
    //"beneficiaries",
    //"cards",
    //"cheques",
    "common",
    //"externalAccounts",
    //"fdrs",
    //"fundstransfer",
    //"fxrates",
    //"genericRequests",
    //"ious",
    "onboarding",
    //"payees",
    //"remittance",
    //"restrictions",
    //"statics",
    "user"
];

sampleDemoClient = { //declared in onboarding.html
    ...sampleClient
};


export const onboardingTutorial = async (subClasses = "") => {
    TheM = new ClassTheM({
        config: {
            AFiInstanceId: "test",
            modulesFolder: "",
            modulesFolderOnboarding: "",
            webworkerFolder: "../TheM/",
            baseLibURL: "../demo/lib/",
            backEndURL: AMPLIFI_CORE_URL,
            socketURL: AMPLIFI_BASE_URL,
            user: {
                DEFAULT_HOMECOUNTRY: "US"
            },
            onboarding: {
                PRESEGMENTS_ALLOWED: {
                    "demo_uoiuqwehflkipahgoqq": "GenericClient"
                }
            }
        },
        libs: {
        }
    });

    //Emulate user device before initializing TheM submodules
    TheM.thisDevice = { ...thisDevice, TheM };

    //Initialize desired submodules
    //Some modules depend on others so must be initialized together
    //For instance, most submodules require the "common" subclass to be initialized
    await TheM.doInit(subClasses);

    //onboarding workflow to try
    //Uncomment to run the whole workflow or follow the instructions in the browser
    /*
    TheM.onboarding.doSetClient("demo_uoiuqwehflkipahgoqq"); //Set the client presegment.
    await TheM.onboarding.doConnectSocket(); //Open a socket connection. This command enables bidirectional, event-based communication.
    for (let key of Object.keys(sampleClient)) { //Fill out TheM.onboarding.client details
        try {
            if (["email", "mobile", "isIntroSeen", "isTCSeen", "ssn", "languageCode"].includes(key)) {
                TheM.onboarding.client[key] = sampleClient[key];
            }
            if (key === "name") {
                TheM.onboarding.client[key].firstName = sampleClient[key].firstName;
                TheM.onboarding.client[key].middleName = sampleClient[key].middleName;
                TheM.onboarding.client[key].lastName = sampleClient[key].lastName;
            }
            if (key === "address") {
                TheM.onboarding.client[key].addressLine1 = sampleClient[key].addressLine1;
                TheM.onboarding.client[key].city = sampleClient[key].city;
                TheM.onboarding.client[key].state = sampleClient[key].state;
                TheM.onboarding.client[key].postalCode = sampleClient[key].postalCode;
                TheM.onboarding.client[key].countryCode = sampleClient[key].countryCode;
                TheM.onboarding.client[key].country = sampleClient[key].country;
            }
            if (key === "dob") {
                TheM.onboarding.client[key].day = sampleClient[key].day;
                TheM.onboarding.client[key].month = sampleClient[key].month;
                TheM.onboarding.client[key].year = sampleClient[key].year;
            }
            if (key === "extra") {
                TheM.onboarding.client[key].sex = sampleClient[key].sex;
                TheM.onboarding.client[key].eyeColor = sampleClient[key].eyeColor;
                TheM.onboarding.client[key].hairColor = sampleClient[key].hairColor;
                TheM.onboarding.client[key].heightMetric = sampleClient[key].heightMetric;
                TheM.onboarding.client[key].weightMetric = sampleClient[key].weightMetric;
            }
            if (key === "document") {
                TheM.onboarding.client[key].type = sampleClient[key].type;
                TheM.onboarding.client[key].number = sampleClient[key].number;
                TheM.onboarding.client[key].issued = sampleClient[key].issued;
                TheM.onboarding.client[key].expires = sampleClient[key].expires;
                TheM.onboarding.client[key].issuingState = sampleClient[key].issuingState;
                TheM.onboarding.client[key].raw = {};
            }
        } catch (err) {
            console.log(err);
        }
    }

    // Push client images onto the imageQueue to be sent to the server
    TheM.onboarding.imageQueue.push({ type: "Face image", imageBase64: AMPLIFI_FACE_IMAGE_B64 });
    TheM.onboarding.imageQueue.push({ "type": "US driving license front document image", "imageBase64": AMPLIFI_FACE_IMAGE_B64 });
    TheM.onboarding.imageQueue.push({ "type": "US driving license back document image", "imageBase64": AMPLIFI_FACE_IMAGE_B64 });

    if (TheM.onboarding.client.isValid) { // Check to make sure TheM.onboarding.client is fully filled out and appears to be valid
        console.log(`TheM.onboarding.client.isValid: ${TheM.onboarding.client.isValid}`);
    } else {
        throw "Client is not valid"
    }

    try {
        let temp = await TheM.onboarding.doSendData(); //Send the data to the server
        if (!temp) {
            throw "Failed sending the data"
        }
    } catch (err) {
        console.log(err);
    }
    await TheM.on("modelBank registration complete", () => { // Set a listener that will react to a successful conversion of the client from prospect to user
        console.log("SUCCESS: the user has been registered successfully");
    }, true);
    await TheM.on("modelBank onboarding device ready for logging in", () => { // Set a listener that will react to a custom device event
        //Once successfully registered, the client can log in using the device for the first time
        TheM.thisDevice.doAuthenticate();
    }, true);
    await TheM.onboarding.doRegister({ pin: "1234" }); // Register the client (server will attempt to convert the client from a prospect to a user)
    */
};

await onboardingTutorial(subClassesToInit.join(" "));

2. The onboarding.js source file will require a base64 encoded image. Create a file in the src folder of your project called image-b64.js. In this tutorial, the same image file is used whereever needed to represent the required image for testing purposes. However, in production, each image would be represented by its own base 64 encoded string.

image-b64.js

const AMPLIFI_IMAGE_B64 ="PUT YOUR B64 ENCODED IMAGE STRING HERE"; //a very long base 64 encoded image string

3. The onboarding.js file also references a sampleClient that has been prepared for testing purposes. Create a file in the src folder of your project called sample-client.js.

sample-client.js

/*
*   This sample client has been provided for testing and exploring TheM.onboarding functionality
*   in the browser while running the provided onboarding demo.
*
*   Example: TheM.onboarding.client.mobile = sampleClient.mobile;
*
*/


const SSN = "3" + (new Date().valueOf() / 1000).toString().substring(1, 9);

export const sampleClient = {
    email: "testemail@email.test",
    mobile: "5556667777",
    isIntroSeen: true,
    isTCSeen: true,
    name: {
        firstName: "Suzy",
        middleName: "Queue",
        lastName: "Tester"
    },
    dob: {
        day: "01",
        month: "15",
        year: "1975"
    },
    address: {
        addressLine1: "123 Main Str.",
        addressLine2: undefined,
        city: "Harrisburg",
        state: "PA",
        postalCode: "12345",
        countryCode: "US",
        country: "US"
    },
    extra: {
        sex: "female",
        eyeColor: "BRO",
        hairColor: "BLK",
        heightMetric: "181",
        weightMetric: "85"
    },
    ssn: SSN,
    document: {
        type: "US driving license",
        number: "99999999",
        issued: "10052019",
        expires: "08042029",
        issuingState: "PA",
        raw: {},
    },
    languageCode: "en"
};

4. The onboarding module expects the client (prospect) to be onboarded via a device. We will emulate the device that the prospect is using to onboard. Create a file in the src folder of your project called android-demo-device.js.

android-demo-device.js

//import fs from "fs"; //node.js environment

const _DEVICE_TAG = Math.random().toString(36).substring(2, 20);
const _SUPER_SECRET = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

export const thisDevice = {
    deviceTag: _DEVICE_TAG,
    isDeviceReady: false,
    isRegistered: false,
    isEnrolled: false,
    isEnroledWithFingerprint: false,
    isFingerprintAvailable: false,
    isFingerprintDeviceChecked: false,
    linkinjected: undefined,
    isFirstRun: true,
    isRecoveryMode: false,
    platform: "android_v1",
    isDebugTelemetryEnabled: false,
    build: "0.0.01",
    deepLink: undefined,
    pushMessToken: undefined,
    dynamicScreensVersion: 1,
    data: {
        platform: "android",
        build: "0.0.01"
    }
};

let _timeoutIsScheduledToSave = false;

thisDevice.doEnroll = function (given) {
    return new Promise(async (resolve, reject) => {
        TheM.newEvent("onboarding enrolling");
        return resolve(_SUPER_SECRET);
    });
};

thisDevice.doSave = function () {
    return new Promise(async (resolve, reject) => {
        return resolve();
    });
};

thisDevice.storeLocally = function (tag, data) {
    console.log("SAVING:", tag, data);
    if (!TheM.isBrowser) { //node.js environment
        //return fs.writeFileSync(`./secrets/${thisDevice.deviceTag}_${tag}`, JSON.stringify(data, null, 2));
    }
    if (_timeoutIsScheduledToSave) return true;
    _timeoutIsScheduledToSave = true;
    setTimeout(() => {
        let savable = { ...data };
        TheM.common.storeLocally({
            tag: tag,
            payload: savable
        }).then(() => {
            TheM.newEvent("modelBank onboarding device ready for logging in");
        });
        _timeoutIsScheduledToSave = false;
    }, 1000);
    return true;
};

thisDevice.retrieveLocally = async function (tag, isJSON) {
    console.log("RETRIEVING:", tag);
    let data;
    if (!TheM.isBrowser) { //node.js environment
        //data = fs.readFileSync(`./secrets/${thisDevice.deviceTag}_${tag}`, 'utf8');
    } else {
        data = await TheM.common.retrieveLocally(tag, isJSON ? {} : false);
    }
    try {
        if (data && isJSON) data = JSON.parse(JSON.stringify(data));
    } catch (err) {
        console.log(data);
        console.log(err);
    }
    return data;
};


thisDevice.doAuthenticate = function (deviceTag) {
    return new Promise(async (resolve, reject) => {
        if (deviceTag) {
            thisDevice.deviceTag = deviceTag;
        }

        let _dts = new Date();
        let _dtsValueString = (_dts).valueOf().toString();
        let temp = await thisDevice.retrieveLocally("encryptedServerSecret", true);
        let encryptedServerSecret = temp.encryptedServerSecret;
        let serverSecret = CryptoJS.AES.decrypt(encryptedServerSecret, _SUPER_SECRET).toString(CryptoJS.enc.Utf8);

        let cryptotext = CryptoJS.AES.encrypt((thisDevice.deviceTag) + _dtsValueString, serverSecret).toString();
        thisDevice.halfRef = TheM.common.GetRandomSTR(40);

        console.log(`deviceTag: ${thisDevice.deviceTag}`);

        await TheM.user.doLogin({
            "dtsValueString": _dtsValueString,
            "deviceTag": thisDevice.deviceTag,
            "deviceData": thisDevice.data,
            "channel": thisDevice.platform,
            "dynamicScreensVersion": thisDevice.dynamicScreensVersion,
            "socket": {
                halfRef: thisDevice.halfRef
            },
            "pushMessToken": thisDevice.pushMessToken,
            "cryptotext": cryptotext
        });

        return resolve();
    });
};

5. Create a new file in the /demo folder of your project called onboarding.html with the following code.

onboarding.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>ampliFi</title>

    <script>
        var TheM;
        var TheM_config;
        var AMPLIFI_FACE_IMAGE_B64;
        var AMPLIFI_DL_FRONT_B64;
        var AMPLIFI_DL_BACK_B64;
        var sampleDemoClient;
    </script>

    <script src="../lib/socket.io.min.js"></script>
    <script src="../lib/lz-string.min.js"></script>
    <script src="../lib/moment.min.js"></script>
    <script src="../lib/axios.min.js"></script>
    <script src="../lib/crypto-js.min.js"></script>
    <script type="module" src="/../src/onboarding.js"></script>

    <style>
        html {
            color: white;
            background-color: black;
        }
    </style>
</head>


<body>
    <div>
        Hit F12 to open the browser console.
        Start working with TheM by typing "TheM" into the browser console.
    </div>
    <br />
    <br />
    <div>
        1. Try typing the following into the browser console to onboard a new user:
        <br /><br />
        <code>TheM.onboarding.doSetClient("demo_uoiuqwehflkipahgoqq"); //This command will set a default base client (TheM.onboarding.client) that corresponds to the presegment argument chosen, if it is an allowed presegment for this instance of TheM.</code>
        <br /><br />
        You can view the client you set by typing TheM.onboarding.client into the browser console.
        Notice that several fields have been prepared which will now need to be filled out, such as name, address,
        mobile number, email, etc.
        <br /><br />
        2. Open a socket connection. This command enables bidirectional, event-based communication.
        <br /><br />
        <code>TheM.onboarding.doConnectSocket();</code>
        <br /><br />
        3. Now, fill out the client fields (name, address, email, mobile. etc.)
        You can choose your own sample data or use the sampleClient created for this demo.
        You can view the sampleClient by typing <code>sampleDemoClient;</code> into the browser console and hitting
        enter.
        Reference specific fields by typing sampleDemoClient.address.address1, sampleDemoClient.email,
        sampleDemoClient.mobile, etc.
        <br /><br />
        <code>
            TheM.onboarding.client.address.address1 = "123 Sample Street"; //or sampleDemoClient.address.address1;<br />
            TheM.onboarding.client.address.addressLine2 = "Apt 456";<br />
            TheM.onboarding.client.address.city = "Harrisburg";<br />
            TheM.onboarding.client.address.state = "PA";<br />
            TheM.onboarding.client.address.countryCode = "US"; //default is "US"<br />
            TheM.onboarding.client.address.postalCode = "12345";
        </code>
        <br /><br />
        4. As we move through the client data, we can test to see if the fields appear valid like so.
        <br /><br />
        <code>
            TheM.onboarding.client.address.isValid; //returns true if address appears to be valid
        </code>
        <br /><br />
        5. Fill out the remaining client fields.
        <br /><br />
        <code>
            TheM.onboarding.client.email = "name.email@email.test";<br />
            TheM.onboarding.client.isValidEmail; //returns true of email appears to be OK
        </code>
        <br /><br />
        <code>
            TheM.onboarding.client.mobile = "1234567890";<br />
            TheM.onboarding.client.isValidMobile; //return true if mobile appears to be OK
        </code>
        <br /><br />
        <code>
            TheM.onboarding.client.name.firstName = "Suzy";<br />
            TheM.onboarding.client.name.middleName = "Queue";<br />
            TheM.onboarding.client.name.lastName = "Tester";<br />

            TheM.onboarding.client.dob.day = "01";<br />
            TheM.onboarding.client.dob.month = "15";<br />
            TheM.onboarding.client.dob.year = "1975";<br />

            TheM.onboarding.client.dob.isValid; //returns true if date is valid
        </code>
        <br /><br />
        <code>
            TheM.onboarding.client.extra.sex = "male";  // or "female"<br />
            TheM.onboarding.client.extra.eyeColor = "BRO"; //optional<br />
            TheM.onboarding.client.extra.hairColor = "BLK"; //optional<br />
            TheM.onboarding.client.extra.heightMetric = "181"; //optional<br />
            TheM.onboarding.client.extra.weightMetric = "85"; //optional
        </code>
        <br /><br />
        <code>
            TheM.onboarding.client.ssn = "123456789"; <br /> //Must be unique
            TheM.onboarding.client.isValidSsn; //returns true if SSN appears to be OK
        </code>
        <br /><br />
        6. As the client progresses through the onboarding process, set the following flags at some point.
        <br /><br />
        <code>
            TheM.onboarding.isTCSeen = true; //Client has seen the terms&conditions<br />
            TheM.onboarding.client.isIntroSeen = true; //Client has seen the first intro screen
        </code>
        <br /><br />
        7. If the client has a referral code, fill it in.
        <br /><br />
        <code>
            TheM.onboarding.client.referral = "";<br />
            TheM.onboarding.client.isReferralValid; //returns true if referral code appears to be OK
        </code>
        <br /><br />
        8. Add the client document data.
        <br /><br />
        <code>
            TheM.onboarding.client.document.type = "US driving license";  //or "Passport"<br />
            TheM.onboarding.client.document.number = "99999999";  //alphanumeric<br />
            TheM.onboarding.client.document.issued = "10052019"; //MMDDYYYY<br />
            TheM.onboarding.client.document.expires = "08042029"; //MMDDYYYY<br />
            TheM.onboarding.client.document.issuingState = "PA";  //Required for driver licenses<br />
            TheM.onboarding.client.document.issuingCountry_ISO3166_alpha3 = "USA"; //Required for passports<br />
            TheM.onboarding.client.document.raw = {}; // an optional JSON blob with arbitrary data<br />
            TheM.onboarding.client.isValidDocument; //returns true if document appears to be OK<br />
            TheM.onboarding.client.isDocumentAlmostExpired; //returns true if the document expiry date is near    
        </code>
        <br /><br />
        9. Check to see if the client is now valid.
        <br /><br />
        <code>
            TheM.onboarding.client.isValid;
        </code>
        <br /><br />
        10. If the client is filled out and valid, then send the data to the server.
        <br /><br />
        <code>
            let temp = await TheM.onboarding.doSendData();<br />
            if (!temp) throw "Failed sending the data";
        </code>
        <br /><br />
        11. Convert png images for the documents to base64 and add them too.
        <br /><br />
        <pre><code>TheM.onboarding.imageQueue.push({<br />  type: "Face image", //selfie of the client<br />  imageBase64: AMPLIFI_FACE_IMAGE_B64 //sample b64 image for testing<br />});<br /></code></pre>
        <pre><code>TheM.onboarding.imageQueue.push({<br />  type: "US driving license full document image",<br />  imageBase64: AMPLIFI_DL_FRONT_B64 //sample b64 image for testing<br />});<br /></code></pre>
        <pre><code>TheM.onboarding.imageQueue.push({<br />  type: "US driving license back document image",<br />  imageBase64: AMPLIFI_DL_BACK_B64 //sample b64 image for testing<br />});<br /> 
        </code></pre>
        Image types required:<br /><br />
        "US driving license full document image", "US driving license back document image", and "Face image"
        <br /><br />
        or
        "Passport raw image", "Passport full document image", and "Face image"
        <br /><br />
        or
        "Passport full document image", and "Face image"
        <br /><br />
        12. As soon as the first image is added, `TheM.onboarding.isDocumentCaptured` will be `true`.
        <br /><br />
        Depending on the comm channel, delivering images may take a few seconds.
        Once all the images are sent `TheM.onboarding.imageQueue.isSendingDone` turns `true`.
        Once the server accepts the document images, `TheM.onboarding.isDocumentDelivered` will be `true`.
        <br /><br />
        <code>
            TheM.onboarding.isDocumentCaptured;<br />
            TheM.onboarding.imageQueue.isSendingDone;
        </code>
        <br /><br />
        13. Now register the filled out client as a prospect.
        Behind the scenes, if everything looks good, the prospect will be converted to a new user.
        Once converted, the new user will be able to log in for the first time.
        <br /><br />
        <pre><code>TheM.on("modelBank converted from prospect to user", () => {<br />  console.log("SUCCESS: the user has been registered successfully");<br >});<br />await TheM.onboarding.doRegister({ pin: "1234" });<br />
        </code></pre>
        14. After the registration is successful, the user can log in for the first time on this device.
        <br /><br />
        <code>
            TheM.thisDevice.doAuthenticate();
        </code>
        <br /><br />
    </div>
</body>

</html>

6. Start a server in the root folder of your project.

py -m http.server 8000

7. Open a browser and enter the following URL: http://localhost:8000/demo/

8. Click on the link for "onboarding.html" and follow the instructions to onboard a new prospect, convert the prospect to a user, and log the user in for the first time.