Accedo Build Elevate Web
For a detailed overview of Elevate across platforms please visit Build Elevate Confluence Page
What is Elevate
An advanced application starting point that jump-starts the development process with user flows, page templates, UI components populated with content, and base integrations ready for customization.
Getting Started
Project Setup
Prerequisites
Elevate 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 Elevate Web as a template for your repo
If you are using Elevate Web as a template to create your own updated version of Elevate Web, there are some things you need to take into account:
- Please read our Elevate 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
Elevate 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 Elevate Service Architecture)
├─ 📂 services ───────> App Services (as per the Elevate 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
Elevate Routes Mapping
Project Documentation
General Documentation
Documentation for Elevate 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
Elevate 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
Elevate 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-elevate.yml - Documentation deployment on
Build-&-Deploy_doc-elevate-web.yml - Component Documentation deployment on
Build-&-Deploy_storybook-elevate-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:
Elevatefor App deploymentstorybookfor component Documentation deploymentdocusaurusfor Documentation deploymente2efor e2e validations (it also requiresElevateone as it trigger over the App deployment)
Danger PR Analysis
We use Danger to do some automatic validations of the "quality" of the Pull request and also to report back into the Pull Request based on the base branch and the Status of the Pull Request.
You can find the specific code in the Dangerfile file.
Commit messages guide
We enforce the usage of conventional commits to create explicit commit messages.
We use commitlint with @commitlint/config-conventional and husky to ensure that the commits follow the proper messages. Please don't skip hooks
Versioning and Releases
Together with the Commit rules, we do automatic versioning based on the rules applied on conventional commits following Semantic Versioning
For the releases, we use Semantic Release with it's own Github Action to define a Workflow to ensure every merge into main creates its own separate Elevate Web version.
You can see how is configured in:
- Workflow:
.github/workflows/release.yml - Semantic Release Config:
.releaserc.json
It is in charge of the following:
- Determine the version to create based on the commits since the previous tag based on the commitlint conventions
- Execute the version change using
@semantic-release/execand set-version - Generate Changelog for both Github Release and CHANGELOG.md file
- Create and push tag with the proper name/version
- Create Github Release with the proper name/version
Initially we create prereleases with the dev tags. This will be changed once we release the first final version of Elevate Web.
Creating Releases
A Release is created based on agreement between:
- The Global Blueprint Solution Owner (Carl Francis)
- The Blueprint Web Leader (Cesar de la Cruz)
- [Optional] The QA team (Oscar Castro is currently leading the team).
The agreement should include a list of desired Tickets that should be includes in the ticket Fix Version field once Jira Releases process is done.
Communication and dependencies
The Global Blueprint Solution Owner (Carl Francis) will be the person in charge of the communication about timeline on releases and will be the main point of contact (via #solution-team-framework ) to handle any problem with the release, dependencies that may or may not be satisfied or that may block the release.
Releasing a new version
There are two stages to making a new release
-
Anything that is merged to main branch will be automatically deployed as a new version. When preparing a new release and everything needed for the release has been merged to main branch then this version can be shared with qa for validation.
-
Once a release is approved by qa and project lead, a demo release can be created with approved version.
Create a QA Release
Releases to QA are created using the existing CI environment: https://elevateweb-ci.apps.ps.accedo.tv/
There are two typical QA release scenarios:
- First release, with all the new features for a defined release
- Future Release candidates, following a first release, to solve any relevant issue identified by the QA team or any other team member.
JIRA Releases
Jira releases are defined in https://accedobroadband.jira.com/projects/BUILDELEVATE?selectedItem=com.atlassian.jira.jira-projects-plugin%3Arelease-page
Those releases are created manually once a release is agreed by the Web Lead (but it can be done by any member of the team in the Lead absence).
For the first scenario, a JIRA release is planned ahead and created with a planned release date based on the team agreement with the format {{DATE}}+WEB-{{RELEASENAME}} as an example 2025.07+WEB-SUBSCRIPTIONS.
For the second scenario, a JIRA release is also needed, which usually include a small number of tickets based on what's agreed to be solved based on severity and priorities with the format {{DATE}}+WEB-{{RELEASENAME}}-rc{{N}} as an example 2025.07+WEB-SUBSCRIPTIONS-rc2.
Branches
Depending on the repo conditions and the status of the QA validation it may be beneficial to create a branch to handle a QA release so we can integrate different changes and avoid merge conflicts later on.
For such purpose a branch with the name releases/{{name}}{{version}} as releases/subscription-rc3 needs to be created.
Later on, these branches will be integrated into the main branch when we want to integrate the release into the CI environment.
Communication
Once a QA release is finished and the updated code is ready in https://elevateweb-ci.apps.ps.accedo.tv/ we need to update the teams in:
Release message template:
{{SubscriptionName}} Release {{Number}} for Web has been deployed :rocket: into https://elevateweb-ci.apps.ps.accedo.tv/
When the QA team finish their QA process they will let us know, usually adding an message in the thread of the release, followed by a report via email with a link to the report in confluence.
If there is any critical issue that needs to be solved we need to continue with a new QA Release. If there is no critical issue, we can move on into a Demo Release.
Create a Demo Release
If there's no major defect (QA gives its approval) and after confirmation from the Blueprint Solution Owner (Carl Francis) a Demo release should be created, to put all the changes into the Demo deployments (https://elevateweb-demo1.apps.ps.accedo.tv/ and https://elevateweb-demo2.apps.ps.accedo.tv/)
An explanation of the Demo release process is included as a video record in https://accedo.slack.com/archives/C06E6Q1G4J0/p1752497838829649?thread_ts=1752495176.491309&cid=C06E6Q1G4J0
Basically we need to:
Create Demo 1
- Open Blueprint Web repo
- Click on the
ActionsTab - Click on the
Demo One - Sync Tokens and DeployPinned item - Click on
Run workflowbutton - Ensure that data is correct based on the requirement of the version, by default it should be:
mainbranch and gitref,VlA6PPZ4nowmchevArz8jp,kcaiPKFPoGMOp8mV3AUIbDfile Key and6870d7eba0e84500181e3065appKey. The values of the optional fields shouldn't be updated.
Create Demo 2
After Creating Demo 1:
- Click on the
Demo Two - Sync Tokens and DeployPinned item - Click on
Run workflowbutton - Ensure that data is correct based on the requirement of the version, by default it should be:
mainbranch and gitref,EC2bD87xQhPARPJ7pppYRU,GHEixiF8UpJkw0nGk0wAfEfile Key and6870d7eba0e84500181e3065appKey. The values of the optional fields shouldn't be updated.
JIRA Release update
Once a Demo release is finished and the update code is ready in https://elevateweb-demo1.apps.ps.accedo.tv/ and https://elevateweb-demo2.apps.ps.accedo.tv/ we need to update the JIRA release to:
- Mark it as released
- Update the release name to include the app version (ie: adding (1.0.0-dev.128))
Communication
After the update release process is done we need to update the teams in:
Release message template:
{{SubscriptionName}} Release {{Number}} for Web has been deployed :rocket: into
- https://elevateweb-demo1.apps.ps.accedo.tv/
- https://elevateweb-demo2.apps.ps.accedo.tv/
Release notes: `{{releasesNotesFromJIRA}}`
Where {{releasesNotesFromJIRA}} is the main release version from Jira Releases
Rollback
In case a rollback is needed due to any detected blocker issue after the release, we just need to repeat the steps on Create demo 1 and Create demo 2 with the previous executed git ref commit hash and git ref.