Skip to main content

Dynamic & Extensible Systems Documentation

Overview

To ensure maximum future-proofing, the system includes several dynamic and extensible mechanisms that allow adding new properties, categories, and relationships without schema changes.

Dynamic Systems

1. LookupTable - Dynamic Categories/Types

Purpose: Replace hard-coded enums with database-driven lookup tables that can be extended by users or administrators.

Benefits:

  • Add new values without code changes
  • User-defined categories
  • Hierarchical categories (parent-child)
  • Metadata for each value
  • Usage tracking

Example Usage:

// Instead of hard-coded enum, use lookup table
var customPower = new LookupTable
{
Category = "RodPower",
Name = "Extra Ultra Light",
Code = "ExtraUltraLight",
IsSystemDefined = false, // User-defined
DisplayOrder = 0
};

// Entities can use both enum (for type safety) AND lookup (for extensibility)
rodBlank.Power = RodPower.UltraLight; // Standard enum
rodBlank.PowerLookupId = customPower.Id; // Custom value

Categories:

  • RodPower, RodAction, RodMaterial
  • GuideType, GuideFrameType, GuideRingType
  • WrapType, WrapPattern
  • FinishType, FinishGloss
  • KnotCategory, KnotDifficulty
  • PressureTrend, PrecipitationType, CloudCoverType
  • TideType, TideRangeType
  • And any future categories

2. EntityAttribute - Generic Attribute System

Purpose: Add custom attributes to any entity without schema changes.

Benefits:

  • No schema changes needed
  • Support for multiple value types (string, number, boolean, DateTime, JSON)
  • Unit support (cm, kg, mph, etc.)
  • Lookup references for standardized values

Example Usage:

// Add custom attribute to a rod
var customAttr = new EntityAttribute
{
EntityType = "Rod",
EntityGuidId = rod.Id,
AttributeKey = "CustomActionRating",
NumericValue = 8.5m,
Unit = "out of 10",
AttributeType = AttributeType.Number,
IsUserDefined = true
};

// Add JSON attribute for complex data
var jsonAttr = new EntityAttribute
{
EntityType = "RodBuild",
EntityIntId = rodBuild.Id,
AttributeKey = "CustomBuildSpecs",
JsonValue = JsonSerializer.Serialize(new {
CustomGuideSpacing = "Progressive",
SpecialWraps = new[] { "Diamond", "Chevron" }
}),
AttributeType = AttributeType.Json
};

3. EntityTag - Generic Tagging System

Purpose: Tag any entity with normalized tags, more flexible than entity-specific tag relationships.

Benefits:

  • Works with any entity type
  • Uses normalized Tag entity
  • Context-aware (Category, UseCase, Condition, etc.)
  • No need for entity-specific tag relationships

Example Usage:

// Tag a rod with multiple contexts
var tag1 = new EntityTag
{
EntityType = "Rod",
EntityGuidId = rod.Id,
TagId = trollingTag.Id,
Context = "UseCase"
};

var tag2 = new EntityTag
{
EntityType = "Rod",
EntityGuidId = rod.Id,
TagId = saltwaterTag.Id,
Context = "WaterType"
};

4. EntityMetadata - JSON Metadata Storage

Purpose: Store extensible JSON data for any entity without schema changes.

Benefits:

  • Store complex nested data
  • Schema versioning support
  • Multiple metadata keys per entity
  • No schema changes needed

Example Usage:

// Store extended weather data
var metadata = new EntityMetadata
{
EntityType = "LocationWeatherHistory",
EntityIntId = weather.Id,
MetadataKey = "ExtendedWeatherData",
SchemaVersion = "1.0",
SchemaType = "ExtendedWeather",
JsonData = JsonSerializer.Serialize(new {
AirQuality = new { AQI = 45, PM25 = 12.5 },
UVIndex = 6,
SolarRadiation = 850,
CustomFields = new Dictionary<string, object>()
})
};

5. EntityRelationship - Generic Relationship System

Purpose: Create relationships between any entities without hard-coded foreign keys.

