Telegram

コミュニケーションメッセージングBot APIミニアプリセキュリティクラウドストレージ

コミュニケーションツール

Telegram

概要

Telegramは、セキュリティとプライバシーを重視したクラウドベースのメッセージングアプリです。エンドツーエンド暗号化、大容量ファイル送信、Bot API、ミニアプリ開発をサポートし、最大20万人のスーパーグループと無制限のチャンネル購読者数を提供します。オープンソースでクロスプラットフォーム対応、高速な同期機能が特徴です。

詳細

Telegram(テレグラム)は、2013年にロシア出身の起業家Pavel Durovによって設立されたクラウドベースのメッセージングプラットフォームです。現在、世界中で8億人以上のアクティブユーザーを持ち、プライバシーと自由な情報共有を重視するユーザーに支持されています。特にセキュリティとオープンソースへのコミットメントで知られています。

2024-2025年には、Mini Apps(ミニアプリ)のフルスクリーン表示、メディア共有機能、位置情報アクセス、DeviceStorage・SecureStorage API、ビジネスアカウント向けAPI、Telegram Premium機能強化、Webhook改善、チャンネル管理API拡充などの大幅な機能強化が行われました。

Telegram Bot APIは包括的なBot開発機能を提供し、Webhook統合、インラインキーボード、ファイル操作、支払い処理、ゲーム開発、ミニアプリ開発が可能です。また、MTProto protocolによる高度なセキュリティと、Telegram Cloudによる無制限ストレージを特徴としています。

メリット・デメリット

メリット

  • 強力なセキュリティ: エンドツーエンド暗号化(Secret Chat)、MTProto protocol
  • 豊富なBot API: 包括的なBot開発機能、ミニアプリ開発サポート
  • 大容量ファイル送信: 最大2GBのファイル送信、無制限クラウドストレージ
  • 大規模グループ: 最大20万人のスーパーグループ、無制限チャンネル
  • クロスプラットフォーム: 全プラットフォーム対応、リアルタイム同期
  • オープンソース: クライアントアプリはオープンソース
  • 無料利用: 基本機能は完全無料、広告なし
  • 高速性: 軽量設計と高速メッセージ配信

デメリット

  • 匿名性の問題: 電話番号が必要、完全匿名ではない
  • プライバシー懸念: 一部の国での規制や監視の可能性
  • エンタープライズ機能不足: ビジネス向け機能の制限
  • サポート体制: 公式サポートの限界
  • ガバナンス: 中央集権的な運営体制
  • デフォルト暗号化: 通常チャットはデフォルトで暗号化されない

主要リンク

書き方の例

Python-telegram-bot を使用したBot開発

# python-telegram-bot v20.x を使用したTelegram Bot実装
import asyncio
import logging
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, WebAppInfo
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes, CallbackQueryHandler

# ログ設定
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)

