summaryrefslogtreecommitdiff
path: root/doc/Design.md
blob: 26fc64c2e9ab07109815d7a9c442d4d8c3345de4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
# たかしの記録 — 技術設計書

## 1. 文書の役割

本書は、[Specifications.md](Specifications.md)で定義した利用者向け要求を、現在のリポジトリでどのように実現しているかを記録する。

記載対象は、実装済みの構成、設定、コンテンツモデル、テンプレート、スタイル、クライアント処理、生成物、検証方法である。将来案や完了済みの実装計画は含めない。コードと本書が異なる場合はコードを正とし、本書を同じ変更内で更新する。

## 2. システム構成

### 2.1 技術要素

| 項目 | 採用内容 |
|---|---|
| Static Site Generator | Zola 0.23.3 |
| Content | Markdown + TOML Front Matter |
| Template | Tera 2 |
| Style | SCSSをZolaでコンパイル |
| Client script | theme切替用のVanilla JavaScript 1ファイル |
| Syntax highlight | Zola組み込み、class方式、`github-light`/`github-dark` |
| 配信形式 | 静的なHTML、CSS、JavaScript、XML、SVG、記事asset |
| 外部theme | 使用しない。`themes/`は空で保持する。 |
| Node.js/frontend framework | 使用しない |
| CDN/外部font | 使用しない |
| Backend/database | 使用しない |

### 2.2 生成フロー

```text
content/*.md ─┐
templates/* ──┼─> Zola ─> public/ ─> deploy.ps1 ─> VPS releases/ ─> current
sass/*.scss ──┤
static/* ─────┘
```

ZolaがSection、Page、Taxonomyを解決し、TeraでHTMLを生成する。SCSSは`main.css`へコンパイルし、`static/`とPage Bundle内のassetを出力へコピーする。公開環境は`public/`の内容だけで成立し、VPSで再ビルドしない。

## 3. リポジトリ構造

```text
.
├── zola.toml
├── deploy.ps1
├── deploy.config.example.psd1
├── deploy.config.psd1          # local only
├── content/
│   ├── _index.md
│   ├── about.md
│   ├── notes/
│   │   ├── _index.md
│   │   └── <slug>.md
│   └── software/
│       ├── _index.md
│       ├── <slug>.md
│       └── <slug>/
│           ├── index.md
│           └── <article-assets>
├── templates/
│   ├── base.html
│   ├── index.html
│   ├── page.html
│   ├── 404.html
│   ├── notes/
│   ├── software/
│   ├── tags/
│   └── partials/
├── sass/
│   ├── main.scss
│   └── _*.scss
├── static/
│   ├── favicon.svg
│   └── js/theme.js
├── doc/
│   ├── Specifications.md
│   ├── Design.md
│   └── content-templates/
├── draft/
├── themes/
└── public/
```

| ディレクトリ | 管理方針 |
|---|---|
| `content/` | 公開対象の原稿だけを置く。 |
| `draft/` | 非公開原稿を置き、Git管理とZola処理の対象外にする。 |
| `themes/` | 外部themeを導入せず空で保持する。 |
| `public/` | ビルド生成物。Git管理対象外とする。 |

`deploy.config.psd1`は環境固有値を含むためGit管理対象外とし、構造だけを示す`deploy.config.example.psd1`を管理する。

## 4. Zola設定

設定の完全な値と各項目の説明は`zola.toml`を正とする。本節では、サイト構造に影響する設定をまとめる。

### 4.1 サイト設定

| Key | 現在値 | 用途 |
|---|---|---|
| `base_url` | `https://www.takashi-2521.com` | canonical URLと絶対URLの基準 |
| `title` | `たかしの記録` | Header、HTML title、Feed |
| `description` | サイト説明文 | meta description、About、Feed |
| `default_language` | `ja` | HTML言語と既定言語 |
| `output_dir` | `public` | 生成先 |
| `compile_sass` | `true` | SCSSコンパイル |
| `minify_html` | `false` | HTMLを可読な状態で出力 |
| `author` | `Takashi` | PageとFeedの既定author |

### 4.2 配信機能

