はじめに
私は今夏、大阪・関西万博「EXPO 2025」 にて、介護施設の個室に設置した遠赤外線カメラ映像の分析を用いた、認知症介護の新しい未来構想について研究、企画展示を行いました。その際、多様な価値観に対応するため、深いカスタマイズとコードの透明性の両立は最優先事項でした。
今回は、UI/UX分野においてshadcn/uiは単なるUIツールキットではなく、AWSの堅牢でスケーラブルなサーバーレスサービス群と組み合わせることで、フルスタックアプリケーションを迅速に構築するための強力な基盤に昇華することを紹介します。
[0. shadcn/uiとは?]
shadcn/ui
は、ReactのUIコンポーネントライブラリです。これは、機能的な骨組みを担うRadix UIと、柔軟なスタイリングを可能にするTailwind CSSを基盤に開発されています。
2023年のJavaScript Rising Starsで1位を獲得するなど、大きな注目を集めています。
[1. AWSアーキテクチャー図]
① サイトにアクセスするとコンテンツが閲覧可能
→ EC2を立ち上げると時間当たりコストが発生するので、CloudFront+ S3を使って静的配信。
AWSのネットワークにはCloudFrontを通じたアクセス以外は拒否
② ユーザー認証を行い登録されたユーザーのみ操作可能
→ Cognitoを使ったユーザー認証/認可を行う。 Cognitoのユーザープール機能でSNS連携(Google、 line等)を使ったユーザー認証を行い、okならアクセス用のトークンを発行。 そのトークンのカスタム属性にユーザーID、 所属、 ロールを含めることでその情報をもとに都度操作可能かを判定可能。
③ 管理画面からmp4形式の動画をアップロードすることで動画を追加
→ S3に直接アップロードはセキュリティ的に問題がある。 AppSync + Lambdaリゾルバーを使うことで、上記のトークンをもとにS3アクセスが可能かを判定し、問題がなければ署名済みURLを発行してS3にアッ プロード可能。
④ アップロードされた動画をHLSに変換 & 暗号化
→ 動画がS3にアップロードされたことをトリガーにLambda関数を起動させ、動画のメタ情報を動画用DynamoDBに保存、 MediaConvertを使ったHLS+AES暗号化、 暗号化キーをSecretsManagerに保存を行う。逆に削除された場合は同様にLambdaを起動させ、削除を行う。
⑤ ユーザー認証を行い、閲覧可能な動画な場合のみ閲覧できるようにする
→ Cognitoのトークン情報からユーザーID、 所属、 ロールを取得、 AppSyncのリゾルバ機能から動画用DynamoDBから取得。 それらを組み合わせてlambda関数で動画が閲覧できるかどうかを判定、閲覧できると分かればCloudFrontから署名付きCookieを発行し、それを返すようにする。フロント側では返り値によってページを変化
⑥ 管理者は所属組織のユーザーの動画閲覧等の権限を変更できる
→ AppSyncを使い、トークンのカスタム属性から編集画面に移れるかを判定。 可能なら遷移。 その後AppSync+Lambdaリゾルバーを使い、カスタム属性を編集。
[2. 導入方法]
2.1. init
コマンド
プロジェクトを初期化し、shadcn/ui
の設定を整えます。
-
目的: 設定ファイル(
components.json
)の作成、必要な依存関係のインストール、CSS変数の設定など。 -
使い方:
pnpm dlx shadcn-ui@latest init
(pnpm
はnpm
,yarn
,bun
などに置き換え可能)
2.2. add
コマンド
特定のコンポーネントをプロジェクトに追加します。
- 目的: コンポーネントのソースコードとその依存関係をプロジェクトにコピーします
-
使い方:
pnpm dlx shadcn-ui@latest add <コンポーネント名>
(例:button
,card
)
[3. DynamoDBと連携したデータテーブルの実装]
DynamoDB
に保存されたデータを取得し、ソートやフィルタリング機能を備えたデータテーブルに表示するアーキテクチャを構築します。
3.1. アーキテクチャ概要
- フロントエンド (Next.js + shadcn/ui): データテーブルを表示。
-
API Gateway + Lambda:
DynamoDB
からデータを取得。 - DynamoDB: データを格納。GSI(グローバルセカンダリインデックス)を利用してクエリを効率化
3.2. データ取得用Lambdaの実装
TypeScriptでLambda関数を作成し、DynamoDB
からデータを取得します。
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, ScanCommand } from "@aws-sdk/lib-dynamodb";
const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);
export const handler = async (event) => {
const command = new ScanCommand({
TableName: process.env.TABLE_NAME,
});
try {
const { Items } = await docClient.send(command);
return {
statusCode: 200,
body: JSON.stringify(Items),
};
} catch (error) {
console.error(error);
return {
statusCode: 500,
body: JSON.stringify({ message: "Error fetching data" }),
};
}
};
3.3. ページコンポーネントでのデータ取得とレンダリング
サーバーコンポーネントでAPIを呼び出し、取得したデータをデータテーブルに渡します。
import { Payment, columns } from "./columns";
import { DataTable } from "./data-table";
import { Amplify } from 'aws-amplify';
import { get } from 'aws-amplify/api';
import amplifyconfig from '@/amplifyconfiguration.json';
Amplify.configure(amplifyconfig, { ssr: true });
async function getData(): Promise<Payment[]> {
try {
const restOperation = get({
apiName: 'paymentsAPI',
path: '/payments'
});
const { body } = await restOperation.response;
const data = await body.json();
return data;
} catch (error) {
console.error('GET call failed: ', error);
return [];
}
}
export default async function DemoPage() {
const data = await getData();
return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={data} />
</div>
);
}
[4. Amazon Cognitoと連携した認証機能の実装]
Amazon Cognito
をユーザー管理に利用し、NextAuth.js
で認証フローを実装します。
4.1. アーキテクチャ概要
- フロントエンド (Next.js + shadcn/ui): ログイン・ログアウトUIを提供。
- NextAuth.js: 認証ロジックを簡素化。
- Amazon Cognito: ユーザーのサインアップ、サインイン、セッション管理。
4.2. NextAuth.jsの設定
next-auth
をインストールし、Cognito
プロバイダーを設定します。
// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import CognitoProvider from "next-auth/providers/cognito";
const handler = NextAuth({
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
issuer: process.env.COGNITO_ISSUER,
}),
],
});
export { handler as GET, handler as POST };
4.3. 認証状態に応じたUIの構築
useSession
フックを使って、ログイン状態によって表示を切り替えます。
// components/auth-components.tsx
"use client";
import { useSession, signIn, signOut } from "next-auth/react";
import { Button } from "@/components/ui/button";
export function AuthButton() {
const { data: session } = useSession();
if (session) {
return (
<>
Signed in as {session.user?.email} <br />
<Button onClick={() => signOut()}>Sign out</Button>
</>
);
}
return (
<>
Not signed in <br />
<Button onClick={() => signIn("cognito")}>Sign in</Button>
</>
);
}
[5. 機能拡張について]
shadcn/ui
には、以下のような拡張機能があります。
- Blocks: ログインフォームやダッシュボードのレイアウトなど、事前に構築されたカスタマイズ可能なレイアウトコンポーネント集
-
Charts:
Recharts
などを基盤としたチャートコンポーネント - Awesome Shadcn UI: コミュニティが作成したコンポーネント、ツール、ボイラープレートなどを集めたリスト