yushonomamaru.com
Tech Stack & Architecture
updated 2026-05-16
サイト概要

ドメイン

用途

家族用プライベートサイト

フレームワーク

Astro 6.1 + Preact 10(Island)

スタイル

Tailwind CSS 4.2(Vite プラグイン)

ランタイム

Node.js 22.12+ / npm

言語

TypeScript(.ts / .tsx)+ Astro

ホスティング

Cloudflare Pages(CDN)

DNS

Cloudflare DNS(SPF / DKIM / MX)

認証 ① サイト全体

Cloudflare Access + Google OAuth

認証 ② /admin のみ

Supabase Magic Link(メールのログインリンク)

バックエンド

Supabase(Auth / DB / Realtime)

メール送信

Resend(Supabase カスタム SMTP)

リポジトリ

エディタ

Cursor & Claude Code(二刀流)
技術スタック

Astro 6.1

静的サイトジェネレーター
.astro → HTML/CSS/JS にビルド

Framework

Preact 10

軽量 React 互換 UI ライブラリ
@astrojs/preact で Island として埋め込み

UI Island
TS

TypeScript

Preact コンポーネント(.tsx)と
lib/supabase.ts などの共有ロジック

Language

Tailwind CSS 4.2

ユーティリティファースト CSS
@tailwindcss/vite で導入(CSS-first)

Styling
🔒

Cloudflare Zero Trust

サイト全体のアクセス制御
許可メアドのみ閲覧可能

Auth (site)
G

Google OAuth 2.0

Cloudflare Access の IdP
Google アカウントでサインイン

IdP
S

Supabase

PostgreSQL + Realtime(WebSocket)+ RLS
@supabase/supabase-js 2.105 でブラウザから直接アクセス

BaaS

Resend

Supabase のカスタム SMTP
/admin 向けログインリンク付きメール送信

Email

GitHub

ソースコード管理
main push → 自動デプロイ発火

VCS

Cloudflare Pages

静的サイトホスティング + CDN
GitHub 連携で自動ビルド & プレビュー配信

Hosting

Cloudflare DNS

yushonomamaru.com の DNS 管理
SPF / DKIM / MX レコードも設定済み

DNS

Node.js 22 + npm

Astro のビルド・開発環境
npm run dev / npm run build

Runtime

Cursor & Claude Code

AI 二刀流で開発!
Cursor で確認 → Claude Code で実装