| Key | 現在値 | 結果 |
|---|---|---|
| `generate_feeds` | `true` | サイト全体のFeedを生成 |
| `feed_filenames` | `atom.xml`, `rss.xml` | AtomとRSSを生成 |
| `taxonomies` | `tags`, `feed=false` | タグページを生成し、タグ別Feedは生成しない |
| `build_search_index` | `false` | 検索indexを生成しない |
| `generate_sitemap` | `true` | `sitemap.xml`を生成 |
| `generate_robots_txt` | `true` | `robots.txt`を生成 |

Software Pageは`include_in_feeds = false`とし、日付を持っていてもサイトFeedへ含めない。現在のサイトFeedは実質的にNotesを購読対象とする。

### 4.3 Markdown

| 設定 | 現在値 | 設計意図 |
|---|---|---|
| `bottom_footnotes` | `true` | 脚注を記事末尾へ集約し、本文への戻りリンクを生成 |
| `insert_anchor_links` | `heading` | 見出し全体をdeep linkにする |
| `lazy_async_image` | `true` | 画像へ遅延・非同期decode属性を付与 |
| `external_links_class` | `external-link` | 外部リンクをCSSで識別 |
| `external_links_external` | `true` | 外部リンクへ`rel="external"`を付与 |
| `smart_punctuation` | `false` | 原稿の文字を自動置換しない |

### 4.4 Syntax highlight

| 設定 | 現在値 |
|---|---|
| 出力方式 | `class` |
| Light theme | `github-light` |
| Dark theme | `github-dark` |
| 未対応言語 | エラー |
| 生成CSS | `giallo-light.css`, `giallo-dark.css` |

class方式を使用し、コード色をHTMLのinline styleへ埋め込まない。Light/Dark用CSSは`base.html`から個別に読み込む。

### 4.5 カスタム設定

`[extra]`はTeraから参照するサイト固有値である。

| Key | 参照先 |
|---|---|
| `home_notes_limit` | Homeに表示するNotes件数 |
| `home_software_limit` | Homeに表示するSoftware件数 |
| `copyright_year` | Footer |
| `mail` | AboutとFooter |
| `cgit` | Software一覧 |
| `github` | 予約済み。現在のTemplateでは未使用 |

## 5. コンテンツモデル

### 5.1 SectionとPage

| Source | Zola model | Template | 並び順 |
|---|---|---|---|
| `content/_index.md` | Root Section | `index.html` | 各Sectionの設定に従う |
| `content/about.md` | Page | `page.html` | 対象外 |
| `content/notes/_index.md` | Section | `notes/section.html` | `date`降順 |
| `content/notes/*.md` | Page | `notes/page.html` | `date` |
| `content/software/_index.md` | Section | `software/section.html` | `date`降順 |
| `content/software/*.md` | Page | `software/page.html` | `date` |
| `content/software/*/index.md` | Page Bundle | `software/page.html` | `date` |

`_index.md`はSection、通常の`.md`と`index.md`はPageとして扱う。Softwareに画像などを併置する場合だけPage Bundleを使用する。

### 5.2 Notes Front Matter

完全な作成用雛形は[content-templates/note.md](content-templates/note.md)に置く。

| Field | 型 | 必須 | 利用箇所 |
|---|---|---:|---|
| `title` | String | Yes | 一覧、詳細、HTML title |
| `description` | String | No | 一覧、詳細、meta description |
| `date` | Date | Yes | 公開日、並び順、年別分類 |
| `updated` | Date | No | 詳細の更新日 |
| `taxonomies.tags` | Array[String] | No | 一覧、タグページ |
| `extra.related_software` | Array[String] | No | 詳細末尾の関連Software |

Markdownファイル名は英語ASCIIのslugとする。表示タイトルは日本語を許可する。

### 5.3 Software Front Matter

完全な作成用雛形は[content-templates/software.md](content-templates/software.md)に置く。

| Field | 型 | 必須 | 利用箇所 |
|---|---|---:|---|
| `title` | String | Yes | 一覧、詳細、HTML title |
| `description` | String | No | 一覧、詳細、meta description |
| `date` | Date | Yes | 並び順 |
| `include_in_feeds` | Boolean | Yes | `false`でサイトFeedから除外 |
| `extra.language` | Array[String] | No | 詳細の使用言語 |
| `extra.license` | String | No | 詳細のライセンス |
| `extra.source` | URL String | Yes | cgit正本へのリンク |
| `extra.github_mirror` | URL String | No | GitHub mirrorへのリンク |
| `extra.related_notes` | Array[String] | No | 詳細末尾の関連Notes |

