# 安排播放時段

/app/schedules 決定「在哪些日子的哪個時段，哪些裝置播哪個版面」。

`/app/schedules` 決定「在哪些日子的哪個時段，哪些裝置播哪個版面」。

<figure class="huan-figure">
	<img src="/huan/screenshots/schedules.png" alt="排程管理畫面" />
	<figcaption>排程管理</figcaption>
</figure>

## 一筆排程包含什麼

| 欄位           | 說明                                       |
| -------------- | ------------------------------------------ |
| 名稱           | 給人看的識別                               |
| 版面           | 要播的版面。實際派送的是它目前已發布的修訂 |
| 時區           | IANA 時區，例如 `Asia/Taipei`              |
| 優先度         | 數字愈大愈優先                             |
| 日期區間       | 可留空表示不限                             |
| 星期           | 星期幾生效                                 |
| 開始／結束時間 | `HH:MM`                                    |
| 目標裝置       | 這筆排程套用在哪些裝置上                   |

典型用法：

```text
星期一至五 08:00–11:00  早餐版面
星期一至五 11:00–14:00  午餐版面
星期一至五 14:00–17:00  下午茶版面
```

沒有任何排程命中的時段，裝置播它的**預設版面**（在裝置設定裡指定）。

## 時區

排程存的是 IANA 時區名稱，不是 UTC 偏移。

這很重要：UTC 偏移會隨日光節約時間改變，時區不會。一個設在 `America/New_York` 早上八點的排程，在三月和十一月對應到不同的 UTC 時刻。只存「UTC 13:00」的話，換季的那個週末看板就會在錯的時間換畫面。

判定完全用當地牆上時間進行，日光節約時間、半小時偏移、南半球的反向切換全都自動正確。

## 跨午夜

結束時間早於或等於開始時間就代表跨午夜。視窗**錨定在開始的那一天**：

```text
星期一 22:00–02:00
= 星期一晚上十點 → 星期二凌晨兩點
```

星期二凌晨一點會命中（屬於星期一開始的視窗），星期三凌晨一點不會。

## 衝突怎麼決勝

兩筆排程同時生效時，依序比較：

1. **優先度**較大的勝出
2. **每日視窗較短**的勝出
3. **指定天數較少**的勝出
4. **有日期區間**的勝過沒有的
5. **最後修改時間較新**的勝出
6. 以 **id** 作為最後的決勝

最後一條的存在是為了讓結果**永遠是決定性的**。兩筆條件完全相同的排程不會隨機挑一筆。

實務上的用法：

```text
優先度 100  星期一至五 08:00–18:00  一般營業版面
優先度 500  星期一至五 12:00–12:30  午間限時活動  ← 勝出
```

## 離線也會照時間切換

排程清單本身會下載到裝置本機。判定完全在裝置上進行。

**Server 離線時，裝置依然會照時間切換版面。**

裝置不會在每個時間點去問 Server「現在要播什麼」——那種設計在網路正常時很優雅，網路一斷就整個停擺，而數位看板最常出問題的地方就是網路。

## 停用

排程可以停用而不刪除。停用的排程不會參與判定，但設定都留著，隨時可以再打開。
