Skip to content

フロントエンド (JS アセット) ​

Lase は Vue 3 ベースのフロントエンドアセットを NPM パッケージ @codebase-jp/lase として提供します。

インストール ​

bash
npm install @codebase-jp/lase

ピア依存関係も合わせてインストールしてください:

bash
npm install vue axios bootstrap bootstrap-icons dayjs vue-router @codebase-jp/vase

モジュール構成 ​

パッケージはコンテキスト別にモジュールが分かれています。

@codebase-jp/lase
├── api/
│   ├── admin/        管理者 API クライアント
│   ├── tenant/       テナント API クライアント
│   ├── common/       共通 API クライアント
│   └── public/       パブリック API クライアント
├── components/
│   ├── admin/        管理画面コンポーネント
│   ├── tenant/       テナント画面コンポーネント
│   └── common/       共通コンポーネント
├── composables/
│   ├── admin/        管理者向け composable
│   └── common/       共通 composable
├── views/
│   ├── admin/        管理画面ビュー(Vue SFC)
│   ├── tenant/       テナント画面ビュー
│   ├── public/       パブリック画面ビュー
│   └── common/       共通ビュー
├── routes/
│   ├── admin/        管理者ルート定義
│   ├── tenant/       テナントルート定義
│   └── public/       パブリックルート定義
├── models/           TypeScript 型定義モデル
├── enums/            TypeScript Enum
├── filters/          フィルター関数
├── utils/            ユーティリティ関数
└── types/            共通型定義

Composables ​

共通 ​

composable説明
useAppアプリケーション情報の取得・管理
useAuth認証状態・ログイン・ログアウト
useAiChatAI チャット
useConfigフロントエンド設定値の取得(詳細)
useLoggerクライアントログの送信
useRecaptchareCAPTCHA v3 トークン取得

テナント ​

composable説明
useEntitlementテナントの有効なエンタイトルメント(機能・利用上限・利用量)の取得と判定

管理者 ​

composable説明
useSenterSenter 課金サービスとの連携

useConfig ​

useConfig は、サーバーサイドの設定値をフロントエンドで参照するための composable です。

仕組み ​

Lase は GET /config エンドポイントを提供しており、Laravel の設定値(config('lase.front') と config('front'))をマージして window.__CONFIG__ としてブラウザに渡します。Blade テンプレートで以下のように読み込みます:

html
<script src="/config"></script>

useConfig はこの window.__CONFIG__ の値を読み取ります。

設定値の定義 ​

設定値は以下の 2 箇所で定義できます。アプリ側(config/front.php)の値が優先されます。

ファイル説明
config/lase.php の front キーパッケージ側のデフォルト値
config/front.phpアプリ側で追加・上書き
php
// config/front.php
return [
    'recaptcha_site_key' => env('FRONT_RECAPTCHA_SITE_KEY'),
    'docs_url' => env('FRONT_DOCS_URL', '/docs/'),
];

WARNING

/config のレスポンスはブラウザに公開されます。秘密鍵やパスワードなどの機密情報は絶対に含めないでください。

API ​

typescript
import useConfig from '@codebase-jp/lase/composables';

const { config, get, has } = useConfig();
プロパティ / メソッド型説明
configRecord<string, ConfigValue>設定オブジェクト全体
get(key, defaultValue?)<T>(key: string, defaultValue?: T) => T | undefinedドット記法で値を取得
has(key)(key: string) => booleanキーが存在するか判定

使用例 ​

typescript
const { get, has } = useConfig();

// 値を取得
const siteKey = get<string>('recaptcha_site_key');

// デフォルト値付き
const docsUrl = get<string>('docs_url', '/docs/');

// ネストされた値をドット記法で取得
const value = get<string>('nested.deep.key');

// 存在チェック
if (has('recaptcha_site_key')) {
  // ...
}

AiChat ​

RAG(AiEmbeddingService)と連携する AI チャット UI です。

vue
<script lang="ts" setup>
import { AiChat } from '@codebase-jp/lase/components';
</script>

<template>
  <AiChat />
</template>

Props ​

prop既定値説明
placeholderメッセージを入力...入力欄のプレースホルダ
welcomeMessageこんにちは!…初回表示時のメッセージ
suggestionsログイン/パスワード/問い合わせの3件質問例のボタン。[] で非表示
showSourcestrue回答の参照元ドキュメントを表示するか
autofocustrue表示直後に入力欄へフォーカスするか