class TelegramBot:
    def __init__(self, token: str):
        self.application = Application.builder().token(token).build()
        self.setup_handlers()
    
    def setup_handlers(self):
        """ハンドラーの設定"""
        # コマンドハンドラー
        self.application.add_handler(CommandHandler("start", self.start_command))
        self.application.add_handler(CommandHandler("help", self.help_command))
        self.application.add_handler(CommandHandler("weather", self.weather_command))
        self.application.add_handler(CommandHandler("task", self.task_command))
        self.application.add_handler(CommandHandler("miniapp", self.miniapp_command))
        
        # メッセージハンドラー
        self.application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, self.echo_message))
        self.application.add_handler(MessageHandler(filters.PHOTO, self.photo_handler))
        self.application.add_handler(MessageHandler(filters.Document.ALL, self.document_handler))
        
        # コールバッククエリハンドラー
        self.application.add_handler(CallbackQueryHandler(self.button_handler))
    
    async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """スタートコマンドの処理"""
        user = update.effective_user
        welcome_text = f"こんにちは、{user.first_name}さん!🚀\n\nTelegram Botへようこそ。\n利用可能なコマンド:\n/help - ヘルプを表示\n/weather - 天気情報\n/task - タスク管理\n/miniapp - ミニアプリを開く"
        
        # インラインキーボードの作成
        keyboard = [
            [InlineKeyboardButton("🌤️ 天気", callback_data='weather_tokyo')],
            [InlineKeyboardButton("📋 タスク作成", callback_data='create_task')],
            [InlineKeyboardButton("🚀 ミニアプリ", web_app=WebAppInfo(url="https://your-webapp.com"))],
            [InlineKeyboardButton("ℹ️ ヘルプ", callback_data='help')]
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        await update.message.reply_text(welcome_text, reply_markup=reply_markup)
    
    async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """ヘルプコマンドの処理"""
        help_text = """
🤖 **Bot Commands**

**基本コマンド:**
/start - Botを開始
/help - このヘルプを表示

**機能コマンド:**
/weather [都市名] - 天気情報を取得
/task [タスク名] - タスクを作成
/miniapp - ミニアプリを起動

**ファイル機能:**
- 画像送信で自動OCR処理
- ドキュメント送信で分析
- 音声メッセージ対応

**特殊機能:**
- インラインボタン操作
- Webアプリ統合
- 支払い処理(Telegram Payments)
        """
        await update.message.reply_text(help_text, parse_mode='Markdown')
    
    async def weather_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """天気コマンドの処理"""
        # 引数から都市名を取得(デフォルト: Tokyo)
        city = ' '.join(context.args) if context.args else 'Tokyo'
        
        try:
            # 外部天気APIを呼び出し(例:OpenWeatherMap)
            weather_data = await self.get_weather_info(city)
            
            if weather_data:
                weather_text = f"""
🌤️ **{weather_data['name']}の天気**

天気: {weather_data['weather']}
気温: {weather_data['temperature']}°C
湿度: {weather_data['humidity']}%
風速: {weather_data['wind_speed']} m/s

更新時刻: {weather_data['updated_at']}
                """
                
                # インラインキーボードで他の都市の天気も表示
                keyboard = [
                    [InlineKeyboardButton("🗾 東京", callback_data='weather_tokyo'),
                     InlineKeyboardButton("🗽 ニューヨーク", callback_data='weather_newyork')],
                    [InlineKeyboardButton("🗼 ロンドン", callback_data='weather_london'),
                     InlineKeyboardButton("🥖 パリ", callback_data='weather_paris')]
                ]
                reply_markup = InlineKeyboardMarkup(keyboard)
                
                await update.message.reply_text(weather_text, reply_markup=reply_markup, parse_mode='Markdown')
            else:
                await update.message.reply_text(f"❌ {city}の天気情報を取得できませんでした。")
                
        except Exception as e:
            logger.error(f"Weather API error: {e}")
            await update.message.reply_text("❌ 天気情報の取得中にエラーが発生しました。")
    
    async def task_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """タスクコマンドの処理"""
        if context.args:
            task_title = ' '.join(context.args)
            # タスクをデータベースまたはファイルに保存
            task_id = await self.save_task(task_title, update.effective_user.id)
            
            task_text = f"""
✅ **タスクが作成されました**

タスクID: {task_id}
タイトル: {task_title}
作成者: {update.effective_user.first_name}
作成日時: {asyncio.get_event_loop().time()}
            """
            
            # タスク管理用インラインキーボード
            keyboard = [
                [InlineKeyboardButton("✅ 完了", callback_data=f'complete_task_{task_id}')],
                [InlineKeyboardButton("✏️ 編集", callback_data=f'edit_task_{task_id}')],
                [InlineKeyboardButton("📋 タスク一覧", callback_data='list_tasks')]
            ]
            reply_markup = InlineKeyboardMarkup(keyboard)
            
            await update.message.reply_text(task_text, reply_markup=reply_markup, parse_mode='Markdown')
        else:
            await update.message.reply_text("タスク名を指定してください。\n例: /task 買い物に行く")
    
    async def miniapp_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """ミニアプリコマンドの処理"""
        # ミニアプリ用のインラインキーボード
        keyboard = [
            [InlineKeyboardButton("🎮 ゲーム", web_app=WebAppInfo(url="https://your-game-app.com"))],
            [InlineKeyboardButton("📊 ダッシュボード", web_app=WebAppInfo(url="https://your-dashboard-app.com"))],
            [InlineKeyboardButton("🛒 ショップ", web_app=WebAppInfo(url="https://your-shop-app.com"))]
        ]
        reply_markup = InlineKeyboardMarkup(keyboard)
        
        await update.message.reply_text(
            "🚀 **ミニアプリを選択してください:**\n\n下のボタンからアプリを起動できます。",
            reply_markup=reply_markup,
            parse_mode='Markdown'
        )
    
    async def echo_message(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """通常メッセージの処理"""
        message_text = update.message.text.lower()
        
        # キーワード検出と自動応答
        if 'こんにちは' in message_text or 'hello' in message_text:
            await update.message.reply_text(f"こんにちは、{update.effective_user.first_name}さん!😊")
        elif 'ありがとう' in message_text or 'thanks' in message_text:
            await update.message.reply_text("どういたしまして!🙏")
        elif 'help' in message_text or 'ヘルプ' in message_text:
            await self.help_command(update, context)
        else:
            # エコー機能
            await update.message.reply_text(f"メッセージを受信しました: {update.message.text}")
    
    async def photo_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """画像メッセージの処理"""
        photo = update.message.photo[-1]  # 最高解像度の画像を取得
        
        # ファイルをダウンロード
        file = await context.bot.get_file(photo.file_id)
        file_path = f"downloads/{photo.file_id}.jpg"
        await file.download_to_drive(file_path)
        
        # OCR処理(例)
        try:
            extracted_text = await self.extract_text_from_image(file_path)
            
            response_text = f"""
📸 **画像を受信しました**

ファイルサイズ: {photo.file_size} bytes
OCR結果:
{extracted_text if extracted_text else '文字は検出されませんでした'}
            """
            
            await update.message.reply_text(response_text, parse_mode='Markdown')
        except Exception as e:
            logger.error(f"Image processing error: {e}")
            await update.message.reply_text("❌ 画像処理中にエラーが発生しました。")
    
    async def document_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """ドキュメントメッセージの処理"""
        document = update.message.document
        
        # ファイルサイズチェック(50MB制限)
        if document.file_size > 50 * 1024 * 1024:
            await update.message.reply_text("❌ ファイルサイズが大きすぎます(50MB以下にしてください)。")
            return
        
        # ファイルをダウンロード
        file = await context.bot.get_file(document.file_id)
        file_path = f"downloads/{document.file_name}"
        await file.download_to_drive(file_path)
        
        response_text = f"""
📄 **ドキュメントを受信しました**

ファイル名: {document.file_name}
サイズ: {document.file_size} bytes
MIME タイプ: {document.mime_type}

ファイルは正常に保存されました。
        """
        
        # ファイルタイプに応じた処理オプション
        keyboard = []
        if document.mime_type == 'text/plain':
            keyboard.append([InlineKeyboardButton("📖 テキスト解析", callback_data=f'analyze_text_{document.file_id}')])
        elif document.mime_type.startswith('image/'):
            keyboard.append([InlineKeyboardButton("🔍 画像解析", callback_data=f'analyze_image_{document.file_id}')])
        
        reply_markup = InlineKeyboardMarkup(keyboard) if keyboard else None
        await update.message.reply_text(response_text, reply_markup=reply_markup, parse_mode='Markdown')
    
    async def button_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
        """インラインボタンの処理"""
        query = update.callback_query
        await query.answer()
        
        callback_data = query.data
        
        if callback_data.startswith('weather_'):
            city = callback_data.replace('weather_', '')
            weather_data = await self.get_weather_info(city)
            
            if weather_data:
                await query.edit_message_text(
                    f"🌤️ **{weather_data['name']}の天気**\n\n"
                    f"天気: {weather_data['weather']}\n"
                    f"気温: {weather_data['temperature']}°C",
                    parse_mode='Markdown'
                )
        
        elif callback_data == 'create_task':
            await query.edit_message_text(
                "📋 タスクを作成するには以下のコマンドを使用してください:\n\n"
                "/task [タスク名]\n\n"
                "例: /task 買い物に行く"
            )
        
        elif callback_data.startswith('complete_task_'):
            task_id = callback_data.replace('complete_task_', '')
            await self.complete_task(task_id)
            await query.edit_message_text(f"✅ タスク {task_id} が完了しました!")
        
        elif callback_data == 'help':
            await self.help_command(update, context)
    
    async def get_weather_info(self, city: str) -> dict:
        """天気情報を取得(外部API呼び出し)"""
        # 実際の実装では外部天気APIを使用
        # ここではサンプルデータを返す
        import random
        
        weather_conditions = ['晴れ', '曇り', '雨', '雪']
        return {
            'name': city.title(),
            'weather': random.choice(weather_conditions),
            'temperature': random.randint(-10, 35),
            'humidity': random.randint(30, 90),
            'wind_speed': round(random.uniform(0, 15), 1),
            'updated_at': 'Now'
        }
    
    async def save_task(self, title: str, user_id: int) -> str:
        """タスクを保存"""
        import uuid
        task_id = str(uuid.uuid4())[:8]
        # 実際の実装ではデータベースに保存
        return task_id
    
    async def complete_task(self, task_id: str):
        """タスクを完了にする"""
        # 実際の実装ではデータベースを更新
        pass
    
    async def extract_text_from_image(self, image_path: str) -> str:
        """画像からテキストを抽出(OCR)"""
        # 実際の実装ではOCRライブラリ(Tesseract等)を使用
        return "サンプルOCRテキスト"
    
    def run(self):
        """Botを実行"""
        logger.info("Bot starting...")
        self.application.run_polling(allowed_updates=Update.ALL_TYPES)

# Bot使用例
async def main():
    """メイン関数"""
    bot_token = "YOUR_BOT_TOKEN"  # BotFatherから取得したトークン
    bot = TelegramBot(bot_token)
    bot.run()

if __name__ == '__main__':
    asyncio.run(main())

Webhook統合(Flask)

from flask import Flask, request, jsonify
import requests
import json
import logging

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

class TelegramWebhook:
    def __init__(self, bot_token: str, webhook_url: str):
        self.bot_token = bot_token
        self.api_url = f"https://api.telegram.org/bot{bot_token}"
        self.webhook_url = webhook_url
    
    def set_webhook(self):
        """Webhookを設定"""
        url = f"{self.api_url}/setWebhook"
        data = {"url": self.webhook_url}
        response = requests.post(url, json=data)
        return response.json()
    
    def send_message(self, chat_id: int, text: str, reply_markup=None):
        """メッセージを送信"""
        url = f"{self.api_url}/sendMessage"
        data = {
            "chat_id": chat_id,
            "text": text,
            "parse_mode": "Markdown"
        }
        if reply_markup:
            data["reply_markup"] = reply_markup
        
        response = requests.post(url, json=data)
        return response.json()
    
    def send_photo(self, chat_id: int, photo_url: str, caption: str = ""):
        """画像を送信"""
        url = f"{self.api_url}/sendPhoto"
        data = {
            "chat_id": chat_id,
            "photo": photo_url,
            "caption": caption
        }
        response = requests.post(url, json=data)
        return response.json()

# グローバルインスタンス
telegram_webhook = TelegramWebhook(
    bot_token="YOUR_BOT_TOKEN",
    webhook_url="https://yourdomain.com/telegram/webhook"
)

@app.route('/telegram/webhook', methods=['POST'])
def telegram_webhook_handler():
    """Telegramからのwebhookを処理"""
    try:
        data = request.get_json()
        
        if 'message' in data:
            message = data['message']
            chat_id = message['chat']['id']
            user = message['from']
            text = message.get('text', '')
            
            # コマンド処理
            if text.startswith('/'):
                return handle_command(chat_id, text, user)
            
            # 通常メッセージ処理
            return handle_message(chat_id, text, user)
        
        elif 'callback_query' in data:
            callback_query = data['callback_query']
            return handle_callback_query(callback_query)
        
        return jsonify({"status": "ok"})
    
    except Exception as e:
        logging.error(f"Webhook処理エラー: {e}")
        return jsonify({"status": "error"}), 500

def handle_command(chat_id: int, command: str, user: dict):
    """コマンドを処理"""
    if command == '/start':
        welcome_text = f"こんにちは、{user['first_name']}さん!\n\nTelegram Webhook Botへようこそ。"
        telegram_webhook.send_message(chat_id, welcome_text)
    
    elif command.startswith('/notify'):
        # GitHub通知の例
        return handle_github_notification(chat_id, command)
    
    elif command.startswith('/deploy'):
        # デプロイメント通知の例
        return handle_deployment_command(chat_id, command)
    
    return jsonify({"status": "ok"})

def handle_message(chat_id: int, text: str, user: dict):
    """通常メッセージを処理"""
    # キーワード検出
    if 'アラート' in text or 'alert' in text.lower():
        alert_keyboard = {
            "inline_keyboard": [
                [{"text": "🚨 緊急", "callback_data": "alert_critical"}],
                [{"text": "⚠️ 警告", "callback_data": "alert_warning"}],
                [{"text": "ℹ️ 情報", "callback_data": "alert_info"}]
            ]
        }
        telegram_webhook.send_message(
            chat_id, 
            "アラートレベルを選択してください:", 
            reply_markup=alert_keyboard
        )
    else:
        telegram_webhook.send_message(chat_id, f"メッセージを受信しました: {text}")
    
    return jsonify({"status": "ok"})

def handle_callback_query(callback_query: dict):
    """コールバッククエリを処理"""
    query_id = callback_query['id']
    chat_id = callback_query['message']['chat']['id']
    data = callback_query['data']
    
    # アラート処理
    if data.startswith('alert_'):
        level = data.replace('alert_', '')
        handle_alert(chat_id, level)
    
    # コールバッククエリに応答
    answer_url = f"{telegram_webhook.api_url}/answerCallbackQuery"
    requests.post(answer_url, json={"callback_query_id": query_id})
    
    return jsonify({"status": "ok"})

def handle_github_notification(chat_id: int, command: str):
    """GitHub通知を処理"""
    # 実際のGitHub webhook統合例
    github_data = {
        "repository": "example/repo",
        "commits": 3,
        "pusher": "developer",
        "branch": "main"
    }
    
    notification_text = f"""
🚀 **GitHub Push Notification**

Repository: {github_data['repository']}
Branch: {github_data['branch']}
Commits: {github_data['commits']}
Pusher: {github_data['pusher']}
    """
    
    telegram_webhook.send_message(chat_id, notification_text)
    return jsonify({"status": "ok"})

def handle_deployment_command(chat_id: int, command: str):
    """デプロイメントコマンドを処理"""
    deployment_keyboard = {
        "inline_keyboard": [
            [{"text": "🔧 Staging", "callback_data": "deploy_staging"}],
            [{"text": "🚀 Production", "callback_data": "deploy_production"}]
        ]
    }
    
    telegram_webhook.send_message(
        chat_id,
        "デプロイ環境を選択してください:",
        reply_markup=deployment_keyboard
    )
    return jsonify({"status": "ok"})

def handle_alert(chat_id: int, level: str):
    """アラートを処理"""
    emojis = {
        "critical": "🚨",
        "warning": "⚠️", 
        "info": "ℹ️"
    }
    
    alert_text = f"{emojis[level]} **{level.upper()} Alert**\n\nアラートが発生しました。詳細を確認してください。"
    telegram_webhook.send_message(chat_id, alert_text)

# 外部システム統合用エンドポイント
@app.route('/api/send-notification', methods=['POST'])
def send_notification():
    """外部システムからの通知送信"""
    try:
        data = request.get_json()
        chat_id = data.get('chat_id')
        message = data.get('message')
        
        if chat_id and message:
            telegram_webhook.send_message(chat_id, message)
            return jsonify({"status": "sent"})
        
        return jsonify({"status": "error", "message": "chat_id and message required"}), 400
    
    except Exception as e:
        logging.error(f"通知送信エラー: {e}")
        return jsonify({"status": "error"}), 500

if __name__ == '__main__':
    # Webhookを設定
    webhook_result = telegram_webhook.set_webhook()
    print(f"Webhook設定結果: {webhook_result}")
    
    # Flaskアプリを実行
    app.run(debug=True, port=5000)

ミニアプリ開発(JavaScript)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Telegram Mini App</title>
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    <style>
        body {
            margin: 0;
            padding: 20px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            background-color: var(--tg-theme-bg-color);
            color: var(--tg-theme-text-color);
        }
        
        .container {
            max-width: 400px;
            margin: 0 auto;
        }
        
        .card {
            background: var(--tg-theme-secondary-bg-color);
            border-radius: 12px;
            padding: 16px;
            margin-bottom: 16px;
        }
        
        .button {
            background: var(--tg-theme-button-color);
            color: var(--tg-theme-button-text-color);
            border: none;
            border-radius: 8px;
            padding: 12px 24px;
            font-size: 16px;
            cursor: pointer;
            width: 100%;
            margin-bottom: 8px;
        }
        
        .input {
            width: 100%;
            padding: 12px;
            border: 1px solid var(--tg-theme-hint-color);
            border-radius: 8px;
            background: var(--tg-theme-bg-color);
            color: var(--tg-theme-text-color);
            font-size: 16px;
            margin-bottom: 16px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card">
            <h2>🎯 タスク管理ミニアプリ</h2>
            <input type="text" id="taskInput" class="input" placeholder="新しいタスクを入力...">
            <button class="button" onclick="addTask()">➕ タスク追加</button>
        </div>
        
        <div class="card">
            <h3>📋 タスクリスト</h3>
            <div id="taskList"></div>
        </div>
        
        <div class="card">
            <h3>🎮 ゲーム機能</h3>
            <button class="button" onclick="startGame()">🎲 ゲーム開始</button>
            <button class="button" onclick="shareScore()">📊 スコア共有</button>
        </div>
        
        <div class="card">
            <h3>💰 支払い機能</h3>
            <button class="button" onclick="makePurchase()">🛒 購入する</button>
        </div>
    </div>

    <script>
        // Telegram Web App初期化
        const tg = window.Telegram.WebApp;
        
        // Web App設定
        tg.ready();
        tg.expand();
        
        // ユーザー情報の取得
        const user = tg.initDataUnsafe?.user;
        if (user) {
            console.log('User:', user);
        }
        
        // タスクデータ
        let tasks = [];
        
        // タスク追加機能
        function addTask() {
            const taskInput = document.getElementById('taskInput');
            const taskText = taskInput.value.trim();
            
            if (taskText) {
                const task = {
                    id: Date.now(),
                    text: taskText,
                    completed: false
                };
                
                tasks.push(task);
                taskInput.value = '';
                renderTasks();
                
                // Telegram Botにデータを送信
                sendDataToBot('task_created', task);
                
                // ハプティックフィードバック
                tg.HapticFeedback.impactOccurred('medium');
                
                // 成功メッセージ
                tg.showAlert('タスクが追加されました!');
            }
        }
        
        // タスクリスト表示
        function renderTasks() {
            const taskList = document.getElementById('taskList');
            
            if (tasks.length === 0) {
                taskList.innerHTML = '<p>タスクがありません</p>';
                return;
            }
            
            taskList.innerHTML = tasks.map(task => `
                <div style="display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--tg-theme-hint-color);">
                    <span style="${task.completed ? 'text-decoration: line-through; opacity: 0.6;' : ''}">${task.text}</span>
                    <div>
                        <button onclick="toggleTask(${task.id})" style="background: none; border: none; font-size: 20px; cursor: pointer;">
                            ${task.completed ? '✅' : '⭕'}
                        </button>
                        <button onclick="deleteTask(${task.id})" style="background: none; border: none; font-size: 16px; cursor: pointer; color: #ff4444;">
                            🗑️
                        </button>
                    </div>
                </div>
            `).join('');
        }
        
        // タスク状態切り替え
        function toggleTask(taskId) {
            const task = tasks.find(t => t.id === taskId);
            if (task) {
                task.completed = !task.completed;
                renderTasks();
                sendDataToBot('task_updated', task);
                tg.HapticFeedback.impactOccurred('light');
            }
        }
        
        // タスク削除
        function deleteTask(taskId) {
            tg.showConfirm('タスクを削除しますか?', (confirmed) => {
                if (confirmed) {
                    tasks = tasks.filter(t => t.id !== taskId);
                    renderTasks();
                    sendDataToBot('task_deleted', { id: taskId });
                    tg.HapticFeedback.impactOccurred('heavy');
                }
            });
        }
        
        // ゲーム機能
        function startGame() {
            // シンプルなクリッカーゲーム
            let score = 0;
            let gameTime = 10;
            
            const gameContainer = document.createElement('div');
            gameContainer.innerHTML = `
                <div style="text-align: center; padding: 20px;">
                    <h3>🎯 クリッカーゲーム</h3>
                    <div style="font-size: 24px; margin: 20px 0;">時間: <span id="gameTimer">${gameTime}</span>秒</div>
                    <div style="font-size: 32px; margin: 20px 0;">スコア: <span id="gameScore">${score}</span></div>
                    <button id="clickButton" style="font-size: 48px; padding: 20px; border: none; border-radius: 50%; background: var(--tg-theme-button-color);">🎯</button>
                </div>
            `;
            
            // 既存のコンテンツを置き換え
            document.querySelector('.container').innerHTML = '';
            document.querySelector('.container').appendChild(gameContainer);
            
            const timer = setInterval(() => {
                gameTime--;
                document.getElementById('gameTimer').textContent = gameTime;
                
                if (gameTime <= 0) {
                    clearInterval(timer);
                    endGame(score);
                }
            }, 1000);
            
            document.getElementById('clickButton').onclick = () => {
                score++;
                document.getElementById('gameScore').textContent = score;
                tg.HapticFeedback.impactOccurred('light');
            };
        }
        
        // ゲーム終了
        function endGame(finalScore) {
            tg.showAlert(`ゲーム終了!\\nスコア: ${finalScore}点`, () => {
                location.reload(); // アプリを再読み込み
            });
            
            // スコアをBotに送信
            sendDataToBot('game_finished', { score: finalScore });
        }
        
        // スコア共有
        function shareScore() {
            const totalTasks = tasks.length;
            const completedTasks = tasks.filter(t => t.completed).length;
            
            const shareText = `🎯 私のタスク進捗\\n✅ 完了: ${completedTasks}/${totalTasks}\\n📊 達成率: ${totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0}%`;
            
            // テキスト共有
            tg.shareText(shareText);
        }
        
        // 購入機能
        function makePurchase() {
            // Telegram Payments API使用
            const invoice = {
                title: 'プレミアム機能',
                description: 'タスク管理の高度な機能を解除します',
                payload: 'premium_upgrade',
                provider_token: 'YOUR_PAYMENT_PROVIDER_TOKEN',
                currency: 'JPY',
                prices: [{ label: 'プレミアム機能', amount: 50000 }] // 500円(金額は最小単位)
            };
            
            tg.invoiceCreate(invoice, (result) => {
                if (result.success) {
                    tg.showAlert('購入が完了しました!');
                    sendDataToBot('purchase_completed', result);
                } else {
                    tg.showAlert('購入がキャンセルされました。');
                }
            });
        }
        
        // Botにデータ送信
        function sendDataToBot(action, data) {
            tg.sendData(JSON.stringify({
                action: action,
                data: data,
                user: user,
                timestamp: Date.now()
            }));
        }
        
        // Web App終了処理
        function closeApp() {
            tg.close();
        }
        
        // MainButtonの設定
        tg.MainButton.setText('完了');
        tg.MainButton.onClick(() => {
            sendDataToBot('app_completed', { tasks: tasks });
            tg.close();
        });
        tg.MainButton.show();
        
        // BackButtonの設定
        tg.BackButton.onClick(() => {
            tg.showConfirm('アプリを終了しますか?', (confirmed) => {
                if (confirmed) {
                    tg.close();
                }
            });
        });
        tg.BackButton.show();
        
        // 初期レンダリング
        renderTasks();
        
        // デバイス情報の取得
        console.log('Platform:', tg.platform);
        console.log('Version:', tg.version);
        console.log('ViewportHeight:', tg.viewportHeight);
        console.log('ViewportStableHeight:', tg.viewportStableHeight);
    </script>
</body>
</html>

環境変数設定

# .env ファイル
# Telegram Bot設定
TELEGRAM_BOT_TOKEN=your-bot-token-from-botfather
TELEGRAM_WEBHOOK_URL=https://yourdomain.com/telegram/webhook

# 外部API連携
OPENWEATHER_API_KEY=your-openweather-api-key
GOOGLE_TRANSLATE_API_KEY=your-google-translate-key

# データベース設定
DATABASE_URL=postgresql://user:password@localhost/telegram_bot
REDIS_URL=redis://localhost:6379

# ファイルストレージ
AWS_S3_BUCKET=your-s3-bucket
AWS_ACCESS_KEY_ID=your-aws-access-key
AWS_SECRET_ACCESS_KEY=your-aws-secret-key

# 支払い処理
STRIPE_SECRET_KEY=your-stripe-secret-key
TELEGRAM_PAYMENT_PROVIDER_TOKEN=your-payment-provider-token

# ミニアプリ設定
MINI_APP_URL=https://your-mini-app.com
MINI_APP_SECRET=your-mini-app-secret

Docker設定例

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# システム依存関係のインストール
RUN apt-get update && apt-get install -y \
    tesseract-ocr \
    tesseract-ocr-jpn \
    libgl1-mesa-glx \
    libglib2.0-0 \
    && rm -rf /var/lib/apt/lists/*

# Python依存関係のインストール
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションファイルのコピー
COPY . .

# 環境変数
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1

# ポート公開
EXPOSE 5000

# ヘルスチェック
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5000/health || exit 1

# アプリケーション起動
CMD ["python", "bot.py"]

Docker Compose設定

# docker-compose.yml
version: '3.8'

services:
  telegram-bot:
    build: .
    container_name: telegram-bot
    restart: unless-stopped
    environment:
      - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
      - DATABASE_URL=postgresql://postgres:password@postgres:5432/telegram_bot
      - REDIS_URL=redis://redis:6379
    depends_on:
      - postgres
      - redis
    volumes:
      - ./downloads:/app/downloads
    ports:
      - "5000:5000"
  
  postgres:
    image: postgres:15-alpine
    container_name: postgres
    restart: unless-stopped
    environment:
      - POSTGRES_DB=telegram_bot
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
  
  redis:
    image: redis:7-alpine
    container_name: redis
    restart: unless-stopped
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"

volumes:
  postgres_data:
  redis_data:

CI/CD通知連携例

# ci_cd_integration.py - CI/CDパイプライン通知
import requests
import json

class TelegramCINotifier:
    def __init__(self, bot_token: str, chat_id: str):
        self.bot_token = bot_token
        self.chat_id = chat_id
        self.api_url = f"https://api.telegram.org/bot{bot_token}"
    
    def send_build_notification(self, status: str, project: str, branch: str, commit: str):
        """ビルド通知を送信"""
        emoji = "✅" if status == "success" else "❌"
        
        message = f"""
{emoji} **ビルド {status.upper()}**

プロジェクト: {project}
ブランチ: {branch}
コミット: {commit[:8]}
時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
        """
        
        keyboard = {
            "inline_keyboard": [
                [{"text": "📊 詳細を見る", "url": f"https://ci.example.com/builds/{commit}"}],
                [{"text": "🚀 デプロイ", "callback_data": f"deploy_{project}_{branch}"}]
            ]
        } if status == "success" else None
        
        self.send_message(message, keyboard)
    
    def send_deployment_notification(self, environment: str, status: str, version: str):
        """デプロイ通知を送信"""
        emoji = "🚀" if status == "success" else "💥"
        
        message = f"""
{emoji} **デプロイ {status.upper()}**

環境: {environment}
バージョン: {version}
時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
        """
        
        self.send_message(message)
    
    def send_message(self, text: str, reply_markup=None):
        """メッセージ送信"""
        url = f"{self.api_url}/sendMessage"
        data = {
            "chat_id": self.chat_id,
            "text": text,
            "parse_mode": "Markdown"
        }
        if reply_markup:
            data["reply_markup"] = reply_markup
        
        requests.post(url, json=data)