diff --git a/README.md b/README.md
index d8a4e8afcbd1b0bf87dfd48b10f32af33ad7abbe..2c33677e4b381c080a40d3a87c8ff53bde005d22 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,12 @@ Idea: make statically typed what is possible and prevent typos.
 - do not write it twice (sync database to database-access-layer classes)
 - do not screw up database - support for rich types as UUID, arrays, ... (easy to add more)
 
+# Docs
+
+- This library currenly missing comprehensive docs.
+- [Cook book](docs/cookbook) – contains useful solutions for situations we have been facing in practise.
+
+
 ## Installation
 
 This is private repo, so you have to add repositories to you `composer.json` manually. This tells composer where to find our packages.
@@ -46,3 +52,4 @@ composer require grifart/tables:dev-master
 # 2. install grifart/class-scaffolder for automatic defintions generation:
 composer require grifart/class-scaffolder
 ````
+
diff --git a/docs/cookbook/migrate-to-composite-field.md b/docs/cookbook/migrate-to-composite-field.md
new file mode 100644
index 0000000000000000000000000000000000000000..dd9b2ea2a3525b72a3023fcd20ef14dc64aabdb6
--- /dev/null
+++ b/docs/cookbook/migrate-to-composite-field.md
@@ -0,0 +1,52 @@
+# Migrate to composite field
+
+Sometimes you start with table containing values, which you then see have dependency on each other. As happened with [Stamp object](https://gitlab.grifart.cz/ivy/server/-/merge_requests/222/diffs#note_69354) (originally named `auditTrail`).
+
+## 1. migrating database
+
+```sql
+-- prepare new data type in PostgreSQL
+CREATE TYPE "public"."auditTrail" AS (
+	"occurredAt" timestamp without time zone,
+	"causedBy" uuid
+);
+
+-- Add column with default value
+ALTER TABLE "clinic"."patient"
+	ADD COLUMN "created" "public"."auditTrail" DEFAULT NULL;
+
+-- migrate data from two original columns to the new composite one
+UPDATE "clinic"."patient" SET
+	"created" = ROW("createdAt", "createdBy");
+
+-- removed old one and remove DEFAULT value (as it should be required filed at the end)
+ALTER TABLE "clinic"."patient"
+	ALTER COLUMN "created" SET NOT NULL,
+	ALTER COLUMN "created" DROP DEFAULT,
+	DROP COLUMN "createdAt",
+	DROP COLUMN "createdBy";
+```
+
+And add mapping of new field. It is useful to use PostgreSQL tools for composite & array types. This helper class will provide you logic for (de)serializing these composite types into standard SQL query.
+
+```php
+<?php
+		$phpToDatabaseMapper->addMapping(
+			static fn(string $dbType): ?string => $dbType === 'stamp' ? Stamp::class : null,
+			static fn(Stamp $trail): string => PostgreSQLTools::toPgComposite([
+				(string) $trail->getOccurredAt(),
+				$trail->getCausedBy()->toString(),
+			]),
+		);
+		$databaseToPhpMapper->addMapping(
+			static fn(string $dbType): ?string => $dbType === 'stamp' ? Stamp::class : null,
+			static function (string $value): Stamp {
+				[$occurredAt, $causedBy] = PostgreSQLTools::fromPgComposite($value);
+				$occurredAtLocal = LocalDateTime::parse($occurredAt, ISO8601Parsers::dateTime());
+				return Stamp::from(
+					AccountId::of($causedBy),
+					$occurredAtLocal->atTimeZone(TimeZone::utc())->getInstant(),
+				);
+			},
+		);
+```
\ No newline at end of file