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:
- BORG
- PORK
- platform-frontends
- jobboard
- Locutus of Borg
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
Our repository:
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
FE PoC
By Milan Herda
FE PoC
- 158