挙動 ​

  • Markdown 描画 — 回答は Markdown として描画されます。LLM の出力はドキュメント経由のプロンプトインジェクションを含み得るため、ChatMarkdownUtil が許可リスト方式でサニタイズします(script / iframe / img / イベントハンドラ属性 / javascript: リンクは除去)。ユーザーの発言は Markdown として解釈せずそのまま表示します。
  • 参照元の表示 — バックエンドが RAG で参照したドキュメントを AI SDK の source-document パートとして通知します。docs_url を基に閲覧用リンクへ変換して表示します。
  • スクロール追従 — 最下部付近にいる間だけ自動追従します。読み返し中に引き戻されません。
  • 入力 — Enter で送信、Shift+Enter で改行、日本語入力の変換確定中は送信しません。高さは入力量に応じて自動調整されます。応答中も入力は可能です(送信のみ抑止)。
  • 中断・再試行・リセット — 応答中は停止ボタン、エラー時は再試行ボタン、会話のリセットボタンを表示します。

TIP

AiChat 自体はチャットの中身(メッセージ一覧・入力欄)のみを提供します。画面右下に浮かべる起動ボタン・パネルごと欲しい場合は、下記の AiChatWidget を使ってください。

AiChatWidget ​

AiChat を画面右下の起動ボタン(FAB)とパネルで包んだ、すぐ使える形の共通ウィジェットです。アプリのルートコンポーネントに1つ置くだけで、全画面共通のAIアシスタントを提供します。

vue
<script lang="ts" setup>
import { AiChatWidget } from '@codebase-jp/lase/components';
</script>

<template>
  <AiChatWidget />
</template>

Props ​

AiChat の placeholder / welcomeMessage / suggestions / showSources をそのまま受け取り、AiChat へ引き渡します(autofocus は非表示中のフォーカスを避けるため常に false で固定)。加えて以下を持ちます。

prop既定値説明
labelAIアシスタントパネルのタイトル・起動ボタンの aria-label

挙動 ​

  • 起動ボタンはクリックでパネルの開閉をトグルします。パネルは Esc キーでも閉じられます。
  • パネルは v-show で保持されるため、閉じても会話は消えません。
  • 幅576px未満の画面では、パネルが画面幅いっぱいに近い大きさになります。

TIP

チャット枠を独自にカスタマイズしたい場合(サイドバーに埋め込む等)は、AiChatWidget ではなく AiChat を直接使ってください。

管理画面ビュー ​

管理画面の Vue コンポーネントが提供されています。

ディレクトリ説明
views/admin/dashboard/ダッシュボード
views/admin/tenants/テナント管理
views/admin/users/ユーザー管理
views/admin/plans/プラン管理
views/admin/announcements/お知らせ管理
views/admin/admin-users/管理者ユーザー管理
views/admin/admin-roles/管理者ロール管理
views/admin/admin-mails/メール管理
views/admin/admin-images/画像管理
views/admin/inquiries/お問い合わせ管理
views/admin/blocked-domains/禁止ドメイン管理
views/admin/tenant-roles/テナントロール管理

ヘッダーのメニュー ​

管理画面のヘッダーのメニューは、/admin の子のルートの meta.menu から作ります。ダッシュボードのほかは、まとまり(meta.menu.group)ごとのドロップダウンにまとめ、項目が増えてもヘッダーが1行に収まるようにしています。

まとまり項目
顧客テナント・ユーザー・パートナー
申込・契約プラン・オプション・追加機能・申込の質問・利用規約・登録審査
分析流入分析
コンテンツお知らせ・画像
サポートメール・お問い合わせ
セキュリティ禁止ドメイン・禁止テナントコード・禁止IPアドレス・操作ログ
システム管理者
  • 開いている画面の項目(まとまりなら、まとまりとその中の項目)に印を付けます。ルート名の1番目の区切りで比べるので、tenants.show や tenants.users でもテナントに印が付きます
  • メニューに無い画面は、meta.activeMenu で印を付ける項目を指せます(例: テナントロールの tenant-roles.index は activeMenu: 'tenants')

テナント詳細のサイドバー ​

テナント詳細(/admin/tenants/:id)のサイドバーには、lase の項目(基本情報・テナントユーザー・許可IPアドレス・利用状況・サブスクリプション・請求履歴)の後ろに、アプリが足した子のルートのうち meta.menu(name・icon)を持つものを並べます。開いている画面の項目には印を付けます(ルート名の前方一致)。子の画面には、テナント(tenant)が props で渡り、update を emit すると読み直します。

typescript
import { AdminRoutes } from '@codebase-jp/lase/routes/admin';

const tenantRoute = AdminRoutes.find((r) => r.path === '/admin')!.children!.find((r) => r.path === 'tenants/:id')!;
tenantRoute.children!.push({
  path: 'customer-data',
  name: 'tenants.customer-data',
  component: CustomerDataPurge,
  meta: { menu: { name: '顧客データの削除', icon: 'bi bi-trash' } },
});

