Skip to content

yqni13/taxi-varga

Repository files navigation

yqni13 | taxi-varga

$\texttt{\color{teal}{v1.6.1}}$



no responsive design at the moment

Technology


Angular   Node.js   GoolgePlacesAPI  
RxJS   Express   GoogleRoutesAPI  
ESLint   i18n   Jest  

visit the WEBSITE


How to:

Start

ALL LISTED COMMANDS ARE DEFINED TO WORK AT LEAST ON POWERSHELL/COMMAND PROMPT.

Create necessary modules (/frontend and /backend):

$ npm install

This web project uses Google API calls, which require to run the application on ssl (https) - both on production environment as well as localhost. Therefore, in development mode you need to use a self-assigned certificate and set your local environment ready to trust the certificate and enable local ssl connection. See the following start-via-ssl configurations for help. Fill environment variables with necessary data/paths and serve on localhost:

npm run start-local-ssl

which will open automatically on https://localhost:4200/. To run backend use:

node server.js

Build & Deploy

The project at /frontend is hosted by Netlify meanwhile /backend is hosted by Vercel.
Currently there are 2 hosted versions accessible - on staging level (branch: staging) to test outside of an local environment and on production level (branch: production) as ready-to-use software.
Note: Netlify does NOT support multi-line environment variables. To use ssh keys, it is neccessary to store the keys as single-line text and convert it back to the preferred format before building the project. Best practice would be to have a script that converts Netlify secrets beforehand or manually add the prepared keys as single-line text and then convert it.
Currently public/private keys are converted from single-line secret to multi-line secret in: set-env.ts

Overview

$\textsf{\color{teal}Features}$

💠 Angular v18 standalone with routing + nested routes on id
🔁 Google Routes/Places API usage in backend
🚩 Google Maps usage in frontend + calculating route by geolocation
🐢 Custom image/video preload
🔍 Custom search-input form component combined with Google Places API
📋 Custom form components (text-, textarea- & select-input)
💻 Key navigation on forms and carousel
🔧 Custom validation Angular/Express-Validator
🔒 Asymmetric/hybrid (RSA/AES) encrypted requests
📧 Mail service with node.js & nodemailer for Backend
📶 Http interception + custom snackbar modal
🌚/🌞 Custom color theme (dark/light mode)
🌐 i18n (internationalization) - translate to german or english
📱 Responsive design 400px > width < 1800px via flexbox & media queries

$\textsf{\color{teal}Customized form}$

All services take input for calculating the offer by addresses, timestamps and checkboxes/radio buttons as well as customer data like name, email, phone and notes. For full control, custom form components in combination with custom validation are used. The example of figure 2 shows built-in required-validator as well as custom time-related validation to be highlighted via red warning symbol and regarding validation message. Data validated by backend inform user via (custom) snackbar-message of invalid input.

404 no picture found Figure 2, v1.0.0-beta

$\textsf{\color{teal}Google API}$

Data from Google, based on the RoutesAPI, PlacesAPI and MapsAPI (Geocode), is used for the calculations and address suggestions/autocompletion. The user can type in the search field for his address and gets a max of 5 addresses listed as a result of the current input. Figure 3 shows, that after every change of the search input, a request is sent providing the listed options in the response. Clicking on an option sends a final request to get all details to the selected address/place, which is necessary to continue the service. If no option is selected, the form will be invalid and the regarding validation message displayed. Google demands to display their logo if a map or place-data (in this case the address options) are used.

 no picture found Figure 3, v1.0.0

Additionally, the service for spontaneous drives offers a feature to use coordinates via Geolocation for determining the starting address and displaying Google Maps with the location marked to improve user experience and checking coordinates accuracy (see Figure 4, location used as pickup address).

 no picture found Figure 4, v1.5.2

$\textsf{\color{teal}Theme + Internationalization}$

