納品はゴールではなくスタートです。本章では、クライアントが長期にわたってサイトを安定運用できるよう、保守体制の設計・引き継ぎドキュメントの作り方・運用を見据えたコーディング規約・HubSpotアップデートへの対応まで体系的に解説します。
多くのプロジェクトで「納品したら終わり」という認識のまま運用フェーズに入り、 後から混乱が生じます。保守体制は納品前に設計し、クライアントと合意するものです。
HubSpot サイトの運用には、技術的な保守とコンテンツ運用の2つの軸があります。 誰が何を担当するかを最初に整理します。
| 契約種別 | 主な内容 | 目安工数/月 |
|---|---|---|
| スポット保守 | 依頼ベース。発生した改修・追加開発を都度見積もり対応する。 | 案件ごと |
| ライト保守 | 月次のパフォーマンス確認・軽微な修正対応(1〜2時間/月程度) | 2〜4h/月 |
| スタンダード保守 | 軽微な改修・新モジュール開発1件程度・月次レポート提出含む | 8〜16h/月 |
| フル保守 | コンテンツ更新代行含む・SEO施策・A/Bテスト・機能追加開発 | 20h〜/月 |
窓口を1つに統一する。「デザインを直したい」等の曖昧な依頼は具体的な要件ヒアリングを行う。スクリーンショット・URLを必ず添付してもらうルールを作る。
変更が他のページ・モジュールに影響しないか確認する。契約内工数で対応可能かを判断し、超過する場合は追加見積もりを提示する。
本番には直接触れず、必ず開発ポータルで実装してからクライアントに確認URLを共有する。
口頭ではなく書面(メール・Slack)で承認をもらうことを原則とする。「問題ありません」の一言でもOK。
git tag を打ち、本番デプロイ後に対象ページを確認。作業完了をクライアントに報告してチケットをクローズ。
引き継ぎドキュメントはマーケター・コンテンツ担当者が自走できるようにするためのものです。 エンジニア視点で書くと「難しすぎる」ドキュメントになります。 読む相手に合わせて内容を設計することが重要です。
モジュールが多い場合、すべてを1枚のドキュメントに書くと読みにくくなります。 モジュール1つにつき1ページのスタイルで、 Notionや社内Wikiに整理するのが最も使われやすい形式です。
# ヒーローバナー モジュール操作ガイド
## このモジュールは何ですか?
ページ最上部に大きな画像とキャッチコピーを表示するバナーです。
トップページ・サービスページ等に配置されています。
## フィールドの説明
| フィールド名 | 内容 | 注意点 |
|-------------|------|--------|
| 見出し | バナーのメインテキスト | 最大30文字推奨 |
| サブ見出し | 見出し下の補足テキスト | 省略可 |
| 背景画像 | バナー全体の背景画像 | 推奨サイズ: 1440x640px |
| CTAボタンのテキスト | ボタンに表示する文言 | 最大15文字推奨 |
| CTAボタンのリンク | ボタンのリンク先URL | 外部リンクは別タブで開く |
## 推奨画像サイズ
- 幅:1440px 以上
- 高さ:640px 〜 800px
- ファイル形式:JPG(写真)/ PNG(透過あり)
- ファイルサイズ:2MB以下に圧縮推奨
## やってはいけないこと
⚠️ 縦長の画像(1:1 以下の比率)は使わないでください。
PC表示でレイアウトが崩れる場合があります。
⚠️ テキスト入りの画像を背景に使うと、
モバイルで読めなくなる場合があります。
テキストドキュメントと合わせて、Loomやスクリーンレコーダーで操作動画を録画して渡すと クライアントの自走率が劇的に上がります。 「ブログ記事を新規作成して公開するまでの5分動画」1本あるだけで、 同じ質問が何度も来なくなります。 特に HubDB の操作・フォームの変更・モジュールの追加方法は動画で伝えると効果大です。
「動くコード」と「運用しやすいコード」は異なります。 開発時の1時間の工夫が、クライアントの運用で何十時間もの迷いを省きます。
| 設計の原則 | 具体的な実装 |
|---|---|
| フィールドで制御できることはフィールドにする | 色・テキスト・リンク・画像はすべて fields.json のフィールドで管理。コードを触らなくても変更できるようにする。 |
| デフォルト値を必ず設定する | すべてのフィールドに意味のある default 値を設定する。未設定でも「それなりに見える」状態を保つ。 |
| フィールドラベルを日本語にする | label を英語のまま放置しない。「bg_color」より「背景色」の方がマーケターが迷わない。 |
| help_text で入力ガイドを添える | 画像フィールドには「推奨サイズ: 1440x640px」、テキストフィールドには「最大〇文字推奨」等を help_text に記載する。 |
| 壊れやすい操作を choice で制限する | レイアウト切り替えを自由入力ではなく choice フィールドで選択式にする。想定外の値の入力を防ぐ。 |
[
{
"type": "text",
"name": "heading",
"label": "見出し",
"required": true,
"default": "見出しテキストを入力してください",
"help_text": "最大 30 文字推奨。長すぎるとスマホで折り返します。"
},
{
"type": "image",
"name": "bg_image",
"label": "背景画像",
"help_text": "推奨サイズ: 1440×640px。JPG形式・2MB以下に圧縮してください。",
"default": {
"src": "",
"alt": "",
"width": 1440,
"height": 640
}
},
{
"type": "choice",
"name": "layout",
"label": "レイアウト",
"help_text": "テキストの配置位置を選択してください。",
"choices": [
["center", "中央(デフォルト)"],
["left", "左寄せ"],
["right", "右寄せ"]
],
"default": "center",
"display": "radio"
},
{
// STYLE タブのフィールドは「上級者向け」として
// 通常の編集画面から切り離す
"type": "color",
"name": "overlay_color",
"label": "オーバーレイカラー",
"tab": "STYLE",
"help_text": "背景画像の上に重ねる色。透明度も設定できます。",
"default": { "color": "#000000", "opacity": 40 }
}
]
テンプレートファイルには、後から触れる人(将来の自分・引き継いだエンジニア)のために コメントを残します。「何をしているか」より「なぜこうしたか」を書くのが原則です。
{# ===================================================== ブログ記事テンプレート (blog-post.html) ===================================================== 【用途】ブログ記事の詳細ページ 【継承】layouts/base.html 【DnD】なし(固定レイアウト) 【更新履歴】 2024-03-15 v1.2 コンテンツ種別別フォーム切り替えを追加 2024-01-10 v1.1 前後記事ナビゲーションを追加 2023-11-01 v1.0 初期リリース 【注意点】 - タグの命名規則は README.md の「タグ設計」を参照すること - フォームIDはこのファイル内の form_config 辞書で管理している - フォームを追加したい場合は form_config に追記すること ===================================================== #} {% extends "./layouts/base.html" %} {# ===== コンテンツ種別の判定 ===== タグのプレフィックスで種別を判定する。 詳細は第6章「タグ設計戦略」を参照。 type: タグが複数付いている場合は最後に見つかった値が使われる(運用上1つのみ推奨) ===================================================== #} {% set ns = namespace(content_type="blog") %} {% for tag in content.tag_list %} {% if tag.slug starts_with "type:" %} {% set ns.content_type = tag.slug|replace("type:","") %} {% endif %} {% endfor %} {# ===== フォーム設定辞書 ===== コンテンツ種別ごとのフォームIDとリダイレクト先を管理。 新しい種別を追加する際はここに追記すれば OK。 フォームIDはHubSpot管理画面のフォーム詳細URLで確認できる。 ===================================================== #} {% set form_config = { "blog" : { "id": "BLOG_FORM_ID", "redirect": "/thanks/contact" }, "seminar" : { "id": "SEMINAR_FORM_ID", "redirect": "/thanks/seminar" }, "whitepaper" : { "id": "WHITEPAPER_FORM_ID", "redirect": "/thanks/whitepaper" } } %}
チームで開発・保守する場合、規約がないとコードの書き方がバラバラになり 保守コストが上がります。最小限でも明文化された規約が必要です。
# HubSpot CMS コーディング規約
## ファイル・ディレクトリ命名規則
- ファイル名・ディレクトリ名:kebab-case(例: hero-banner, blog-post)
- モジュール名:kebab-case + .module(例: hero-banner.module)
- CSS クラス名:BEM(Block__Element--Modifier)
- HubL 変数名:snake_case(例: content_type, form_id)
## HubL 規約
### 変数定義
- ループ外で使う変数は冒頭でまとめて定義する
- 辞書(マップ)は set で定義してから参照する
- namespace(ns)は状態を持つループ処理でのみ使用する
### テンプレートコメント
- ファイル先頭:目的・更新履歴・注意事項を記載する(必須)
- 複雑なロジック:「なぜこうしたか」を書く(何をしているかは読めばわかる)
- TODO:「TODO: 」プレフィックスで検索しやすくする
### 存在チェックの原則
- image フィールド:{% if module.image.src %} でチェック
- link フィールド :{% if module.link.url %} でチェック
- テキスト :{% if module.text %} でチェック
- 存在チェックなしで .src 等を参照してはいけない
## CSS 規約
### 命名規則(BEM)
.module-name {} ← Block
.module-name__element {} ← Element
.module-name--modifier {} ← Modifier
.module-name__element--mod{} ← Element + Modifier
### レスポンシブ
- モバイルファースト(min-width でブレークポイントを上書き)
- ブレークポイントは CSS 変数で統一する
--bp-sm: 480px;
--bp-md: 768px;
--bp-lg: 1024px;
--bp-xl: 1280px;
### CSS変数の参照
- theme.json のカラー・フォントは必ず CSS 変数経由で参照する
- 直接値(#ff0000 等)はハードコードしない
## アクセシビリティ規約
- 全 img タグに alt 属性を設定する(装飾画像は alt="")
- インタラクティブ要素に aria-label を設定する
- カラーコントラスト比は WCAG AA(4.5:1)以上を維持する
- キーボード操作でフォーカスが視覚的に確認できること
## Git コミットメッセージ規約
feat: 新機能追加
fix: バグ修正
style: 見た目の調整(機能変更なし)
refactor:リファクタリング
docs: ドキュメントのみの変更
deploy: 本番デプロイ(バージョンタグと合わせて使用)
HubSpotは継続的にアップデートされるプラットフォームです。 機能追加・UI変更・非推奨化への対応を定期的に行うことで、 サイトの品質を長期維持できます。
| 項目 | 頻度 | 内容 |
|---|---|---|
| CLI バージョン確認・更新 | 月1回 | npm update -g @hubspot/cli で最新版に更新。変更履歴(CHANGELOG)を確認してBreaking Changeがないか確認する。 |
| PageSpeed Insights 確認 | 月1回 | 代表的なページ(トップ・ブログ一覧・記事詳細)のスコアを記録。前月比で悪化していないか確認する。 |
| Search Console 確認 | 週1回 | カバレッジエラー・Core Web Vitals の問題ページを確認。新たなエラーがあれば即対応する。 |
| HubSpot 製品アップデート確認 | 月1回 | HubSpotの「製品アップデート」ページと開発者向けChangelog(developers.hubspot.com)を確認する。 |
| リンク切れチェック | 3ヶ月に1回 | Screaming Frog 等のツールでサイト全体のリンク切れを確認する。 |
| Personal Access Key の更新 | 150日ごと | キーの期限(180日)切れ前に更新。GitHub Secrets も同時に更新する。 |
| HubSpot テンプレートの非推奨確認 | 半年に1回 | 使用しているHubL機能が非推奨(deprecated)になっていないかHubSpot開発者ドキュメントで確認する。 |
blog_recent_posts() 等の関数仕様は変わることがある。HubSpot 開発者ドキュメントの "Deprecated" セクションを定期確認する。hubdb_table_rows() のクエリパラメータに変更がある場合がある。HubDB を多用するサイトは特に注意。js.hsforms.net/forms/embed/v2.js のバージョンが上がった際は動作確認が必要。
開発者ドキュメント: developers.hubspot.com/docs/cms
製品アップデート: www.hubspot.com/product-updates
開発者フォーラム: community.hubspot.com/t5/HubSpot-Developers
GitHub(HubSpot CLI): github.com/HubSpot/hubspot-cli/releases
HubSpot Developer Changelog: developers.hubspot.com/changelog
| 症状 | 原因の確認箇所 | 解決策 |
|---|---|---|
| ページが真っ白になった | 直前のデプロイ内容・HubL の構文エラー | hs lint でエラー確認 → 直前のgit tagをチェックアウトしてロールバック |
| モジュールが表示されない | fields.json の構文エラー・required フィールドの未設定 | HubSpotのページエディターでモジュールを選択してエラーメッセージを確認 |
| CSS が反映されない | ブラウザのキャッシュ・get_asset_url の使用有無 | ハード再読み込み(Ctrl+Shift+R)でキャッシュをクリア。CLIで再アップロード。 |
| フォームが送信できない | フォームIDの正確性・ポータルIDの一致・広告ブロッカー | 別ブラウザ・シークレットモードで確認。HubSpot管理画面でフォームのIDを再確認。 |
| hs upload が失敗する | 認証トークンの期限切れ・ネットワーク・ファイルパスの誤り | hs auth で再認証。--portal フラグの指定を確認。 |
| HubDB のデータが表示されない | テーブルのPublished状態・クエリの条件・フィールド名の誤記 | HubDB管理画面でテーブルが「Published」になっているか確認。クエリパラメータを単純化してデバッグ。 |
| スマホでレイアウトが崩れた | 画像の width/height 未指定・CSS の flexbox 設定 | Chrome DevTools でレスポンシブモードに切り替えて要素を特定。aspect-ratio または width/height を明示する。 |
| ページのOGP画像が古いまま | SNSのキャッシュ | Facebook: OGデバッガー(developers.facebook.com/tools/debug)でキャッシュをクリア。Twitter: Card Validator で確認。 |
{# ===== 変数の中身を確認する ===== 本番環境では必ず削除すること! ===================================================== #} {# ① 変数の型と値を確認 #} <pre>{{ module|pprint }}</pre> {# ② ループカウンタの確認 #} {% for item in module.items %} {# loop の状態を出力 #} <p>index:{{ loop.index }} / first:{{ loop.first }} / last:{{ loop.last }} / length:{{ loop.length }}</p> {% endfor %} {# ③ 条件分岐の確認(判定結果を出力)#} <p>content_type: {{ ns.content_type }}</p> <p>is_featured: {{ ns.is_featured }}</p> {# ④ HubDB データの確認 #} {% set rows = hubdb_table_rows("my_table") %} <p>取得件数: {{ rows|length }}</p> <pre>{{ rows|pprint }}</pre> {# ⑤ request オブジェクトの確認(URLパラメータ等)#} <pre>{{ request|pprint }}</pre>
保守契約に含まれる場合、月次でクライアントにレポートを提出します。以下の項目を含めると信頼性が高まります。
npm outdated -g @hubspot/cli で更新があれば適用する。
役割分担・依頼フロー・契約内容を事前に合意しておく。曖昧なまま運用フェーズに入ると認識の食い違いが起きる。
マーケター向けには「どう操作するか」を。エンジニア向けには「なぜこう設計したか」を。両者の視点を分けてドキュメントを書く。
help_text・日本語ラベル・choice による入力制限・デフォルト値。開発時の1時間の丁寧さがクライアントの何十時間かの迷いを防ぐ。
月次のPageSpeed・Search Console確認と、150日ごとのトークン更新。カレンダーに入れて「仕組みとして」対応する。
第0章の全体像から、HubL・テンプレート・モジュール・データ活用・フォーム・パフォーマンス・CLI・そして運用設計まで。
この教科書で学んだ技術と設計思想は、HubSpot CMS の案件に限らず、
「エンジニアとしてクライアントとどう向き合うか」という問いへの答えでもあります。
コードは手段です。クライアントのビジネスを前進させることが目的です。
現場で迷ったときは、この教科書を辞書として開いてください。