ルート名は tenants. で始めてください(ヘッダーで「テナント」に印が付きます)。

ルーティング ​

Lase のルートをアプリの Vue Router に組み込む例:

typescript
import { createRouter, createWebHistory } from 'vue-router';
import { AuthRoutes, ExpiredRoutes, AnnouncementRoutes, InquiryRoutes, createSettingsRoutes, createTenantAccountRoutes } from '@codebase-jp/lase/routes/tenant';
import { ErrorRoutes } from '@codebase-jp/lase/routes/common';

const router = createRouter({
  history: createWebHistory(),
  routes: [
    ...AuthRoutes,
    ...ErrorRoutes,
    ...ExpiredRoutes,
    {
      path: '',
      component: Layout, // アプリのレイアウト(ヘッダー)
      children: [
        // アプリの画面
        createSettingsRoutes(), // 組織の設定(/settings)
        createTenantAccountRoutes(), // 個人の設定(/account)
        ...AnnouncementRoutes, // 運営からのお知らせ
        ...InquiryRoutes, // お問い合わせ
      ],
    },
  ],
});

組織の設定と個人の設定 ​

Lase がテナント向けに用意する機能は、次の画面にまとめます。アプリが変わっても、共通の部分は同じ並び・同じ名前になります。

まとまりルート中身使う人
組織の設定createSettingsRoutes()(/settings)組織(基本情報・営業日と休日・セキュリティ・ユーザー・エージェント・操作ログ)、アプリの設定、契約とお支払い(ご利用プラン・追加機能・ご利用状況・請求履歴・お支払い方法・解約の申し込み)管理する人
個人の設定createTenantAccountRoutes()(/account)プロフィール・メールアドレスの変更・連携中のアプリ(MCP の OAuth 連携)全員
ヘルプAnnouncementRoutes・InquiryRoutes・GuideRoutes運営からのお知らせ・ガイド・お問い合わせ全員

どちらも MenuLayout(サイドバーのメニュー付きのレイアウト。スマホではオフキャンバス)を使い、サイドバーは子のルートの meta.menu から作ります。項目は meta.menu.permission(いずれかを持っていれば出す)と meta.menu.visible で出し分け、項目が無くなった区切りは出しません。項目を選ばずに開くと、出せる最初の項目へ移ります。

アプリの画面を足す ​

typescript
createSettingsRoutes({
  // アプリの区切り(order を省くと、組織と契約とお支払いのあいだに並ぶ)
  sections: [{ key: 'operations', name: '業務の設定' }],
  routes: [
    {
      path: 'tags',
      name: 'settings.tags',
      component: TagIndex,
      meta: { menu: { name: 'タグ', icon: 'bi bi-tags', section: 'operations', order: 10, permission: TenantPermission.TAG_WRITE } },
    },
  ],
  // ユーザー(人とエージェント)の編集に足すタブ
  userTabs: [{ key: 'affiliation', name: '所属・担当', component: AffiliationTab }],
  // 契約を Lase で扱わないアプリは false
  billing: true,
});

createTenantAccountRoutes({
  routes: [{ path: 'notifications', name: 'account.notifications', component: NotificationSettings, meta: { menu: { name: '通知', icon: 'bi bi-bell', order: 40 } } }],
});
meta.menu説明
name / icon見出しとアイコン
section区切りの key(組織は ORGANIZATION_SECTION、契約とお支払いは BILLING_SECTION)
order並び順(小さいほど上)
permissionいずれかを持っていれば出すテナントの権限
visible権限以外で出し分けるとき
matchこの名前で始まるルートでも選択中にする(詳細の画面など)

組織の設定を使わずに置く ​

組織の設定・個人の設定のまとまりを使わず、これまでの画面の並びのままにしたいアプリは、画面の部品をアプリのルートとレイアウトに置けます。

書き出し部品
@codebase-jp/lase/views/tenantTenantProfile(基本情報)・BusinessCalendar(営業日と休日)・Security(2段階認証の決まりとIPアドレス制限)・ActivityLogIndex(操作ログ)、契約とお支払いの Plan・AddonIndex・Usage・InvoiceIndex・InvoiceShow・Payment・Cancel
@codebase-jp/lase/views/commonAccountProfile・AccountEmailChange・TwoFactorSettings・NotificationSettings(個人の設定の各画面)

Lase の部品は、組織の設定・個人の設定に置いたときのルート名で、ほかの画面へリンクします。アプリのルートにも同じ名前を付けてください(パスとレイアウトは自由です)。

