diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..05b076f
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+  // Use IntelliSense to learn about possible attributes.
+  // Hover to view descriptions of existing attributes.
+  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "type": "java",
+      "name": "SeminarApplication",
+      "request": "launch",
+      "mainClass": "ru.ulstu.SeminarApplication",
+      "projectName": "seminar"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..0ca4d0b
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+  "java.compile.nullAnalysis.mode": "automatic"
+}
\ No newline at end of file
diff --git a/src/main/java/ru/ulstu/file/model/FileData.java b/src/main/java/ru/ulstu/file/model/FileData.java
new file mode 100644
index 0000000..b85884f
--- /dev/null
+++ b/src/main/java/ru/ulstu/file/model/FileData.java
@@ -0,0 +1,64 @@
+package ru.ulstu.file.model;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+import ru.ulstu.model.BaseEntity;
+
+import java.util.Date;
+
+@Entity
+@Table(name = "file")
+public class FileData extends BaseEntity {
+    private String name;
+
+    private long size;
+
+    @Column(name = "create_date")
+    private Date createDate;
+
+    private byte[] data;
+
+    @Column(name = "is_latex_attach")
+    private Boolean isLatexAttach;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public long getSize() {
+        return size;
+    }
+
+    public void setSize(long size) {
+        this.size = size;
+    }
+
+    public Date getCreateDate() {
+        return createDate;
+    }
+
+    public void setCreateDate(Date createDate) {
+        this.createDate = createDate;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    public void setData(byte[] data) {
+        this.data = data;
+    }
+
+    public Boolean isLatexAttach() {
+        return isLatexAttach;
+    }
+
+    public void setLatexAttach(Boolean latexAttach) {
+        isLatexAttach = latexAttach;
+    }
+}
diff --git a/src/main/java/ru/ulstu/file/model/FileDataDto.java b/src/main/java/ru/ulstu/file/model/FileDataDto.java
new file mode 100644
index 0000000..d33e14a
--- /dev/null
+++ b/src/main/java/ru/ulstu/file/model/FileDataDto.java
@@ -0,0 +1,96 @@
+package ru.ulstu.file.model;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class FileDataDto {
+    private Integer id;
+    private String name;
+    private String fileName;
+    private String tmpFileName;
+    private boolean deleted;
+    private Boolean isLatexAttach;
+
+    public FileDataDto() {
+    }
+
+    @JsonCreator
+    public FileDataDto(@JsonProperty("id") Integer id,
+                       @JsonProperty("name") String name,
+                       @JsonProperty("isLatexAttach") Boolean isLatexAttach,
+                       @JsonProperty("fileName") String fileName,
+                       @JsonProperty("tmpFileName") String tmpFileName) {
+        this.id = id;
+        this.name = name;
+        this.fileName = fileName;
+        this.tmpFileName = tmpFileName;
+        this.isLatexAttach = isLatexAttach;
+    }
+
+    public FileDataDto(FileData fileData) {
+        this.id = fileData.getId();
+        this.name = fileData.getName();
+        this.isLatexAttach = fileData.isLatexAttach();
+    }
+
+    public FileDataDto(String fileName, String tmpFileName) {
+        this.fileName = fileName;
+        this.tmpFileName = tmpFileName;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public String getTmpFileName() {
+        return tmpFileName;
+    }
+
+    public void setTmpFileName(String tmpFileName) {
+        this.tmpFileName = tmpFileName;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
+
+    public void setDeleted(boolean deleted) {
+        this.deleted = deleted;
+    }
+
+    public Boolean isLatexAttach() {
+        return isLatexAttach;
+    }
+
+    public Boolean getIsLatexAttach() {
+        return isLatexAttach;
+    }
+
+    public void setLatexAttach(Boolean latexAttach) {
+        isLatexAttach = latexAttach;
+    }
+
+    public void setIsLatexAttach(Boolean latexAttach) {
+        isLatexAttach = latexAttach;
+    }
+}
diff --git a/src/main/java/ru/ulstu/file/repository/FileRepository.java b/src/main/java/ru/ulstu/file/repository/FileRepository.java
new file mode 100644
index 0000000..509cc1b
--- /dev/null
+++ b/src/main/java/ru/ulstu/file/repository/FileRepository.java
@@ -0,0 +1,7 @@
+package ru.ulstu.file.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import ru.ulstu.file.model.FileData;
+
+public interface FileRepository extends JpaRepository<FileData, Integer> {
+}
diff --git a/src/main/java/ru/ulstu/file/service/FileService.java b/src/main/java/ru/ulstu/file/service/FileService.java
new file mode 100644
index 0000000..de2bbeb
--- /dev/null
+++ b/src/main/java/ru/ulstu/file/service/FileService.java
@@ -0,0 +1,123 @@
+package ru.ulstu.file.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+import ru.ulstu.file.model.FileData;
+import ru.ulstu.file.model.FileDataDto;
+import ru.ulstu.file.repository.FileRepository;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+@Service
+public class FileService {
+    private final static int META_FILE_NAME_INDEX = 0;
+    private final static int META_FILE_SIZE_INDEX = 1;
+
+    private final String tmpDir;
+    private final FileRepository fileRepository;
+
+    public FileService(FileRepository fileRepository) {
+        tmpDir = System.getProperty("java.io.tmpdir");
+        this.fileRepository = fileRepository;
+    }
+
+    private FileData createFileFromTmp(String tmpFileName) throws IOException {
+        FileData fileData = new FileData();
+        fileData.setData(getTmpFile(tmpFileName));
+        fileData.setSize(getTmpFileSize(tmpFileName));
+        fileData.setCreateDate(new Date());
+        return fileRepository.save(fileData);
+    }
+
+    private String uploadToTmpDir(MultipartFile multipartFile) throws IOException {
+        String tmpFileName = String.valueOf(System.currentTimeMillis()) + UUID.randomUUID();
+        Files.write(getTmpFilePath(tmpFileName), multipartFile.getBytes());
+        String meta = multipartFile.getOriginalFilename() + "\n" + multipartFile.getSize();
+        Files.write(getTmpFileMetaPath(tmpFileName), meta.getBytes(UTF_8));
+        return tmpFileName;
+    }
+
+    private String[] getMeta(String tmpFileName) throws IOException {
+        return new String(Files.readAllBytes(getTmpFileMetaPath(tmpFileName)), UTF_8)
+                .split("\n");
+    }
+
+    private long getTmpFileSize(String tmpFileName) throws IOException {
+        return Long.valueOf(getMeta(tmpFileName)[META_FILE_SIZE_INDEX]).longValue();
+    }
+
+    public String getTmpFileName(String tmpFileName) throws IOException {
+        return getMeta(tmpFileName)[META_FILE_NAME_INDEX];
+    }
+
+    public byte[] getTmpFile(String tmpFileName) throws IOException {
+        return Files.readAllBytes(getTmpFilePath(tmpFileName));
+    }
+
+    public FileData getFile(Integer fileId) {
+        return fileRepository.getOne(fileId);
+    }
+
+    public void deleteTmpFile(String tmpFileName) throws IOException {
+        Files.delete(getTmpFilePath(tmpFileName));
+    }
+
+    private Path getTmpFilePath(String tmpFileName) {
+        return Paths.get(tmpDir, tmpFileName);
+    }
+
+    private Path getTmpFileMetaPath(String tmpFileName) {
+        return Paths.get(getTmpFilePath(tmpFileName) + ".meta");
+    }
+
+    public void deleteFile(FileData fileData) {
+        fileRepository.delete(fileData);
+    }
+
+    public List<FileData> saveOrCreate(List<FileDataDto> fileDtos) throws IOException {
+        List<FileData> files = new ArrayList<>();
+        for (FileDataDto file : fileDtos) {
+            files.add(file.getId() != null ? update(file) : create(file));
+        }
+        return files;
+    }
+
+    @Transactional
+    private FileData update(FileDataDto fileDataDto) {
+        FileData file = fileRepository.findById(fileDataDto.getId())
+                .orElseThrow(() -> new RuntimeException("File not found by id"));
+        return fileRepository.save(copyFromDto(file, fileDataDto));
+    }
+
+    @Transactional
+    private FileData create(FileDataDto fileDataDto) throws IOException {
+        FileData newFile = createFileFromTmp(fileDataDto.getTmpFileName());
+        copyFromDto(newFile, fileDataDto);
+        return fileRepository.save(newFile);
+    }
+
+    private FileData copyFromDto(FileData fileData, FileDataDto fileDataDto) {
+        fileData.setName(fileDataDto.getName());
+        fileData.setLatexAttach(fileDataDto.isLatexAttach());
+        return fileData;
+    }
+
+    @Transactional
+    public void delete(Integer fileId) {
+        fileRepository.deleteById(fileId);
+    }
+
+    public FileDataDto createFromMultipartFile(MultipartFile multipartFile) throws IOException {
+        return new FileDataDto(multipartFile.getOriginalFilename(), uploadToTmpDir(multipartFile));
+    }
+}
diff --git a/src/main/java/ru/ulstu/files/FileSystemStorageService.java b/src/main/java/ru/ulstu/files/FileSystemStorageService.java
deleted file mode 100644
index 805aa2f..0000000
--- a/src/main/java/ru/ulstu/files/FileSystemStorageService.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package ru.ulstu.files;
-
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.UrlResource;
-import org.springframework.stereotype.Service;
-import org.springframework.util.FileSystemUtils;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.stream.Stream;
-
-@Service
-public class FileSystemStorageService implements StorageService {
-	public static final String UPLOAD_DIR = "upload";
-
-	private final Path rootLocation = Paths.get(UPLOAD_DIR);
-
-	@Override
-	public void store(MultipartFile file) {
-		try {
-			if (file.isEmpty()) {
-				throw new StorageException("Failed to store empty file " + file.getOriginalFilename());
-			}
-			Files.copy(file.getInputStream(), this.rootLocation.resolve(file.getOriginalFilename()));
-		} catch (IOException e) {
-			throw new StorageException("Failed to store file " + file.getOriginalFilename(), e);
-		}
-	}
-
-	@Override
-	public Stream<Path> loadAll() {
-		try {
-			return Files.walk(this.rootLocation, 1)
-					.filter(path -> !path.equals(this.rootLocation))
-					.map(path -> this.rootLocation.relativize(path));
-		} catch (IOException e) {
-			throw new StorageException("Failed to read stored files", e);
-		}
-
-	}
-
-	@Override
-	public Path load(String filename) {
-		return rootLocation.resolve(filename);
-	}
-
-	@Override
-	public Resource loadAsResource(String filename) {
-		try {
-			Path file = load(filename);
-			Resource resource = new UrlResource(file.toUri());
-			if (resource.exists() || resource.isReadable()) {
-				return resource;
-			} else {
-				throw new StorageFileNotFoundException("Could not read file: " + filename);
-
-			}
-		} catch (MalformedURLException e) {
-			throw new StorageFileNotFoundException("Could not read file: " + filename, e);
-		}
-	}
-
-	@Override
-	public void deleteAll() {
-		FileSystemUtils.deleteRecursively(rootLocation.toFile());
-	}
-
-	@Override
-	public void init() {
-		try {
-			Files.createDirectory(rootLocation);
-		} catch (IOException e) {
-			throw new StorageException("Could not initialize storage", e);
-		}
-	}
-}
diff --git a/src/main/java/ru/ulstu/files/FileUtil.java b/src/main/java/ru/ulstu/files/FileUtil.java
deleted file mode 100644
index e2ccfc2..0000000
--- a/src/main/java/ru/ulstu/files/FileUtil.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package ru.ulstu.files;
-
-import org.springframework.web.multipart.MultipartFile;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-
-public class FileUtil {
-
-    public static void saveFile(String uploadDir, String fileName,
-                                MultipartFile multipartFile) throws IOException {
-        Path uploadPath = Paths.get(uploadDir);
-
-        if (!Files.exists(uploadPath)) {
-            Files.createDirectories(uploadPath);
-        }
-
-        try (InputStream inputStream = multipartFile.getInputStream()) {
-            Path filePath = uploadPath.resolve(fileName);
-            Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
-        } catch (IOException ioe) {
-            throw new IOException("Could not save image file: " + fileName, ioe);
-        }
-    }
-}
diff --git a/src/main/java/ru/ulstu/files/FilesController.java b/src/main/java/ru/ulstu/files/FilesController.java
deleted file mode 100644
index 5df8814..0000000
--- a/src/main/java/ru/ulstu/files/FilesController.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package ru.ulstu.files;
-
-import org.springframework.core.io.Resource;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-@Controller
-public class FilesController {
-    private final StorageService storageService;
-
-    public FilesController(StorageService storageService) {
-        this.storageService = storageService;
-    }
-
-    @GetMapping("/files/{filename:.+}")
-    @ResponseBody
-    public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
-        Resource file = storageService.loadAsResource((filename == null || filename.equals("null") || filename.isEmpty())
-                ? "logo.png"
-                : filename);
-        return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
-                "filename=\"" + file.getFilename() + "\"").body(file);
-    }
-}
diff --git a/src/main/java/ru/ulstu/files/StorageException.java b/src/main/java/ru/ulstu/files/StorageException.java
deleted file mode 100644
index eb7da9f..0000000
--- a/src/main/java/ru/ulstu/files/StorageException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package ru.ulstu.files;
-
-public class StorageException extends RuntimeException {
-
-	public StorageException(String message) {
-		super(message);
-	}
-
-	public StorageException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}
diff --git a/src/main/java/ru/ulstu/files/StorageFileNotFoundException.java b/src/main/java/ru/ulstu/files/StorageFileNotFoundException.java
deleted file mode 100644
index 085c94d..0000000
--- a/src/main/java/ru/ulstu/files/StorageFileNotFoundException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package ru.ulstu.files;
-
-public class StorageFileNotFoundException extends StorageException {
-
-	public StorageFileNotFoundException(String message) {
-		super(message);
-	}
-
-	public StorageFileNotFoundException(String message, Throwable cause) {
-		super(message, cause);
-	}
-}
diff --git a/src/main/java/ru/ulstu/files/StorageService.java b/src/main/java/ru/ulstu/files/StorageService.java
deleted file mode 100644
index 48e3461..0000000
--- a/src/main/java/ru/ulstu/files/StorageService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package ru.ulstu.files;
-
-import org.springframework.core.io.Resource;
-import org.springframework.web.multipart.MultipartFile;
-
-import java.nio.file.Path;
-import java.util.stream.Stream;
-
-public interface StorageService {
-
-	void init();
-
-	void store(MultipartFile file);
-
-	Stream<Path> loadAll();
-
-	Path load(String filename);
-
-	Resource loadAsResource(String filename);
-
-	void deleteAll();
-
-}