This repo is the home for the My Career NJ web app (mycareer.nj.gov), a one-stop shop for New Jerseyans seeking to explore training programs, in-demand career insights, and data-driven career advice custom-tailored to users’ experiences. Note that this repository does not yet include Career Navigator.
- The frontend is written in Typescript, a single page app built with React using the
create-react-app
setup. - The backend is written in Typescript, with an Express-based server API.
- The databases include multiple PostgreSQL tables (which are imported from raw CSV files stored in
backend/data
directory). For more information on the tables, see thedata_model
guide. - The entire app is deployed to production Amazon Web Services (AWS) instances in a Node 18 environment. We use CircleCI for continuous integration/deployment.
decision_log
lists architectural decisions and their rationaledata_model
lists data tables and columnsdb_migration_guide
gives steps on how to update our databasesetpl_table_seed_guide
gives steps on how to specifically update the ETPL database
After cloning this repo, run through the following steps to run the app locally.
If you are using a newer Mac (Apple Silicon), you will likely need to install jq. Run brew install jq
or install a pre-built
binary here.
./scripts/install-all.sh
-
If not already installed, install postgres
-
Create postgres database on your local machine:
psql -c 'create database d4adlocal;' -U postgres
- Run database migrations from
d4ad
directory:
./scripts/db-migrate.sh
Note: If you get a key error when running the script, make sure that you have the correct DB password for the user
postgres
updated in the code. It assumes the password is an empty string, but it will be what you entered when you initially set up thepostgres
user after installation. You need to update it indatabase.json
and the fall-back value inapp.ts
.
In one terminal window, start backend dev server:
./scripts/backend-start.sh
In another window, start frontend dev server. It should automatically open up localhost:3000
in your browser.
./scripts/frontend-start.sh
Always push via ship-it (why?)
./scripts/ship-it.sh
We use circleci for CI/CD and deploy both the user research environment to Google Cloud Platform (GCP) environments. Pipelines for AWS prod, test, dev incoming. Our pipeline is:
npm install
(frontend and backend)- run all unit tests (frontend and backend)
- build code and run feature tests
- deploy to GCP User Research2 environment (reach out to developer for URL or look in D4AD User Research 2 App Engine settings)
- Manual approval step - go to CircleCI build and "prod-approval" step, and click "Approve" button.
- deploy to GCP User Research2 environment
TBD
This will likely change as features are rolled out.
REACT_APP_FEATURE_MULTILANG
- Enable/disable multi-language support in the React app.REACT_APP_FEATURE_CAREER_PATHWAYS
- Toggle the display of career pathways feature as well as any reference to it.REACT_APP_FEATURE_CAREER_NAVIGATOR
- Toggle the display of the Career Navigator landing page as well as any references to it.REACT_APP_FEATURE_PINPOINT
- Show or hide any instance of the Pinpoint email collection tool.
Dev, QA, and production databases are hosted in AWS as SQL instances running PostgreSQL.
DB_DEV_PASS
- Password forpostgres
user in dev environment
Dev and prod environments use a CareerOneStop account owned by NJ Office of Innovation.
CAREER_ONESTOP_USERID
- account username used both in dev and prodCAREER_ONESTOP_AUTH_TOKEN
- account auth token used both in dev and prod
ONET_BASEURL
- O*NET account base URL (dev + prod)ONET_USERNAME
- O*NET account username (dev + prod)ONET_PASSWORD
- O*NET account password (dev + prod)
BASE_URL
- Typicallyhttps://graphql.contentful.com
ENVIRONMENT
-master
, unless you have multiple environmentsSPACE_ID
- Your project's unique space ID
SENTRY_DSN
- Sentry Data Source Name (DSN)
IS_CI
- boolean flag for whether environment is deployed using continuous integrationNO_COLOR
ZIPCODE_BASEURL
ZIPCODE_API_KEY
Generally, developers won't have to do this - we have automated deploys to dev and prod via circleci.
Build frontend, build backend, compile all into one directory:
./scripts/build.sh
Start the production server (frontend & backend):
./scripts/prod-start.sh
Use these two scripts below in order to run our normal testing flows, which include:
- Formatting with Prettier
- Linting with ESLint
- Unit tests with Jest and React Testing Library
- End to end tests with Cypress
To run all jest tests, and linting:
./scripts/test-all.sh
To run cypress feature tests:
./scripts/feature-tests.sh
- UI Components: We use a combination of Material UI React components and modular CSS from the New Jersey Web Design System, which is a customized version of the U.S. Web Design System.
- Internationalization (i18n): We use the i18next library to implement the logic of storing English and Spanish content and switching between the two on the client-side. All the content is stored in JSON files in
frontend/src/locales
. - Routing: We add client-side routing to this single page app using the Reach Router library, similar to the more common React Router.
- User engagement: We track user engagement using Google Analytics, including pageviews and specific event-based interactions that we implement manually in different parts of the app, such as tracking what filters a user clicks on the training search page. Please request access from the NJ Office of Innovation in order to view our analytics dashboards.
- Accessibility: We have automated a11y tests that run as part of our Cypress feature tests using the
cypress-axe
package. We also use tools such as axe DevTools and WAVE Chrome extensions to do manual checks. - Data APIs: We fetch data from the following Web APIs: O*NET Web API, CareerOneStop. To access API keys to set as environment variables, request access for the NJInnovation Bitwarden account, and see the "Training Explorer Secrets" file in it.
- SDKs - We use AWS SDK for JavaScript for Node.js to collect user email address signups and retrieve secrets on the back-end.
This repo uses good-fences to enforce module boundaries.
Most importantly, the backend
and frontend
cannot import from each other.
Additionally, fences are used in the backend subdirectories to enforce dependency inversion.
The routes
and database
folders depend on the interfaces defined in domain
(only - not on each other), and domain
is not allowed to
import from any of these implementation directories.
Fences are enforced via a linting-like command that will fail when any violations are flagged:
npm --prefix=backend run fences
npm --prefix=frontend run fences