AIに「店舗のサイトを作って」と頼むと、見た目の整った画面ができることがあります。では、お知らせの文章はどこに置くのか。担当者が内容を変えたら、どの仕組みを通って画面に届くのか。実際に使うことを考えると、見た目のデザインだけでなく、設計しておく必要があることも出てきます。
そこで今回は、架空の店舗「こもれび工房」のお知らせを、画面とデータを返す処理に分けて作ります。使うのはReact、NestJS、TypeScriptです。AIエージェントが実際にローカル環境へファイルを作り、日本語検索から通信を止めたときの表示まで検証しました。
サンプルコードについて
掲載するコードは、これからReactやNestJSを使ってみたい方に向けた入門用のサンプルです。画面とAPIがどうつながるかを、小さな構成で確かめられるようにしています。実際のサイトでは、用途に応じて機能や処理が増え、構成も複雑になります。そのまま業務で使える完成形ではなく、実用性や堅牢性を高めていく前の、最初の足がかりとしてご覧ください。
同じように試したい方へ、AIへの依頼例、必要なファイル、起動方法、結果の確かめ方をご案内しています。コードをすべて読めなくても、何を作り、どこまで確かめたのかを追える順番で進めます。
今回作るところ
お知らせ3件の表示、日本語での検索、0件の案内、通信失敗からの再試行までを作ります。更新管理画面や本番公開は含みません。ヘッドレスCMSとの接続は、この先に更新方法を決めるときの選択肢です。
React・NestJS・TypeScriptは、何を担当するのか
最初に、名前と役割を揃えておきます。どれもサイト制作で見かけますが、同じ種類の製品ではありません。
| 名称 | 役割 | 今回の使い方 |
|---|---|---|
| React | 画面の部品を組み合わせてユーザーインターフェースを作るライブラリ | お知らせ、検索欄、読み込み中・失敗時の表示 |
| NestJS(公式文書ではNestとも表記) | Node.js上でサーバー側のアプリケーションを作るフレームワーク | 検索語を受け取り、お知らせのデータを返すAPI |
| TypeScript | JavaScriptに型の仕組みを加えたプログラミング言語 | 画面側・サーバー側の両方で、データの形や処理を記述 |
| Node.js | JavaScriptをブラウザーの外で実行する環境 | NestJSと、開発用のツールを動かす |
| Vite | 開発中の画面配信と公開用ファイルの生成を行うツール | Reactの開発画面を開き、ビルドする |
ブラウザーでお知らせを開くと、Reactの画面がAPIへデータを求めます。NestJSが受け取り、タイトルと本文をJSONというデータ形式で返す。その内容をReactが表示します。今回の通信は次の一本です。
ブラウザーのReact画面(127.0.0.1:8790)
→ お知らせの取得を依頼
NestJSのAPI(127.0.0.1:8791/api/notices)
→ タイトル・本文のデータを返す
Reactが受け取ったデータを画面に表示TypeScriptが担当するのは、この処理を書くときの型の確認です。「タイトルは文字列」「IDは数値」といった形をコードで表せます。ただし、外から届くデータまで自動的に正しい形になるわけではありません。後のコードでは、APIの応答を受け取ったときにも形を調べます。
名称と役割はReact公式、NestJS公式、TypeScript公式、Node.js公式、Vite公式の説明を要約しています。確認日:2026年10月1日。
Next.jsとヘッドレスCMSは、いつ必要になるのか
NestJSと似た名前に、Next.jsがあります。Next.jsはReactを使ってWebアプリケーションを作るフレームワークで、ページの構成やサーバー側での描画なども扱います。NestJSはサーバー側の処理を組み立てるためのものです。名前が似ていても、同じ製品ではありません。
今回Next.jsを入れないのは、画面とAPIの接続を小さく確かめるためです。ReactとViteで画面、NestJSでAPIという分担を見える形にします。公開する企業サイトでページ数、検索流入、初期表示まで設計するなら、Next.jsなどのフレームワークを含めて構成を選び直します。Next.jsからNestJSのAPIを呼ぶ組み合わせもありますが、APIを別に管理する必要がないサイトへ両方を機械的に追加することは勧めません。
React公式の案内でも、アプリケーションにはフレームワークの利用を勧め、学習や条件に応じて一から組む方法を説明しています。今回の作り方は後者に当たります。Next.jsの役割はNext.js公式資料を参照しています。
もう一つ、「ヘッドレス」はTypeScriptの別名でも、Reactを使ったサイト全体の呼び名でもありません。ヘッドレスCMS(コンテンツ管理システム)は、文章・画像などを管理する側と、それを表示する側を分け、APIを通して内容を渡す仕組みです。たとえば、担当者がお知らせをCMSの管理画面で更新し、その内容をReactやNext.jsのサイトへ表示する構成が考えられます。
今回はNestJSのコード内に架空のお知らせを置きます。今回は読み取り用APIを作り、画面との接続を確かめるところまでです。CMSの更新管理機能は含めていません。更新管理まで最初に増やすと、表示できない原因が画面・API・CMSのどこにあるかを追いにくくなるため、まずは二つをつなぎます。CMSの役割はContentfulの公式説明と照合しています。特定のCMSを今回導入・検証したという意味ではありません。
AIには完成イメージと確認条件を一緒に渡す
「Reactでおしゃれに作って」だけでは、AIが見た目を整えた時点で終わってしまうかもしれません。何を表示するかに加え、つながらないときの振る舞いまで伝えると、作業の終わりを判断しやすくなります。
以下は、今回実施した条件を依頼しやすい形に整理した例です。会話の逐語記録ではありません。ファイル作成とコマンド実行ができるAIエージェントを想定しています。通常のチャットへ貼っただけで、手元のPCに環境ができるわけではありません。
架空店舗のお知らせサイトを、新しい専用フォルダーに作ってください。
画面はReactとTypeScript、APIはNestJSとTypeScriptを使います。
Next.jsとNestJSを混同せず、今回はNext.jsやCMSを追加しないでください。
・画面は127.0.0.1:8790、APIは127.0.0.1:8791だけで待ち受ける
・使用中なら既存サービスを止めず、先に報告する
・実データ、APIキー、個人情報、外部への送信は使わない
・架空のお知らせ3件と、見出しの日本語部分一致検索を作る
・検索は40文字まで。APIでも文字列と長さを検査する
・読み込み中、0件、通信失敗、再試行を画面に用意する
・APIの応答形式を実行時にも検査する
・HTMLのような文字列は、HTMLとして実行せず文字で表示する
・正常な検索、異常な入力、API停止と再開を確認する
・ビルド結果、失敗と修正、起動・停止手順、未確認事項を残す
既存のWordPressや他のプロジェクトは変更しないでください。ご自身の店舗で試すなら、まず「お知らせ」を「メニュー」や「教室の日程」に読み替える程度から始めると変化を追いやすくなります。予約受付や決済まで同時に頼まず、表示したい情報が届くところを最初の到達点にします。
新しいフォルダーと実行環境を用意する
今回使ったのはWindowsのローカル環境です。Node.jsは執筆時点の最新LTS、npmは最新の安定版を専用フォルダーに用意しました。AIに最初の確認を頼む場合も、使用中の環境を勝手に更新せず、現在のバージョンを報告してもらいます。
node --version
npm --version検証時はNode.js 24.21.0、npm 12.2.0、React 19.3.0、NestJS 12.1.2、TypeScript 7.0.2、Vite 8.3.2でした。「最新版なら同じ結果になる」とはせず、下の設定に実際に使ったバージョンを残しています。
次に、PowerShellで専用フォルダーを作ります。すでに同名のフォルダーがある場合は、中身を上書きせず別の名前にしてください。8790・8791番が使われているかも調べます。この番号は今回選んだもので、製品の必須値ではありません。
Get-NetTCPConnection -LocalPort 8790,8791 -ErrorAction SilentlyContinue
mkdir react-nest-lab
cd react-nest-lab
mkdir api
mkdir webポートの情報が返った場合は、そのまま起動せず、AIに使用状況を調べてもらいます。別の番号を使うときは、起動先・画面の接続先・許可する画面のURLをまとめて変更する必要があります。既存サービスを止めて番号を空ける手順ではありません。
作るファイルは次のとおりです。AIへ作成を任せる場合も、保存先がこの新しいフォルダーの中だけになっているかを確認すると、既存サイトとの境界が分かります。
react-nest-lab/
package.json
tsconfig.api.json
tsconfig.web.json
.gitignore
index.html
api/main.ts
web/main.tsx
web/style.css
package-lock.json ← npm installで生成される画面とAPIをつなぐファイル一式
ここからは、実際に動作を確かめたファイルです。まとまったコードが続きますが、見る順番は「必要な部品」「データを返す処理」「受け取って表示する画面」の三つです。AIに作成を頼む場合の照合にも使えます。
1.使う部品と実行コマンドを決める
package.jsonには依存パッケージとコマンドを置きます。privateはnpmへ誤ってパッケージを公開することを防ぐ設定であり、サイトのアクセス制限ではありません。type: moduleは後述するモジュール形式のエラーを直した設定です。
{
"name": "gwcm-111-react-nest-lab",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build:api": "tsc -p tsconfig.api.json",
"build:web": "tsc -p tsconfig.web.json && vite build",
"api": "node dist-api/main.js",
"web": "vite --host 127.0.0.1 --port 8790 --strictPort"
},
"dependencies": {
"@nestjs/common": "12.1.2",
"@nestjs/core": "12.1.2",
"@nestjs/platform-express": "12.1.2",
"react": "19.3.0",
"react-dom": "19.3.0",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.2"
},
"devDependencies": {
"@types/node": "^24.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"typescript": "7.0.2",
"vite": "8.3.2"
}
}tsconfig.api.jsonはAPI側のTypeScriptを実行用JavaScriptへ変換する設定です。NestJSが使うデコレーターの設定もここに置きます。
{
"compilerOptions": {
"target": "ES2022", "module": "Node16", "moduleResolution": "Node16",
"outDir": "dist-api", "rootDir": "api", "strict": true,
"experimentalDecorators": true, "emitDecoratorMetadata": true,
"esModuleInterop": true, "skipLibCheck": true
},
"include": ["api/**/*.ts"]
}tsconfig.web.jsonは画面側の型検査を行います。CSSの読み込みもViteの型定義で扱います。画面の実行用ファイルを作る処理はViteに任せます。
{
"compilerOptions": {
"target": "ES2022", "module": "ESNext", "moduleResolution": "Bundler",
"jsx": "react-jsx", "strict": true, "noEmit": true,
"lib": ["ES2022", "DOM"], "types": ["vite/client"], "skipLibCheck": true
},
"include": ["web/**/*.tsx"]
}.gitignoreは、依存パッケージ、ビルド結果、環境設定、ログをGit管理から除外するためのものです。すでに追跡された秘密情報を取り除く機能ではありません。今回、秘密値を必要とする処理は作りません。
node_modules/
dist/
dist-api/
*.log
.env*2.NestJSでお知らせを返す
api/main.tsに、お知らせ3件と検索処理を置きます。検索語が文字列でない、または40文字を超えるときは400を返します。正常な検索結果は、該当なしでも200と空の配列です。0件と処理失敗を分けている点を見てください。
import 'reflect-metadata';
import { BadRequestException, Controller, Get, Module, Query } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
const notices = [
{ id: 1, title: '秋の営業案内', body: '架空の店舗です。営業時間は10時から18時です。' },
{ id: 2, title: '体験会のお知らせ', body: '10月の体験会をご案内しています。予約機能はありません。' },
{ id: 3, title: '表示テスト', body: '<img src=x onerror=alert(1)> は文字として表示します。' }
];
@Controller('api/notices')
class NoticesController {
@Get()
list(@Query('q') q: unknown) {
if (q !== undefined && (typeof q !== 'string' || q.length > 40)) {
throw new BadRequestException('検索語は40文字以内で入力してください。');
}
const word = typeof q === 'string' ? q.trim() : '';
return notices.filter(n => n.title.includes(word));
}
}
@Module({ controllers: [NoticesController] })
class AppModule {}
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({ origin: 'http://127.0.0.1:8790', methods: ['GET'] });
await app.listen(8791, '127.0.0.1');
}
void bootstrap();@Controllerが受け付けるURL、@Getが読み取りの入口、@Moduleが使う処理の登録です。小さい例なので一つのファイルですが、処理が増えれば責務ごとに分けます。
画面とAPIはポートが違うため、ブラウザーから見ると別のオリジンです。enableCorsには今回の画面のURLだけを指定しています。CORSはブラウザーで応答の読み取りを制御する仕組みで、APIへのアクセスを認証する機能ではありません。公開前の認証設計の代わりにはなりません。
検索語の長さはJavaScriptのlengthで数えています。絵文字などは見た目の1文字と数え方が一致しないため、業務用では「40文字」の定義と案内も揃えます。今回の検証対象は通常の日本語、空白、長すぎる入力と重複クエリです。
3.Reactで受け取り、状況に応じて表示する
index.htmlは画面の入口です。検索エンジンへ登録しない意図でnoindexを入れていますが、非公開化の機能ではありません。今回外部へ公開しない条件は、ローカルアドレスだけで待ち受ける設定で保ちます。
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex,nofollow" />
<title>こもれび工房|架空店舗のサンプルサイト</title>
</head>
<body><div id="root"></div><script type="module" src="/web/main.tsx"></script></body>
</html>web/main.tsxが画面本体です。APIの応答をそのまま表示せず、ステータスとデータの形を調べます。待機が続いたときは5秒で取得を打ち切り、失敗の案内へ移る実装です。再検索時は前の取得を取り消し、古い結果で上書きしないようにしています。
import { useEffect, useState } from 'react';
import type { FormEvent } from 'react';
import { createRoot } from 'react-dom/client';
import './style.css';
type Notice = { id: number; title: string; body: string };
function isNotices(value: unknown): value is Notice[] {
return Array.isArray(value) && value.every(n =>
n !== null && typeof n === 'object' &&
typeof n.id === 'number' && typeof n.title === 'string' && typeof n.body === 'string');
}
function App() {
const [q, setQ] = useState('');
const [request, setRequest] = useState({ q: '', version: 0 });
const [rows, setRows] = useState<Notice[]>([]);
const [status, setStatus] = useState<'loading' | 'ready' | 'error'>('loading');
useEffect(() => {
const controller = new AbortController();
let active = true;
setStatus('loading');
setRows([]);
const timer = window.setTimeout(() => controller.abort(), 5000);
async function load() {
try {
const response = await fetch(
`http://127.0.0.1:8791/api/notices?q=${encodeURIComponent(request.q)}`,
{ signal: controller.signal });
if (!response.ok) throw new Error('HTTP error');
const data: unknown = await response.json();
if (!isNotices(data)) throw new Error('Invalid response');
if (active) { setRows(data); setStatus('ready'); }
} catch {
if (active) setStatus('error');
} finally { window.clearTimeout(timer); }
}
void load();
return () => { active = false; window.clearTimeout(timer); controller.abort(); };
}, [request]);
function search(event: FormEvent) {
event.preventDefault();
setRequest(previous => ({ q, version: previous.version + 1 }));
}
return <main>
<p className="eyebrow">LOCAL DEMO / 架空店舗</p>
<h1>こもれび工房</h1>
<p>暮らしの道具と、小さな体験会。これは架空の情報で作ったサンプルサイトです。</p>
<section aria-labelledby="notice-heading">
<h2 id="notice-heading">お知らせ</h2>
<form onSubmit={search}>
<label htmlFor="q">見出しから探す(40文字以内)</label>
<div className="search"><input id="q" value={q} maxLength={40}
onChange={event => setQ(event.target.value)} /><button>検索</button></div>
</form>
<div aria-live="polite">
{status === 'loading' && <p>読み込んでいます。</p>}
{status === 'error' && <p role="alert">お知らせを取得できませんでした。
<button type="button" onClick={() => setRequest(p => ({ ...p, version: p.version + 1 }))}>再試行</button></p>}
{status === 'ready' && <p>{rows.length ? `${rows.length}件のお知らせ` : '該当するお知らせはありません。'}</p>}
</div>
{status === 'ready' && rows.map(row => <article key={row.id}>
<h3>{row.title}</h3><p>{row.body}</p></article>)}
</section>
<footer>公開・予約・問い合わせの送信機能はありません。</footer>
</main>;
}
createRoot(document.getElementById('root')!).render(<App />);isNoticesは、受け取った値が配列で、各項目に必要な種類の値があるかを調べています。TypeScriptでNotice[]と書くだけでは、通信先から返る実データは検査されません。この違いがあるため、型検査と実行時の検査を両方入れています。
本文は{row.body}として表示し、HTMLを直接挿入する機能を使いません。3件目に置いたHTML風の文字列が、画像として動かず文字になることを後で確かめます。これだけでサイト全体の安全性が証明できるわけではありませんが、今回の表示方法を確認する具体的な試験になります。
最後はweb/style.cssです。狭い画面でも検索欄がはみ出さないようにし、本文の長い文字列も折り返します。
:root { font-family: system-ui, sans-serif; color: #18322e; background: #f7f6ef; }
body { margin: 0; }
main { max-width: 760px; padding: 64px 24px; margin: auto; }
.eyebrow { color: #44665e; letter-spacing: .12em; font-size: 12px; }
h1 { font-size: clamp(32px, 7vw, 56px); margin: 12px 0; }
p { line-height: 1.9; overflow-wrap: anywhere; }
section { margin-top: 48px; }
label { display: block; margin-bottom: 8px; }
.search { display: flex; gap: 8px; }
input { min-width: 0; flex: 1; padding: 12px; font: inherit; border: 1px solid #647d74; }
button { background: #234e43; color: white; padding: 12px 20px; border: 0; font: inherit; cursor: pointer; }
button:focus-visible, input:focus-visible { outline: 3px solid #ad6519; outline-offset: 3px; }
article { padding: 16px 0; border-top: 1px solid #aebfb4; }
footer { margin-top: 48px; font-size: 13px; }
[role=alert] button { display: block; margin-top: 12px; }起動して、お知らせが届くところを見る
ファイルが揃ったら、専用フォルダーのPowerShellで次を実行します。npm installはパッケージを取得するためインターネット接続が必要です。今回はインストール時のスクリプトを実行しない条件で取得し、ビルドまで確認しています。
npm install --ignore-scripts
npm run build:api
npm run build:web1行ずつ結果を見て、失敗したら次へ進まず原因を調べます。画面側でbuiltと出れば、公開用ファイルを生成する処理が完了した状態です。本番公開の完了を意味しません。生成されたpackage-lock.jsonは依存関係を固定する記録として保管し、同じ構成の再取得にはnpm ci --ignore-scriptsを使います。
続いてAPIを起動します。この端末は動かしたままにします。
npm run apiもう一つPowerShellを開き、同じ専用フォルダーへ移動して画面側を起動します。
cd 専用フォルダーの実際のパス
npm run webブラウザーでhttp://127.0.0.1:8790/を開くと、「こもれび工房」と3件のお知らせが見えます。今回はURLをlocalhostへ読み替えず、127.0.0.1に揃えてください。CORSで許可した画面のURLと一致させるためです。
画面が出ないときは画面側の端末、見出しは出るのにお知らせを取得できないときはAPI側の端末を見ます。APIだけを確認するなら、別のPowerShellで次を実行します。
Invoke-RestMethod http://127.0.0.1:8791/api/noticesここで3件返るのに画面に届かない場合は、ブラウザーのURL、画面内の接続先、CORS設定の順に照合します。原因が分からないまま許可先をすべてに広げると、何を直したのか追えなくなります。
検索・通信失敗・再試行を確かめる
3件が見えたら、次は実際に操作します。検索欄に「秋」と入力して検索すると「秋の営業案内」だけが残る。存在しない言葉なら、エラーではなく「該当するお知らせはありません。」と出る。この二つで、日本語の接続と0件の扱いが分かります。
| 操作・条件 | 期待する結果 | 今回の確認結果 |
|---|---|---|
| 最初に開く/検索語を空にする | お知らせ3件 | API 200、画面で3件 |
| 「秋」で検索 | 部分一致で1件 | API 200、画面で1件 |
| 「存在しない」で検索 | 0件の案内 | API 200と空配列、画面に0件の案内 |
| APIへ41文字を送る | 入力エラー | 400を確認 |
| APIへq=a&q=bを送る | 複数値を受け付けない | 400を確認 |
| APIだけ停止して検索 | 取得失敗と再試行ボタン | 画面で確認 |
| APIを再開し、再試行 | 再読み込みせず復旧 | 3件の表示へ復帰 |
| 3件目のHTML風文字列 | 文字として表示 | 文字を表示し、記事内の画像要素は0件 |
ブラウザーの入力欄に文字数制限があっても、APIへは直接リクエストを送れます。そこで画面の制限とは別に、APIの拒否も確認しました。AIに検査を任せる場合は、次のように追加で頼めます。
画面が動いただけで完了にせず、APIへ41文字と重複クエリを送り、
400で拒否されるか確かめてください。
結果が0件の場合は200で空配列になることも分けて記録してください。
画面の表示とAPIの応答を、別々の確認結果として残してください。通信失敗の試験は、自分で起動したAPIの端末だけでCtrl+Cを押し、画面で検索します。失敗の案内が見えたら、同じAPIの端末でnpm run apiを実行し、画面の「再試行」を押します。別のNode.jsプロセスをまとめて停止しないでください。
今回はAPI停止と復旧、PCとスマートフォン幅での表示を実際に確認しました。5秒間応答がない場合や、不正な形式の応答を返す場合の分岐はコードにありますが、遅延・不正応答を注入する試験は未実施です。動くはずだという判断を、実測結果の表へ混ぜていません。
使い終わったら、APIと画面それぞれの専用端末でCtrl+Cを押します。再開は同じフォルダーでnpm run apiとnpm run webです。APIのコードを変更した場合は、停止後にnpm run build:apiで作り直してから再起動します。今回のお知らせはコード内の固定値なので、管理画面から追加したデータが保存される構成ではありません。
実際に出たエラーと、直した箇所
今回の構築は、最初からすべて通ったわけではありません。APIの最初のビルドでは、CommonJS形式のコードからECMAScript Modules形式のパッケージを読み込もうとして、TS1479が出ました。package.jsonへ"type": "module"を加え、モジュール形式を揃えることで解消しています。
画面側は、import './style.css'の型宣言が見つからないというTS2882でした。画面用のTypeScript設定へ"types": ["vite/client"]を追加し、Viteが扱うファイルの型定義を読み込ませました。掲載しているコードは、この二つを修正した後のものです。
エラーが出るたびに新しいパッケージを足したのではなく、どのファイルの、何の設定が不足しているかを絞っています。AIへ修正を頼むときも、次のように条件を添えると変更を追いやすくなります。
エラーの原因と、変更するファイル・理由を説明してください。
既存機能を削らず、必要な設定だけを修正してください。
修正後はAPIと画面のビルドを両方実行し、検索も再確認してください。一方、EADDRINUSEは今回の構築では発生していません。別の環境でこのエラーが出たら、ポートが使われている可能性を調べるための情報です。「今回出たエラー」と「起こり得る症状の調べ方」は分けて考えてください。
お知らせを更新できるサイトへ進めるには
ここまでできると、表示だけでなく「担当者がお知らせを書き換えたい」という次の希望が出てきます。今回のままでは、文章を変えるたびにコードを修正してAPIを作り直します。日々の更新担当者にそれを任せる運用は、別途考える必要があります。
更新画面が必要なら、CMSで文章を管理する構成を検討します。ヘッドレスCMSから公開済みのお知らせを取り出し、サイトへ表示する方法です。ただし、CMSがあるからNestJSも必須になるわけではありません。公開済みコンテンツを読み取るだけなら、Next.jsなどの表示側からCMSを利用する構成で足りる場合があります。独自の権限判定や他システムとの連携をまとめたいときに、NestJSのようなAPI側を別に持つ理由が生まれます。
CMSの秘密キーを使う場合は、ブラウザーへ送るコードに入れません。どの処理をサーバー側へ置くか、下書きは誰が見られるか、公開後いつ画面へ反映されるかまで設計します。今回のコードはキーを扱っていないため、この部分を検証済みとはしていません。
| 次に実現したいこと | 担当者が決めること | 制作・運用側が確認すること |
|---|---|---|
| 担当者がお知らせを更新 | 誰が書き、誰が公開するか | CMSの権限、下書き確認、公開・取り消しの反映 |
| 検索から店舗を見つけてもらう | 見つけてもらいたい内容とページ | HTMLの生成方法、タイトル、URL、クロールと表示速度 |
| 問い合わせや予約を受ける | 受付後の対応担当と流れ | 入力検証、認証が必要な範囲、保存・通知、迷惑送信対策 |
| 公開後も使い続ける | 更新担当と、止まったときの連絡先 | 依存関係の更新、監視、バックアップ・復元、戻し方 |
今回のReact画面は、ブラウザーでJavaScriptを実行してからお知らせを取得します。ビルドしたHTMLだけにお知らせ本文が揃う構成ではありません。企業サイトとして公開する際は、検索と初期表示の要件に応じて、静的生成やサーバーでの描画も比較します。Next.jsを選べば検索順位が上がる、という保証ではありません。
また、今回の依存パッケージ取得時の監査では脆弱性の報告は0件でした。これはその時点でツールが把握する依存関係の結果です。生成したコードの安全性、認証、負荷への強さ、公開環境の設定まで検査したことにはなりません。本番公開、実データ、認証、CMS連携、負荷試験、バックアップ復元、包括的な安全性監査は未実施です。
試したものを、使い続けられる形へ
画面とAPIがつながると、AIに頼む内容を少し具体的にできます。「サイトを作って」から、「このお知らせを担当者が更新できるようにしたい」「通信に失敗しても案内を出したい」へ進めるからです。何を確かめたかが残っていれば、次の作業も選びやすくなります。
すべての構成を、ご自身で決めてから相談する必要はありません。毎日更新したいのか、月に一度でよいのか。お知らせを載せたいのか、申し込みまで受けたいのか。普段の業務で分かることから、必要な更新方法と公開までの作業を整理できます。
grandworkでは、ReactやヘッドレスCMSを使うサイト制作と、公開後の運用支援をご案内しています。AIで作ったものがある場合は、現在の状態と実現したい内容を伺い、引き継げる部分、確認が必要な部分、対応範囲と費用を整理します。AIへの頼み方から一緒に試したい場合は、AI活用 伴走支援も選べます。
- 試作を、自社で更新できるサイトへ進めたい使いたい画面や更新の頻度から、構成と制作範囲をご相談いただけます。サイト制作の内容と相談方法を見る
- AIと作る進め方から相談したいAIに任せる作業と確認する作業を整理し、小さな検証から進めます。AI活用 伴走支援を見る
実装で参照した公式資料
NestJSの処理の入口はControllers、画面からの接続許可はCORSを参照しています。React・Next.js・TypeScript・Vite・ヘッドレスCMSの役割は、本文内の公式資料リンクをご覧ください。各仕様の確認と動作確認は、2026年10月1日に行っています。
