アーキテクチャ

技術スタック

レイヤー

技術

フレームワーク

Next.js 15 (App Router)

UI ライブラリ

React 19

言語

TypeScript 5.7

デザインシステム

IBM Carbon Design System (@carbon/react)

スタイリング

SCSS + Carbon トークン

Markdown

react-markdown + remark-gfm + remark-math

数式レンダリング

KaTeX (rehype-katex)

ダイアグラム

Mermaid.js

テスト

Vitest + React Testing Library + jsdom

CMS

Strapi v5 (ヘッドレス)

プロジェクト構成

www/
├── public/                    Static assets (fonts, images)
│   ├── fonts/                 Custom typeface (SyriusSans)
│   └── images/                Homepage assets, blog placeholder
├── scripts/                   Seed and mock scripts
│   ├── mock-strapi.mjs        Mock Strapi v5 server
│   ├── seed-blog-articles.mjs Seed 9 articles to real Strapi
│   ├── seed-blog-content.mjs  Article content definitions
│   └── seed-blog-edge-cases.mjs  11 edge-case test articles
├── src/
│   ├── app/                   Next.js App Router pages
│   │   ├── [locale]/          Locale-scoped routes
│   │   │   ├── blog/          Blog listing, detail, filters
│   │   │   ├── gallery/       Gallery listing, detail
│   │   │   └── [slug]/        CMS-driven dynamic pages
│   │   ├── robots.ts          SEO robots.txt
│   │   └── sitemap.ts         Dynamic sitemap generator
│   ├── components/            React components
│   │   ├── homepage/          Static homepage fallback
│   │   └── sections/          CMS section renderers
│   ├── lib/                   Core utilities
│   │   ├── strapi.ts          Server-side Strapi API client
│   │   ├── types.ts           TypeScript interfaces
│   │   ├── i18n.ts            Locale config + translations
│   │   └── consoleUrl.ts      Runtime console/stargate URL derivation
│   ├── styles/                SCSS stylesheets
│   │   ├── _tokens.scss       Carbon Design imports
│   │   ├── globals.scss       Root styles and themes
│   │   ├── layout.scss        Layout components
│   │   ├── homepage.scss      Homepage styles
│   │   └── sections.scss      Page section styles
│   ├── middleware.ts           Locale routing middleware
│   └── __tests__/             Vitest unit tests
└── docs/                      This documentation (Sphinx)

ルーティング

すべてのルートにはロケールプレフィックスが付与されます。src/middleware.ts のミドルウェアにより以下のルールが適用されます:

  1. /_next/api/fonts、または静的ファイルへのリクエストはそのまま通過

  2. パスの最初のセグメントが有効なロケール(enzh-CNja)である場合、リクエストはそのまま通過

  3. それ以外の場合は、Accept-Language ヘッダーから優先ロケールを検出し、ユーザーを /{locale}{path} にリダイレクト

ルートマップ

ルート

説明

/[locale]

ホームページ(CMS コンテンツまたは静的フォールバック)

/[locale]/blog

ブログ一覧(ページネーション、5件/ページ)

/[locale]/blog/[slug]

記事詳細ページ

/[locale]/blog/categories/[slug]

カテゴリビュー(カテゴリ内の全記事)

/[locale]/blog/tags/[slug]

タグフィルター(ページネーション、5件/ページ)

/[locale]/gallery

ギャラリー一覧(ページネーション、12件/ページ)

/[locale]/gallery/[slug]

ギャラリーコレクション詳細

/[locale]/[slug]

CMS 駆動の動的ページ

コンポーネント

レイアウトコンポーネント

  • Navbar --- Header with logo, nav links, theme toggle, locale switcher, StarGate admin sign-in link, login button, mobile hamburger menu. The admin link (adminUrl) points to stargate.{domain} and is derived at runtime from the current hostname (see consoleUrl.ts below), so it automatically resolves to the correct partition (.ai or .com).

  • Footer --- 3 accordion sections (Platform, Services, Company), legal links, copyright. The "Services" section includes a "My Account" link (to StartPoint) and an "Admin" link (to StarGate), both using runtime-derived URLs.

  • ThemeProvider --- Dark/light mode context (white / g100 Carbon themes). Persists the user's choice to a cross-subdomain cookie (fg-theme, scoped to .flexgalaxy.ai or .flexgalaxy.com) so the preference carries over to console apps. Falls back to localStorage and then prefers-color-scheme media query.

  • LocaleSwitcher --- Language dropdown preserving current path. On mount and on every language switch it writes a cross-subdomain cookie (fg-lang) so other apps on the same base domain can pick up the preferred locale.

  • CookieConsent --- 必須/パフォーマンス/広告の各トグルを備えた GDPR バナー

コンテンツコンポーネント

  • ArticleCard --- カバー画像、カテゴリリンク、タイトル、要約、タグピルを含むブログプレビューカード。::after オーバーレイによるカード全体のクリック対応

  • RichMarkdown --- GFM、KaTeX 数式、生 HTML、Mermaid ダイアグラムに対応した Markdown レンダラー

  • MermaidBlock --- Mermaid ライブラリを遅延読み込みし、Carbon ブルーテーマで SVG をレンダリング。エラー時は生コードにフォールバック

  • CategoryArticleViewer --- サイドバー記事リスト、記事コンテンツエリア、目次サイドバーを備えたカテゴリページレイアウト

  • Pagination --- 前へ/次へボタンとページインジケーター

  • ErrorState --- HTTP ステータスコードをローカライズされたエラーページにマッピング

CMS セクションコンポーネント

SectionRenderer は Strapi のダイナミックゾーンコンポーネントを振り分けます:

__component

コンポーネント

page-sections.hero

HeroSection

page-sections.feature-grid

FeatureGridSection

page-sections.rich-text

RichTextSection

page-sections.call-to-action

CallToActionSection

page-sections.image-gallery

ImageGallerySection

スタイリング

すべてのスタイルは _tokens.scss 経由で IBM Carbon Design トークンをインポートした SCSS を使用しています。以下の4つのレスポンシブブレークポイントが定義されています:

トークン

$bp-sm

320px

$bp-md

672px

$bp-lg

1056px

$bp-xlg

1584px

テーマの切り替えは <html> 要素の data-carbon-theme 属性を使用した CSS 駆動で、white``(ライト)と ``g100``(ダーク)の Carbon テーマを切り替えます。すべての色は CSS カスタムプロパティ(例: ``var(--cds-text-primary))を参照しています。

Runtime URL Derivation

External URLs (Console, StarGate) are derived at runtime from the browser's current hostname, not from build-time environment variables. This is implemented in src/lib/consoleUrl.ts via the useConsoleUrls() React hook.

The hook inspects window.location.hostname to determine:

  1. Base domain --- the last two segments of the hostname (e.g., flexgalaxy.ai or flexgalaxy.com)

  2. Environment prefix --- dev- if the hostname starts with dev-, empty otherwise

It then constructs:

  • startUrl = https://{prefix}console.{baseDomain}/start/

  • signupUrl = https://{prefix}console.{baseDomain}/start/?register=true

  • adminUrl = https://{prefix}stargate.{baseDomain}

This means the same build artifact works on both .ai (international) and .com (China) deployments without rebuild. The NEXT_PUBLIC_START_URL and NEXT_PUBLIC_SIGNUP_URL environment variables serve only as SSR fallbacks (used during server-side rendering before hydration).