'array', 'version' => 'integer', ]; /** * Plans that were created from this template version. */ public function plans(): HasMany { return $this->hasMany(AgentPlan::class, 'template_version_id'); } /** * Find an existing version by content hash, or create a new one. * * Deduplicates identical template content so we don't store redundant rows * when the same (unchanged) template is used multiple times. */ public static function findOrCreateFromTemplate(string $slug, array $content): self { $hash = hash('sha256', json_encode($content, JSON_UNESCAPED_UNICODE)); $existing = static::where('slug', $slug) ->where('content_hash', $hash) ->first(); if ($existing) { return $existing; } $nextVersion = (static::where('slug', $slug)->max('version') ?? 0) + 1; return static::create([ 'slug' => $slug, 'version' => $nextVersion, 'name' => $content['name'] ?? $slug, 'content' => $content, 'content_hash' => $hash, ]); } /** * Get all recorded versions for a template slug, newest first. * * @return Collection */ public static function historyFor(string $slug): Collection { return static::where('slug', $slug) ->orderByDesc('version') ->get(); } }