feat(templates): phase 1 — derived-template schema (additive)
Phase 1 of the design at
docs/plans/2026-05-12-derive-on-compose-design.md.
Additive schema only — no behavior changes. Existing data and code
paths continue to work; subsequent phases will start writing the
new fields.
Template gains:
IsDerived true when this row was auto-created to back
a composition slot
OwnerCompositionId back-ref to the owning TemplateComposition
(plain int, not an EF nav property — managed
by TemplateService for cascade-delete)
TemplateAttribute / TemplateScript each gain:
IsInherited row copied from base and not yet overridden;
changes to the base flow downward
LockedInDerived on a base, blocks derived from overriding;
enforced at the service layer in later phases
EF Core migration AddDerivedTemplateFields adds four columns:
Templates.IsDerived bit NOT NULL DEFAULT 0
Templates.OwnerCompositionId int NULL
TemplateAttributes.IsInherited bit NOT NULL DEFAULT 0
TemplateAttributes.LockedInDerived bit NOT NULL DEFAULT 0
TemplateScripts.IsInherited bit NOT NULL DEFAULT 0
TemplateScripts.LockedInDerived bit NOT NULL DEFAULT 0
Existing rows get the defaults. Tests across SiteRuntime / TemplateEngine
/ CentralUI suites stay green (129 / 199 / 159).
Next: phase 2 — wire AddCompositionAsync to derive on compose for
new compositions. Old data still flows the direct-reference path
until phase 3's migration script.
This commit is contained in:
@@ -12,6 +12,21 @@ public class Template
|
||||
public ICollection<TemplateScript> Scripts { get; set; } = new List<TemplateScript>();
|
||||
public ICollection<TemplateComposition> Compositions { get; set; } = new List<TemplateComposition>();
|
||||
|
||||
/// <summary>
|
||||
/// True when this template was auto-derived to back a TemplateComposition
|
||||
/// slot. Derived templates inherit from a base (see <see cref="ParentTemplateId"/>),
|
||||
/// are owned by their composition row (see <see cref="OwnerCompositionId"/>),
|
||||
/// and are hidden from the main template tree by default.
|
||||
/// </summary>
|
||||
public bool IsDerived { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Back-reference to the <see cref="TemplateComposition"/> that owns this
|
||||
/// derived template. Non-null only when <see cref="IsDerived"/>; cascade-
|
||||
/// delete when the composition is removed. Always null on base templates.
|
||||
/// </summary>
|
||||
public int? OwnerCompositionId { get; set; }
|
||||
|
||||
public Template(string name)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
|
||||
@@ -13,6 +13,21 @@ public class TemplateAttribute
|
||||
public string? Description { get; set; }
|
||||
public string? DataSourceReference { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True when this row was copied from the base template and has not been
|
||||
/// overridden on the derived template. Changes to the base flow downward
|
||||
/// for inherited rows; an explicit override flips this to false.
|
||||
/// Always false on base (non-derived) templates.
|
||||
/// </summary>
|
||||
public bool IsInherited { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set on a base attribute. When true, derived templates may not override
|
||||
/// the value — the row is rendered readonly with a 🔒 in the derived UI,
|
||||
/// and any attempt to update it through the API is rejected.
|
||||
/// </summary>
|
||||
public bool LockedInDerived { get; set; }
|
||||
|
||||
public TemplateAttribute(string name)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
|
||||
@@ -13,6 +13,21 @@ public class TemplateScript
|
||||
public string? ReturnDefinition { get; set; }
|
||||
public TimeSpan? MinTimeBetweenRuns { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True when this row was copied from the base template and has not been
|
||||
/// overridden on the derived template. Changes to the base flow downward
|
||||
/// for inherited rows; an explicit override flips this to false.
|
||||
/// Always false on base (non-derived) templates.
|
||||
/// </summary>
|
||||
public bool IsInherited { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set on a base script. When true, derived templates may not override
|
||||
/// the script body — the row is rendered readonly with a 🔒 in the derived
|
||||
/// UI, and any attempt to update it through the API is rejected.
|
||||
/// </summary>
|
||||
public bool LockedInDerived { get; set; }
|
||||
|
||||
public TemplateScript(string name, string code)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
|
||||
Reference in New Issue
Block a user