diff --git a/src/Entity/Graphy.php b/src/Entity/Graphy.php
index 39160d8cc61cd70749cbc4c03801795a9afb9c87..c3e7ff4f68bfd1e345f2ab3eaa9523d3fb1590ac 100644
--- a/src/Entity/Graphy.php
+++ b/src/Entity/Graphy.php
@@ -56,6 +56,11 @@ class Graphy
      */
     private $graphyLists;
 
+    /**
+     * @ORM\OneToMany(targetEntity=MetaInfo::class, mappedBy="graphies")
+     */
+    private $metaInfos;
+
     public function __construct()
     {
         $this->headwords = new ArrayCollection();
diff --git a/src/Entity/MetaInfo.php b/src/Entity/MetaInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..beea0badaf0dece7d951c8c55c1c528fb5351023
--- /dev/null
+++ b/src/Entity/MetaInfo.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace App\Entity;
+
+use App\Repository\MetaInfoRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation\Groups;
+use OpenApi\Annotations as OA;
+
+/**
+ * @ORM\Entity(repositoryClass=MetaInfoRepository::class)
+ * @ORM\HasLifecycleCallbacks
+ */
+class MetaInfo
+{
+    const META_INFO_CATEGORY_BOOLEAN = 'bool';
+    const META_INFO_CATEGORY_INTEGER = 'int';
+    const META_INFO_CATEGORY_STRING  = 'string';
+
+    const META_INFO_LIST_CATEGORIES = [
+        self::META_INFO_CATEGORY_BOOLEAN => self::META_INFO_CATEGORY_BOOLEAN,
+        self::META_INFO_CATEGORY_INTEGER => self::META_INFO_CATEGORY_INTEGER,
+        self::META_INFO_CATEGORY_STRING  => self::META_INFO_CATEGORY_STRING,
+    ];
+
+    /**
+     * @ORM\Id
+     * @ORM\GeneratedValue
+     * @ORM\Column(type="integer")
+     */
+    private $id;
+
+    /**
+     * @Groups({"metaInfo:read"})
+     * @ORM\Column(type="datetime_immutable")
+     */
+    private $createdAt;
+
+    /**
+     * @ORM\Column(type="datetime_immutable", nullable=true)
+     */
+    private $updatedAt;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=User::class, inversedBy="metaInfos")
+     * @Groups({"metaInfo:read"})
+     */
+    private $createdBy;
+
+    /**
+     * @ORM\ManyToOne(targetEntity=Graphy::class, inversedBy="metaInfos")
+     * @Groups({"metaInfo:read"})
+     */
+    private $createdBy;
+
+    public function __toString()
+    {
+        return $this->getLabel();
+    }
+
+    /**
+     * @ORM\PrePersist
+     * @ORM\PreUpdate
+     */
+    public function updatedTimestamps(): void
+    {
+        $this->setUpdatedAt(new \DateTimeImmutable('now'));
+        if ($this->getCreatedAt() === null) {
+            $this->setCreatedAt(new \DateTimeImmutable('now'));
+        }
+    }
+
+    public function __construct()
+    {
+        $this->createdAt = new \DateTimeImmutable();
+    }
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getCreatedAt(): ?\DateTimeImmutable
+    {
+        return $this->createdAt;
+    }
+
+    public function setCreatedAt(\DateTimeImmutable $createdAt): self
+    {
+        $this->createdAt = $createdAt;
+
+        return $this;
+    }
+
+    public function getOrigin(): ?string
+    {
+        return $this->origin;
+    }
+
+    public function setOrigin(?string $origin): self
+    {
+        $this->origin = $origin;
+
+        return $this;
+    }
+
+    public function getAction(): ?string
+    {
+        return $this->action;
+    }
+
+    public function setAction(?string $action): self
+    {
+        $this->action = $action;
+
+        return $this;
+    }
+
+    public function getAdditionalInfo(): ?array
+    {
+        return $this->additionalInfo;
+    }
+
+    public function setAdditionalInfo(?array $additionalInfo): self
+    {
+        $this->additionalInfo = $additionalInfo;
+
+        return $this;
+    }
+
+    public function getCreatedBy(): ?User
+    {
+        return $this->createdBy;
+    }
+
+    public function setCreatedBy(?User $createdBy): self
+    {
+        $this->createdBy = $createdBy;
+
+        return $this;
+    }
+}
diff --git a/src/Entity/Trace.php b/src/Entity/Trace.php
index 90f02be18ab23d6dacaf1d5225e67ee61e84bd3f..84829ffb4cf35927f5dd9da735a2efb4a93ac782 100644
--- a/src/Entity/Trace.php
+++ b/src/Entity/Trace.php
@@ -11,7 +11,6 @@ use OpenApi\Annotations as OA;
 
 /**
  * @ORM\Entity(repositoryClass=TraceRepository::class)
- * @ORM\HasLifecycleCallbacks
  */
 class Trace
 {
diff --git a/src/Entity/User.php b/src/Entity/User.php
index a882c7d3f31d994e867f0c9639d83b5b7c5ded42..27c07ad18ab9b8f5996b9e34781ceeed2d0ca2a6 100644
--- a/src/Entity/User.php
+++ b/src/Entity/User.php
@@ -194,6 +194,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
      */
     private $traces;
 
+    /**
+     * @ORM\OneToMany(targetEntity=MetaInfo::class, mappedBy="createdBy")
+     */
+    private $metaInfos;
+
     public function __toString()
     {
         return $this->getPseudo();
diff --git a/src/Repository/MetaInfoRepository.php b/src/Repository/MetaInfoRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..5cc26f4d918b469043e3450d54f32a39f38c79bc
--- /dev/null
+++ b/src/Repository/MetaInfoRepository.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\MetaInfo;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @extends ServiceEntityRepository<MetaInfo>
+ *
+ * @method MetaInfo|null find($id, $lockMode = null, $lockVersion = null)
+ * @method MetaInfo|null findOneBy(array $criteria, array $orderBy = null)
+ * @method MetaInfo[]    findAll()
+ * @method MetaInfo[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
+ */
+class MetaInfoRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, MetaInfo::class);
+    }
+
+    public function search($filter)
+    {
+        $qb = $this->createQueryBuilder('t');
+
+        if ($filter['date'] ?? null) {
+            $qb->andWhere('DATE(t.createdAt) = DATE(:date)')
+                ->setParameter('date', $filter['date'])
+            ;
+        }
+
+        if ($filter['user'] ?? null) {
+            $qb->andWhere('t.createdBy = :user')
+                ->setParameter('user', $filter['user'])
+            ;
+        }
+
+        if ($filter['action'] ?? null) {
+            $qb->andWhere('t.action = :action')
+                ->setParameter('action', $filter['action'])
+            ;
+        }
+
+        if ($filter['origin'] ?? null) {
+            $qb->andWhere('t.origin = :origin')
+                ->setParameter('origin', $filter['origin'])
+            ;
+        }
+
+        return $qb->getQuery()->getResult();
+
+    }
+
+    public function add(MetaInfo $entity, bool $flush = false): void
+    {
+        $this->getEntityManager()->persist($entity);
+
+        if ($flush) {
+            $this->getEntityManager()->flush();
+        }
+    }
+
+    public function remove(MetaInfo $entity, bool $flush = false): void
+    {
+        $this->getEntityManager()->remove($entity);
+
+        if ($flush) {
+            $this->getEntityManager()->flush();
+        }
+    }
+
+//    /**
+//     * @return MetaInfo[] Returns an array of MetaInfo objects
+//     */
+//    public function findByExampleField($value): array
+//    {
+//        return $this->createQueryBuilder('e')
+//            ->andWhere('e.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->orderBy('e.id', 'ASC')
+//            ->setMaxResults(10)
+//            ->getQuery()
+//            ->getResult()
+//        ;
+//    }
+
+//    public function findOneBySomeField($value): ?MetaInfo
+//    {
+//        return $this->createQueryBuilder('e')
+//            ->andWhere('e.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->getQuery()
+//            ->getOneOrNullResult()
+//        ;
+//    }
+}