ルート名リンクしている部品
settings.billing.planExpired・ログイン後の契約の無い組織の移動先(useAuth)
settings.billing.paymentPlan・AddonIndex(カードの登録の案内)、Payment(Stripe からの戻り先)
settings.billing.invoices.index・settings.billing.invoices.showInvoiceShow(パンくず)・InvoiceIndex(詳細へ)
account.two-factorTenantProfile(2段階認証の設定へ)
account.notifications・notifications.indexNotificationMenu・通知の一覧(無ければリンクを出さない)
typescript
import { Plan, AddonIndex, Payment } from '@codebase-jp/lase/views/tenant';

const contractRoutes = {
  path: '/contract',
  component: ContractLayout, // アプリのレイアウト
  children: [
    { path: '', name: 'settings.billing.plan', component: Plan },
    { path: 'addons', name: 'settings.billing.addons', component: AddonIndex },
    { path: 'payment', name: 'settings.billing.payment', component: Payment },
  ],
};

アプリの画面のまとまりに使う ​

MenuLayout は、組織の設定・個人の設定と同じサイドバーを、アプリの画面のまとまり(レポートなど)にも使えます。親のルートの component に置いて meta.menuLayout に見出しと区切りを書き、子のルートに meta.menu を付けます。

typescript
import { MenuLayout } from '@codebase-jp/lase/views/common';

const reportRoutes = {
  path: 'reports',
  name: 'reports',
  component: MenuLayout,
  meta: { menuLayout: { title: 'レポート', sections: [{ key: 'tasks', name: 'タスク' }, { key: 'workflows', name: 'ワークフロー' }] } },
  children: [
    { path: 'trend', name: 'reports.trend', component: TrendReport, meta: { menu: { name: '推移', icon: 'bi bi-graph-up', section: 'tasks', order: 10 } } },
  ],
};

ユーザーの編集に足すタブ ​

userTabs のタブの部品は、props の tenantUserId(所属の ID)を受け取って自分で内容を読み込み、defineExpose で次を公開します。ユーザーの編集の「保存」は、Lase の基本の項目(ステータス・役割)を保存してから、変更のあるタブの save() を順に呼びます。エージェントは、エージェントの画面のボタンから開く画面で同じタブを編集します。

公開するもの説明
isDirty保存していない変更があるか
save()保存する(失敗したら例外を投げる)
reset()保存前の内容に戻す

ヘッダーの入口 ​

部品説明
HelpMenuヘルプのメニュー。置いているルート(お知らせ・ガイド・お問い合わせ)と、links で渡すアプリのリンク(ヘルプのサイトなど)を並べる
AccountMenuログイン中のユーザーのメニュー。組織の名前の下に組織の設定(出せる項目が1つも無い人には出さない)、ユーザーの名前の下に個人の設定を並べ、最後にログアウトを置く。default のスロットでアプリの項目を足せる(個人の設定とログアウトのあいだ)
vue
<script setup lang="ts">
import { AccountMenu, HelpMenu } from '@codebase-jp/lase/components';
</script>

<template>
  <ul class="navbar-nav">
    <HelpMenu :links="[{ name: 'ヘルプ', href: '/docs/' }]" />
    <AccountMenu />
  </ul>
</template>

運営からのお知らせ ​

運営が管理画面で書いたお知らせを、利用者に見せる部品です。利用者に見えるのは、公開(PUBLISHED)で、日付が今日までのものだけです(日付を先にすると、その日から見える)。

部品・ルート説明
AnnouncementRoutes一覧(announcements.index、/announcements)と詳細(announcements.show)。ヘルプのメニューから開ける
RecentAnnouncementsトップ画面に置く、最近のお知らせ。管理画面で「ホームに表示する」にしたものを、新しい順に limit 件(既定は5件)まで並べる。1件も無ければ何も出さない
UrgentAnnouncementBannerヘッダーの上に置く、緊急のお知らせ。管理画面で「緊急表示の期限」を入れたものを、その日時まで出す。5分ごとに読み直す。利用者は閉じられ、閉じたものはそのブラウザでは内容が変わるまで出さない。無ければ何も出さない

UrgentAnnouncementBanner は高さが変わるため、ヘッダーを画面の上に固定しているアプリは、ヘッダーと一緒に固定し、本文の余白をその高さに合わせてください。

vue
<template>
  <div class="fixed-top">
    <UrgentAnnouncementBanner />
    <Header />
  </div>
  <main><RouterView /></main>
</template>

TypeScript 型 ​

モデルの TypeScript 型は @codebase-jp/lase/models からインポートできます:

typescript
import type { Tenant, User, Subscription, Plan } from '@codebase-jp/lase/models';