Cyborg Update

august 2024

Cyborg Update

august 2024

What we did in august

  • deployed to AWS
  • configuration & service container
  • components, design tokens & Spirit integration
  • decided how to localize URL
  • decided what is a plugin a how to integrate it
  • decided how to work with secrets

Deployment to AWS

  • we use Amplify (only for now)
    • managed by github actions
    • configuration in repository
    • not sure about Amplify in production
  • every branch deployed on its own URL
  • 4 portals

Configuration

&

Service Container

  • No significant changes in overal philosophy since previous update
  • We are moving and refactoring experimental code to the main branch

What is in configuration?

  • feature flags: boolean values indicating what functionality is enabled
  • parameters: scalar values like default language, number of items per page etc.
  • secrets: passwords, hidden token values...
  • components that can be overridden
  • plugins: path to their configuration and enabled/disabled status
  • routes: localized variants of accessible URLs

Everything that we want to allow to be overriden on specific jobboard

Components,

Design Tokens

&

Spirit integration

  • SCSS and (S)CSS modules
    • CSS-in-JS problems with RSC
    • native CSS and HTML is getting better
  • Unification of design tokens across all job portals needed (spirit-design-tokens v3)
  • Design tokens in form of Figma variables
  • For PoC we will use some temporary workarounds
    • icons from Jobs.cz
    • current design tokens for all job portals (only minor changes in designs)
  • For Prace.cz we will have to wait for:
    • decision about its design
    • design itself

Advert Detail Page

Search Results Page

Localized URLs

Requirements

  • we have a possibility to define URL for every locale available on a domain
  • URLs for different locales can have different shape (number of segments, their order, parameter placement...)
  • every domain have its default locale
  • URLs for default locale does not have a prefix:
    • /job-offers
  • every non-default locale has a prefix in URL:
    • /sk/praca
    • /de/arbeit

Route Definition

interface Route {
  name: string;
  targetPath: string; // Next.js route
  path: {
    en: string;
    de: string;
    sk: string;
    cs: string;
    hr: string;
  };
  meta?: {
    authRequired?: boolean;
  };
}
apiVersion: cyborg/v1
kind: Routes
metadata: 
  name: default
spec: 
  homepage: 
    targetPath: '/'
    path: 
      en: '/'
      de: '/'
      sk: '/'
      cs: '/'
      hr: '/'
  search_results:
    targetPath: '/search-results'
    path:
      en: '/work'
      de: '/arbeit-suchen'
      sk: '/praca'
      cs: '/nabidky'
      hr: '/pretraga-poslova'
  advert:
    targetPath: '/advert/:advertId'
    path:
      en: '/work/:advertId'
      de: '/arbeit/:advertId'
      sk: '/praca/:advertId'
      cs: '/nabidka/:advertId'
      hr: '/posao/:advertId'
 

Link/Path generation

function ListingItem() {
  const { createPath } = useRoutes();
        
  return (
    <>
      <Link href={createPath('advert', { advertId: 123, utmSource: 'listing'})}>Detail</Link>
    <>
  );
}

Next.js route detection in middleware

export async function middleware(request: NextRequest) {
  const requestData = routingMiddleware(request);

  const requestHeaders = new Headers(request.headers);

  requestHeaders.set('x-locale', requestData.locale);
  requestHeaders.set('x-correlation-id', generateCorrelationId());
  requestHeaders.set('x-request-url', request.url);

  if (!requestData.currentRoute) {
    return NextResponse.rewrite(new URL('not-found', request.url), {
      request: {
        headers: requestHeaders,
      },
    });
  }
  
  return NextResponse.rewrite(new URL(requestData.targetUrl, request.url), {
    request: {
      headers: requestHeaders,
    },
  });
}

Plugins vs Libraries

Library

  • specialized code inside its own package
  • placed in libs folder
  • developed by anyone

Plugin

  • specialized code inside its own package
  • placed in plugins folder
  • developed by other platform team
  • contains its own configuration

Secrets

  • are usually in ENV variables
  • can be written in configuration
  • or read from ENV in configuration
  • are available in application through Service Container (only in server environment)
    • container is static and created at build time
    • change of secret in ENV will not be applied immediately (redeployment will be needed)

Thank you

Any Questions?