A Bit of Vyuh

Understanding the Vyuh Framework fundamentals - features, plugins, and content system

Before diving into the Entity System, let's understand the Vyuh Framework fundamentals. The Entity System is built on top of these core concepts, so understanding them will help you work more effectively.

What is Vyuh?

Vyuh is a feature-based framework for building modular, Content-driven Flutter applications at scale. It provides a structured approach to decomposing complex applications into independent, reusable features that can be assembled together.

Core Philosophy

Vyuh treats everything as content - from simple text blocks to complex business entities. This unified content model enables:

  • Building applications by assembling features
  • Driving UI from a Content Source (such as a CMS or a Database)
  • Creating reusable components across projects
  • Managing complexity through modular architecture

The Feature System

Features as Building Blocks

In Vyuh, applications are composed of features - self-contained modules that encapsulate related functionality. A feature can be described with a simple manifest that contains:

  • Domain models and business logic
  • UI components and layouts
  • Routes and navigation
  • Extensions to the framework
// A simple feature
final inventoryFeature = FeatureDescriptor(
  name: 'inventory',
  title: 'Inventory Management',
  description: 'Manage products, orders, and stock',
  icon: Icons.inventory,
  routes: () async => [/* feature routes */],
  extensions: [/* feature extensions */],
);

Features as Building Blocks

You can keep the feature in your application as a separate folder or as a completely separate Flutter package.

Assembling Features into Applications

Applications are created by combining features:

import 'package:vyuh_core/vyuh_core.dart' as vc;

void main() {
  vc.runApp(
    initialLocation: '/',
    features: () => [
      // Core features
      authFeature,
      dashboardFeature,

      // Business features
      inventoryFeature,
      orderManagementFeature,
      reportingFeature,
    ],
    plugins: vc.PluginDescriptor(
      content: ContentPlugin(),
      navigation: NavigationPlugin(),
      network: NetworkPlugin(),
      others: [
        EntitySystemPlugin(),
        // ... other custom plugins
      ],
    ),
  );
}

This composition model allows you to:

  • Develop features independently as separate packages
  • Reuse features across multiple applications
  • Enable/disable features based on configuration
  • Test features in isolation before integration

The Content System

At the heart of Vyuh is a powerful content system that treats all displayable items as content. This includes everything from simple text to complex entities.

Core Components

Every content item in Vyuh requires three key pieces:

1. TypeDescriptor

Defines the type identity and JSON serialization:

class Product extends EntityBase {
  static const schemaType = 'inventory.products';

  static final typeDescriptor = TypeDescriptor(
    schemaType: schemaType,
    title: 'Product',
    fromJson: Product.fromJson,
  );

  // ... fields and methods
}

The TypeDescriptor:

  • Identifies the content type via schemaType
  • Provides human-readable title
  • Enables JSON deserialization via fromJson

2. Layout Configuration

Defines the visual representation:

class ProductDetailLayout extends LayoutConfiguration<Product> {
  static final typeDescriptor = TypeDescriptor(
    schemaType: 'inventory.product.layout.detail',
    title: 'Product Detail Layout',
    fromJson: ProductDetailLayout.fromJson,
  );

  ProductDetailLayout() : super(schemaType: typeDescriptor.schemaType);

  static ProductDetailLayout fromJson(Map<String, dynamic> json) =>
      ProductDetailLayout();

  @override
  Widget build(BuildContext context, Product content) {
    return ProductDetailView(product: content);
  }
}

The LayoutConfiguration:

  • Extends LayoutConfiguration<T> where T is the content type
  • Specifies how to render the content
  • Can have multiple layouts for the same content type
  • Supports CMS-driven layout selection

3. ContentBuilder

Connects content to its layouts:

ContentBuilder(
  content: Product.typeDescriptor,
  defaultLayout: ProductDetailLayout(),
  defaultLayoutDescriptor: ProductDetailLayout.typeDescriptor,
)

The ContentBuilder:

  • Maps a content type to its available layouts
  • Defines the default layout
  • Enables runtime layout switching (CMS-driven)

Content Registration

Content is registered within features via extensions:

final inventoryFeature = FeatureDescriptor(
  name: 'inventory',
  title: 'Inventory Management',
  icon: Icons.inventory,
  extensions: [
    ContentExtensionDescriptor(
      contents: [
        ContentDescriptor(
          type: Product.typeDescriptor,
          layouts: [
            ProductCardLayout.typeDescriptor,
            ProductDetailLayout.typeDescriptor,
          ],
        ),
      ],
    ),
  ],
);

Extension System

Features extend the framework through extensions. Common extension types:

1. ContentExtensionDescriptor

Registers content types and their layouts:

ContentExtensionDescriptor(
  contents: [
    ContentDescriptor(
      type: Article.typeDescriptor,
      layouts: [CardLayout.typeDescriptor, FullLayout.typeDescriptor],
    ),
  ],
)

2. EntityExtensionDescriptor (Entity System)

Registers business entities with CRUD operations:

