diff --git a/README.md b/README.md
index 69e5ddf..9dd73cd 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,72 @@
-
-
- p1ctos4ve
-
-
- selfhosted image preservation service
-
-
+# p1ctos4ve
+Проект в рамках дисциплины «Конструирование программного обеспечения»: сервис сохранения и организации медиа со внешних ресурсов
+## Участники
+- Железняков Марк Викторович - `5130904/30105`
+- Михеев Егор Романович - `5130904/30105`
+- Михальченко Владислав Сергеевич - `5130904/30105`
+- Ботыгин Иван Алексеевич - `5130904/30105`
+
+## Определение проблемы
+Пользователи, сохраняющие большое количество медиафайлов (фотографий, видео, GIF) из разных источников (социальные сети, мессенджеры и другие специализированные платформы), сталкиваются с трудностями их систематизации и последующего поиска. Файлы скапливаются в беспорядке, отсутствует единая система тегов и категорий, что делает быстрый поиск нужного материала практически невозможным и требует значительных ручных усилий по организации. При этом всегда присутствует риск удаления материалов из первоисточника.
+
+## Выработка требований
+
+### Пользовательские истории
+1. Как пользователь, я хочу добавлять медиафайлы (фото, видео, GIF) в свою библиотеку из различных источников (прямая загрузка, по ссылке, через интеграцию с Tenor/Pinterest), чтобы централизованно хранить все материалы.
+2. Как пользователь, я хочу иметь мощную систему поиска по библиотеке с фильтрацией по типу файла, тегам, категориям и дате добавления, чтобы быстро находить конкретные материалы.
+3. Как пользователь, я хочу иметь возможность просматривать свою медиатеку в удобном интерфейсе (галерея, список) с предпросмотром, чтобы легко ориентироваться в содержимом.
+
+## Разработка архитектуры и детальное проектирование
+
+### Оценка масштаба
+> Оценка масштаба производится при условии нагрузки на сервис в размере 10 000 активных пользователей в сутки. При этом сервис подазумевает опцию селфхостинга, что может снизить требования к ресурсам центрального экземпляра (инстанса) сервиса.
+
+#### Характер нагрузки
+
+##### Соотношение R/W нагрузки
+**70% на чтение и 30% на запись.** Обосновать это можно тем, что запись метаданных и загрузка файлов будет занимать большую долю операций в сервисе с пиками во время массовых импортов из Tenor/Pinterest. При этом чтение данных будет производится сильно реже
+
+##### Трафик
+Для входящего трафика предположим, что один пользователь в среднем будем генерировать 10 МБ данных. Так, 10 000 пользователей * 10 МБ = 100 ГБ/день.
+
+##### Объемы дисковой системы
+При начальном размере файла ~5 МБ и 10 загрузках на пользователя в день: 10 000 * 10 * 5 МБ = 500 ГБ/день. Поэтому может потребоваться дешевое S3-хранилище.
+
+### Диаграммы C4 Model
+
+#### Контекст
+![[assets/С4-1context.jpg]]
+
+#### Контейнеры
+![[assets/С4-2containers.jpg]]
+
+#### Компоненты
+![[С4-3components.jpg]]
+
+#### Код
+> WIP
+
+### Контракты API
+Краткая информация о методах API доступна в [assets/API.md](API.md), а полная документация - в [Scalar](https://scalar.com/) на эндпоинте `/openapi`.
+
+### Схема БД и оправдание с точки зрения нефункциональных требований
+> WIP
+
+### Схема масштабирования сервиса при росте нагрузки в 10 раз
+Для возможности масштабирования можно использовать следующие подходы:
+- Размещение бекенда за балансировщиком нагрузки (например, Nginx, Traefik или Caddy): трафик будет распределяться равномерно между двумя или более экземплярами API
+- Репликация БД - основная база принимает запись, а одна или несколько реплик получают изменения по журналу (WAL) и обслуживают преимущественно чтение.
+- Кеширование частозапрашиваемых данных через Redis: результаты чтения (например, списки, карточки по ID, агрегации, результаты поиска с популярными фильтрами) складываются в KV хранилище с некоторым TTL, что позволяет сократить время ответа на повторяющиеся запросы
+
+## Кодирование и отладка
+> WIP
+
+## Unit-тестирование
+> WIP
+
+## Интеграционное тестирование
+> WIP
+
+## Сборка и запуск
+> WIP
diff --git a/assets/API.md b/assets/API.md
new file mode 100644
index 0000000..19100f3
--- /dev/null
+++ b/assets/API.md
@@ -0,0 +1,283 @@
+# p1ctos4ve - контракты API
+
+## Better Auth
+API использует фреймворк [Better Auth](https://better-auth.com) для управления пользователями и сессиями.
+
+Для работы с авторизацией необходимо использовать [клиентскую библиотеку](https://www.better-auth.com/docs/concepts/client) Better Auth, прямой вызов методов авторизации из клиентов не предусматривается.
+
+### `POST /auth/api/sign-up/email`
+
+Регистрация нового пользователя с почтой и паролем.
+
+**Параметры запроса:**
+```json
+{
+ "name": "string",
+ "email": "string",
+ "password": "string",
+ "image": "string (опционально)",
+ "callbackURL": "string (опционально)",
+ "rememberMe": "boolean (опционально, по умолчанию true)"
+}
+```
+
+**Ответ (200):**
+```json
+{
+ "token": "string | null",
+ "user": {
+ "id": "string",
+ "email": "string",
+ "name": "string",
+ "image": "string | null",
+ "emailVerified": "boolean",
+ "createdAt": "string (date-time)",
+ "updatedAt": "string (date-time)"
+ }
+}
+```
+
+### `POST /auth/api/sign-in/email`
+
+Вход с использованием почты и пароля.
+
+**Параметры запроса:**
+```json
+{
+ "email": "string",
+ "password": "string",
+ "callbackURL": "string (опционально)",
+ "rememberMe": "string (опционально)"
+}
+```
+
+**Ответ (200):**
+```json
+{
+ "redirect": false,
+ "token": "string",
+ "url": null,
+ "user": {
+ "id": "string",
+ "email": "string",
+ "name": "string | null",
+ "image": "string | null",
+ "emailVerified": "boolean",
+ "createdAt": "string (date-time)",
+ "updatedAt": "string (date-time)"
+ }
+}
+```
+
+### `POST /auth/api/sign-out`
+
+Выход из системы и завершение текущей сессии.
+
+**Ответ (200):**
+```json
+{
+ "success": "boolean"
+}
+```
+
+## Сейвы
+API для работы с сохраненными медиафайлами (видео, фото). Каждый сейв имеет настройку видимости, определяющую режим доступа.
+
+### Режимы видимости сейва
+- `public` - сейв доступен всем пользователям, отображается в публичных списках и профиле владельца
+- `link` - сейв доступен только по прямой ссылке (shareUrl), не отображается в публичных списках. Владелец всегда видит его в своих списках
+
+### `GET /saves/my`
+
+Возвращает все сейвы текущего пользователя независимо от режима видимости.
+
+**Аутентификация:** Опциональна
+
+**Ответ (200):**
+```json
+[
+ {
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "description": "string",
+ "tags": ["string"],
+ "visibility": "public" | "link",
+ "shareUrl": "string (только для visibility: link)",
+ "createdAt": "string (date-time)",
+ "updatedAt": "string (date-time)"
+ }
+]
+```
+
+### `GET /saves/u/{slug}`
+Возвращает **только публичные сейвы** (visibility: public) конкретного пользователя по его никнейму (slug). Сейвы с видимостью "link" не включаются в этот список, даже если запрашивает владелец.
+
+**Параметры пути:**
+- `slug` (string, обязательный) - никнейм пользователя
+
+**Аутентификация:** Опциональна
+
+**Ответ (200):**
+```json
+[
+ {
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "description": "string",
+ "tags": ["string"],
+ "visibility": "public",
+ "createdAt": "string (date-time)",
+ "updatedAt": "string (date-time)"
+ }
+]
+```
+
+### `GET /saves/{id}`
+Возвращает информацию о конкретном сейве.
+
+**Параметры пути:**
+- `id` (number/string, обязательный) - ID сейва
+
+**Аутентификация:** Опциональна
+
+**Правила доступа:**
+- **Владелец:** полный доступ ко всем сейвам (public и link)
+- **Другие пользователи:**
+ - **public сейвы:** доступны всем
+ - **link сейвы:** доступны только при обращении по корректной shareUrl; запрос по голому ID вернет `404 Not Found`
+
+**Ответ (200):**
+```json
+{
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "description": "string",
+ "tags": ["string"],
+ "visibility": "public" | "link",
+ "shareUrl": "string (только для visibility: link)",
+ "userId": "string",
+ "createdAt": "string (date-time)",
+ "updatedAt": "string (date-time)"
+}
+```
+
+**Коды ошибок:**
+- `404 Not Found` - сейв не найден или недоступен (для link сейвов без shareUrl)
+- `403 Forbidden` - нет прав доступа
+
+### `DELETE /saves/{id}`
+Удаляет сейв по его ID. Доступно только владельцу.
+
+**Параметры пути:**
+- `id` (number/string, обязательный) - ID сейва
+
+**Аутентификация:** Обязательна
+
+**Ответ (200):**
+```json
+{
+ "success": true,
+ "message": "Сейв успешно удален"
+}
+```
+
+### `PATCH /saves/{id}`
+Обновляет метаданные сейва (название, описание, теги, видимость). Доступно только владельцу.
+
+**Параметры пути:**
+- `id` (number/string, обязательный) - ID сейва
+
+**Параметры запроса:**
+```json
+{
+ "name": "string (опционально)",
+ "description": "string (опционально)",
+ "tags": ["string"] (опционально),
+ "visibility": "public" | "link" (опционально)
+}
+```
+
+**Аутентификация:** Обязательна
+
+**Content-Type:** `application/json`, `application/x-www-form-urlencoded`, или `multipart/form-data`
+
+**Ответ (200):**
+```json
+{
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "description": "string",
+ "tags": ["string"],
+ "visibility": "public" | "link",
+ "shareUrl": "string (если visibility: link)",
+ "updatedAt": "string (date-time)"
+}
+```
+
+**Примечание:** При установке `visibility: "link"` сервер автоматически генерирует или возвращает существующую `shareUrl`. При смене на `visibility: "public"` поле `shareUrl` становится неактуальным.
+
+### `POST /saves/external`
+Скачивает и сохраняет медиафайл по URL из стороннего источника.
+
+**Параметры запроса:**
+```json
+{
+ "url": "string (URI, обязательный)",
+ "name": "string (опционально)",
+ "description": "string (опционально)",
+ "tags": ["string"] (опционально),
+ "visibility": "public" | "link" (опционально, по умолчанию: link)"
+}
+```
+
+**Аутентификация:** Обязательна
+
+**Content-Type:** `application/json`, `application/x-www-form-urlencoded`, или `multipart/form-data`
+
+**Ответ (200):**
+```json
+{
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "url": "string",
+ "visibility": "public" | "link",
+ "shareUrl": "string (если visibility: link)",
+ "createdAt": "string (date-time)"
+}
+```
+
+Если `visibility` не указана, по умолчанию устанавливается `link`.
+
+### `POST /saves/upload`
+Загружает медиафайл с устройства.
+
+**Параметры запроса (multipart/form-data):**
+- `file` (`binary`, обязательный) - файл для загрузки
+- `name` (`string`, опционально) - название сейва
+- `description` (`string`, опционально) - описание сейва
+- `tags` (`array[string]`, опционально) - теги
+- `visibility` (`"public" | "link"`, опционально, по умолчанию: "link") - режим видимости
+
+**Аутентификация:** Обязательна
+
+**Content-Type:** `multipart/form-data`
+
+**Ответ (200):**
+```json
+{
+ "id": "number",
+ "name": "string",
+ "type": "string",
+ "url": "string",
+ "visibility": "public" | "link",
+ "shareUrl": "string (если visibility: link)",
+ "createdAt": "string (date-time)"
+}
+```
+
+Если `visibility` не указана, по умолчанию устанавливается `link`.
diff --git a/assets/С4-1context.jpg b/assets/С4-1context.jpg
new file mode 100644
index 0000000..3988d3b
Binary files /dev/null and b/assets/С4-1context.jpg differ
diff --git a/assets/С4-2containers.jpg b/assets/С4-2containers.jpg
new file mode 100644
index 0000000..ace05a0
Binary files /dev/null and b/assets/С4-2containers.jpg differ
diff --git a/assets/С4-3components.jpg b/assets/С4-3components.jpg
new file mode 100644
index 0000000..53a981d
Binary files /dev/null and b/assets/С4-3components.jpg differ