> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 튜토리얼 - Laravel Console Starter

> Laravel Console Starter를 사용한 콘솔 앱 구축 절차. 명령어 작성, GitHub Actions 스케줄링, 알림 전송, 실전 앱 예시를 배웁니다.

## 시작하며

이 튜토리얼에서는 `revolution/laravel-console-starter`를 사용해 커스텀 artisan 명령어를 갖춘 Laravel 애플리케이션을 구축합니다.

이 스타터 키트를 사용하는 이점:

* **빠른 셋업** — 복잡한 설정 없이 콘솔 앱 개발을 바로 시작할 수 있습니다
* **Laravel 에코시스템** — 태스크 스케줄링·데이터베이스·알림 등 Laravel의 풍부한 기능을 이용할 수 있습니다
* **Artisan 명령어** — Laravel의 강력한 Artisan 시스템으로 자체 명령어를 손쉽게 만들고 관리할 수 있습니다
* **테스트 용이성** — Laravel의 테스트 프레임워크로 명령어 테스트를 작성할 수 있습니다

## 전제 조건

다음 소프트웨어를 설치하세요.

* PHP `^8.3`
* Composer([https://getcomposer.org/](https://getcomposer.org/))
* Laravel Installer(`composer global require laravel/installer`)

## 프로젝트 셋업

<Steps>
  <Step title="새 프로젝트 생성">
    터미널에서 다음 명령어를 실행합니다.

    ```bash theme={null}
    laravel new my-app --using=revolution/laravel-console-starter --no-interaction
    ```

    `my-app` 디렉터리가 생성되고, 콘솔 앱의 기본 구조가 셋업됩니다.

    설치 시에 다음이 자동 실행됩니다.

    * `.env.example`에서 `.env` 파일 생성
    * `php artisan key:generate`에 의한 애플리케이션 키 설정

    주요 디렉터리 구조:

    ```
    my-app/
    ├── app/Console/Commands/   # 커스텀 명령어 배치
    ├── .github/workflows/
    │   └── cron.yml            # GitHub Actions 스케줄 예시
    ├── config/                 # 애플리케이션 설정
    └── routes/console.php      # 명령어 등록
    ```
  </Step>

  <Step title="환경 설정 확인">
    기본적으로 메일 전송은 로그 출력으로 설정되어 있습니다(`MAIL_MAILER=log`).

    실제로 메일 전송이 필요한 경우에는 `.env` 파일에서 Mailgun이나 Postmark, SES 등의 서비스를 설정하세요.
  </Step>
</Steps>

## 콘솔 명령어 작성

<Steps>
  <Step title="명령어 생성">
    `make:command` Artisan 명령어로 새 명령어를 생성합니다.

    ```bash theme={null}
    php artisan make:command YourCommandName --command=your:command
    ```

    * `YourCommandName` — 생성할 명령어의 클래스 이름(예: `SendDailyReport`)
    * `your:command` — 명령어 호출 이름(예: `report:send-daily`)

    `app/Console/Commands/YourCommandName.php`가 생성됩니다.
  </Step>

  <Step title="명령어 구현">
    생성된 파일을 편집해 로직을 구현합니다. 다음은 Hello World 명령어의 예시입니다.

    ```php theme={null}
    <?php

    namespace App\Console\Commands;

    use Illuminate\Console\Command;
    use Illuminate\Support\Facades\Log;

    class HelloWorldCommand extends Command
    {
        protected $signature = 'hello:world';
        protected $description = 'Displays a hello world message in the log';

        public function handle(): int
        {
            Log::info('Hello, World from Artisan Command!');
            $this->info('Hello, World message has been logged.');
            return Command::SUCCESS;
        }
    }
    ```

    `$signature`에서 명령어 호출 이름을 정의하고, `handle()` 메서드에 로직을 기술합니다.
  </Step>

  <Step title="명령어 실행">
    ```bash theme={null}
    php artisan hello:world
    ```

    실행 후, `storage/logs/laravel.log`와 콘솔에 메시지가 출력됩니다.
  </Step>
</Steps>

## GitHub Actions에서의 태스크 스케줄링

GitHub Actions를 사용하면 서버 cron 잡 없이 명령어를 정기 실행할 수 있습니다.

<Steps>
  <Step title="워크플로 파일 확인">
    스타터 키트에는 `.github/workflows/cron.yml`이 사전 설정되어 포함되어 있습니다.

    ```yaml theme={null}
    name: cron

    on:
      schedule:
        - cron: '0 0 * * *'  # 매일 UTC 오전 0시

    jobs:
      cron:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v6
          - uses: shivammathur/setup-php@v2
            with:
              php-version: 8.5
              coverage: none
          - run: composer install --no-dev -q
          - run: cp .env.example .env
          - run: php artisan key:generate
          - run: php artisan inspire
    ```
  </Step>

  <Step title="명령어 변경">
    `php artisan inspire`를 자신의 명령어로 대체합니다.

    ```yaml theme={null}
    - name: Run Command
      run: php artisan your:command
    ```

    여러 명령어를 실행하는 경우:

    ```yaml theme={null}
    - name: Run Commands
      run: |
        php artisan first:command
        php artisan second:command
    ```
  </Step>

  <Step title="스케줄 조정">
    `cron` 식을 변경하여 실행 주기를 설정합니다.

    | cron 식        | 실행 타이밍       |
    | ------------- | ------------ |
    | `0 0 * * *`   | 매일 UTC 오전 0시 |
    | `0 */6 * * *` | 6시간마다        |
    | `0 0 * * 1`   | 매주 월요일 오전 0시 |
  </Step>

  <Step title="기밀 정보를 시크릿으로 관리">
    API 키나 패스워드 등의 기밀 정보는 GitHub 저장소 시크릿을 사용합니다.

    GitHub 저장소의 **Settings > Secrets and variables > Actions**에서 시크릿을 추가하고, 워크플로에서 참조합니다.

    ```yaml theme={null}
    - name: Run Command with Secrets
      run: php artisan your:command
      env:
        API_KEY: ${{ secrets.API_KEY }}
        DB_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
    ```
  </Step>
</Steps>

## 알림 기능

명령어의 실행 결과나 에러를 메일·Slack 등으로 알릴 수 있습니다.

<Steps>
  <Step title="알림 클래스 생성">
    ```bash theme={null}
    php artisan make:notification TaskCompleted
    ```

    `app/Notifications/TaskCompleted.php`가 생성됩니다.
  </Step>

  <Step title="알림 채널 설정">
    필요에 따라 설정 파일을 공개합니다.

    ```bash theme={null}
    php artisan config:publish mail
    php artisan config:publish services
    ```
  </Step>

  <Step title="명령어에서 알림 전송">
    ```php theme={null}
    <?php

    namespace App\Console\Commands;

    use App\Notifications\TaskCompleted;
    use Illuminate\Console\Command;
    use Illuminate\Support\Facades\Notification;

    class ProcessDataCommand extends Command
    {
        protected $signature = 'data:process';
        protected $description = '데이터를 처리하고 완료 시 알림을 전송';

        public function handle()
        {
            $this->info('데이터를 처리 중...');

            // 처리 로직...

            Notification::route('mail', 'admin@example.com')
                ->notify(new TaskCompleted('데이터 처리가 정상적으로 완료되었습니다'));

            return Command::SUCCESS;
        }
    }
    ```
  </Step>
</Steps>

<Info>
  자세한 내용은 [Laravel 알림 문서](https://laravel.com/docs/notifications)를 참조하세요.
</Info>

## 실전 애플리케이션 예시

### 예시 1: 웹사이트 헬스 체크와 Slack 알림

웹사이트가 온라인인지 확인하고, 문제가 감지된 경우 Slack에 알림을 전송하는 명령어입니다.

<Steps>
  <Step title="Slack 알림 채널 설치">
    ```bash theme={null}
    composer require laravel/slack-notification-channel
    ```
  </Step>

  <Step title="명령어와 알림 생성">
    ```bash theme={null}
    php artisan make:command MonitorWebsites --command=monitor:websites
    php artisan make:notification WebsiteDown
    ```
  </Step>

  <Step title="Slack 설정">
    ```bash theme={null}
    php artisan config:publish services
    ```

    `.env`에 Slack webhook URL을 추가합니다.

    ```
    SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
    ```

    `config/services.php`를 업데이트합니다.

    ```php theme={null}
    'slack' => [
        'webhook_url' => env('SLACK_WEBHOOK_URL'),
    ],
    ```
  </Step>

  <Step title="알림 구현">
    `app/Notifications/WebsiteDown.php`를 편집합니다.

    ```php theme={null}
    <?php

    namespace App\Notifications;

    use Illuminate\Notifications\Messages\SlackMessage;
    use Illuminate\Notifications\Notification;

    class WebsiteDown extends Notification
    {
        public function __construct(
            protected string $website,
            protected string $error,
        ) {}

        public function via($notifiable): array
        {
            return ['slack'];
        }

        public function toSlack($notifiable): SlackMessage
        {
            return (new SlackMessage)
                ->error()
                ->content('웹사이트 다운 알림!')
                ->attachment(function ($attachment) {
                    $attachment->title($this->website)
                               ->content("에러: {$this->error}")
                               ->timestamp(now());
                });
        }
    }
    ```
  </Step>

  <Step title="명령어 구현">
    `app/Console/Commands/MonitorWebsites.php`를 편집합니다.

    ```php theme={null}
    <?php

    namespace App\Console\Commands;

    use App\Notifications\WebsiteDown;
    use Illuminate\Console\Command;
    use Illuminate\Support\Facades\Http;
    use Illuminate\Support\Facades\Log;
    use Illuminate\Support\Facades\Notification;

    class MonitorWebsites extends Command
    {
        protected $signature = 'monitor:websites {--timeout=10}';
        protected $description = '웹사이트 헬스 체크와 다운 시 Slack 알림 전송';

        protected array $websites = [
            'https://example.com',
            'https://yourwebsite.com',
        ];

        public function handle(): int
        {
            $timeout = (int) $this->option('timeout');
            $webhookUrl = config('services.slack.webhook_url');
            $hasErrors = false;

            foreach ($this->websites as $website) {
                try {
                    $response = Http::timeout($timeout)->get($website);
                    if ($response->successful()) {
                        $this->info("{$website}: 온라인 ✓");
                    } else {
                        $error = "HTTP 상태: " . $response->status();
                        $this->error("{$website}: 다운 ({$error})");
                        Notification::route('slack', $webhookUrl)
                            ->notify(new WebsiteDown($website, $error));
                        $hasErrors = true;
                    }
                } catch (\Exception $e) {
                    $this->error("{$website}: 에러 ({$e->getMessage()})");
                    Log::error("{$website} 확인 실패", ['error' => $e->getMessage()]);
                    Notification::route('slack', $webhookUrl)
                        ->notify(new WebsiteDown($website, $e->getMessage()));
                    $hasErrors = true;
                }
            }

            return $hasErrors ? Command::FAILURE : Command::SUCCESS;
        }
    }
    ```
  </Step>

  <Step title="GitHub Actions에서 스케줄 설정">
    `.github/workflows/cron.yml`을 업데이트합니다.

    ```yaml theme={null}
    name: Website Monitoring

    on:
      schedule:
        - cron: '*/15 * * * *'  # 15분마다 실행

    jobs:
      monitor:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v6
          - uses: shivammathur/setup-php@v2
            with:
              php-version: 8.5
          - run: composer install --no-dev -q
          - run: cp .env.example .env
          - run: php artisan key:generate
          - name: Monitor Websites
            run: php artisan monitor:websites
            env:
              SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
    ```
  </Step>
</Steps>

### 예시 2: 암호 자산 포트폴리오 업데이트와 Discord 알림

CoinGecko API에서 암호 자산 가격을 취득하고, Discord 웹훅으로 업데이트를 전송하는 명령어입니다.

<Steps>
  <Step title="Discord 알림 채널 설치">
    ```bash theme={null}
    composer require revolution/laravel-notification-discord-webhook
    ```
  </Step>

  <Step title="명령어와 알림 생성">
    ```bash theme={null}
    php artisan make:command UpdateCryptoPortfolio --command=crypto:portfolio
    php artisan make:notification CryptoPortfolioUpdate
    ```
  </Step>

  <Step title="Discord 설정">
    `.env`에 Discord webhook URL을 추가합니다.

    ```
    DISCORD_WEBHOOK=https://discord.com/api/webhooks/YOUR/WEBHOOK
    ```

    `config/services.php`를 업데이트합니다.

    ```php theme={null}
    'discord' => [
        'webhook' => env('DISCORD_WEBHOOK'),
    ],
    ```
  </Step>

  <Step title="명령어 구현 및 실행">
    자세한 구현은 [GitHub 저장소의 튜토리얼](https://github.com/invokable/laravel-console-starter/blob/main/docs/tutorial_ja.md)을 참조하세요.

    ```bash theme={null}
    php artisan crypto:portfolio
    ```
  </Step>
</Steps>

### 예시 3: 웹사이트 콘텐츠 스크래핑과 메일 알림

웹사이트에서 콘텐츠를 스크래핑하고, 결과를 메일로 전송하는 명령어입니다.

<Steps>
  <Step title="명령어와 알림 생성">
    ```bash theme={null}
    php artisan make:command WebScraper --command=scrape:website
    php artisan make:notification ScrapingCompleted
    ```
  </Step>

  <Step title="메일 설정">
    ```bash theme={null}
    php artisan config:publish mail
    ```

    `.env` 파일에 메일 설정을 추가합니다.

    ```
    MAIL_MAILER=smtp
    MAIL_HOST=smtp.mailtrap.io
    MAIL_PORT=2525
    MAIL_USERNAME=your_username
    MAIL_PASSWORD=your_password
    MAIL_ENCRYPTION=tls
    MAIL_FROM_ADDRESS=your-app@example.com
    MAIL_FROM_NAME="${APP_NAME}"
    ```
  </Step>

  <Step title="명령어 구현 및 실행">
    ```php theme={null}
    protected $signature = 'scrape:website {--url=https://example.com} {--email=admin@example.com}';

    public function handle(): int
    {
        $url = $this->option('url');
        $email = $this->option('email');

        $response = Http::timeout(30)->get($url);

        // 콘텐츠를 처리하고 알림을 전송...
        Notification::route('mail', $email)
            ->notify(new ScrapingCompleted(true, $url, $title, $content));

        return Command::SUCCESS;
    }
    ```

    ```bash theme={null}
    php artisan scrape:website --email=admin@example.com
    ```
  </Step>
</Steps>

## 다음 단계

이제 `revolution/laravel-console-starter`를 사용한 Laravel 콘솔 애플리케이션의 기본을 배웠습니다.

더 깊이 배우기 위해서:

* **Laravel 문서를 탐색하세요** — [Laravel 공식 문서](https://laravel.com/docs)에서 콘솔 앱을 강화할 수 있는 기능을 확인해 봅시다
* **테스트를 구현하세요** — Laravel의 테스트 프레임워크로 명령어 테스트를 작성해 신뢰성을 확보합시다
* **패키지 개발을 검토하세요** — 여러 프로젝트에서 유사한 명령어를 만든다면, 재사용 가능한 Laravel 패키지로 공개하는 것을 검토해 주세요
* **최신 정보를 파악하세요** — [Laravel News](https://laravel-news.com/)나 공식 블로그를 팔로우하여 베스트 프랙티스를 항상 파악합시다


## Related topics

- [봇 튜토리얼 - Laravel Bluesky](/ko/packages/laravel-bluesky/bot-tutorial.md)
- [Laravel Console Starter](/ko/packages/laravel-console-starter/index.md)
- [콘솔 테스트](/ko/console-tests.md)
- [디렉터리 구조](/ko/directory-structure.md)
- [Laravel이란](/ko/introduction.md)