EntityExtensionDescriptor(
  entities: [
    EntityRegistration<Product>(
      productConfig,  // EntityConfiguration
      ContentBuilder(
        content: Product.typeDescriptor,
        defaultLayout: ProductDetailLayout(),
        defaultLayoutDescriptor: ProductDetailLayout.typeDescriptor,
      ),
    ),
  ],
)

Notice how the Entity System builds on top of the content system - entities are just specialized content with CRUD capabilities!

Plugins

Plugins provide cross-cutting capabilities for the entire application. They are configured using PluginDescriptor when initializing the app with vc.runApp():

vc.runApp(
  features: () => [/* features */],
  plugins: vc.PluginDescriptor(
    // Core framework plugins
    content: ContentPlugin(),      // Content rendering
    navigation: NavigationPlugin(), // Routing and navigation
    network: NetworkPlugin(),      // API communication
    auth: AuthPlugin(),           // Authentication
    telemetry: TelemetryPlugin(), // Analytics and logging

    // Custom/domain-specific plugins
    others: [
      EntitySystemPlugin(),        // Entity management
      CustomDomainPlugin(),        // Your custom plugin
    ],
  ),
);

The PluginDescriptor organizes plugins by their role:

  • content - Content rendering and CMS integration
  • navigation - Routing and navigation behaviors
  • network - HTTP client and API configuration
  • auth - Authentication and authorization
  • telemetry - Logging, analytics, error tracking
  • others - Custom plugins like EntitySystemPlugin

How It All Fits Together

Here's the complete picture:

// 1. Define your content model
class Product extends EntityBase {
  static final typeDescriptor = TypeDescriptor(
    schemaType: 'inventory.products',
    title: 'Product',
    fromJson: Product.fromJson,
  );

  final String name;
  final double price;
  // ... other fields
}

// 2. Create layout(s) for your content
class ProductDetailLayout extends LayoutConfiguration<Product> {
  static final typeDescriptor = TypeDescriptor(
    schemaType: 'inventory.product.layout.detail',
    title: 'Product Detail Layout',
    fromJson: ProductDetailLayout.fromJson,
  );

  ProductDetailLayout() : super(schemaType: typeDescriptor.schemaType);

  static ProductDetailLayout fromJson(Map<String, dynamic> json) =>
      ProductDetailLayout();

  @override
  Widget build(BuildContext context, Product content) {
    return ProductDetailView(product: content);
  }
}

// 3. Register content in a feature
final inventoryFeature = FeatureDescriptor(
  name: 'inventory',
  title: 'Inventory Management',
  icon: Icons.inventory,
  extensions: [
    EntityExtensionDescriptor(
      entities: [
        EntityRegistration<Product>(
          productConfig,
          ContentBuilder(
            content: Product.typeDescriptor,
            defaultLayout: ProductDetailLayout(),
            defaultLayoutDescriptor: ProductDetailLayout.typeDescriptor,
          ),
        ),
      ],
    ),
  ],
);

// 4. Assemble features and plugins into your app
void main() {
  vc.runApp(
    initialLocation: '/',
    features: () => [
      inventoryFeature,
      // ... other features
    ],
    plugins: vc.PluginDescriptor(
      content: ContentPlugin(),
      navigation: NavigationPlugin(),
      network: NetworkPlugin(),
      others: [
        EntitySystemPlugin(),
        // ... other custom plugins
      ],
    ),
  );
}

Key Takeaways

Understanding these Vyuh fundamentals is essential:

1. Everything is a Feature

Decompose your application into independent features. Features are self-contained modules that can be developed, tested, and deployed separately.

2. Content is the Foundation

All visual elements are content with:

  • A TypeDescriptor (identity + serialization)
  • Layouts (visual representation)
  • A ContentBuilder (connecting the two)

3. Plugins for Cross-Cutting Capabilities

Plugins provide application-wide capabilities that span across features:

  • Organized by role via PluginDescriptor (content, navigation, network, auth, telemetry)
  • Shared infrastructure - Authentication, logging, API clients used by all features
  • Framework integration - Extend core Vyuh capabilities at the platform level

4. Extensions Enable Composition

Extensions allow you to build independent pieces and compose them together:

  • ContentExtensionDescriptor - Register displayable content independently
  • EntityExtensionDescriptor - Register business entities as separate modules
  • Independent development - Build extensions in isolation, then compose into features
  • Reusable components - Share extensions across multiple features and applications

5. Composition Over Inheritance

The classic software engineering principle applied throughout Vyuh:

  • Features - Compose independent domain modules into applications
  • Plugins - Compose cross-cutting capabilities into a unified system
  • Extensions - Compose specialized capabilities into features
  • Result - Flexible, maintainable architectures that scale

Decompose complexity into features and plugins, build independently, then assemble through composition.

Why This Matters for Entity System

The Entity System you're about to learn is built entirely on these foundations:

  • Entities are content - They use TypeDescriptor and ContentBuilder
  • Entity features - Registered via EntityExtensionDescriptor extension
  • Entity layouts - Multiple views (list, detail, analytics) of entity content
  • Feature composition - Entity features compose with other features

Now that you understand how Vyuh works, you're ready to dive into the Entity System and see how these concepts power enterprise-grade CRUD applications!

Next Steps

On this page