Acecore(エースコア)公式Webサイト。
| 技術 | 用途 |
|---|---|
| Astro v6 | 静的サイトジェネレーター |
| UnoCSS | ユーティリティファースト CSS |
| Cloudflare Pages | ホスティング・CDN |
| Cloudflare Images Transformations | 外部画像の自動最適化(/cdn-cgi/image/) |
| Cloudflare Email Service | お問い合わせフォームのメール送信 |
| Cloudflare Workers AI | 問い合わせ前の AI FAQ アシスタント |
| Pagefind | 静的全文検索 |
| Sveltia CMS | Git ベース CMS(ブログ・ページ文言管理) |
| satori + sharp | OG 画像の自動生成 |
| Google AdSense | 広告配信(ブログページ) |
デフォルト言語は日本語(ja)。以下の 9 言語に対応しています。
ja · en · zh-cn · es · pt · fr · ko · de · ru
- デフォルトロケール(
ja)は URL プレフィクスなし(/blog/...) - その他のロケールは
/{locale}/blog/...のパスで配信 - ブログ記事の翻訳は
src/content/blog/{locale}/に配置 - Sveltia CMS では日本語ソース記事、日本語ページ文言、著者、タグを管理
- CMS 経由で編集された多言語記事・ページ文言は Copilot translation PR task で AI に委譲
- UI・固定ページ文字列は日本語ソースを
src/i18n/source/ja/、翻訳先をsrc/i18n/translations/で管理し、Sveltia CMS の「ページ・サイト文言」からページ/用途別に編集
npm install
npm run devnpm run build # astro build && pagefind --site dist
npm run preview| ページ | パス | 説明 |
|---|---|---|
| ホーム | / |
トップページ |
| サービス | /services/ |
サービス詳細 |
| 会社概要 | /about/ |
理念・活動 |
| ブログ | /blog/ |
記事一覧(ページネーション付き) |
| プログラミングスクール | https://schools.acecore.net/ |
別リポジトリの Schools サイトへ誘導 |
| AceStudio | /acestudio/ |
AceStudio 紹介 |
| お問い合わせ | /contact/ |
フォーム(Turnstile 付き) |
| プライバシーポリシー | /privacy/ |
個人情報方針 |
| RSS フィード | /rss.xml |
ブログ配信 |
ブログ配下のサブページ:
| パス | 説明 |
|---|---|
/blog/{slug}/ |
記事詳細 |
/blog/tags/ |
タグ一覧 |
/blog/tags/{tag}/ |
タグ別記事 |
/blog/authors/{author}/ |
著者別記事 |
/blog/archive/{month}/ |
月別アーカイブ |
/blog/page/{n}/ |
ページネーション |
/blog/og/{slug}.png |
OG 画像(自動生成) |
src/
├── components/ # 共通 UI コンポーネント(Astro)
├── content/
│ └── blog/ # Markdown 記事(ja ベース + 各言語サブフォルダ)
├── data/ # サイト定数・著者情報
├── i18n/ # 多言語設定・翻訳ファイル・ユーティリティ
├── layouts/ # BaseLayout
├── pages/ # ルーティング(ja ルート + [locale]/ サブルート)
├── utils/ # ユーティリティ(画像最適化・rehype プラグイン等)
└── views/ # ページ単位のビューコンポーネント
外部画像は Cloudflare Images Transformations で自動変換されます。
src/utils/image.ts— URL を/cdn-cgi/image/{options}/{sourceUrl}形式に変換src/utils/rehype-optimize-images.ts— Markdown 内の外部画像を自動で変換する rehype プラグイン- 許可オリジン:
acecore.net,images.unsplash.com,cdn.discordapp.com
- 本番では
https://acecore.net/admin/index.html、ローカルではhttp://localhost:4321/admin/index.htmlにアクセス - 本番編集は GitHub OAuth でサインインする。このリポジトリは GitHub 認証型で、Cloudflare Access を使う場合も前段の入口保護に限定する
- ローカル確認では
Work with Local Repositoryを選び、repo root を指定する - 「ブログ」から日本語ソース記事のみ新規作成・編集
- 「ページ・サイト文言」からナビ、フッター、SEO、固定ページの日本語テキストをページ/用途別に編集
- 「告知・キャンペーン」からトップ告知バナーやページ内キャンペーン通知を編集
- 著者・タグは「著者」「タグ」から編集
- CMS 経由の日本語ソース編集のみ、Copilot translation PR task で翻訳へ反映
- 本番ソースの正は
mainです。Cloudflare Pages の production deploy 元も GitHub 連携のmainにします。 - Sveltia CMS は
backend.branch: mainとpublish_mode: editorial_workflowで運用します。 - CMS 保存時は
cms/...のような短命 branch と PR が作られ、mainに直接 commit しません。 - 恒久的な
cms-content投稿受け皿 branch は使いません。 - CMS PR は通常の merge commit または rebase merge でマージします。squash merge では
cms: ...commit subject が失われ、翻訳 PR task の自動検出対象外になる場合があります。 - CMS PR が
mainに merge されると、Cloudflare Pages が GitHubmainpush を受けて production deploy します。 - 旧 remote
cms-contentbranch は未反映差分がないことを確認して削除済みです。
運用判断は docs/cms-write-workflow.md を参照してください。
- 告知やキャンペーンは「告知・キャンペーン」に1件ずつ並びます。新しく追加する場合は一覧右上の追加ボタンから作成します。
種別がトップ告知バナーの項目はサイト上部に表示されます。複数有効な場合は表示順の小さいものから順に表示されます。種別がページ内キャンペーン通知の項目は、選択した表示ページのヒーロー下に表示されます。- 告知バナーとページ内通知は
表示する、表示開始日時、表示終了日時で公開期間を制御します。表示状態は訪問者のブラウザで判定するため、デプロイ後も時刻到達時に切り替わります。日時は日本時間のYYYY-MM-DDTHH:mmとして扱われます。 タイトルと本文は種別ごとに表示され方が変わります。トップ告知バナーではタイトルが小さなラベル、本文が告知文です。ページ内キャンペーン通知ではタイトルが見出し、本文が説明文です。- キャンペーン通知の表示位置はページごとに固定です。CMSでは
トップページ、サービス、実績、会社概要、お問い合わせ、AceStudioから選択します。 - キャンペーン通知ではボタン文言、リンクURL、表示トーン、アイコン、表示開始/終了日時を CMS から変更できます。表示トーンは色アイコン付き、アイコンは用途別のアイコン付き選択肢から選びます。
- 季節キャンペーンの詳細記事は通常どおり「ブログ」で作成し、告知バナーやキャンペーン通知のリンクURLに該当記事や問い合わせページを設定します。
src/content/blog/ に Markdown ファイルを追加:
---
title: '記事タイトル'
description: '記事の概要'
date: 2026-01-01
tags: ['タグ1', 'タグ2']
image: 'https://images.unsplash.com/photo-xxx'
author: 'author-id'
---
本文をここに書きます。翻訳記事は src/content/blog/{locale}/{slug}.md に同名ファイルで配置します。
Sveltia CMS は日本語ソース記事と日本語の固定ページ文言を編集できます。多言語記事本文とページ文言は GitHub Copilot coding agent が作成する Pull Request ベースで管理します。PR 量を抑えるため、push 連動の対象は Sveltia CMS の cms: ... commit だけに限定します。
- 日本語ソースを Sveltia CMS で更新する
- editorial workflow が短命な CMS branch と
main向け PR を作成する - CMS PR を
mainにマージすると、CMS commit の本文差分または日本語文言 key 差分だけを GitHub Actions が検出する - Copilot coding agent が該当差分だけに沿って
src/content/blog/{locale}/またはsrc/i18n/translations/{locale}.jsonを更新する - 完了時に
[translation]PR が ready for review になったら、内容とビルドを確認してから必要に応じて手動マージする
著者情報、タグ定義の多言語フィールドは Sveltia CMS から直接編集できます。ローカル開発や通常の Git commit による日本語ソース変更では、自動翻訳 PR task は作成しません。
- Workflow:
.github/workflows/create-translation-prs.yml - Script:
scripts/create-translation-prs.mjs - Trigger:
src/content/blog/*.mdまたはsrc/i18n/source/ja/**/*.jsonのmain反映時。ただし自動実行は Sveltia CMS のcms: ...commit のみ - CMS commit と通常 commit が同じ push に混在した場合は、自動翻訳 PR task を作成せず workflow を止める。CMS PR の merge commit はこの判定から除外する
- 日本語ソース記事ごとに Copilot translation PR task を作成し、同じソースの open PR があれば重複作成しない
- ページ文言は変更された JSON key だけを対象に、まとめて 1 つの Copilot translation PR task を作成する
- blog 記事は frontmatter だけの変更では task を作成せず、Markdown 本文が変わったときだけ PR task を作成する
- blog 記事の更新 PR task には本文 diff を渡し、翻訳済み記事の未変更部分は書き換えないよう指示する
- 1 回の blog 翻訳 PR task 数は
max_blog_tasks(既定値3)で制限する - authors/tags の翻訳 PR task は
workflow_dispatchでinclude_non_blog_sources=trueを指定したときだけ作成する COPILOT_AGENT_TOKENsecret を使い、GitHub Copilot coding agent API で issue を介さず直接 task を作成する- 重複判定は PR body に含める
translation-source:マーカーで行う
COPILOT_AGENT_TOKEN には、Copilot coding agent API を呼べるユーザートークンを設定します。GitHub CLI で確認した現在トークンの scope は repo と workflow を含んでいます。
- Workflow:
.github/workflows/translation-pr-build.yml - Workflow:
.github/workflows/merge-translation-pr.yml - Script:
scripts/merge-translation-pr.mjs - 対象は
app/copilot-swe-agentが作成した[translation]で始まる PR のみ Translation PR Buildは対象 PR のビルド確認だけを行う- マージは
.github/workflows/merge-translation-pr.ymlのworkflow_dispatchで PR 番号を指定したときだけ実行する - merge 後は同一リポジトリ上の Copilot ブランチを削除する
サイト全体に右下の AI チャットを表示し、お問い合わせページでは FAQ の後に AI チャットを開ける導線を配置しています。AI で答えきれない見積りや正式な相談はフォームへ、短い相談や教室関連は LINE に自然につなげます。メール・電話は常時露出せず、問い合わせページ下部の「直接やりとりしたい場合」や AI が必要と判断した場合の案内に限定します。
functions/api/ai-contact.ts の Cloudflare Pages Function から Cloudflare Workers AI binding を呼び出します。既定では GLM 5.2 (@cf/zai-org/glm-5.2) を reasoning effort low で使います。ブラウザには AI 実行用のキーを渡しません。
Cloudflare Pages 側で以下を設定してください。
- Workers AI binding:
AI CLOUDFLARE_AI_MODEL: 使用モデル(未設定時は@cf/zai-org/glm-5.2)CLOUDFLARE_AI_REASONING_EFFORT: 推論 effort(未設定時はlow)
フォーム送信は functions/api/contact.ts の Cloudflare Pages Function で受け、Cloudflare Email Service の REST API から通知メールを送信します。ブラウザから外部フォームサービスへ直接送信しません。
Cloudflare Turnstile はフォーム上に表示し、Pages Function 側で TURNSTILE_SECRET_KEY によるサーバーサイド検証を行います。
Cloudflare 側で以下を設定してください。
- Email Service:
acecore.netを送信ドメインとしてオンボード CLOUDFLARE_ACCOUNT_ID: Email Service を有効化した Cloudflare account IDCLOUDFLARE_EMAIL_API_TOKEN: Email Sending 権限を持つ Cloudflare API tokenTURNSTILE_SECRET_KEY: Cloudflare Turnstile の secret keyCONTACT_FROM_EMAIL: 送信元メールアドレス(未設定時はnoreply@acecore.net)CONTACT_TO_EMAIL: 通知先メールアドレス(未設定時はinfo@acecore.net)CONTACT_ALLOWED_HOSTNAMES: 問い合わせ API と Turnstile hostname 検証で許可する hostname 一覧
記事詳細のコメントは Cloudflare Pages Function + D1 + Turnstile で実装しています。投稿は承認待ちにせず即時公開しますが、API 側で Turnstile サーバー検証、origin チェック、レート制限、URL・メールアドレス・HTML・宣伝語句の拒否を行います。
Cloudflare Pages の Functions binding は wrangler.jsonc で管理します。
COMMENTS_DB->acecore-comments
Cloudflare Pages secret は以下を設定します。
TURNSTILE_SECRET_KEY: Cloudflare Turnstile の secret keyCOMMENT_HASH_SALT: IP/UA ハッシュ用 secret
wrangler.jsonc では production/preview の COMMENT_ALLOWED_HOSTNAMES を acecore.net,www.acecore.net,acecore-net.pages.dev に明示しています。未設定時はコード側で acecore.net,www.acecore.net,acecore-net.pages.dev,localhost,127.0.0.1 にフォールバックします。登録した hostname とその配下のサブドメインを許可するため、acecore-net.pages.dev で Git プレビュー URL も通ります。ほかの Pages プロジェクトで共用する場合は、そのプロジェクトの <project>.pages.dev を COMMENT_ALLOWED_HOSTNAMES に追加してください。
D1 schema は migrations/0001_create_blog_comments.sql です。初回は D1 database を作成後、以下で適用します。
npx wrangler d1 execute acecore-comments --remote --file=./migrations/0001_create_blog_comments.sqlスパムなどを非表示にする場合は、対象レコードの deleted_at に ISO 8601 の日時を入れます。deleted_at IS NULL のコメントのみ表示されます。
Cloudflare Pages に接続し、以下を設定:
- ビルドコマンド:
npm run build - 出力ディレクトリ:
dist
GitHub への push で自動デプロイされます。
| ファイル | 説明 |
|---|---|
astro.config.mjs |
Astro 設定(i18n・rehype プラグイン含む) |
uno.config.ts |
UnoCSS テーマ・ショートカット |
src/content.config.ts |
コンテンツコレクション定義 |
public/admin/index.html |
Sveltia CMS 管理画面 |
public/admin/config.yml |
Sveltia CMS 設定 |
workers/sveltia-cms-auth |
Sveltia CMS GitHub OAuth 用 Cloudflare Worker |
public/ads.txt |
Google AdSense 認証 |
public/_headers |
Cloudflare Pages HTTP ヘッダー(キャッシュ・CSP・セキュリティ) |