Accedo Assemble Web
For a detailed overview of Assemble across platforms please visit Assemble Confluence Page
What is Assemble
The solution is the combination of all the software and services required to deliver an OTT video service. The solution
- is an end-to-end blueprint for video service providers in Media & Entertainment.
- has been designed to support service providers looking to outsource the technology and the operation of their existing or planned OTT video service.
- includes all people, processes and tools involved in the operation and evolution of the service.
Getting Started
Project Setup
Prerequisites
Assemble Web uses pnpm as dependency manager, if you want to use another alternative, please go to package.json file and update the packageManager value.
For more information, please visit official node section about packageManager.
We use nvm to select proper node version.
Install dependencies and run app
# First, install nvm, the node version used in this project is defined in the .nvmrc file.
nvm use
corepack enable pnpm
pnpm i
# Run the development server
pnpm dev
dev server watch
Sometimes .next folder with cached build chunks, and missing dependencies can cause issues when changing branch. .next folder is automatically removed when dev server is started, but pnpm dev needs to be restarted manually. use pnpm dev:watch to start dev server and automatically install dependencies and restart dev server when branch changes.
Debug the application
Building locally
- New relic secret values are injected when building on github. These are required for the build to complete. When building locally the same values need to be available, or set environment variable
ENABLE_NEW_RELIC=false. - If build fails on github but works locally, one issue can be filename casing - build environment on github is case sensitive, but local environment may not be. git will also not always recognize file name changes when only the casing is changed, so file name changes may not have been committed as expected.
Using Assemble Web as a template for your repo
If you are using Assemble Web as a template to create your own updated version of Assemble Web, there are some things you need to take into account:
- Please read our Assemble Control Setup instructions and ensure that those are followed
- Create your set of repository variables and secrets
- [Optional] Create an
.envfile for any custom environment variable. Please, review Our environments variable type definition to understand which one are needed.
Variables:
NAMESPACEPREFIXPrefix to be used as part of the deployment process for the name and url of such deployment. Please Sync with the DevOps team for the associated deployments as that will be used for the CI/CD.APP_DOMAIN: Application base domain (apps.ps.accedo.tv). Please Sync with the DevOps team for the associated deploymentsCI_APPNAME: Next Application appname to be used in the deployment process and hostDOC_APPNAME: Doc Application appname to be used in the deployment process and hostSTORYBOOK_APPNAME: Storybook Application appname to be used in the deployment process and hostAWS_CLUSTERNAME: Cluster name for the deployment. Please Sync with the DevOps to understand the value you should use here.AWS_REGION: AWS region to be used by default on the deployments. Please Sync with the DevOps to understand the value you should use here.TESTRAIL_PROJECTID: TestRail Project IDTESTRAIL_SUITEID: TestRail Suite IDTESTRAIL_TITLE: TestRail Run base titleTESTRAIL_URL: TestRail Base URLNEW_RELIC_APP_NAME_VAR: New Relic Application name. Please ask your Architect/PM for a project specific value.NEW_RELIC_APP_NAME_PROD: New Relic Prod Account Application name. Please ask your Architect/PM for a project specific value.
Note: We also use DEMO1_APPNAME and DEMO1_APPNAME for our internal demo purposes, but you won't need those.
Secrets:
AWSARN: AWS Amazon Resource Name to be used in the deployments. Please Sync with the DevOps to understand the value you should use here.FIGMA_TOKEN: Figma API Token to be used to be able to fetch the Design Tokens from your the Figma files associated with the project. Please avoid using personal token and use a "corporate" one instead.NEW_RELIC_LICENSE_KEY_NEW: New Relic license key. Please ask your Architect/PM for a project specific value.NEW_RELIC_LICENSE_KEY_PROD: New Relic Prod account license key. Please ask your Architect/PM for a project specific value.NPM_RESOLVER: npm token to be used to fetch the@accedoand similar private dependencies from the npm registry. Please avoid using personal token and use a "corporate" one instead.SLACK_WEBHOOK: Slack Application webhook token. Please Sync with the DevOps/IT to understand the value you should use here.SONAR_TOKEN_CI: SonarCloud access token to allow the CI to report to Sonar. Please Sync with the DevOps/IT to understand the value you should use here.TESTRAIL_KEY: TestRail User apiKeyTESTRAIL_PROJECT: TestRail Project NameTESTRAIL_USER: TestRail user emailE2E_EMAIL: Application username to be used on the e2e testsE2E_PASSWORD: Application password to be used on the e2e tests
NPM Scripts
Project App Structure
Assemble Web is a Next.js based application, so some conventions are based on the conventions defined in the framework itself, we recommend you to read at least App Routing Conventions
Component Structure
We are following a Component structure based on two concepts:
- Complexity-based: reusable components that can be used across any page/template, with a separation in two:
- simple: stateless, very reusable components
- complex: Usually composed from other simple components and can have state
- Feature-based: every complex component, that is not going to be reusable, but just part of an specific feature (EPG, Auth, Player, ...)
Besides that, we need to take into account that Pages/views and partially, any possible route-based template will be created under the app folder following the App Routing Conventions from Next.js
The reason to keep this structure and not a pure Atom-based model is to avoid having all the components under the components folder, making very hard to traverse and look for the proper component, but limit it with the feature-based list of components and then simplify the 3-4 other layers (pages/views should be always under the app folder due to Next.js) into 2 at least initially to have a clear separation for the atomic, non-composed ones (and also stateless) from the others.
General Structure
📂 docs ───────> project documentation
📂 public ───────> web static assets
📂 scripts ───────> general scripts used locally
📂 src ───────> source dir
├─ 📂 app ───────> next.js routes
│ └─ 📂 [[...routeSegments]] ───────> Single dynamic route page (more on the next section)
│ └─ 📄 layout ───────> default page layout
│ ...
├─ 📂 components ───────> Complexity-based Components folder
│ └─ 📂 simple ───────> Simple Components (Reels components or not composed and without state)
│ └─ 📂 base ───────> Reels Components (Component from the Component library based on PD&A Reels)
│ └─ 📂 complex ───────> Complex Components (composed from simple components or with state)
├─ 📂 config ───────> Application configuration
├─ 📂 context ───────> App global React contexts
├─ 📂 dataModels ───────> Any app data model
├─ 📂 dataTypes ───────> Data types generated from api documentation
├─ 📂 dev-utils ───────> Utilities used for development purposes
├─ 📂 features ───────> Feature-based Components folder
│ └─ 📂 ... ───────> A per feature folder, it will include all the needed code outside of the Data Fetching related one
├─ 📂 hooks ───────> App hooks, use for common shared utilities fns and Service access
├─ 📂 stores ───────> Global state management using Zustand, for shared application state
├─ 📂 providers ───────> App Providers (as per the Assemble Service Architecture)
├─ 📂 services ───────> App Services (as per the Assemble Service Architecture)
├─ 📂 types ───────> Typescript type utilities and global types
├─ 📂 utils ───────> Global utils
├─ 📂 views ───────> Application dynamic views (mapped from [[...routeSegments]]) and mapper
📄 .env ───────> environment variables
📄 next-env.d.ts ───────> next.js type defs
📄 next.config.js ───────> next.js config
📄 package.json ───────> project readme
📄 [other configs] ───────> Any other config file
Assemble Routes Mapping
Project Documentation
General Documentation
Documentation for Assemble Web is created using Docusaurus inside the docs folder. There's a separate "project" inside that folder with its own npm project structure and so on.
The initial page uses this README.md file to create and display its content
To access documentation:
cd docs
pnpm start
To create documentation build:
cd docs
pnpm run build
pnpm run serve
If you need to add any extra Documentation, please add a new entry into docs/docs
You can use the helper command from the root of the repository to access the documentation:
pnpm run docs
Diagrams
Assemble uses mermaid for the diagrams which integrates directly with Github and with an integration with Docusaurus
Components
Data types
Data types for interacting with backend are imported directly from swagger documentation using pnpm run sync-data-types.
Code rules
Code and CSS Style Guidelines
We are using eslint, prettier and stylelint to define the project code style and ensure that everyone follows the same rules.
We enforce the usage of typescript as default language to ensure better type check and remove possible situations/issues.
typed-css-modules is used to enforce typing for css modules so only existing module classes can be used in typescript files. pnpm generate-css-types task can be run alone and will generate type files for all css modules, but types need to be generated for build and for type validation and continuosly during development, so this has been setup to run automatically.
Please refer to the .eslintrc.json and .stylelintrc.json to see the specific configuration we use for each tool.
You can also read the Next.js Docs about the default eslint config.
- Do not disable linting rules in code unless there is no other option. if a rule is disabled then a comment describing why must always be included.
App Styling
Assemble Web uses CSS Modules together with Design tokens to create the styles for the applications and components.
Style entry point file is globals.css and it includes all the Design System tokens from variables.css.
Custom pages/layout styles, component styles or features styles should be included in its own folder and use Design System tokens when possible.
Font Family is not used based on the Design tokens variables but using next/font/google instead as it's the standard way of working on Next.js
Font styles
Manually defining font styles in each instance should be avoided. Instead, implement the font styles defined in Figma in fontStyles.module.css so they can be reused wherever needed, like
.className {
composes: body-small-regular-sm from '@/app/fontStyles.module.css';
}
Refer to how this is implemented in the existing styles. If a font style is missing from fontStyles.module.css, add it there before using it.
See fontStyles.module.css for more details.
Spelling
cspell is used to ensure spelling in code and documentation. cspell will only capture spelling mistakes, not grammar mistakes. Spellcheck is run automatically when committing files.
cspall may report false positives, so whitelisted words are maintained in cspell.json -
- words - any word to add as a valid word, may be suggested as correction
- ignoreWords - words to exclude from spellcheck and ignore, will not be suggested as a correction
use /* cspell:disable-next-line -- [explanation] */ in file for false positives, for example picking up "Fmovies" as a spelling mistake in "redirectTo=%2Fmovies", or // cspell:ignore lcov at top of file if the false positives appear multiple times in the file.
Testing
We use jest, testing-library, storybook and playwright for the Automatic testing of the application.
jestis used as test runner and assertion librarytesting-libraryis used for the component and component interaction library on the simple cases.storybookis used for the component interaction test for more detailed casesplaywrightis used for end to end testing.
Running tests locally
playwright
pnpm run e2e:e2e is used for ci validation on github.
- start dev server
pnpm run dev - set
E2E_EMAILandE2E_PASSWORDin .env.test.local file in project root pnpm run e2e:e2e
some tests may fail locally unless the same credentials configured on github are used.
- playwright tests will default to using 1 worker/thread when running on github.
- set
E2E_WORKERSin .env.test.local to do parallel testing and speed up the tests when running locally.
set as a fixed number likeE2E_WORKERS=5, or a percentage likeE2E_WORKERS=70%. higher values will run the tests faster when possible, but can also slow down the computer when doing other things while the tests are running.
- set
E2E_TIMEOUTcan also be set in .env.test.local if tests are timing out
debugging
pnpm run e2e:ui is used for local development or debugging. It helps focus on specific tests instead of running the entire suite. With this command, the user can run individual E2E tests interactively, filter and re-run tests quickly, and view test results, logs, and traces in a visual interface.
GitFlow and Related Rules
Branching and Code Reviews
We have a main branch main and usually we work toward that branch every time, we don't use long-live branches, develop branch or any other alternative. Our philosophy is to Ship as fast as possible into the main branch and use the Setup validations to ensure everything works as expected.
We follow a Ship/Show/Ask approach where:
- We Ship directly into
mainbranch anything that doesn't require any validation or it's totally straightforward. - We Show creating a PR into
mainwith the tag[SHOW]to create a PR that doesn't require manual validation, but that can benefit from it or has something that can be interesting to show to peers. Automatic validations will help to avoid merging an invalid PR. - We Ask creating a PR that requires manual validation for any peer/contributor to ensure a pattern is properly implemented or there's no mistake in the implementation (apart from the automatic validations)
For all the cases, there's a PR template for Github located in .github/pull_request_template.md
Branch Naming conventions
We use short-lived feature branches to handle features work, and bugfix branches for any fix needed.
The prefixes for those are: feat and fix and the general naming convention for the branches will be:
{type}/BUILDELEVATE-XXXX_description-name: for ticket related branches{type}/description-name: for non-ticket related branches
Github Actions
Validations
We have separate Github actions created to do all the actions related to a change for every PR (creation, change) and main push that will execute (pr.yml and main.yml):
Then we have split the workflows into validations (validations.yml) and deployments.
The validations will run:
- All the code validations (linters and tsc)
- Unit and component test validation with code coverage report
- Component Accessibility Validation using Storybook
- Danger Pull request analysis
- Sonar Analysis with report to SonarCloud, including the test coverage from the test report and the automatic generation of sonar properties from template
After all the static validations, the main workflows will trigger the CI/CD workflows if the conditions for the trigger checks are met (ie: we wouldn't trigger from pr.yml the deployment if the trigger was an edited event.action as it will not include code changes)
CI/CD
We have three separate Github actions created for each of the deploy types as workflow_call:
- Nextjs Application deployment on
Build-&-Deploy_webci-assemble.yml - Documentation deployment on
Build-&-Deploy_doc-assemble-web.yml - Component Documentation deployment on
Build-&-Deploy_storybook-assemble-web.yml
This process will deploy corresponding application/static site following the rules:
https://elevateweb-ci.apps.ps.accedo.tvfor the Nextjs App onmainbranchhttps://elevateweb-ci-{N}.apps.ps.accedo.tvfor the Nextjs App on a PR with numberNon Githubhttps://elevateweb-doc.apps.ps.accedo.tvfor the General Documentation onmainbranchhttps://elevateweb-doc-{N}.apps.ps.accedo.tvfor the General Documentation on a PR with numberNon Githubhttps://elevateweb-storybook.apps.ps.accedo.tvfor the Component Documentation onmainbranchhttps://elevateweb-storybook-{N}.apps.ps.accedo.tvfor the Component Documentation on a PR with numberNon Github
Note: PR related deployments will only be triggered if the following labels are included in the PR:
Assemblefor App deploymentstorybookfor component Documentation deploymentdocusaurusfor Documentation deploymente2efor e2e validations (it also requiresAssembleone as it trigger over the App deployment)