Create platform

Platform aspect is the bedrock of how your composable features are unified for the shell app. It provides layout, routing and other APIs for Aspects to integrate with the platform.

Platform Aspect is providing the API to feature teams
Platform Aspect is providing the API to feature teams

Symphony provides a ready-to-use platform foundation built with React, GraphQL and Express. You can use Symphony and customize it for your needs by replacing its capabilities with your own tools.

To learn how to use platform aspects and integrate with them, start by creating an aspect:

bit create aspect pied-platform
CopiedCopy

Now you can use the Symphony platform APIs. Later you will customize Symphony.

Platform basics

Harmony brings an API first approach to platform engineering, enabling to provide a clear, programmatic API for feature integration. This platform's layout and operations, promotes consistency, and streamlines collaboration between feature teams:

// people.browser.runtime.tsx
import type { Route } from '@bitdev/symphony.frontends.route';
import { SymphonyPlatformAspect, SymphonyPlatformBrowser } from '@bitdev/symphony.symphony-platform';

export class PiedPlatformBrowser {
  constructor(
    private config: PiedPlatformConfig,
    private symphonyPlatform: SymphonyPlatformBrowser,
  ) {}

  // Define your platform APIs.
  registerRoute(routes: Route[]) {
    this.symphonyPlatform.registerRoute(routes);
    return this;
  }

  static dependencies = [SymphonyPlatformAspect];

  static async provider([symphonyPlatform]: [SymphonyPlatformBrowser],
    config: PiedPlatformConfig,
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    // integrate the application layout and further components as needed.
    symphonyPlatform.registerLayoutEntry([
      {
        position: 'top',
        component: () => {
          return <Header />;
        }
      }
    ]);

    return piedPlatform;
  }
}

export default PiedPlatformBrowser;
CopiedCopy

The basic above example demonstrates a simple platform aspect exposing the registerRoute API allowing other aspects to register new routes and integrating the Header component into the platform.

Theming

To customize the theme, use the registerTheme API method provided by the Symphony API.

export class PiedPlatformBrowser {
  static dependencies = [SymphonyPlatformAspect];

  static async provider(
    [symphonyPlatform]: [SymphonyPlatformBrowser],
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    // register your custom theme to the Symphony platform.
    symphonyPlatform.registerTheme((props) => {
      return <PiedTheme {...props} />;
    });

    return piedPlatform;
  }
}

export default PiedPlatformBrowser;
CopiedCopy

The example above replaces the default Sparks Theme provided by Symphony with a custom theme. You can checkout the full component examples in the Pied Piper demo.

Routing

By default, Symphony uses React Router. Use the Platform aspect's API to register routes and integrate components into specific slots within the unified app:

export class PiedPlatformBrowser {
  static dependencies = [SymphonyPlatformAspect];

  static async provider(
    [symphonyPlatform]: [SymphonyPlatformBrowser],
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    // register a new route to the app.
    symphonyPlatform.registerRoute([
      {
        path: '/',
        component: () => {
          return <Homepage />
        }
      },
    ]);
    
    // register a page not found.
    symphonyPlatform.registerPageNotFound(() => <PageNotFound />);

    return piedPlatform;
  }
}
CopiedCopy

You can use also render React Router <Routes> in route components for internal or nested routing.Within your route components, you can also use React Router components (e.g., <Route>, <Switch>, etc.) for nested or internal routing.

Global context

To provide global context for features (such as theming or internationalization), create a React context in your aspect. Then, use a provider component from your aspect to wrap the root of your application. This makes the context accessible to all components in the application.

Top level components

To wrap the root of your app, register a top level component and ensure to accept and render the component children:

export class PiedPlatformBrowser {
  static dependencies = [SymphonyPlatformAspect];

  static async provider(
    [symphonyPlatform]: [SymphonyPlatformBrowser],
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    // register a global authentication provider.
    symphonyPlatform.registerTopLevel([
      component: ({ children }) => {
        return <AuthProvider>{children}</AuthProvider>
      }
    ]);

    return piedPlatform;
  }
}
CopiedCopy

Hud

The Hud API allows you to register components that render above the main content area, without needing to wrap the existing content. This is particularly helpful for displaying overlays, notifications, or other UI elements that shouldn't interfere with the underlying page structure. For example, this is how you display notices.

export class PiedPlatformBrowser {
  static dependencies = [SymphonyPlatformAspect];

  static async provider(
    [symphonyPlatform]: [SymphonyPlatformBrowser],
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    symphonyPlatform.registerHud([
      () => {
        return <Notice />
      }
    ]);

    return piedPlatform;
  }
}
CopiedCopy

App layout

Symphony provides a simple and flexible app layout component and APIs for registering components to different sections of the layout:

export class PiedPlatformBrowser {
  static dependencies = [SymphonyPlatformAspect];

  static async provider(
    [symphonyPlatform]: [SymphonyPlatformBrowser],
  ) {
    const piedPlatform = new PiedPlatformBrowser(config, panelSlot);

    symphonyPlatform.registerLayoutEntry([
      {
        position: 'top',
        component: () => {
         return <Header />;
        }
      },
      {
        position: 'left',
        component: () => {
         return <SidebarNav />;
        }
      },
    ]);

    return piedPlatform;
  }
}
CopiedCopy

The Sparks App Layout component is used by default, but you can replace it using registerLayoutComponent.

Data fetching

Symphony supports data fetching using both GraphQL and RESTful APIs. By default, it sets up @apollo/client to use the API gateway. Here's an example for a React hook component utilizing Apollo Client to fetch data from the aspect GraphQL API.

For RESTful data fetching, consider building a dedicated hook that leverages environment variables to interact with the Symphony API gateway. This approach promotes better code organization and maintainability.

State management

To effectively manage state throughout the platform, we recommend leveraging React's state management capabilities with Hooks. By encapsulating Context providers within custom Hooks, you can enhance code organization, improve reusability, and promote a more maintainable codebase.

If a particular piece of state needs to be accessible across multiple parts of your application, consider using the provided global context APIs. However, use global state sparingly to avoid potential complexity and unexpected side effects.

Environment variables

The Symphony platform provides the following default environment variables:

  • NODE_RUNTIME_PORT. The port the API gateway to set to.
  • NODE_RUNTIME_URL. The full URL the API gateway.

To enhance privacy and security for your platform, avoid storing or processing sensitive data (secrets) directly within the browser's runtime environment. Instead, leverage the Node.js runtime for managing and handling secrets, ensuring they remain protected and secure

Legacy apps

You can reuse your 100% of your existing code by following our gradual migration guide. To learn more, head to the Gradual migration documentation.

Learn more