diff --git a/app/config/packages/security.yaml b/app/config/packages/security.yaml
index 198b9ae5195ffc64cea98b8f0696dcb2f9a09201..37c76cf6cff9308a7408e42bc197bad85b5666ed 100644
--- a/app/config/packages/security.yaml
+++ b/app/config/packages/security.yaml
@@ -55,6 +55,10 @@ security:
 
         - { path: ^/api/profile/recovery, roles: PUBLIC_ACCESS }
         - { path: ^/api/profile/recovery/check, roles: PUBLIC_ACCESS }
+        - { path: ^/api/profile/reset/email, roles: ROLE_USER }
+        - { path: ^/api/profile/reset/field, roles: ROLE_USER }
+        - { path: ^/api/profile/change, roles: ROLE_USER }
+        - { path: ^/api/profile, roles: ROLE_USER }
         - { path: ^/api,       roles: ROLE_CONFIRMED }
         # - { path: ^/admin, roles: ROLE_ADMIN }
         # - { path: ^/profile, roles: ROLE_USER }
diff --git a/app/config/services.yaml b/app/config/services.yaml
index 4fe458b04fddda5bf74a022019a51ed2bd0704bb..cc9ab17cf9cfaf64c2a46cf3cc4ea788506f15c7 100644
--- a/app/config/services.yaml
+++ b/app/config/services.yaml
@@ -44,6 +44,10 @@ services:
 
     App\Service\Action\ActionServiceInterface $resetPasswordService: '@App\Service\Action\Classes\ResetPassword'
 
+    App\Service\Action\ActionServiceInterface $profileChangeService: '@App\Service\Action\Classes\ChangeProfile'
+
+    App\Service\Action\ActionServiceInterface $resetEmailService: '@App\Service\Action\Classes\ResetEmail'
+
     App\Service\Action\ActionServiceInterface: '@App\Service\Action\Classes\None'
 
 
@@ -58,6 +62,8 @@ services:
 
     App\Service\Dto\DtoServiceInterface $passwordDto: '@App\Service\Dto\Classes\ChangePasswordDto'
 
+    App\Service\Dto\DtoServiceInterface $profileDto: '@App\Service\Dto\Classes\ChangeProfileDto'
+
     App\Service\Dto\DtoServiceInterface $recoveryDto: '@App\Service\Dto\Classes\RecoveryDto'
 
     App\Service\Dto\DtoServiceInterface: '@App\Service\Dto\Classes\NoneDto'
diff --git a/app/migrations/Version20240620091453.php b/app/migrations/Version20240620091453.php
new file mode 100644
index 0000000000000000000000000000000000000000..0cbe709689d044264d857fde7e1a195a7396ba00
--- /dev/null
+++ b/app/migrations/Version20240620091453.php
@@ -0,0 +1,37 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240620091453 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE SEQUENCE user_history_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+        $this->addSql('CREATE TABLE user_history (id INT NOT NULL, related_user_id INT NOT NULL, date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, field VARCHAR(255) DEFAULT NULL, type VARCHAR(255) NOT NULL, value VARCHAR(255) DEFAULT NULL, old_value VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');
+        $this->addSql('CREATE INDEX IDX_7FB76E4198771930 ON user_history (related_user_id)');
+        $this->addSql('ALTER TABLE user_history ADD CONSTRAINT FK_7FB76E4198771930 FOREIGN KEY (related_user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE SCHEMA public');
+        $this->addSql('DROP SEQUENCE user_history_id_seq CASCADE');
+        $this->addSql('ALTER TABLE user_history DROP CONSTRAINT FK_7FB76E4198771930');
+        $this->addSql('DROP TABLE user_history');
+    }
+}
diff --git a/app/migrations/Version20240620121602.php b/app/migrations/Version20240620121602.php
new file mode 100644
index 0000000000000000000000000000000000000000..56d05ee180b5c4def1aaafda8bc41e64e4a2268c
--- /dev/null
+++ b/app/migrations/Version20240620121602.php
@@ -0,0 +1,32 @@
+<?php
+
+declare(strict_types=1);
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\Migrations\AbstractMigration;
+
+/**
+ * Auto-generated Migration: Please modify to your needs!
+ */
+final class Version20240620121602 extends AbstractMigration
+{
+    public function getDescription(): string
+    {
+        return '';
+    }
+
+    public function up(Schema $schema): void
+    {
+        // this up() migration is auto-generated, please modify it to your needs
+        $this->addSql('ALTER TABLE "user" ALTER patronymic DROP NOT NULL');
+    }
+
+    public function down(Schema $schema): void
+    {
+        // this down() migration is auto-generated, please modify it to your needs
+        $this->addSql('CREATE SCHEMA public');
+        $this->addSql('ALTER TABLE "user" ALTER patronymic SET NOT NULL');
+    }
+}
diff --git a/app/src/Controller/ProfileController.php b/app/src/Controller/ProfileController.php
index 75f10cf03a15604ad1173cd9e86379781de3638b..348eac7bfa59ea28489876f3e1794ad6e740a89f 100644
--- a/app/src/Controller/ProfileController.php
+++ b/app/src/Controller/ProfileController.php
@@ -3,6 +3,7 @@
 namespace App\Controller;
 
 use App\Service\Action\ActionServiceInterface;
