FE PoC

FE Proof-of-Concept

JobBoard Platform Frontend

Frontend Platform

Who we are?

Team developing

frontend code

to be used by all of ALMA job-boards

Team developing

frontend code

to be used by all of ALMA job-boards

Team developing

frontend framework

to be used by all of ALMA job-boards

Team developing

frontend framework

to be used by all of ALMA job-boards

Team developing

frontend framework

all ALMA job-boards will be build with

3 months to deliver

3 months to deliver

  • skilled and responsible developers
  • various skill sets
  • various experiences
  • speed over processes
    • quality is important

Proof-of-Concept

Goals for Q3/2024

Validated and agreed Proof of Concept for one common frontend:

  • we prepare two jobboard pages (job offer detail and one another page) in jobs.cz, prace.cz and moj-posao.hr design
  • we will have recommendations (approved by the architecture team) for other components teams how they should develop FE

Unofficial Goals

  • easy to understand
  • simple to use for other developers
  • tools familiar to the majority of developers
  • UX > DX
  • testing and code reviews from the start

Why are we doing this?

I heard that Alma Career South already has a solution for this

BORG

I heard that Alma Career South already has a solution for this

BORG

  • different technology (Vue vs. React)
  • different standards regarding test coverage
  • not built with the whole ALMA in mind

Decisions made so far

  • tech stack
  • name of the project
  • monorepo development
  • components overriding
  • how many spaces for indentation

Decisions made so far

Tech stack

Tech stack

React

Next.js

Decisions made so far

Project name

Cyborg

Name of the project

  • has a reference to the BORG
  • short
  • somewhat cool

Name of the project

Some other candidates:

Decisions made so far

Monorepo development

Monorepo development

  • One GIT repository
  • projects and libraries in different folders
  • easy and faster to integrate
  • uniform tooling and settings
  • different teams can work in the same repo

Monorepo development

Monorepo development

Decisions made so far

Components overriding

1. Design based on

the current portal

2. Different components for the same functionality

3. Different set of features

1. Design based on

the current portal

Colors, spacing, shadows...

Design Tokens

2. Different components for the same functionality

3. Different set of features

Let's start with an obvious approach

'use client';

import HeroBannerPrace from '@prace/ui/HeroBanner';
import HeroBannerJobs from '@jobs/ui/Homepage/HeroBanner';
import DefaultHeroBanner from '@local/ui/hero/HeroBanner';
import SearchForm from '@local/ui/search/SearchForm';
import useHostname from '@local/router/infrastructure/react/useHostname';

export default function Homepage() {
    const hostname = useHostname();
  
    let HeroBanner = DefaultHeroBanner;
  
    if (hostname === 'prace.cz') {
        HeroBanner = HeroBannerPrace;
    } else if (hostname === 'jobs.cz') {
        HeroBanner = HeroBannerJobs;
    }
 
    return (
        <>
            <HeroBanner />
            <SearchForm />
            <>
        </>
    );
}

Our goal

'use client';

import SearchForm from '@local/ui/search/SearchForm';

export default function Homepage() {
    const HeroBanner = resolveComponent("Homepage/HeroBanner");
   
    return (
        <>
            <HeroBanner />
            <SearchForm />
            <>
        </>
    );
}

Our approach (client component)

'use client';

import SearchForm from '@local/ui/search/SearchForm';
import useHostname from '@local/router/infrastructure/react/useHostname';
import ServiceContainerContext from '@almacareer/service-container/react';

export default function Homepage() {
    const { resolveComponent } = useContext(ServiceContainerContext);
  
    const HeroBanner = resolveComponent("Homepage/HeroBanner");
   
    return (
        <>
            <HeroBanner />
            <SearchForm />
            <>
        </>
    );
}

Our approach (server component)

import SearchForm from '@local/ui/search/SearchForm';
import useHostname from '@local/router/infrastructure/react/useHostname';
import serviceContainer from '@local/serviceContainer/server';

export default function Homepage() {
    const { resolveComponent } = serviceContainer;
  
    const HeroBanner = resolveComponent("Homepage/HeroBanner");
   
    return (
        <>
            <HeroBanner />
            <SearchForm />
            <>
        </>
    );
}

Registry

  • place where services and parameters are defined (container)
  • allow services to be overriden
  • more ways to do this
    • we decided to build registry from configuration at build step

Configuration

  • multiple YAML files
  • spread over multiple (but defined) folders
    • app/jobboard/config/default/
    • app/jobboard/config/mojposao.hr/
    • app/jobboard/config/jobs.cz/
    • libs/search/config/default/
    • libs/search/config/jobs.cz/
  • some contains default services
  • other defines overrides for a certain domain
  • we compile and compose them during build

Configuration

apiVersion: cyborg/v1
kind: Components
metadata:
spec:
  SearchForm: '@cyborg-search/ui/form/SearchForm'
  Homepage/HeroBanner: 
    path: '@jobs-cz/ui/homepage/HeroBanner'
    isLazy: true
  SearchResults:
    path: '@cyborg-search/ui/listing/Results'
    isServer: true

--
apiVersion: cyborg/v1
kind: Parameters
metadata:
spec:
  searchResult:
    itemsPerPage: 20
  homepage:
    isHeroBannerVisible: '$env(HERO_BANNER_VISIBLE, false)'

Other explored option

'use client';
'borg:role Homepage/HeroBanner';

export default HeroBanner() {
  // the usual React component stuff
  
  return (
      <>
          <h1>Hello</h1>
      </>
  );
}

File-system based resolver

  • it is good to have the same way of configuring multiple things (component and parameters)
  • it is more readable and it will be easier to understand
  • it is more friendly to testing
  • it provides ways to be extended (versioning, schema validation...)
  • it is clearer in separating of concerns (configuration and UI), which is closer to the DDD architecture paradigm and more suitable for larger projects

We decided to use the "configuration" solution because we feel:

Decisions made so far

How many spaces for indentation

  • 4 spaces in Profesia

  • 2 spaces in LMC

  • 2 spaces in Croatia

  • 4 spaces in PHP

We are going to use

Tabs

Reasons

  • tooling got better
  • everyone can set their own preffered tab size
  • accessibility:
    • tabs have semantical meaning
    • can help developers with eyesight impairness (it can even be us in a few years)

Next Steps

  • implement and polish service container & configuration
  • work on design tokens
  • TypeScript support for registry
  • URL localization
  • feature plugin integration (especially routing)
  • components needed for PoC
  • how to work with secrets
  • AWS deployment
  • ...

Thank you