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:
Client
: The MyWordlist mobile app or other frontend clientGraphQLServer
: https://github.com/Yorkshireman/my_wordlist_graphqlGQLServerDB
: my_wordlist_graphql
's provisioned postgres databaseAuthServer
: https://github.com/Yorkshireman/authentication-serverAuthServerDB
: authentication-server
's provisioned postgres databasesequenceDiagram
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
authentication-server
on port 3001
(r s -p 3001
)my_wordlist_graphql
on port 3000
(r s -p 3000
).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
.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
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'
authentication-server
with r s -p 8081
my_wordlist_graphql
with r s
npm run android
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.
nvm use; npm install -g eas-cli
Check you're logged in with eas whoami
eas.json
to .gitignore
eas.json
file at root level{
"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.