Benefits:

  • Dynamic relationships
  • Relationship types (RelatedTo, SimilarTo, Replaces, etc.)
  • Relationship strength/confidence
  • Bidirectional support
  • Metadata for relationship details

Example Usage:

// Relate two rods
var relationship = new EntityRelationship
{
SourceEntityType = "Rod",
SourceEntityGuidId = rod1.Id,
TargetEntityType = "Rod",
TargetEntityGuidId = rod2.Id,
RelationshipType = "SimilarTo",
Strength = 0.85f,
Notes = "Similar action and power"
};

// Relate gear items
var gearRel = new EntityRelationship
{
SourceEntityType = "Lure",
SourceEntityGuidId = lure1.Id,
TargetEntityType = "Lure",
TargetEntityGuidId = lure2.Id,
RelationshipType = "VariantOf",
Notes = "Color variant"
};

Hybrid Approach: Enums + Lookup Tables

For maximum flexibility, many entities support both enums (for type safety) and lookup tables (for extensibility):

public class RodBlank
{
// Enum for type safety and standard values
public RodPower Power { get; set; }

// Lookup table for custom/extended values
public int? PowerLookupId { get; set; }
public LookupTable? PowerLookup { get; set; }
}

Benefits:

  • Type safety for standard values (enums)
  • Extensibility for custom values (lookup tables)
  • Best of both worlds

Migration Strategy

Phase 1: Use Enums (Current)

  • Enums provide type safety
  • Standard values are well-defined
  • Easy to use in code

Phase 2: Add Lookup Tables (Future)

  • Seed lookup tables with enum values
  • Add optional lookup table references to entities
  • Maintain backward compatibility

Phase 3: Full Dynamic (Future)

  • Migrate to lookup tables for user-defined values
  • Keep enums for system-defined values
  • Use EntityAttribute for completely custom properties

Best Practices

  1. Use Enums for Standard Values: Keep enums for well-defined, stable categories
  2. Use Lookup Tables for Extensible Values: Use lookup tables for categories that may grow
  3. Use EntityAttribute for Custom Properties: Use attributes for entity-specific custom fields
  4. Use EntityMetadata for Complex Data: Use metadata for nested/complex data structures
  5. Use EntityTag for Flexible Categorization: Use tags for multi-dimensional categorization
  6. Use EntityRelationship for Dynamic Links: Use relationships for flexible entity connections

Examples

Adding Custom Rod Power

// 1. Create lookup table entry
var customPower = new LookupTable
{
Category = "RodPower",
Name = "Super Heavy",
Code = "SuperHeavy",
IsSystemDefined = false,
DisplayOrder = 8
};

// 2. Use in rod blank
rodBlank.Power = RodPower.UltraHeavy; // Closest enum
rodBlank.PowerLookupId = customPower.Id; // Custom value

Adding Custom Weather Property

// Add custom weather attribute
var customWeather = new EntityAttribute
{
EntityType = "LocationWeatherHistory",
EntityIntId = weather.Id,
AttributeKey = "SolarRadiation",
NumericValue = 850m,
Unit = "W/m²",
AttributeType = AttributeType.Number
};

Storing Complex Build Data

// Store complex rod build metadata
var buildMetadata = new EntityMetadata
{
EntityType = "RodBuild",
EntityIntId = rodBuild.Id,
MetadataKey = "BuildProcess",
JsonData = JsonSerializer.Serialize(new {
Steps = new[] {
new { Step = "Guide Placement", Time = "2 hours" },
new { Step = "Wrapping", Time = "4 hours" },
new { Step = "Finishing", Time = "1 hour" }
},
ToolsUsed = new[] { "Power Wrapper", "Finish Turner" },
CustomNotes = "Used custom guide spacing formula"
})
};

Future Enhancements

  1. UI for Managing Lookup Tables: Admin interface for managing categories
  2. User-Defined Categories: Allow users to create their own categories
  3. Category Templates: Pre-defined category sets for common use cases
  4. Attribute Schemas: Define schemas for EntityAttribute values
  5. Relationship Validation: Validate relationship types and entities
  6. Metadata Schemas: Versioned schemas for EntityMetadata JSON data