本文の章立ては固定しないが、原則として概要、背景、開発の過程を含める。スクリーンショットはPage Bundle内へ置き、相対pathで参照する。

### 5.4 Aboutとサイト共通値

Aboutは汎用`page.html`を使用する。サイト説明とメールアドレスは本文へ重複記載せず、`config.description`と`config.extra.mail`を参照する。

### 5.5 関連コンテンツ

関連付けはタグから自動推測せず、Front Matterで明示する。

```toml
[extra]
related_software = ["software/example/index.md"]
related_notes = ["notes/example.md"]
```

pathは`content/`を基準にしたMarkdown pathとする。Partial内で`get_page(path=path)`を使用するため、対象を削除すると`zola check`が失敗する。記事削除時は相互参照と本文中の内部リンクも同時に削除する。

## 6. URLと生成物

### 6.1 Page URL

| 種別 | URL |
|---|---|
| Home | `/` |
| About | `/about/` |
| Notes一覧 | `/notes/` |
| Note詳細 | `/notes/<slug>/` |
| Software一覧 | `/software/` |
| Software詳細 | `/software/<slug>/` |
| タグ一覧 | `/tags/`(タグ使用時) |
| タグ別一覧 | `/tags/<term-slug>/`(タグ使用時) |
| 404 | `/404.html` |

`slugify.paths`、`slugify.taxonomies`、`slugify.anchors`は`on`とする。Markdown内の内部リンクは`@/`記法、Tera内は`get_url(path="@/...")`を使用し、`base_url`や配置変更へ追従させる。

### 6.2 サイト共通出力

| 出力 | 生成元 |
|---|---|
| `main.css` | `sass/main.scss` |
| `giallo-light.css` | Zola syntax highlight |
| `giallo-dark.css` | Zola syntax highlight |
| `js/theme.js` | `static/js/theme.js` |
| `favicon.svg` | `static/favicon.svg` |
| `atom.xml` | Zola built-in Feed template |
| `rss.xml` | Zola built-in Feed template |
| `sitemap.xml` | Zola built-in sitemap template |
| `robots.txt` | Zola built-in robots template |

## 7. Template設計

### 7.1 継承構造

```text
base.html
├── index.html
├── page.html
├── 404.html
├── notes/section.html
├── notes/page.html
├── software/section.html
├── software/page.html
├── tags/list.html
└── tags/single.html
```

`base.html`は文書骨格、metadata、共通CSS/JavaScript、Header、Footer、`main`を提供する。各ページは`title`、`description`、`content` blockを上書きする。

### 7.2 共通部品

| Partial | 役割 |
|---|---|
| `partials/header.html` | サイト名、Home/Notes/Software/About、theme切替 |
| `partials/footer.html` | copyright、Atom、RSS、Mail |
| `partials/note-list-item.html` | Noteの日付、タイトル、説明、タグ |
| `partials/software-list-item.html` | Software名と説明 |
| `partials/related-notes.html` | Softwareから関連Notesを解決 |
| `partials/related-software.html` | Noteから関連Softwareを解決 |
| `partials/toc.html` | Zolaの階層化された目次を再帰描画 |

### 7.3 Metadata

`base.html`は全ページへ次を出力する。

- UTF-8とresponsive viewport
- `lang="ja"`
- ページ固有またはサイト共通のdescription
- ページ固有のtitle
- canonical URL
- SVG favicon
- Atom/RSS autodiscovery
- Light/Dark syntax CSS
- `main.css`と`theme.js`

Page titleは詳細・一覧とも`<ページ名> | <サイト名>`、Homeはサイト名だけとする。

### 7.4 HeaderとFooter

Headerは`current_path`から現在地を判定し、対象リンクへ`aria-current="page"`を付ける。モバイルではHeaderを折り返し、ナビゲーションを次行へ配置する。

`body`を縦Flex、`main`を可変領域、Footerを固定高ではない終端領域とする。短いページではFooterをviewport下端へ置き、長いページでは本文の直後へ配置する。Footer内の上下paddingは全ページ共通である。