+use App\Service\Dto\Classes\ChangeProfileDto;
 use App\Service\Dto\Classes\RecoveryCodeDto;
 use App\Service\Dto\Classes\RecoveryDto;
 use App\Service\Response\Classes\ProfileResponse;
@@ -82,4 +83,37 @@ class ProfileController extends AbstractController
     {
         return $checkRecoveryService->getResponse();
     }
+
+    #[Route('/profile/change', name: 'profile_change', methods: ['POST'])]
+    #[OA\RequestBody(
+        content: new OA\JsonContent(ref: new Model(type: ChangeProfileDto::class))
+    )]
+    #[OA\Response(
+        response: 200,
+        description: 'Ответ',
+        content: new OA\JsonContent(
+            ref: new Model(type: ProfileResponse::class, groups: ["message", "data", "profile"])
+        )
+    )]
+    public function changeProfile(
+        ActionServiceInterface $profileChangeService,
+    ): JsonResponse
+    {
+        return $profileChangeService->getResponse();
+    }
+
+    #[Route('/profile/reset/email', name: 'profile_reset_email', methods: ['GET'])]
+    #[OA\Response(
+        response: 200,
+        description: 'Ответ',
+        content: new OA\JsonContent(
+            ref: new Model(type: Response::class, groups: ["message"])
+        )
+    )]
+    public function resetLastConfirmEmail(
+        ActionServiceInterface $resetEmailService,
+    ): JsonResponse
+    {
+        return $resetEmailService->getResponse();
+    }
 }
diff --git a/app/src/Entity/User.php b/app/src/Entity/User.php
index 1ec76ec0bcf09d742a86fc849c22c6db5132d051..96c4f82e327292e7e36312a4ce86e81312640a87 100644
--- a/app/src/Entity/User.php
+++ b/app/src/Entity/User.php
@@ -3,11 +3,22 @@
 namespace App\Entity;
 
 use App\Repository\UserRepository;
+use Doctrine\Common\Collections\ArrayCollection;
+use Doctrine\Common\Collections\Collection;
 use Doctrine\ORM\Mapping as ORM;
+use ReflectionClass;
+use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
 use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
 use Symfony\Component\Security\Core\User\UserInterface;
 use Symfony\Component\Serializer\Annotation\Groups;
 use Symfony\Component\Serializer\Annotation\Ignore;
+use Symfony\Component\Serializer\Encoder\JsonEncoder;
+use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
+use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
+use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
+use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
+use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
+use Symfony\Component\Serializer\Serializer;
 use Symfony\Component\Validator\Constraints as Assert;
 
 #[ORM\Entity(repositoryClass: UserRepository::class)]
@@ -41,7 +52,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
     #[ORM\Column(length: 255)]
     private ?string $surname = null;
 
-    #[ORM\Column(length: 255)]
+    #[ORM\Column(length: 255, nullable: true)]
     private ?string $patronymic = null;
 
     #[ORM\Column(length: 255, nullable: true)]
@@ -59,6 +70,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
     #[ORM\OneToOne(mappedBy: 'related_user', cascade: ['persist', 'remove'])]
     private ?UserCode $register_code = null;
 
+    /**
+     * @var Collection<int, UserHistory>
+     */
+    #[ORM\OneToMany(targetEntity: UserHistory::class, mappedBy: 'related_user', cascade: ['persist', 'remove'],fetch: 'EAGER')]
+    private Collection $userHistories;
+
+    public function __construct()
+    {
+        $this->userHistories = new ArrayCollection();
+    }
+
     #[Groups(['all'])]
     public function getId(): ?int
     {
@@ -178,7 +200,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
         return $this->patronymic;
     }
 
-    public function setPatronymic(string $patronymic): static
+    public function setPatronymic(?string $patronymic): static
     {
         $this->patronymic = $patronymic;
 
@@ -221,7 +243,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
         return $this;
     }
 
-    #[Groups(['all', 'profile'])]
+    #[Groups(['all', 'profile', 'edit'])]
     public function isConfirm(): ?bool
     {
         return $this->confirm;
@@ -234,6 +256,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
         return $this;
     }
 