IDE / AI
アーキテクチャ図
① 開発環境(ローカル) ⌘ Cursor AI 搭載コードエディタ ✦ Claude Code AI CLI — 実装・ファイル操作を自動化 ▲ Astro 6 + Preact(Island アーキテクチャ) + Tailwind CSS 4 ⬡ Node.js 📦 npm ENV VARS(Cloudflare Pages で管理) PUBLIC_SUPABASE_URL PUBLIC_SUPABASE_ANON_KEY ② GitHub / CI ⚙ GitHub kitamura0307/yushonomamaru main ブランチ → 本番反映 push → Webhook 発火 CF Pages が自動ビルド開始 ③ 本番環境 / フロントエンド ☁ Cloudflare Pages Astro → dist/ にビルド 静的 HTML / CSS / JS を CDN 配信 ⊙ Cloudflare DNS yushonomamaru.com の DNS 管理 SPF / DKIM / MX 設定済み 🔒 Cloudflare Access(Zero Trust) 許可 Google アカウントのみ通過可 / Google OAuth 2.0 で認証 🌐 ユーザー ブラウザ Astro 静的ページを受信 ④ バックエンド / 外部サービス S Supabase [ /family・/contact・/admin ページが利用 ] 🔑 Auth — Magic Link(メール) /admin のみ・リンクをクリックしてログイン ⚡ Realtime WebSocket で多端末同期 🗄 DB — family テーブル群 ballet_urls / saved_urls(RLS: anon 可) 🗄 DB — contacts INSERT: anon / SELECT: 認証 🛡 RLS — family テーブルは CF Access が前段ガード ✉ Resend [ Supabase カスタム SMTP ] noreply@yushonomamaru.com ログインリンク付きメールを送信 SPF / DKIM 認証済み git push auto build CDN /family・/contact・/admin (Preact Island) ログインリンク
ページ構成
ページ URL ソースファイル 状態 動的処理
ホーム / src/pages/index.astro LIVE なし(純静的)
旅行 /travel src/pages/travel/index.astro LIVE なし
福岡旅行 2026 /fukuoka src/pages/fukuoka/index.astro LIVE なし
福岡 屋台マップ /fukuoka/yatai src/pages/fukuoka/yatai/index.astro LIVE なし
熱海旅行 2026 /26atami src/pages/26atami/index.astro LIVE なし
女子3人旅 2026 /26girls-trip src/pages/26girls-trip/index.astro LIVE なし
那須 親族旅行 2026 /26nasu-trip src/pages/26nasu-trip/index.astro LIVE なし
家族 /family src/pages/family/index.astro LIVE Supabase ballet_urls / saved_urls + Realtime(Preact Island・CF Access ゲート)
写真 /photos src/pages/photos/index.astro LIVE なし(Google フォト共有アルバム一覧)
お問い合わせ /contact src/pages/contact/index.astro LIVE Supabase contacts テーブルに INSERT(Preact Island・anon)
管理画面 /admin src/pages/admin/index.astro LIVE Supabase メールのログインリンクで認証 → contacts SELECT(Preact Island・authenticated)
技術スタック /tech-stack src/pages/tech-stack/index.astro LIVE なし(このページ)
404 /* src/pages/404.astro LIVE
ファイル構成
yushonomamaru/ ├── astro.config.mjs ← Astro 設定(Preact + Tailwind Vite プラグイン) ├── package.json ← 依存パッケージ(Astro / Preact / Tailwind / Supabase) ├── tsconfig.json ├── public/ │ ├── favicon.svg │ └── images/ │ └── home-hero.svg ← トップページのヒーロー画像 ├── src/ │ ├── assets/ │ │ ├── astro.svg │ │ └── background.svg │ ├── components/ │ │ ├── BalletUrlList.tsx ← バレエ出席確認リスト(Preact + Supabase Realtime) │ │ ├── SavedUrlList.tsx ← 汎用URLメモ(Preact + Supabase Realtime) │ │ ├── ContactForm.tsx ← お問い合わせフォーム(Preact → Supabase contacts INSERT) │ │ ├── AdminContactList.tsx ← 管理画面用問い合わせ一覧(メールのログインリンクで認証 → contacts SELECT) │ │ ├── Header.astro ← 共通ヘッダー(PC + ハンバーガーナビ) │ │ └── Welcome.astro │ ├── layouts/ │ │ └── Layout.astro ← 共通レイアウト(Header 含む) │ ├── lib/ │ │ └── supabase.ts ← Supabase クライアント初期化 + 行型定義 │ ├── pages/ │ │ ├── 26atami/ ← 熱海旅行ページ(旅程 + 旅行記) │ │ ├── 26girls-trip/ ← 女子3人旅ページ │ │ ├── 26nasu-trip/ ← 那須 親族旅行ページ │ │ ├── admin/ ← 問い合わせ管理画面(ナビ非表示・独自ヘッダー) │ │ ├── contact/ ← お問い合わせフォームページ │ │ ├── family/ ← 家族ページ(CF Access ゲート、ballet_urls + saved_urls) │ │ ├── fukuoka/ ← 福岡旅行ページ │ │ │ └── yatai/ ← 屋台マップ │ │ ├── photos/ ← 写真ページ(Google フォト共有アルバム集) │ │ ├── tech-stack/ ← このページ │ │ ├── travel/ ← 旅行一覧(マル予防接種証明書リマインダー付き) │ │ ├── 404.astro │ │ └── index.astro ← ホーム │ └── styles/ │ └── global.css ├── supabase/ │ └── migrations/ ← DB スキーマ / RLS の SQL マイグレーション │ ├── 20260502_create_contacts.sql │ ├── 20260502_drop_family_auth_add_saved_urls.sql │ └── 20260502_allow_authenticated_on_family_tables.sql └── docs/ └── system-architecture.md ← システム構成ドキュメント(このページの元ネタ)
データの流れ

デプロイフロー

git push (main)
→ GitHub Webhook
→ Cloudflare Pages ビルド
→ CDN エッジに配信

/family ページ(CF Access で認証)

ブラウザでアクセス
→ Cloudflare Access が Google OAuth で許可メアド確認
→ 通過後そのまま BalletUrlList / SavedUrlList を表示
→ ページ内の追加ログインなし

/family ページ(Realtime 同期)

端末 A でURL追加・編集・削除
→ Supabase ballet_urls / saved_urls 更新
→ WebSocket で即時配信
→ 端末 B / C に自動反映

/contact ページ(送信)

フォーム送信(Preact)
→ Supabase contacts に INSERT
→ RLS: anon の INSERT のみ許可
→ 即時保存完了

/admin ページ(一覧)

管理者メアド宛のログインリンクで認証
→ セッション確立後に SELECT
→ RLS: authenticated のみ許可
contacts 一覧を表示
Supabase スキーマ & RLS

DDL は supabase/migrations/ の SQL ファイルで管理。anon キーが公開されてもテーブル単位の RLS で守れる設計。

テーブル 主なカラム 用途 RLS ポリシー Realtime
ballet_urls id, url, label, done, added_at, created_by バレエ出席確認URLのチェックリスト anon + authenticated: SELECT / INSERT / UPDATE / DELETE すべて許可
(CF Access が前段ガード)
ON
saved_urls id, url, title, memo, added_at 家族で共有したい汎用 URL メモ anon + authenticated: SELECT / INSERT / UPDATE / DELETE すべて許可
(CF Access が前段ガード)
ON
contacts id, name, email, message, created_at お問い合わせフォームの受信箱 anon + authenticated: INSERT のみ許可
SELECT は authenticated のみ(/admin 用)
OFF
環境変数

本番環境は Cloudflare Pages のダッシュボードで管理。PUBLIC_ プレフィックスの変数はブラウザに公開されるが、サイト全体は CF Access が前段で守り、Supabase 側も RLS でガードするので問題ない設計。

変数名 用途 公開
PUBLIC_SUPABASE_URL Supabase プロジェクトの URL ブラウザ公開
PUBLIC_SUPABASE_ANON_KEY Supabase 匿名キー(RLS で保護) ブラウザ公開
ビルド & デプロイ

ビルドコマンド

npm run build

出力ディレクトリ

dist/

ローカル開発

npm run dev → :4321

本番デプロイ

git push main → 自動

プレビュー

PR 作成 → Cloudflare Pages がプレビュー URL 生成

ブランチ戦略

feature ブランチ → PR → main マージで本番反映