Record Web
For project tracking visit the Record Jira Board
What is Record Web
Record Web is an OTT video streaming web application built on the Accedo Assemble blueprint. It delivers a full end-to-end video service including content browsing, playback, authentication, profiles, and subscription management.
Getting Started
Project Setup
Prerequisites
Record 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
Before installing dependencies, you will need to have a valid npm config for the @accedo scoped packages. Follow the instruction in https://accedobroadband.jira.com/wiki/spaces/BW/pages/168100346/How+to+Access+the+Accedo+Build+Web+npm+Modules#Setup-Accedo-Artifactory-with-scoped-packages to configure your npm using the required scoped packages.
Note: A SESSION_KEY environment variable is required in order to handle the session, so before anything, run:
openssl rand -hex 64
and paste it as SESSION_KEY=<your-generated-key> into your .env.local file
# 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.
Repository Variables and Secrets
Create your repository variables and secrets in GitHub. Review Our environments variable type definition for runtime variables.
Variables:
CI_APPNAME_RECORD: Next.js application appname used in deployment and hostDOC_APPNAME_RECORD: Documentation appname used in deployment and hostSTORYBOOK_APPNAME_RECORD: Storybook appname used in deployment and hostAWS_REGION: AWS region for deployments. Sync with DevOps.NEW_RELIC_APP_NAME_DEV: New Relic application name (dev). Ask your Architect/PM.NEW_RELIC_APP_NAME_PROD: New Relic application name (prod). Ask your Architect/PM.
Environment-based variables:
AWSARN_RECORD: AWS Amazon Resource Name Account Id. Sync with DevOps.APP_DOMAIN: Application base domain. Sync with DevOps.AWS_CLUSTERNAME_RECORD: Cluster name for the deployment. Sync with DevOps.UNIFIED_API_BASEURL: Base URL of the Unified CMS+Config →NEXT_PUBLIC_UNIFIED_API_BASE_URLOVP_BASEURL: Base URL of the OVP API →NEXT_PUBLIC_OVP_BASE_URLIDP_BASEURL: Base URL of the IDP API →NEXT_PUBLIC_IDP_BASE_URLPROFILE_BASEURL: Base URL of the Profile API →NEXT_PUBLIC_PROFILE_BASE_URLSUBSCRIPTION_BASEURL: Base URL of the Subscription API →NEXT_PUBLIC_SUBSCRIPTION_BASE_URLPLAYBACK_BASEURL: Base URL of the Playback API →NEXT_PUBLIC_PLAYBACK_BASE_URLEPG_BASEURL: Base URL of the EPG API →NEXT_PUBLIC_EPG_BASE_URL
Secrets:
FIGMA_TOKEN: Figma API Token to fetch Design Tokens. Use a corporate token, not personal.NPM_RESOLVER: npm token for@accedoprivate packages. Use a corporate token, not personal.SLACK_WEBHOOK: Slack webhook token. Sync with DevOps/IT.SONAR_TOKEN: SonarCloud access token. Sync with DevOps/IT.
Environment-based Secrets:
NEW_RELIC_LICENSE_KEY: New Relic license key. Ask your Architect/PM. One per environment.UNIFIED_API_KEY: API key for the Unified CMS+Config service.
NPM Scripts
Project App Structure
Record 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
Inside this repo, 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 (Not composed and without state or non-migrated/In progress/on a Figma branch Reels components)
│ └─ 📂 base ───────> Reels Components (Component from the Component library based on PD&A Reels) non-migrated/In progress/on a Figma branch
│ └─ 📂 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 Service Architecture)
├─ 📂 services ───────> App Services (as per the 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
Routes Mapping
Project Documentation
General Documentation
Documentation for Record 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
Record Web uses mermaid for the diagrams which integrates directly with Github and with an integration with Docusaurus
CI/CD Workflows
Record Web uses GitHub Actions for continuous integration and deployment. The workflow architecture is designed for maintainability, reusability, and proper environment management with approval gates.
Workflow Architecture
The CI/CD system is built around a unified orchestrator pattern with specialized reusable workflows:
primary.yml (orchestrator)
├── setup → determines environment, PR context, deployment decisions
├── validations → lint, type-check, tests
├── update-pr → PR decoration with deployment URLs
├── cleanup → delete namespace (PR close only)
├── release → semantic versioning + version output (develop/staging/main only)
├── deploy-ci → Build & deploy main app (uses release version)
├── deploy-doc → Build & deploy documentation
└── deploy-storybook → Build & deploy Storybook
Primary Workflow (.github/workflows/primary.yml)
Triggers:
- Pull request events:
opened,synchronize,reopened,ready_for_review,edited,labeled,closed - Push to branches:
main,staging,develop
Purpose: Single entry point that orchestrates all CI/CD operations based on event type and context.
How it works:
-
Setup Job - Analyzes the event context and sets outputs for all downstream jobs:
- Determines environment (
prod,uat, ordev) based on branch - Extracts PR number if applicable
- Sets boolean flags:
is_pr,is_pr_closed,should_deploy,should_cleanup,should_release
- Determines environment (
-
Conditional Execution - All downstream jobs use setup outputs to decide whether to run:
if: needs.setup.outputs.should_deploy == 'true' -
Concurrency Control - Prevents duplicate runs:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: false
Use Cases:
- PR Workflow: Opens PR → triggers validations + deployments to
dev-{appname}-{PR#}namespace - Branch Workflow: Push to
develop→ creates release + deploys to dev environment - Staging Release: Push to
staging→ creates release candidate + deploys to uat - Production Release: Push to
main→ creates release + deploys to prod (requires approval) - PR Cleanup: Close PR → deletes namespace and resources
Validation Workflows
Validate Workflow (.github/workflows/validate.yml)
Type: Reusable workflow (workflow_call)
Purpose: Runs all code quality checks before deployment.
Jobs:
- ESLint validation
- TypeScript type checking
- Prettier formatting check
- CSS linting
- Spell checking
- Unit tests with coverage reporting
- SonarCloud analysis
Use Cases:
- Runs on every PR to ensure code quality
- Gates deployment - must pass before deploy jobs run
- Provides early feedback on code issues
Deployment Workflows
Build & Deploy Workflows
Build-&-Deploy_webci-record.yml- Main applicationBuild-&-Deploy_doc-record-web.yml- Documentation siteBuild-&-Deploy_storybook-record-web.yml- Storybook component library
Type: Reusable workflows
Purpose: Build Docker images and deploy to Kubernetes/ECS.
How they work:
- Checkout code
- Configure AWS credentials
- Build and push Docker image to ECR
- Deploy to Kubernetes using Helm
- Send Slack notification with deployment status
Namespace Convention:
- PRs:
{NAMESPACE}-{PR_NUMBER}(e.g.,dev-record-web-12) - Branches:
{NAMESPACE}(e.g.,dev-record-web,uat-record-web,prod-record-web)
Use Cases:
- PR deployments for testing
- Staging deployments to UAT
- Production deployments
- Multiple isolated environments per PR
Cleanup Workflow (.github/workflows/cleanup.yml)
Type: Reusable workflow
Triggers: PR close events (called from primary workflow)
Purpose: Delete namespace and resources when PR is closed/merged.
How it works:
- Receives PR number and environment as inputs
- Configures AWS credentials
- Deletes Kubernetes namespace:
{namespace}-{PR_NUMBER} - Removes all associated resources
- Sends Slack notification
Use Cases:
- Automatic cleanup on PR merge
- Cost optimization - removes unused environments
- Prevents namespace accumulation
Release Workflow (.github/workflows/release.yml)
Type: Reusable workflow
Triggers: Push to develop, staging, or main
Purpose: Create GitHub releases with semantic versioning and expose the version to downstream deploy jobs.
How it works:
- Analyzes commit messages for version bumps (conventional commits)
- Generates changelog from commits
- Creates GitHub release with tag
- Publishes release notes
- Outputs
version— consumed by deploy jobs to setNEXT_PUBLIC_APP_VERSIONat build time
Version format per environment:
develop/ PR:0.0.0-pr.{PR_NUMBER}(PRs) or pre-release tag (develop push)staging: release candidate (e.g.0.1.0-rc.1)main/ prod: clean semver (e.g.0.1.0)
Use Cases:
- Automated versioning across all environments
- Version visible in the app's Settings page
- Changelog generation
- Release tracking
GitHub Environments & Approval Gates
Record Web leverages GitHub Environments to provide deployment control, security, and reusability.
Environment Configuration
Three environments configured:
-
dev- Development environment- No restrictions
- Automatic deployments
- Used for PR previews and develop branch
-
uat- User Acceptance Testing- Optional: Can require approval from QA team
- Used for staging branch
- Pre-production validation
-
prod- Production environment- Requires approval from designated reviewers
- Branch protection: Only
mainbranch can deploy - Production-grade resources
- Audit logging enabled
How Environments Enable Reusability
1. Environment-Specific Secrets & Variables
Each environment has its own set of secrets/variables accessed automatically:
jobs:
deploy:
environment: ${{ inputs.environment }} # 'dev', 'uat', or 'prod'
steps:
- name: Deploy
env:
AWS_ARN: ${{ secrets.AWSARN }} # Automatically uses dev/uat/prod ARN
APP_DOMAIN: ${{ vars.APP_DOMAIN }} # Automatically uses dev/uat/prod domain
Example Variables per Environment:
AWSARN_RECORD(per env)APP_DOMAIN(per env)AWS_CLUSTERNAME_RECORD(per env)NEW_RELIC_LICENSE_KEY(per env)
2. Single Workflow for Multiple Environments
The same Build-&-Deploy_webci-record.yml workflow deploys to dev, uat, and prod:
# Primary workflow calls deployment
deploy-ci:
uses: ./.github/workflows/Build-&-Deploy_webci-record.yml
with:
environment: ${{ needs.setup.outputs.environment }} # Dynamic!
pr_number: ${{ needs.setup.outputs.pr_number }}
secrets: inherit
Benefits:
- No workflow duplication
- Consistent deployment process across environments
- Single source of truth for deployment logic
- Easier maintenance and updates
Approval Gates for Production
How it works:
-
Deployment Request
- When primary workflow targets
prodenvironment - GitHub pauses the workflow execution
- Sends notification to configured reviewers
- When primary workflow targets
-
Review Process
- Reviewers see deployment request in GitHub UI
- Can view all deployment details (commit, changes, previous runs)
- Must explicitly approve or reject
-
Deployment Execution
- On approval → workflow continues to production
- On rejection → workflow stops, deployment prevented
- All actions logged for audit trail
Configuration Example (GitHub UI):
Environment: prod
├── Required reviewers: @devops-team, @tech-lead
├── Wait timer: 0 minutes
├── Deployment branches: main only
└── Environment secrets:
├── AWSARN_RECORD
├── NEW_RELIC_LICENSE_KEY
└── ...
Real-World Flow:
Developer pushes to main branch
↓
Primary workflow triggers
↓
Setup job determines environment = 'prod'
↓
Validation jobs run (lint, test, etc.)
↓
Deploy job requests 'prod' environment
↓
⏸️ WORKFLOW PAUSES - Approval Required
↓
Reviewers receive notification
↓
Reviewer approves deployment
↓
✅ Deployment proceeds to production
↓
Release job creates GitHub release
↓
Slack notification sent
Security Benefits:
- Prevents accidental production deployments
- Enforces change control process
- Audit trail for compliance
- Branch protection (only
main→prod) - Time-based deployment windows (optional)
Use Cases:
- Production deployments require explicit approval
- QA sign-off before UAT deployment (optional)
- Emergency hotfix approvals
- Compliance and audit requirements
Best Practices
- Branch Strategy:
- Feature branches → PRs → Deploy to dev
develop→ Auto-deploy to devstaging→ Auto-deploy to uat (with approval if configured)main→ Requires approval → Deploy to prod
- Cleanup: Always close/merge PRs to trigger automatic cleanup
- Monitoring: Check Slack notifications for deployment status
- Approvals: Configure production reviewers for approval gates
For more details about the Component documentation and usage read Component documentation
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
Record 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 cases
GitFlow and Related Rules
Branching and Code Reviews
We have a default branch develop and usually we work toward that branch every time, we don't use long-live branches or any other alternative. Our philosophy is to Ship as fast as possible into develop and use the setup validations to ensure everything works as expected.
We follow a Ship/Show/Ask approach where:
- We Ship — apply the
SHIPlabel for changes that are straightforward and don't require peer review. - We Show — apply the
SHOWlabel for changes that don't require review but benefit from visibility or feedback. - We Ask — apply the
ASKlabel for changes that require peer review before merging.
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 general naming convention for branches:
{type}/RECORD-XXXX-short-description: for ticket related branches (e.g.feature/RECORD-1234-add-buffer-tracking){type}/short-description: for non-ticket branches (e.g.chore/update-dependencies)release/vX.Y.Z: for release branches (e.g.release/v1.2.0)
Where type is one of: feature, fix, hotfix, chore, docs, ci
For personal or agent-assisted short-lived work: {username}/{type}/RECORD-XXXX-short-description
Github Actions
Validations
All CI/CD is orchestrated by a single primary.yml workflow that handles PRs and branch pushes. It splits 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
After all the static validations, primary.yml triggers the CI/CD workflows based on event context (e.g. edited events skip deployment as they include no code changes).
CI/CD
Three deployment workflows as workflow_call:
- Nextjs Application deployment on
Build-&-Deploy_webci-record.yml - Documentation deployment on
Build-&-Deploy_doc-record-web.yml - Component Documentation deployment on
Build-&-Deploy_storybook-record-web.yml
Deployment URLs follow the pattern {APPNAME}.{APP_DOMAIN} where appnames are configured as GitHub environment variables (CI_APPNAME_RECORD, DOC_APPNAME_RECORD, STORYBOOK_APPNAME_RECORD).
PR deployments use the namespace {APPNAME}-{PR_NUMBER}.{APP_DOMAIN}.
Note: PR related deployments will only be triggered if the following labels are included in the PR:
storybookfor component Documentation deploymentdocusaurusfor Documentation 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.
PR title format (enforced by Danger): type(scope): description
typemust be one of:feat,fix,hotfix,chore,docs,ci,refactor,style,test,perf,build,revertscopeis optionalticket-referenceis optional, included as free text in the description- Examples:
feat(player): RECORD-1234 add buffer tracking(with scope and ticket)chore: update dependencies(no scope, no ticket)
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.
Allowed commit types: feat, fix, hotfix, docs, style, refactor, test, chore, build, ci, perf, revert
Use conventional-commit-types for type usage definition
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 the main branches creates its own separate Record 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
Releases are created automatically on every push to develop, staging, and main via semantic-release, driven by commit message types.
Creating Releases
Releases are fully automated through the release.yml workflow triggered on pushes to develop, staging, and main.
Version format
developpush: pre-release (e.g.0.1.0-dev.1)stagingpush: release candidate (e.g.0.1.0-rc.1)mainpush: stable release (e.g.0.1.0)
The version is also injected into the app at build time via NEXT_PUBLIC_APP_VERSION and is visible in the Settings page.
- Merge all desired changes to
developvia PRs - Semantic Release automatically determines the version bump from commit types, updates
CHANGELOG.md, creates a GitHub Release tag, and outputs the version to the deploy jobs - The deploy jobs pick up the version and build the app with
NEXT_PUBLIC_APP_VERSIONset