Yorkshireman / my-wordlist-mobile

react-native (expo) app backed by authentication-server and my-wordlist-graphql. Project board: https://github.com/users/Yorkshireman/projects/2
1 stars 0 forks source link

MyWordlist

An app, for learners of English as a second language, to store and organise their english vocabulary through categorisation. They will also be able to save notes on each wordlist entry. Features may also include:

Sequence diagram

Key

sequenceDiagram
  actor User
  participant Client
  participant LocalStorage
  participant GraphQLServer
  participant GQLServerDB
  participant AuthServer
  participant AuthServerDB

  User -->> Client: open app
  Client -->> User: render Home screen
  Client -->> LocalStorage: getAuthToken()

  alt localStorage has an auth token
    LocalStorage -->> Client: JWT
    Client -->> User: render loading spinner
    Client ->> GraphQLServer: JWT in headers, query myWordlist
    GraphQLServer -->> GraphQLServer: decode JWT

    alt JWT expired
      GraphQLServer ->> Client: 401
      Client -->> User: go to Signin screen
      User -->> Client: submit signin form
      Client -->> User: render loading spinner
      Client ->> AuthServer: /signin
      AuthServer -->> AuthServerDB: find User by email/password
      AuthServerDB -->> AuthServer: User
      AuthServer -->> AuthServer: create JWT containing user_id
      AuthServer ->> Client: JWT
      Client -->> LocalStorage: storeAuthToken(JWT)
      Client -->> User: go to Home screen
      Client -->> LocalStorage: getAuthToken()
      LocalStorage -->> Client: JWT
      Client -->> User: render loading spinner
      Client ->> GraphQLServer: JWT in headers, query myWordlist
      GraphQLServer -->> GraphQLServer: decode JWT
    end

    GraphQLServer -->> GQLServerDB: user_id
    GQLServerDB -->> GraphQLServer: data
    GraphQLServer -->> GraphQLServer: create JWT containing user_id
    GraphQLServer ->> Client: myWordlist data + JWT
    Client -->> LocalStorage: storeAuthToken(JWT)
    Client -->> User: render user's wordlist
  end

  alt localStorage has no auth token
    LocalStorage -->> Client: null
    Client -->> User: go to Signin screen

    alt new user
      User -->> Client: click signup cta
      Client -->> User: go to Signup screen
      User -->> Client: submit signup form
      Client -->> User: render loading spinner
      Client ->> AuthServer: /signup
      AuthServer -->> AuthServerDB: create User
      AuthServerDB -->> AuthServer: User
      AuthServer -->> AuthServer: create JWT containing user_id
      AuthServer ->> Client: JWT
      Client -->> LocalStorage: storeAuthToken(JWT)
      Client ->> GraphQLServer: myWordlistCreate mutation
      GraphQLServer -->> GraphQLServer: decode JWT
      GraphQLServer -->> GQLServerDB: user_id
      GQLServerDB -->> GQLServerDB: create Wordlist with user_id
      GQLServerDB -->> GraphQLServer: data
      GraphQLServer -->> GraphQLServer: create JWT containing user_id
      GraphQLServer ->> Client: myWordlist data + JWT
      Note right of Client: store is reset with client.resetStore(), so active queries are refetched with new auth token
    end

    alt existing user on new device
      User -->> Client: submit signin form
      Client -->> User: render loading spinner
      Client ->> AuthServer: /signin
      AuthServer -->> AuthServerDB: find User by email/password
      AuthServerDB -->> AuthServer: User
      AuthServer -->> AuthServer: create JWT containing user_id
      AuthServer ->> Client: JWT
      Client -->> LocalStorage: storeAuthToken(JWT)
    end

    Client -->> User: go to Home screen
    Client -->> LocalStorage: getAuthToken()
    LocalStorage -->> Client: JWT
    Client -->> User: render loading spinner
    Note right of Client: this query may be resolved from apollo cache instead
    Client ->> GraphQLServer: JWT in headers, query myWordlist
    GraphQLServer -->> GraphQLServer: decode JWT
    GraphQLServer -->> GQLServerDB: user_id
    GQLServerDB -->> GraphQLServer: data
    GraphQLServer -->> GraphQLServer: create JWT containing user_id
    GraphQLServer ->> Client: myWordlist data + JWT
    Client -->> LocalStorage: storeAuthToken(JWT)
    Client -->> User: render user's Wordlist
  end

To run whole stack locally

For Web

.env.development:

MY_WORDLIST_GRAPHQL_URL=http://localhost:3000/graphql
SIGN_IN_URL=http://localhost:3001/signin
SIGN_UP_URL=http://localhost:3001/signup

npm run web

For iOS Simulator

.env.development:

MY_WORDLIST_GRAPHQL_URL=http://localhost:3000/graphql
SIGN_IN_URL=http://localhost:3001/signin
SIGN_UP_URL=http://localhost:3001/signup

npm run ios

For Android Simulator

Hardcode the following values into the code instead of relying on the values being pulled from .env.development: MY_WORDLIST_GRAPHQL_URL: 'http://10.0.2.2:3000/graphql' SIGN_IN_URL: 'http://10.0.2.2:8081/signin' SIGN_UP_URL: 'http://10.0.2.2:8081/signup'

It's currently a mystery as to why it works this way and not from relying on the .env.development file with exactly the same values.

Building a downloadable APK to install on Android devices

Install the EAS CLI

nvm use; npm install -g eas-cli

Check you're logged in with eas whoami

Provide configuration for EAS

{
  "build": {
    "staging-internal": {
      "android": {
        "buildType": "apk",
        "env": {
          "MY_WORDLIST_GRAPHQL_URL": <url>,
          "SIGN_IN_URL": <url>,
          "SIGN_UP_URL": <url>
        }
      }
    },
    "staging": {
      "env": {
        "MY_WORDLIST_GRAPHQL_URL": <url>,
        "SIGN_IN_URL": <url>,
        "SIGN_UP_URL": <url>
      }
    }
  }
}

NB strictly speaking, only the staging-internal part is needed for this specific task

eas build -p android --profile staging-internal

This will build remotely and, when completed, provide an apk download url in the terminal.