The webpage offeres two theme settings: $\textsf{\color{gray}{dark mode}}$ & $\textsf{\color{goldenrod}{light mode}}$. The information on the active setting is stored in the localstorage with dark mode as default setting at the beginning. Additionally, internationalization was implemented (via ngx-translate/core & /http-loader) and at this point 2 languages are available to select (see Figure 5). Dynamic and static texts can be displayed in english or german by choosing the regarding option in the footer. The value gets saved in the localstorage (same as the colour theme) and will stay translated in the selected language. To improve maintanence, the TranslateHttpLoader was customized to join multiple .json files for the same language translation rather than the usual way with only 1 file per language see custom-translate-loader.ts.

 no picture found Figure 5, v1.5.6

$\textsf{\color{teal}Security}$

For security reasons, the user automatically starts a service with a background-login process which sends an init request (see figure 6). The payload consists of the service in use and the credential data. Currently both username and password are asymmetrically encrypted => best practice is to hash the password but we dont use a database for hash comparison. The server compares the data to authenticate the validity of the client and generates a random jsonwebtoken with an appropriate expiration time. In the response of figure 6 we can see the generated token that gets stored (currently not cookie, follows with update) and included with each following request to ensure authentication.

 no picture found Figure 6, v1.0.0

Hybrid encryption is used for encrypting sensible data like the user input used for sending the emails (name, phone number, message and so forth...). Figure 7 displays the encrypted data in the request, decrypted in the backend to handle logic and again encrypting data for the response. On client side, the webcrypto api support Angular to handle RSA and AES en/decryption and in NodeJS on the backend node-forge comes to use.

 no picture found Figure 7, v1.0.0

$\textsf{\color{teal}Preloading}$

To prevent any delay between building the page and displaying the active assets (images/videos), the AssetsPreloadService and AssetsPreloadGuard are in use to load everything accordingly.

Whereas the guard is used within the *.routes.ts files to load assets predetermined (see Figure 8, code block), the service can also be used to preload assets/data dynamically or modular:

this.assetsPreloadService.preloadAssets({
    images?: imagePathArray,
    videos?: videoPathArray
}).finally(() => {
    this.isLoadingFlag = false;
})
 no picture found Figure 8, v1.2.2

Testing

$\textsf{\color{teal}Jest}$

Added jest testing framework to project providing unit tests and integration tests for the backend.
Install the packages @jest/globals, @types/jest, supertest additional to jest:

npm install jest @jest/globals @types/jest supertest --save-dev

200+ tests exist currently for models, utils, validators and workflows (integration tests) - see tests.
Run tests on local device by including setup for dotenv/config to provide environment variables:

set NODE_MODE=staging && jest --setupFiles dotenv/config

or simply save as script command in package.json to run npm test:

  "scripts": {
    "start": "node server.js",
    "test": "set NODE_MODE=staging && jest --setupFiles dotenv/config"
  }

To automatically check tests before merging feature/development branch further up, a GitHub Action is set up, see main.yml.
Preventing an unwanted merge with unfinished/failed test run, the project is set up to disable merging until all tests have passed (see Figure 9).

 no picture found Figure 9, v1.3.1

$\textsf{\color{teal}Angular ESLint}$

Added angular-eslint to project for next step of testing.
Install ESLint global via node package manager:

$ npm install -g eslint

Install ESLint local for angular project:

$ ng add @angular-eslint/schematics

Run ESLint to list all current lint errors:

$ npm run lint

Cross-browser testing

Firefox Chrome Opera Edge DuckGo Brave
Yes* Yes Yes Yes Yes Yes

*This browser has problems with some loading/processing.


Updates

list of all updates

$\textsf{last\ update\ 1.5.10\ &gt;&gt;\ {\color{pink}1.6.1}}$

  • $\textsf{\color{green}Change:}$ Added staging environment to test software outside of local environment before shipping as ready-to-use software.
  • $\textsf{\color{red}Patch:}$ Updated calculations on services 'destination' to adapt discount-by-distance.

Aimed objectives for next $\textsf{\color{green}minor}$ update:

- update email format
- update token handling (refresh token)
- update logging & exception handling (client side)
- add testing (frontend)