+    #[Groups(['all', 'profile', 'edit'])]
     public function isDeleted(): ?bool
     {
         return $this->deleted;
@@ -273,4 +296,101 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
 
         return $this;
     }
+
+    /**
+     * @return Collection<int, UserHistory>
+     */
+    #[Groups(['all', 'profile'])]
+    public function getUserHistories(): Collection
+    {
+        return $this->userHistories;
+    }
+
+    public function addUserHistory(UserHistory $userHistory): static
+    {
+        if (!$this->userHistories->contains($userHistory)) {
+            $this->userHistories->add($userHistory);
+            $userHistory->setRelatedUser($this);
+        }
+
+        return $this;
+    }
+
+    public function removeUserHistory(UserHistory $userHistory): static
+    {
+        if ($this->userHistories->removeElement($userHistory)) {
+            // set the owning side to null (unless already changed)
+            if ($userHistory->getRelatedUser() === $this) {
+                $userHistory->setRelatedUser(null);
+            }
+        }
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getLastConfirmEmail(): ?string
+    {
+        $lastDate = null;
+        $lastEmail = null;
+        foreach ($this->getUserHistories() as $userHistory) {
+            if ($userHistory->getField() === 'confirm' && $userHistory->getDate() && $userHistory->getType() === UserHistory::TYPE_CREATE) {
+                if ($lastDate === null || $lastDate->getTimestamp() < $userHistory->getDate()->getTimestamp()) {
+                    $lastDate = $userHistory->getDate();
+                    $lastEmail = $userHistory->getValue();
+                }
+            }
+        }
+
+        return $lastEmail;
+    }
+
+    /**
+     * Создание пользователя по массиву
+     *
+     * @param array $data
+     *
+     * @return self
+     */
+    #[Ignore()]
+    public static function createByArray(array $data, array $groups = ['edit']): ?self
+    {
+        try {
+            $normalizer = new ObjectNormalizer(
+                new ClassMetadataFactory(new AttributeLoader()),
+                new CamelCaseToSnakeCaseNameConverter(),
+                null,
+                new ReflectionExtractor()
+            );
+            $serializer = new Serializer(
+                [$normalizer, new DateTimeNormalizer()],
+                [new JsonEncoder()]
+            );
+            return $serializer->deserialize(
+                json_encode($data, JSON_THROW_ON_ERROR),
+                __CLASS__,
+                'json',
+                [
+                    'groups' => $groups,
+                ]
+            );
+        } catch (\Exception $exception) {
+            return null;
+        }
+    }
+
+    #[Ignore()]
+    public function newCopy(array $groups = ['edit']): ?self
+    {
+        $normalizer = new ObjectNormalizer(
+            new ClassMetadataFactory(new AttributeLoader()),
+            new CamelCaseToSnakeCaseNameConverter(),
+            null,
+            new ReflectionExtractor()
+        );
+        $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
+        $data = $serializer->serialize($this, 'json', ['groups' => $groups]);
+        $array = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
+        return self::createByArray($array, $groups);
+    }
 }