### 7.5 Home

Homeは本文用`h1`や紹介文を表示せず、最近のNotesとSoftwareだけを表示する。それぞれのSection Pageを取得し、`config.extra.home_*_limit`件まで描画する。対象が0件の場合は説明付き空状態を表示する。

### 7.6 Notes

一覧は`section.pages`を`year`でgroup化し、年見出しとNote一覧を生成する。詳細はタイトル、公開日、任意の更新日・説明、目次、本文、関連Softwareの順に描画する。

目次は`page.toc`が空でない場合だけ表示する。脚注はMarkdown rendererが記事末尾へ生成する。

### 7.7 Software

一覧はSoftware名と説明を簡潔に表示し、末尾からサイト共通のcgitへ案内する。詳細はタイトル、説明、metadata、本文、関連Notesの順に描画する。

metadataはデスクトップで2列、モバイルで1列とする。項目数が奇数の場合、最後の項目を全幅にして罫線を維持する。Sourceは必須、language、license、Mirrorは値がある場合だけ表示する。

### 7.8 Tagsと404

タグ一覧は`terms`の名称と記事数を表示する。タグ別ページは`term.pages`をNote一覧Partialで表示する。404はHome、Notes、Softwareへの復帰導線を持つ。

## 8. Presentation設計

### 8.1 SCSS構成

`sass/main.scss`から次の順でPartialを読み込む。

| Partial | 責務 |
|---|---|
| `_tokens.scss` | 色、font、幅、罫線のcustom properties |
| `_reset.scss` | box modelと既定marginの初期化 |
| `_base.scss` | body、link、focus、外部link |
| `_typography.scss` | 見出しとmetadata文字 |
| `_layout.scss` | container、page余白、共通配置 |
| `_header.scss` | Header、navigation、theme button |
| `_footer.scss` | Footer |
| `_archive.scss` | Notes一覧、タグ表示、空状態 |
| `_article.scss` | 記事header、目次、本文、脚注、関連項目 |
| `_software.scss` | Software一覧とmetadata |
| `_taxonomy.scss` | タグ一覧 |
| `_code.scss` | inline codeとcode block |
| `_theme.scss` | 手動themeとreduced motion |
| `_utilities.scss` | skip link、視覚非表示utility |

### 8.2 Design tokens

| Token | Light | Dark |
|---|---|---|
| Background | `#f6f5f1` | `#17191b` |
| Surface | `#fbfaf7` | `#1d2022` |
| Text | `#202124` | `#e9e9e6` |
| Muted | `#666b70` | `#a0a3a6` |
| Border | `#d6d8da` | `#363a3e` |
| Link | `#315f82` | `#86b6d8` |
| Focus | `#1e668f` | `#86b6d8` |

本文fontはsystem sans-serif、metadataとcodeはsystem monospaceを使用する。外部fontは読み込まない。本文最大幅は`72ch`、サイト最大幅は`72rem`とする。

### 8.3 Responsive layout

| 対象 | Breakpoint | 変更 |
|---|---:|---|
| Footer | `32rem` | 縦積み |
| Home section heading | `38rem` | 縦積み |
| Notes一覧 | `40rem` | 年・日付と本文を1列化 |
| Header/Software | `42rem` | Header折返し、Softwareを1列化 |

containerは左右に最低`1rem`の余白を確保する。表とcode blockは必要に応じて横スクロールさせ、ページ全体の横overflowを防ぐ。画像はcontainer幅を超えない。

## 9. Theme切替

初期themeは`prefers-color-scheme`に従う。JavaScriptが動作するとtheme buttonを表示し、選択した`light`または`dark`を`localStorage.theme`へ保存する。

`static/js/theme.js`は次を同期する。

1. `<html data-theme>`
2. theme buttonの表示、`aria-label`、`aria-pressed`
3. Light/Dark syntax CSSの`media`
4. OS theme変更。ただし手動選択済みの場合は上書きしない。

Storageへアクセスできない場合も現在のページでは切替を継続する。JavaScriptが無効な場合はbuttonを非表示にし、CSSの`prefers-color-scheme`だけで表示する。

## 10. Accessibility設計

