diff --git a/contracts/admin.py b/contracts/admin.py
index 0d7f8d03ab21e71b383098ea0e40054281e4bca5..7b4aa4ac1285ec591d5dbb364511ce0a8ed9687e 100644
--- a/contracts/admin.py
+++ b/contracts/admin.py
@@ -3,6 +3,7 @@ import typing
 
 from django.contrib import admin
 from django.contrib.auth.models import Permission
+from django.db import models
 from django.utils.html import format_html
 from import_export import resources
 from nested_admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline
@@ -300,10 +301,17 @@ class ContractAdmin(
         queryset = super().get_queryset(request)
 
         if not request.user.has_perm("contracts.view_confidential"):
-            queryset = queryset.filter(is_public=True)
+            # Allow user to view their own objects, even if not public
+            queryset = queryset.filter(
+                models.Q(is_public=True)
+                | models.Q(created_by=request.user)
+            )
 
         if not request.user.has_perm("contracts.approve"):
-            queryset = queryset.filter(is_approved=True)
+            queryset = queryset.filter(
+                models.Q(is_approved=True)
+                | models.Q(created_by=request.user)
+            )
 
         return queryset
 
diff --git a/contracts/migrations/0022_contract_cost_amount_other_alter_contract_cost_unit_and_more.py b/contracts/migrations/0022_contract_cost_amount_other_alter_contract_cost_unit_and_more.py
new file mode 100644
index 0000000000000000000000000000000000000000..8613bcd4977df848f8a38a947ce112acc9b30720
--- /dev/null
+++ b/contracts/migrations/0022_contract_cost_amount_other_alter_contract_cost_unit_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 4.1.4 on 2023-03-30 21:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0021_contract_updated_on_alter_contractee_address_country_and_more'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='contract',
+            name='cost_amount_other',
+            field=models.CharField(blank=True, help_text="Je nutno vyplnit v případě, že máš vybranou možnost 'jiné' v jednotce nákladů.", max_length=128, null=True, verbose_name='Jednotka nákladů (jiné)'),
+        ),
+        migrations.AlterField(
+            model_name='contract',
+            name='cost_unit',
+            field=models.CharField(blank=True, choices=[('hour', 'Hodina'), ('month', 'Měsíc'), ('year', 'Rok'), ('total', 'Celkem'), ('other', 'Jiné')], max_length=5, null=True, verbose_name='Jednotka nákladů'),
+        ),
+        migrations.AlterField(
+            model_name='contract',
+            name='publishing_rejection_comment',
+            field=models.TextField(blank=True, help_text='Obsah není veřejně přístupný.', max_length=65536, null=True, verbose_name='Důvod nezveřejnění'),
+        ),
+    ]
diff --git a/contracts/migrations/0023_alter_contractfile_is_public.py b/contracts/migrations/0023_alter_contractfile_is_public.py
new file mode 100644
index 0000000000000000000000000000000000000000..b948a41a0d7c347cecf68ed9c298846b34804115
--- /dev/null
+++ b/contracts/migrations/0023_alter_contractfile_is_public.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.4 on 2023-03-30 21:31
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0022_contract_cost_amount_other_alter_contract_cost_unit_and_more'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='contractfile',
+            name='is_public',
+            field=models.BooleanField(default=True, verbose_name='Veřejně dostupný'),
+        ),
+    ]
diff --git a/contracts/migrations/0024_alter_contract_is_approved.py b/contracts/migrations/0024_alter_contract_is_approved.py
new file mode 100644
index 0000000000000000000000000000000000000000..d3bfc0e3025e8f0147743f1ca35f88aa773b9dd8
--- /dev/null
+++ b/contracts/migrations/0024_alter_contract_is_approved.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.1.4 on 2023-03-30 22:33
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contracts', '0023_alter_contractfile_is_public'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='contract',
+            name='is_approved',
+            field=models.BooleanField(default=False, help_text='Mohou měnit jen schvalovatelé. Pokud je smlouva veřejná, schválením se vypustí ven.', verbose_name='Je schválená'),
+        ),
+    ]
diff --git a/contracts/models.py b/contracts/models.py
index eedfe6df006d14d5896328e26a80c07d6c7cfdea..a3d10c872b0b78f9079723a2b1c82ec4b86a9bf7 100644
--- a/contracts/models.py
+++ b/contracts/models.py
@@ -374,6 +374,7 @@ class Contract(NameStrMixin, models.Model):
 
     is_approved = models.BooleanField(
         verbose_name="Je schválená",
+        default=False,
         help_text=(
             "Mohou měnit jen schvalovatelé. Pokud je "
             "smlouva veřejná, schválením se vypustí ven."
@@ -452,7 +453,7 @@ class Contract(NameStrMixin, models.Model):
         verbose_name="Stav fyzického dokumentu",
     )
 
-    publishing_rejection_comment = models.CharField(
+    publishing_rejection_comment = models.TextField(
         max_length=65536,
         blank=True,
         null=True,
@@ -487,6 +488,7 @@ class Contract(NameStrMixin, models.Model):
         MONTH = "month", "Měsíc"
         YEAR = "year", "Rok"
         TOTAL = "total", "Celkem"
+        OTHER = "other", "Jiné"
 
     cost_amount = models.PositiveIntegerField(
         blank=True, null=True, verbose_name="Náklady (Kč)"
@@ -500,6 +502,14 @@ class Contract(NameStrMixin, models.Model):
         verbose_name="Jednotka nákladů",
     )
 
+    cost_amount_other = models.CharField(
+        max_length=128,
+        verbose_name="Jednotka nákladů (jiné)",
+        help_text="Je nutno vyplnit v případě, že máš vybranou možnost 'jiné' v jednotce nákladů.",
+        blank=True,
+        null=True,
+    )
+
     filing_area = models.ForeignKey(
         ContractFilingArea,
         on_delete=models.SET_NULL,
@@ -585,6 +595,44 @@ class Contract(NameStrMixin, models.Model):
         self.save()
 
     def clean(self):
+        if (
+            not self.is_public
+            and self.publishing_rejection_comment is None
+        ):
+            raise ValidationError(
+                {
+                    "publishing_rejection_comment": "Pokud smlouva není veřejná, toto pole musí být vyplněné."
+                }
+            )
+        elif (
+            self.is_public
+            and self.publishing_rejection_comment is not None
+        ):
+            raise ValidationError(
+                {
+                    "publishing_rejection_comment": "Nemůže být definováno, pokud je smlouva veřejná."
+                }
+            )
+
+        if (
+            self.cost_unit == self.CostUnits.OTHER[1]
+            and self.cost_amount_other is None
+        ):
+            raise ValidationError(
+                {
+                    "cost_amount_other": "Musí být definováno, pokud je vybrána jednotka nákladů 'jiné'."
+                }
+            )
+        elif (
+            self.cost_unit != self.CostUnits.OTHER[1]
+            and self.cost_amount_other is not None
+        ):
+            raise ValidationError(
+                {
+                    "cost_amount_other": "Nemůže být definováno, pokud není vybrána jednotka nákladů 'jiné'."
+                }
+            )
+
         if (
             self.primary_contract is not None
             and self.is_public
@@ -625,7 +673,7 @@ class ContractFile(NameStrMixin, models.Model):
 
     is_public = models.BooleanField(
         verbose_name="Veřejně dostupný",
-        default=False,
+        default=True,
     )
 
     file = models.FileField(
diff --git a/contracts/views.py b/contracts/views.py
index 2c57b6f0c755bd3cd8bced2a88de7641c2ee3b6e..0fefc0021021e1aebb2383a0d1500a300711d573 100644
--- a/contracts/views.py
+++ b/contracts/views.py
@@ -1,8 +1,7 @@
-import typing
-
 import requests
 from django.conf import settings
 from django.core.paginator import Paginator
+from django.db import models
 from django.http import HttpResponse
 from django.shortcuts import get_object_or_404, render
 from django_downloadview import ObjectDownloadView
@@ -46,18 +45,25 @@ def get_pagination(request, objects) -> tuple:
     return page, paginator
 
 
-def get_paginated_contracts(request, filter: typing.Union[None, dict] = None) -> tuple:
+def get_paginated_contracts(request, filter=None) -> tuple:
     if filter is None:
-        filter = {}
+        filter = models.Q()
 
-    filter["is_approved"] = True
+    filter = models.Q(is_approved=True)
 
     if not request.user.has_perm("contracts.view_confidential"):
-        filter["is_public"] = True
+        filter = filter & (
+            models.Q(is_public=True) |
+            (
+                models.Q(created_by=request.user)
+                if not request.user.is_anonymous
+                else True
+            )
+        )
 
     contracts = (
         get_objects_for_user(request.user, "contracts.view_contract")
-        .filter(**filter)
+        .filter(filter)
         .order_by("valid_start_date")
         .all()
     )
@@ -84,15 +90,22 @@ def index(request):
 
 
 def view_contract(request, id: int):
-    filter = {"is_approved": True}
+    filter = models.Q(is_approved=True)
 
     if not request.user.has_perm("contracts.view_confidential"):
-        filter["is_public"] = True
+        filter = filter & (
+            models.Q(is_public=True) |
+            (
+                models.Q(created_by=request.user)
+                if not request.user.is_anonymous
+                else True
+            )
+        )
 
     contract = get_object_or_404(
         (
             get_objects_for_user(request.user, "contracts.view_contract")
-            .filter(**filter)
+            .filter(filter)
         ),
         id=id
     )
@@ -119,7 +132,7 @@ def view_contract_filing_area(request, id: int):
     )
 
     contracts_page, contracts_paginator = get_paginated_contracts(
-        request, {"filing_area": filing_area}
+        request, models.Q(filing_area=filing_area)
     )
 
     return render(
@@ -146,7 +159,7 @@ def view_contract_issue(request, id: int):
     )
 
     contracts_page, contracts_paginator = get_paginated_contracts(
-        request, {"issues": issue}
+        request, models.Q(issues=issue)
     )
 
     return render(
@@ -170,7 +183,7 @@ def view_contract_type(request, id: int):
     )
 
     contracts_page, contracts_paginator = get_paginated_contracts(
-        request, {"types": type_}
+        request, models.Q(types=type_)
     )
 
     return render(
@@ -194,7 +207,7 @@ def view_contractee(request, id: int):
     )
 
     contracts_page, contracts_paginator = get_paginated_contracts(
-        request, {"contractee_signatures__contractee": contractee}
+        request, models.Q(contractee_signatures__contractee=contractee)
     )
 
     return render(
@@ -218,7 +231,7 @@ def view_signee(request, id: int):
     )
 
     contracts_page, contracts_paginator = get_paginated_contracts(
-        request, {"signee_signatures__signee": signee}
+        request, models.Q(signee_signatures__signee=signee)
     )
 
     return render(