diff --git a/app/src/Entity/UserHistory.php b/app/src/Entity/UserHistory.php
new file mode 100644
index 0000000000000000000000000000000000000000..cc4d2889392cf302c8de901683d9b6d4a2a76637
--- /dev/null
+++ b/app/src/Entity/UserHistory.php
@@ -0,0 +1,182 @@
+<?php
+
+namespace App\Entity;
+
+use App\Listeners\UserListener;
+use App\Repository\UserHistoryRepository;
+use Doctrine\DBAL\Types\Types;
+use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation\Groups;
+
+#[ORM\Entity(repositoryClass: UserHistoryRepository::class)]
+class UserHistory
+{
+    public const TYPE_CREATE = 'create';
+    public const TYPE_UPDATE = 'update';
+    public const TYPE_DELETE = 'delete';
+    public const TYPE_RECOVERY = 'recovery';
+
+    #[ORM\Id]
+    #[ORM\GeneratedValue]
+    #[ORM\Column]
+    private ?int $id = null;
+
+    #[ORM\ManyToOne(inversedBy: 'userHistories')]
+    #[ORM\JoinColumn(nullable: false)]
+    private ?User $related_user = null;
+
+    #[ORM\Column(type: Types::DATETIME_MUTABLE)]
+    private ?\DateTimeInterface $date = null;
+
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $field = null;
+
+    #[ORM\Column(length: 255)]
+    private ?string $type = null;
+
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $value = null;
+
+    #[ORM\Column(length: 255, nullable: true)]
+    private ?string $old_value = null;
+
+    public function getId(): ?int
+    {
+        return $this->id;
+    }
+
+    public function getRelatedUser(): ?User
+    {
+        return $this->related_user;
+    }
+
+    public function setRelatedUser(?User $related_user): static
+    {
+        $this->related_user = $related_user;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getDate(): ?\DateTimeInterface
+    {
+        return $this->date;
+    }
+
+    public function setDate(\DateTimeInterface $date): static
+    {
+        $this->date = $date;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getField(): ?string
+    {
+        return $this->field;
+    }
+
+    public function setField(?string $field): static
+    {
+        $this->field = $field;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getType(): ?string
+    {
+        return $this->type;
+    }
+
+    public function setType(string $type): static
+    {
+        $this->type = $type;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getValue(): ?string
+    {
+        return $this->value;
+    }
+
+    public function setValue(?string $value): static
+    {
+        $this->value = $value;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getOldValue(): ?string
+    {
+        return $this->old_value;
+    }
+
+    public function setOldValue(?string $old_value): static
+    {
+        $this->old_value = $old_value;
+
+        return $this;
+    }
+
+    #[Groups(['all', 'profile'])]
+    public function getText(): ?string
+    {
+        $text = '';
+        $type = $this->getType();
+
+        switch ($field = $this->getField()) {
+            case 'confirm':
+                switch ($type) {
+                    case self::TYPE_CREATE:
+                        $text = 'Почта подтверждена';
+                        break;
+                    case self::TYPE_DELETE:
+                        $text = 'Подтверждение почты сброшено';
+                        break;
+                }
+                break;
+            case 'user':
+                switch ($type) {
+                    case self::TYPE_CREATE:
+                        $text = 'Пользователь зарегистрирован';
+                        break;
+                    case self::TYPE_UPDATE:
+                        $text = 'Пользователь обновлен';
+                        break;
+                    case self::TYPE_RECOVERY:
+                        $text = 'Пользователь восстановлен';
+                        break;
+                    case self::TYPE_DELETE:
+                        $text = 'Пользователь удален';
+                        break;
+                }
+                break;
+            default:
+                if (isset(UserListener::HISTORY_FIELDS[$field])) {
+                    switch ($type) {
+                        case self::TYPE_CREATE:
+                            $text = 'Поле "' . UserListener::HISTORY_FIELDS[$field] . '" заполнено';
+                            break;
+                        case self::TYPE_UPDATE:
+                            $text = 'Поле "' . UserListener::HISTORY_FIELDS[$field] . '" обновлено';
+                            break;
+                        case self::TYPE_DELETE:
+                            $text = 'Поле "' . UserListener::HISTORY_FIELDS[$field] . '" удалено ';
+                            break;
+                    }
+                }
+                break;
+        }
+
+        $time = '';
+        if ($date = $this->getDate()) {
+            $time = $date->format('d.m.Y H:i:s') . ' - ';
+        }
+
+        return $time .  $text;
+    }
+}
diff --git a/app/src/Listeners/UserListener.php b/app/src/Listeners/UserListener.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac6c08418622ee84337d40ed70aafb8ed105e9f9
--- /dev/null
+++ b/app/src/Listeners/UserListener.php
@@ -0,0 +1,139 @@
+<?php
+
+namespace App\Listeners;
+
+use App\Entity\User;
+use App\Entity\UserHistory;
+use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;
+use Doctrine\ORM\Event\PreFlushEventArgs;
+use Doctrine\ORM\Event\PreUpdateEventArgs;
+use Doctrine\ORM\Events;
+use Doctrine\ORM\UnitOfWork;
+use Doctrine\Persistence\ObjectManager;
+use ReflectionClass;
+
+#[AsEntityListener(event: Events::preFlush, method: 'prePersist', entity: User::class)]
+#[AsEntityListener(event: Events::preUpdate, method: 'preUpdate', entity: User::class)]
+#[AsEntityListener(event: Events::preFlush, method: 'prePersistHistory', entity: UserHistory::class)]
+#[AsEntityListener(event: Events::preUpdate, method: 'preUpdateHistory', entity: UserHistory::class)]
+class UserListener
+{
+    public const HISTORY_FIELDS = [
+        'email' => 'Email',
+        'name' => 'Имя',
+        'surname' => 'Фамилия',
+        'patronymic' => 'Отчество',
+        'phone_number' => 'Номер телефона'
+    ];
+
+    public function prePersist(User $user, PreFlushEventArgs $args): void
+    {
+        $this->checkEmail($user, $args->getObjectManager());
+        $this->saveHistory($user, $args->getObjectManager());
+    }
+
+    public function preUpdate(User $user, PreUpdateEventArgs $args): void
+    {
+        $this->checkEmail($user, $args->getObjectManager());
+        $this->saveHistory($user, $args->getObjectManager());
+    }
+
+    public function saveHistory(User $user, ObjectManager $om): void
+    {
+        /** @var UnitOfWork $uow */
+        $uow = $om->getUnitOfWork();
+        $originalValues = $uow->getOriginalEntityData($user);
+        $userExists = null;
+        if ($originalValues) {
+            $userExists = User::createByArray($originalValues);
+        }
+        $checkUser = $user->newCopy();
+
+        if ($user->getId() && $userExists) {
+            $reflectionClass = new ReflectionClass($user);
+            foreach ($reflectionClass->getProperties() as $property) {
+                $name = $property->getName();
+                if (!isset(self::HISTORY_FIELDS[$name])) {
+                    continue;
+                }
+                $value = $property->getValue($checkUser);
+                $oldValue = $property->getValue($userExists);
+                if ($value !== $oldValue) {
+                    if (empty($value) && empty($oldValue)) {
+                        continue;
+                    }
+
+                    $type = UserHistory::TYPE_UPDATE;
+                    if (empty($value)) {
+                        $type = UserHistory::TYPE_DELETE;
+                    } elseif (empty($oldValue)) {
+                        $type = UserHistory::TYPE_CREATE;
+                    }
+                    $newUserHistory = new UserHistory();
+                    $newUserHistory->setType($type);
+                    $newUserHistory->setField($name);
+                    $newUserHistory->setValue($value);
+                    $newUserHistory->setOldValue($oldValue);
+                    $user->addUserHistory($newUserHistory);
+                }
+            }
+            if ($userExists->isDeleted() !== $user->isDeleted()) {
+                $newUserHistory = new UserHistory();
+                $newUserHistory->setType($user->isDeleted() ? UserHistory::TYPE_DELETE : UserHistory::TYPE_RECOVERY);
+                $newUserHistory->setField('user');
+                $user->addUserHistory($newUserHistory);
+            }
+            if ($userExists->isConfirm() !== $user->isConfirm()) {
+                $newUserHistory = new UserHistory();
+                $newUserHistory->setType($user->isConfirm() ? UserHistory::TYPE_CREATE : UserHistory::TYPE_DELETE);
+                if ($user->isConfirm()) {
+                    $newUserHistory->setValue($user->getEmail());
+                }
+                $newUserHistory->setField('confirm');
+                $user->addUserHistory($newUserHistory);
+            }
+        } else {
+            $newUserHistory = new UserHistory();
+            $newUserHistory->setType(UserHistory::TYPE_CREATE);
+            $newUserHistory->setField('user');
+            $user->addUserHistory($newUserHistory);
+        }
+    }
+
+    public function checkEmail(User $user, ObjectManager $om): void
+    {
+        if ($user->getId()) {
+            /** @var UnitOfWork $uow */
+            $uow = $om->getUnitOfWork();
+            $originalValues = $uow->getOriginalEntityData($user);
+            $userExists = null;
+            if ($originalValues) {
+                $userExists = User::createByArray($originalValues);
+            }
+            if ($userExists) {
+                if ($userExists->getEmail() !== $user->getEmail()) {
+                    $user->setConfirm($user->getLastConfirmEmail() === $user->getEmail());
+                }
+            }
+        } else {
+            $user->setConfirm(false);
+        }
+    }
+
+    public function prePersistHistory(UserHistory $userHistory, PreFlushEventArgs $args): void
+    {
+        $this->setHistoryDate($userHistory);
+    }
+
+    public function preUpdateHistory(UserHistory $userHistory, PreUpdateEventArgs $args): void
+    {
+        $this->setHistoryDate($userHistory);
+    }
+
+    public function setHistoryDate(UserHistory $userHistory): void
+    {
+        if (!$userHistory->getDate()) {
+            $userHistory->setDate(new \DateTime());
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/Repository/UserHistoryRepository.php b/app/src/Repository/UserHistoryRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..276bcaa258ee4fb1a97f8b4bd2dd782d42b7dfd8
--- /dev/null
+++ b/app/src/Repository/UserHistoryRepository.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Repository;
+
+use App\Entity\UserHistory;
+use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
+use Doctrine\Persistence\ManagerRegistry;
+
+/**
+ * @extends ServiceEntityRepository<UserHistory>
+ */
+class UserHistoryRepository extends ServiceEntityRepository
+{
+    public function __construct(ManagerRegistry $registry)
+    {
+        parent::__construct($registry, UserHistory::class);
+    }
+
+//    /**
+//     * @return UserHistory[] Returns an array of UserHistory objects
+//     */
+//    public function findByExampleField($value): array
+//    {
+//        return $this->createQueryBuilder('u')
+//            ->andWhere('u.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->orderBy('u.id', 'ASC')
+//            ->setMaxResults(10)
+//            ->getQuery()
+//            ->getResult()
+//        ;
+//    }
+
+//    public function findOneBySomeField($value): ?UserHistory
+//    {
+//        return $this->createQueryBuilder('u')
+//            ->andWhere('u.exampleField = :val')
+//            ->setParameter('val', $value)
+//            ->getQuery()
+//            ->getOneOrNullResult()
+//        ;
+//    }
+}
diff --git a/app/src/Repository/UserRepository.php b/app/src/Repository/UserRepository.php
index 53ebb8c7ef75289955006f23802bd7aa6ba35b4e..7046472538cde69ec47f70ed2821d93176c12537 100644
--- a/app/src/Repository/UserRepository.php
+++ b/app/src/Repository/UserRepository.php
@@ -59,6 +59,13 @@ class UserRepository extends ServiceEntityRepository implements PasswordUpgrader
             ->getOneOrNullResult();
     }
 
+    public function getById(int $id): ?User
+    {
+        $oQuery = $this->createQueryBuilder('u');
+        $oQuery->andWhere('u.id = :id')->setParameter('id', $id);
+        return $oQuery->getQuery()->getOneOrNullResult();
+    }
+
     //    /**
     //     * @return User[] Returns an array of User objects
     //     */
diff --git a/app/src/Service/Action/Classes/ChangeProfile.php b/app/src/Service/Action/Classes/ChangeProfile.php
new file mode 100644
index 0000000000000000000000000000000000000000..62d1ef0f2c9dafa26813a204376cbf7c3cf4d53c
--- /dev/null
+++ b/app/src/Service/Action/Classes/ChangeProfile.php
@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Service\Action\Classes;
+
+use App\Entity\User;
+use App\Service\Action\BaseActionService;
+use App\Service\Dto\Classes\ChangeProfileDto;
+use App\Service\Dto\DtoServiceInterface;
+use App\Service\Response\ResponseServiceInterface;
+use Doctrine\Persistence\ManagerRegistry;
+use Symfony\Bundle\SecurityBundle\Security;
+
+class ChangeProfile extends BaseActionService
+{
+    private ?User $user;
+
+    public function __construct(
+        private ResponseServiceInterface $profileResponse,
+        private DtoServiceInterface      $profileDto,
+        private ManagerRegistry          $doctrine,
+        Security                         $security
+    )
+    {
+        $this->user = $security->getUser();
+        parent::__construct($profileResponse);
+    }
+
+    public function runAction(): void
+    {
+        /** @var ChangeProfileDto $dto */
+        $dto = $this->profileDto->getClass();
+
+        /** @var ?User $userExists */
+        $userExists = $this->doctrine->getRepository(User::class)
+            ->findOneByUniq($dto->email, $dto->phoneNumber, $this->user->getId());
+
+        if ($userExists !== null) {
+            if ($userExists->getEmail() === $dto->email) {
+                $this->profileResponse->addError('Email занят другим пользователем');
+            } elseif ($userExists->getPhoneNumber() === $dto->phoneNumber) {
+                $this->profileResponse->addError('Номер телефона занят другим пользователем');
+            } else {
+                $this->profileResponse->addError('Email или номер телефона занят другим пользователем');
+            }
+        } else {
+            $changed = false;
+
+            if ($dto->name !== null && $dto->name !== $this->user->getName()) {
+                $this->user->setName($dto->name);
+                $changed = true;
+            }
+
+            if ($dto->surname !== null && $dto->surname !== $this->user->getSurname()) {
+                $this->user->setSurname($dto->surname);
+                $changed = true;
+            }
+
+            if ($dto->patronymic !== null && $dto->patronymic !== $this->user->getPatronymic()) {
+                $this->user->setPatronymic($dto->patronymic);
+                $changed = true;
+            }
+
+            if ($dto->phoneNumber !== null && $dto->phoneNumber !== $this->user->getPhoneNumber()) {
+                $this->user->setPhoneNumber($dto->phoneNumber);
+                $changed = true;
+            }
+
+            if ($dto->email !== null  && $dto->email !== $this->user->getEmail()) {
+                $this->user->setEmail($dto->email);
+                $changed = true;
+            }
+
+            if ($changed) {
+                try {
+                    $em = $this->doctrine->getManager();
+                    $em->persist($this->user);
+                    $em->flush();
+                    $this->profileResponse->setData($this->user);
+                } catch (\Exception $e) {
+                    $this->profileResponse->addError('Ошибка сохранения профиля');
+                }
+            } else {
+                $this->profileResponse->setData($this->user);
+            }
+        }
+    }
+
+    public function validate(): bool
+    {
+        if ($this->user === null) {
+            $this->profileResponse->addError('Вы не авторизованы');
+            return false;
+        }
+        return $this->profileDto->validate($this->profileResponse);
+    }
+}
\ No newline at end of file
diff --git a/app/src/Service/Action/Classes/GetProfile.php b/app/src/Service/Action/Classes/GetProfile.php
index 73f5526444fda9331f13b0410e512f021b07bb96..8a98a3a812026af5270f5f6fa502d8a80c13f014 100644
--- a/app/src/Service/Action/Classes/GetProfile.php
+++ b/app/src/Service/Action/Classes/GetProfile.php
@@ -17,7 +17,6 @@ class GetProfile extends BaseActionService
     /**
      * @param ProfileResponse $profileResponse
      * @param Security $security
-     * @param SerializerInterface $serializer
      */
     public function __construct(
         private ResponseServiceInterface $profileResponse,
@@ -47,6 +46,10 @@ class GetProfile extends BaseActionService
             $this->profileResponse->addError('Вы не авторизованы');
             return false;
         }
-        return $this->user->isConfirm() && !$this->user->isDeleted();
+        if ($this->user->isDeleted()) {
+            $this->profileResponse->addError('Профиль удален');
+            return false;
+        }
+        return true;
     }
 }
\ No newline at end of file
diff --git a/app/src/Service/Action/Classes/None.php b/app/src/Service/Action/Classes/None.php
index d75a862a57e091ca46e17a3d9ac0fd86363ab220..f891845a8ff2c574291898571514b90712f2e7d3 100644
--- a/app/src/Service/Action/Classes/None.php
+++ b/app/src/Service/Action/Classes/None.php
@@ -15,7 +15,7 @@ class None extends BaseActionService
     public function validate(): bool
     {
         if ($this->responseService) {
-            $this->responseService->getResponse()->addError('Действие не выбрано');
+            $this->responseService->addError('Действие не выбрано');
         }
         return false;
     }
diff --git a/app/src/Service/Action/Classes/Register.php b/app/src/Service/Action/Classes/Register.php
index 4dd29cdb8a19e8df5abc514cd4064de86ebef275..12291099361a1fcd81da1acc3222a6ca75e74793 100644
--- a/app/src/Service/Action/Classes/Register.php
+++ b/app/src/Service/Action/Classes/Register.php
@@ -69,6 +69,7 @@ class Register extends BaseActionService
                     $this->registerCodeSendService->setResponse($this->response);
                     $this->registerCodeSendService->send();
                 } catch (\Exception $exception) {
+                    dd($exception);
                     $this->response->addError('Ошибка регистрации пользователя');
                 }
 
diff --git a/app/src/Service/Action/Classes/ResetEmail.php b/app/src/Service/Action/Classes/ResetEmail.php
new file mode 100644
index 0000000000000000000000000000000000000000..07f270936f12e74a1f28385799c969bc9c8e2e6a
--- /dev/null
+++ b/app/src/Service/Action/Classes/ResetEmail.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace App\Service\Action\Classes;
+
+use App\Entity\User;
+use App\Service\Action\BaseActionService;
+use App\Service\Response\ResponseServiceInterface;
+use Doctrine\Persistence\ManagerRegistry;
+use Symfony\Bundle\SecurityBundle\Security;
+
+class ResetEmail extends BaseActionService
+{
+    private ?User $user;
+
+    /**
+     * @param ResponseServiceInterface $response
+     * @param ManagerRegistry $doctrine
+     * @param Security $security
+     */
+    public function __construct(
+        private ResponseServiceInterface $response,
+        private ManagerRegistry          $doctrine,
+        Security                         $security
+    )
+    {
+        $this->user = $security->getUser();
+        parent::__construct($response);
+    }
+
+    public function runAction(): void
+    {
+        if ($email = $this->user->getLastConfirmEmail()) {
+            if ($email === $this->user->getEmail()) {
+                $this->response->addMessage('Подтвержденный email уже установлен');
+            } else {
+                try {
+                    $this->user->setEmail($email);
+                    $em = $this->doctrine->getManager();
+                    $em->persist($this->user);
+                    $em->flush();
+                    $this->response->addMessage('Установлен email: ' . $email);
+                } catch (\Exception $e) {
+                    $this->response->addError('Ошибка сохранения email');
+                }
+            }
+        } else {
+            $this->response->addError('Нет последнего подтвержденного email');
+        }
+    }
+
+    public function validate(): bool
+    {
+        if ($this->user === null) {
+            $this->response->addError('Вы не авторизованы');
+            return false;
+        }
+        if ($this->user->isDeleted()) {
+            $this->response->addError('Профиль удален');
+            return false;
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/app/src/Service/Dto/BaseDto.php b/app/src/Service/Dto/BaseDto.php
index 0a149d4c6a97519fee9d5f91a7170517e97aa46c..b3abff01ee86261b7fceff8c91974fb7a09bd1c7 100644
--- a/app/src/Service/Dto/BaseDto.php
+++ b/app/src/Service/Dto/BaseDto.php
@@ -61,15 +61,15 @@ abstract class BaseDto implements DtoServiceInterface
     public function toArray(): ?array
     {
         try {
-            $oNormalizer = new ObjectNormalizer(
+            $normalizer = new ObjectNormalizer(
                 null,
                 new CamelCaseToSnakeCaseNameConverter(),
                 null,
                 new ReflectionExtractor()
             );
-            $oSerializer = new Serializer([$oNormalizer], [new JsonEncoder()]);
-            $sData = $oSerializer->serialize($this->getClass(), 'json');
-            return json_decode($sData, true, 512, JSON_THROW_ON_ERROR);
+            $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
+            $data = $serializer->serialize($this->getClass(), 'json');
+            return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
         } catch (\Exception $oException) {
             return null;
         }
diff --git a/app/src/Service/Dto/Classes/ChangeProfileDto.php b/app/src/Service/Dto/Classes/ChangeProfileDto.php
new file mode 100644
index 0000000000000000000000000000000000000000..129af968e3620c90eaaa31a52821a520859556f0
--- /dev/null
+++ b/app/src/Service/Dto/Classes/ChangeProfileDto.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace App\Service\Dto\Classes;
+
+use App\Service\Dto\BaseDto;
+use Symfony\Component\Validator\Constraints as Assert;
+
+class ChangeProfileDto extends BaseDto
+{
+    #[Assert\Email(
+        message: 'Email "{{ value }}" неверный.',
+    )]
+    public ?string $email = null;
+
+    public ?string $name = null;
+
+    public ?string $surname = null;
+
+    public ?string $patronymic = null;
+
+    #[Assert\Regex(
+        pattern: '/^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$/i',
+        message: 'Неверный формат телефона'
+    )]
+    public ?string $phoneNumber = null;
+}
\ No newline at end of file
diff --git a/app/src/Service/Response/Classes/Response.php b/app/src/Service/Response/Classes/Response.php
index cf0ffdec4777caf96ece6e6e04fcc7cb4eb534af..5e10801f5812f364d28690d22da523354d4ef626 100644
--- a/app/src/Service/Response/Classes/Response.php
+++ b/app/src/Service/Response/Classes/Response.php
@@ -11,6 +11,7 @@ use Symfony\Component\Serializer\Encoder\JsonEncoder;
 use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
 use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
 use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
+use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
 use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
 use Symfony\Component\Serializer\Serializer;
 
@@ -139,7 +140,7 @@ class Response implements ResponseServiceInterface
             null,
             new ReflectionExtractor()
         );
-        $serializer = new Serializer([$normalizer], [new JsonEncoder()]);
+        $serializer = new Serializer([new DateTimeNormalizer(), $normalizer], [new JsonEncoder()]);
         $dataStr = $serializer->serialize($this, 'json', ['groups' => $groups]);
         $dataArray = json_decode($dataStr, true, 512, JSON_THROW_ON_ERROR);
 
diff --git a/app/src/Service/Send/Classes/CodeSendService.php b/app/src/Service/Send/Classes/CodeSendService.php
index d8b5e4f5d271c7cf38034866f2b292cc5cf12c79..eabbcb8862fb176e58c43d46685697edf74f9b21 100644
--- a/app/src/Service/Send/Classes/CodeSendService.php
+++ b/app/src/Service/Send/Classes/CodeSendService.php
@@ -100,11 +100,7 @@ class CodeSendService implements SendServiceInterface
     {
         $body = $this->getBody();
 
-        foreach ($values as $name => $value) {
-            $body = str_replace('{' . $name . '}', $value, $body);
-        }
-
-        return $body;
+        return self::textReplace($body, $values);
     }
 
     /**
@@ -118,10 +114,31 @@ class CodeSendService implements SendServiceInterface
     {
         $subject = $this->getSubject();
 
+        return self::textReplace($subject, $values);
+    }
+
+    /**
+     * Замена переменных текста
+     *
+     * @param string $text
+     * @param array $values
+     *
+     * @return string
+     */
+    private static function textReplace(string $text, array $values): string
+    {
         foreach ($values as $name => $value) {
-            $subject = str_replace('{' . $name . '}', $value, $subject);
+            if (is_string($value)) {
+                $text = str_replace('{' . $name . '}', $value, $text);
+            }
+        }
+
+        $match = [];
+        preg_match('/{\w+}/', $text, $match);
+        foreach ($match as $value) {
+            $text = str_replace($value, '', $text);
         }
 
-        return $subject;
+        return $text;
     }
 }
\ No newline at end of file