| 要求 | 実装 |
|---|---|
| Landmark | `header`、`nav`、`main`、`article`、`section`、`footer`を用途に応じて使用 |
| Skip link | ページ先頭から`#main-content`へ移動 |
| 現在地 | Header linkの`aria-current="page"` |
| Focus | 全操作要素へ3px outlineを表示 |
| 見出し | 一覧・詳細はページ名を`h1`、本文を`h2`以下とする。Homeはサイト名の重複表示を避け、各領域を`h2`とする。 |
| 日付 | 表示値と`datetime`を持つ`time` |
| 目次 | `nav`と`aria-label="目次"` |
| Theme | buttonの状態と操作内容をARIAへ反映 |
| Motion | `prefers-reduced-motion: reduce`でanimationとtransitionを抑制 |
| 画像 | Markdownで代替textを必須とする |

## 11. Feed・Taxonomy・SEO

### 11.1 Feed

サイトrootへAtomとRSSを生成し、全HTMLからautodiscovery linkを提供する。SoftwareはPage単位でFeedから除外する。タグ別Feedは生成しない。

### 11.2 Taxonomy

`tags`だけを定義する。Noteの`taxonomies.tags`からタグ一覧とタグ別ページを自動生成する。タグを持つNoteが0件の場合、Zolaはタグページを生成しない。タグURLは`slugify.taxonomies = "on"`に従う。

### 11.3 SEO metadata

全ページにtitle、description、canonical URLを設定する。sitemapとrobots.txtはZola組み込みtemplateで生成する。Open Graph、SNS card、構造化dataは実装しない。

## 12. Security・Privacy・Performance

### 12.1 SecurityとPrivacy

- inline scriptとinline event handlerを使用しない。
- Syntax highlightはclass方式とし、inline styleを生成しない。
- 外部theme、CDN、外部font、analytics、commentsを使用しない。
- 新しいtabを開く明示的な外部linkには`noopener noreferrer`を付ける。
- theme選択以外の利用者dataを保存しない。
- 動的入力、認証、server-side処理を持たない。

この構成は厳格なContent Security Policyを適用しやすいが、CSP header自体は配信環境の責務であり本リポジトリでは設定しない。

### 12.2 Performance

- JavaScriptはtheme切替の1ファイルだけを`defer`で読み込む。
- system fontを使用し、font downloadを発生させない。
- Markdown画像へlazy loadingとasync decodingを付ける。
- Pageごとに必要な静的HTMLを生成し、実行時renderingを行わない。
- Syntax CSSはthemeごとに分離する。

## 13. 執筆・保守手順

### 13.1 記事追加

1. [content-templates/README.md](content-templates/README.md)を確認する。
2. NotesまたはSoftwareの雛形をコピーする。
3. Front Matterの説明コメントを削除し、必須値を入力する。
4. 関連pathとMarkdown内部リンクを確認する。
5. `zola check`と`zola build`を実行する。

Markdownを追加するだけでSection一覧、個別URL、Homeの最新一覧へ反映される。Templateの変更は不要である。

### 13.2 記事削除

削除対象を参照する次の箇所を先に検索する。

```text
extra.related_notes
extra.related_software
Markdownの @/ 内部リンク
```

参照を残すと`get_page`またはlink checkerによりビルドが失敗する。削除後は必ず`zola check`を実行する。

### 13.3 Draft

公開しない原稿はrootの`draft/`へ置く。`draft/`は`.gitignore`に含まれ、Gitでも管理しない。公開時にFront Matterを整え、対応する`content/`配下へ移す。

## 14. Build・検証・配信境界

### 14.1 Command

| 目的 | Command |
|---|---|
| 開発表示 | `zola serve` |
| 構造・link検証 | `zola check` |
| 生成 | `zola build` |
| 本番deploy | `.\deploy.ps1` |

### 14.2 必須検証

