diff --git a/database/migrations/2025_10_06_180000_alter_document_templates_slug_unique.php b/database/migrations/2025_10_06_180000_alter_document_templates_slug_unique.php
new file mode 100644
index 0000000..a86f173
--- /dev/null
+++ b/database/migrations/2025_10_06_180000_alter_document_templates_slug_unique.php
@@ -0,0 +1,44 @@
+dropUnique('document_templates_slug_unique');
+ } catch (Throwable $e) {
+ // Ignore if already dropped / not present (SQLite memory or prior manual change)
+ }
+ // Add composite unique to allow multiple versions per slug while preventing duplicate version numbers
+ $table->unique(['slug', 'version'], 'document_templates_slug_version_unique');
+ // Optional plain index on slug alone (not unique) to speed lookups by slug
+ $table->index('slug', 'document_templates_slug_index');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::table('document_templates', function (Blueprint $table) {
+ // Drop composite + plain indices
+ try {
+ $table->dropIndex('document_templates_slug_index');
+ } catch (Throwable $e) {
+ }
+ try {
+ $table->dropUnique('document_templates_slug_version_unique');
+ } catch (Throwable $e) {
+ }
+ // Restore original simple unique on slug
+ try {
+ $table->unique('slug', 'document_templates_slug_unique');
+ } catch (Throwable $e) {
+ }
+ });
+ }
+};
diff --git a/tests/Feature/DocumentTemplateVersioningTest.php b/tests/Feature/DocumentTemplateVersioningTest.php
new file mode 100644
index 0000000..75e4783
--- /dev/null
+++ b/tests/Feature/DocumentTemplateVersioningTest.php
@@ -0,0 +1,59 @@
+create();
+ $role = Role::firstOrCreate(['slug' => 'admin'], ['name' => 'Admin']);
+ $user->roles()->sync([$role->id]);
+ $this->actingAs($user);
+
+ $docxV1 = $this->fakeDocxWithBody('{{contract.reference}}');
+ $this->post(route('admin.document-templates.store'), [
+ 'name' => 'Povzetek pogodbe',
+ 'slug' => 'contract-summary',
+ 'file' => $docxV1,
+ ])->assertRedirect();
+
+ $this->assertDatabaseHas('document_templates', [
+ 'slug' => 'contract-summary',
+ 'version' => 1,
+ ]);
+
+ $docxV2 = $this->fakeDocxWithBody('{{contract.reference}} {{generation.date}}');
+ $this->post(route('admin.document-templates.store'), [
+ 'name' => 'Povzetek pogodbe',
+ 'slug' => 'contract-summary',
+ 'file' => $docxV2,
+ ])->assertRedirect();
+
+ $this->assertDatabaseHas('document_templates', [
+ 'slug' => 'contract-summary',
+ 'version' => 2,
+ ]);
+
+ $this->assertEquals(2, \App\Models\DocumentTemplate::where('slug', 'contract-summary')->count());
+ }
+
+ private function fakeDocxWithBody(string $body): UploadedFile
+ {
+ $tmp = tempnam(sys_get_temp_dir(), 'docx');
+ $zip = new \ZipArchive;
+ $zip->open($tmp, \ZipArchive::OVERWRITE);
+ $zip->addFromString('[Content_Types].xml', '');
+ $zip->addFromString('word/document.xml', ''.$body.'');
+ $zip->close();
+
+ return UploadedFile::fake()->createWithContent('template.docx', file_get_contents($tmp));
+ }
+}