diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..fe1152b
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,30 @@
+**/.classpath
+**/.dockerignore
+**/.env
+**/.git
+**/.gitignore
+**/.project
+**/.settings
+**/.toolstarget
+**/.vs
+**/.vscode
+**/*.*proj.user
+**/*.dbmdl
+**/*.jfm
+**/azds.yaml
+**/bin
+**/charts
+**/docker-compose*
+**/Dockerfile*
+**/node_modules
+**/npm-debug.log
+**/obj
+**/secrets.dev.yaml
+**/values.dev.yaml
+LICENSE
+README.md
+!**/.gitignore
+!.git/HEAD
+!.git/config
+!.git/packed-refs
+!.git/refs/heads/**
\ No newline at end of file
diff --git a/DailyDigestWorker.csproj b/DailyDigestWorker.csproj
index 85e844c..3b69bb9 100644
--- a/DailyDigestWorker.csproj
+++ b/DailyDigestWorker.csproj
@@ -5,12 +5,15 @@
enable
enable
dotnet-DailyDigestWorker-14a227e9-5097-46b5-8901-6f6dab4c4a9c
+ Linux
+ .
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..ae5b460
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,41 @@
+# --- Стадия сборки ---
+# Используем официальный образ .NET SDK для сборки приложения
+# Укажите вашу версию .NET (8.0, 7.0, 6.0)
+FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
+WORKDIR /source
+
+# Копируем .sln и .csproj файлы для восстановления зависимостей
+# Копируем сначала их, чтобы использовать кэширование слоев Docker
+# Если зависимости не менялись, этот слой не будет пересобираться
+COPY *.sln .
+COPY DailyDigestWorker/*.csproj ./DailyDigestWorker/
+# Копируем другие проекты, если они есть в решении
+
+# Восстанавливаем NuGet пакеты для всего решения
+RUN dotnet restore "./DailyDigestWorker/DailyDigestWorker.csproj"
+# Если есть другие проекты, возможно, лучше восстановить для .sln: RUN dotnet restore
+
+# Копируем весь остальной исходный код
+COPY . .
+
+# Публикуем приложение в Release конфигурации
+# --no-restore т.к. мы уже восстановили пакеты
+# -o /app/publish указывает папку для вывода опубликованного приложения
+WORKDIR /source/DailyDigestWorker
+RUN dotnet publish "./DailyDigestWorker.csproj" -c Release -o /app/publish --no-restore
+
+# --- Финальная стадия ---
+# Используем официальный образ .NET Runtime (он меньше, чем SDK)
+# Укажите ту же версию .NET, что и SDK
+FROM mcr.microsoft.com/dotnet/runtime:8.0 AS final
+WORKDIR /app
+
+# Копируем опубликованное приложение из стадии сборки
+COPY --from=build /app/publish .
+
+# Устанавливаем переменную окружения для правильной работы с глобализацией (культуры, форматы)
+ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
+
+# Указываем точку входа - команду для запуска нашего приложения
+# Замените DailyDigestWorker.dll на фактическое имя вашей сборки, если оно другое
+ENTRYPOINT ["dotnet", "DailyDigestWorker.dll"]
\ No newline at end of file
diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json
index 63ab6f4..c5e2fc9 100644
--- a/Properties/launchSettings.json
+++ b/Properties/launchSettings.json
@@ -1,12 +1,15 @@
-{
- "$schema": "http://json.schemastore.org/launchsettings.json",
+{
"profiles": {
"DailyDigestWorker": {
"commandName": "Project",
- "dotnetRunMessages": true,
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
- }
+ },
+ "dotnetRunMessages": true
+ },
+ "Container (Dockerfile)": {
+ "commandName": "Docker"
}
- }
-}
+ },
+ "$schema": "http://json.schemastore.org/launchsettings.json"
+}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..207e7b7
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,46 @@
+version: '3.8' # Указываем версию Docker Compose
+
+services:
+ daily-digest-worker: # Имя нашего сервиса (может быть любым)
+ # build: . # Раскомментируйте, если Portainer будет САМ собирать образ из Dockerfile
+ image: your-dockerhub-username/daily-digest-worker:latest # <-- ЗАМЕНИТЕ на ваше имя образа (или оставьте build)
+ container_name: daily-digest-worker # Имя контейнера после запуска
+ restart: unless-stopped # Перезапускать контейнер, если он остановился сам (кроме ручной остановки)
+
+ environment:
+ # --- ПЕРЕДАЧА СЕКРЕТОВ И НАСТРОЕК ЧЕРЕЗ ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ ---
+ # Формат: Section__NestedSection__Key=Value
+ # Замените YOUR_... на ваши реальные значения!
+
+ # Настройки бота
+ BotConfiguration__BotToken: "7370439998:AAFKMvzbkv3Vh-E477De7_QKrTCQblI7wlc"
+ BotConfiguration__TargetChatId: "-1002642759581" # Например, -1001234567890
+
+ # Настройки Client API Telegram
+ TelegramClient__ApiId: "11104889" # Должно быть числом, но передаем как строку
+ TelegramClient__ApiHash: "81f467fd132d401fe69eaf45ae4275eb"
+ TelegramClient__PhoneNumber: "+79069302883" # Например, +79123456789
+ TelegramClient__TargetChannelUsername: "topor"
+ TelegramClient__SessionPath: "/app/session/telegram_session.dat" # <-- Путь ВНУТРИ контейнера (см. volumes)
+
+ # Ключи API
+ ApiKeys__OpenWeatherMap: "1425466ae8a0a723bd3300526ced0fff"
+ ApiKeys__Gemini: "AIzaSyClYI2zhYbAZgtT300JHAfYjIiyxrMV6W8"
+
+ # Настройки планировщика (если не хотите менять appsettings.json в образе)
+ # Можно переопределить массив JSON через переменную окружения, но это сложнее.
+ # Проще оставить в appsettings.json или использовать Config Map, если Portainer поддерживает.
+ # Либо использовать переменные для КАЖДОГО времени, но это не гибко.
+
+ # Настройки логирования и прочие (можно переопределить при необходимости)
+ Logging__LogLevel__Default: "Information"
+ DOTNET_ENVIRONMENT: "Production" # Устанавливаем окружение как Production
+
+ volumes:
+ # Создаем или используем именованный том 'session_data' для хранения файла сессии Telegram
+ # Это КЛЮЧЕВОЙ момент, чтобы не проходить авторизацию Client API при каждом перезапуске контейнера!
+ - session_data:/app/session # Монтируем том 'session_data' в папку /app/session внутри контейнера
+
+volumes:
+ # Объявляем именованный том
+ session_data:
\ No newline at end of file