| 分類 | 確認内容 |
|---|---|
| Zola | `zola check`と`zola build`が成功する。 |
| Page | Home、About、Notes、Software、404が生成され、タグ使用時はTagsも生成される。 |
| Feed | `atom.xml`と`rss.xml`が生成され、Softwareを含まない。 |
| Crawler | `sitemap.xml`と`robots.txt`が生成される。 |
| Asset | `main.css`、syntax CSS 2種、theme.js、favicon、記事assetが生成される。 |
| Link | 削除済みPage、存在しない関連path、誤った内部linkがない。 |
| HTML | canonical URLとFeed autodiscoveryが正しい。 |
| Security | inline script、inline event handler、外部CDN参照がない。 |
| Responsive | Header、一覧、Software metadata、Footerが各breakpointで崩れない。 |
| Accessibility | skip link、focus、現在地、見出し順、theme buttonを確認する。 |
| Deploy script | PowerShell構文、設定欠落・不正値のnon-zero終了、archive直下の`index.html`を確認する。 |

### 14.3 配信境界

サイト生成処理の責務は`public/`までとする。`deploy.ps1`は生成物を既設VPSへ転送し、既存のrelease構造へ配置する外部配信操作を自動化するが、VPS上でZolaやGitを実行しない。

| 項目 | 設計 |
|---|---|
| 設定読込 | rootの`deploy.config.psd1`を`Import-PowerShellDataFile`で自動読込する。command line引数は使用しない。 |
| 接続 | 設定内の`DeployHost`と`DeployUser`をWindows OpenSSHの`ssh`/`scp`へ渡す。 |
| 認証 | `IdentityFile`が空ならOpenSSH標準key探索を使用し、値があれば指定fileを使用する。秘密鍵のpassphraseは`scp`/`ssh`が対話入力を求め、fileへ保存しない。失敗時cleanupだけは`BatchMode=yes`で入力待ちを防ぐ。 |
| Remote base | 設定内の`RemoteBase`を使用し、誤操作防止のため`/srv/www/`配下だけを許可する。 |
| 転送単位 | `public/`の中身だけを含む一時`tar.gz`。 |
| Release ID | ローカル時刻の`yyyyMMdd-HHmmss`。 |
| Remote release | `<RemoteBase>/releases/<release-id>/` |
| 公開切替 | `current.new`を作り、`mv -Tf current.new current`でatomicに置換する。 |
| Cleanup | local/remote archive、失敗時の`current.new`と新規作成releaseを削除する。 |
| 保持 | 過去releaseを削除せず、手動rollbackに利用できる状態を保つ。 |

設定fileのschemaは次のとおりである。

| Key | 必須 | 内容 |
|---|---:|---|
| `DeployHost` | Yes | SSH host名またはSSH config alias |
| `DeployUser` | Yes | deploy専用Unix user |
| `RemoteBase` | Yes | `/srv/www/`配下の公開base |
| `IdentityFile` | Yes | 空文字列またはSSH identity file path |
| `SiteUrl` | Yes | 成功時に表示するHTTPS URL |

初回だけ`deploy.config.example.psd1`を`deploy.config.psd1`へコピーして実値を設定する。以後は`.\deploy.ps1`だけで実行する。実設定は`.gitignore`によりcommitしない。

切替前にlocalとremote双方の`index.html`を確認する。既存releaseが同名の場合は失敗させ、上書きしない。`zola check`、`zola build`、archive作成、転送、展開のいずれかが失敗した場合はnon-zeroで終了する。

VPS、Caddy、TLS、Unix user、filesystem権限、cache、CSP headerの構築と変更は本リポジトリの対象外である。`deploy.ps1`はsudo、Caddy reload、`git pull`、remote buildを行わない。実VPSへの実行は明示的な運用操作として扱う。

## 15. 仕様との対応

| 仕様領域 | 主な実装箇所 |
|---|---|
| Home | `templates/index.html`、`home_*_limit` |
| Notes | `content/notes/`、`templates/notes/`、`_archive.scss`、`_article.scss` |
| Tags | `taxonomies`、`templates/tags/`、`_taxonomy.scss` |
| Software | `content/software/`、`templates/software/`、`_software.scss` |
| About | `content/about.md`、`templates/page.html`、`zola.toml` |
| 共通navigation | `partials/header.html`、`partials/footer.html` |
| Theme | `_tokens.scss`、`_theme.scss`、`static/js/theme.js` |
| Accessibility | `base.html`、各semantic template、`_utilities.scss` |
| Feed・crawler | `zola.toml`、`base.html`、Zola built-in templates |
| Privacy・Security | `zola.toml`、`base.html`、local asset構成 |