@squadbase/vantage-template 0.1.0-dev.47d956c → 0.1.0-dev.55898c0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/base-template/.squadbase/skills/vantage-app/SKILL.md +6 -6
- package/base-template/AGENTS.md +47 -231
- package/base-template/agents/api.md +49 -0
- package/base-template/agents/csv.md +32 -0
- package/base-template/agents/page.md +185 -0
- package/base-template/agents/slide.md +34 -0
- package/base-template/agents/xlsx.md +33 -0
- package/base-template/automations/.gitkeep +0 -0
- package/base-template/bun.lock +907 -0
- package/base-template/package.json +1 -1
- package/base-template/pipelines/pyproject.toml +5 -0
- package/base-template/squadbase.yml +1 -0
- package/dist/index.js +15 -6
- package/package.json +2 -2
- package/base-template/.squadbase/skills/adamas-automation/SKILL.md +0 -118
- package/base-template/package-lock.json +0 -5767
package/README.md
CHANGED
|
@@ -14,22 +14,22 @@ npx @squadbase/vantage-template <command> [options]
|
|
|
14
14
|
|
|
15
15
|
#### `init`
|
|
16
16
|
|
|
17
|
-
Initialize a new Vantage project in the current directory. Copies the base template — `src/index.tsx`, `src/_layout.tsx`, `src/_404.tsx`, `src/_error.tsx`, `src/styles.css`, `server/api/`, `tsconfig.json`, `squadbase.yml`, plus the agent guidance in `AGENTS.md` and `.squadbase/skills/` — and installs dependencies.
|
|
17
|
+
Initialize a new Vantage project in the current directory. Copies the base template — `src/index.tsx`, `src/_layout.tsx`, `src/_404.tsx`, `src/_error.tsx`, `src/styles.css`, `server/api/`, `tsconfig.json`, `squadbase.yml`, plus the agent guidance in `AGENTS.md` (and `agents/`, when the framework ships per-type knowledge files) and `.squadbase/skills/` — and installs dependencies.
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
npx @squadbase/vantage-template init
|
|
21
21
|
npx @squadbase/vantage-template init --force # Overwrite existing files
|
|
22
|
-
npx @squadbase/vantage-template init --skip-install # Skip npm
|
|
22
|
+
npx @squadbase/vantage-template init --skip-install # Skip dependency install (bun, or npm if bun is absent)
|
|
23
23
|
npx @squadbase/vantage-template init --chart sunset # Apply a chart preset during init
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
After initialization:
|
|
26
|
+
After initialization (the template ships `bun.lock` and declares `package_manager: bun` in `squadbase.yml`; `npm run` works too once dependencies are installed):
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
bun run dev # vantage dev --no-overlay — dev server + API on :5173
|
|
30
|
+
bun run build # vantage build → dist/
|
|
31
|
+
bun run check # vantage check — static diagnostics
|
|
32
|
+
bun run routes # vantage routes — page/API route map
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
There is no `vite.config.ts`, no `main.tsx`, and no route table: adding a file under `src/` adds a route (`src/index.tsx` → `/`, `src/sales/[id].tsx` → `/sales/:id`), and `src/_layout.tsx` builds the nav from `useRoutes()`.
|
|
@@ -14,7 +14,7 @@ description: Vantage(@squadbase/vantage)ダッシュボードアプリを一か
|
|
|
14
14
|
|
|
15
15
|
## 全体の流れ
|
|
16
16
|
|
|
17
|
-
1. **骨組み** — `
|
|
17
|
+
1. **骨組み** — `bun run dev` が上がるところまで
|
|
18
18
|
2. **ルートを決める** — ページファイルを置き、`vantage routes` で URL を確認
|
|
19
19
|
3. **データを繋ぐ** — 外部 API か、自前の `server/api` か
|
|
20
20
|
4. **仕上げ** — `check` → `build` → `preview`
|
|
@@ -52,7 +52,7 @@ exit 1 になる。
|
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
`index.tsx` はデフォルトエクスポートの React コンポーネント 1 つ(これが `/` になる)。あとは
|
|
55
|
-
`
|
|
55
|
+
`bun install && bun run dev` で http://localhost:5173 が上がる(このプロジェクトの package manager は bun。`bun.lock` を持つ)。
|
|
56
56
|
|
|
57
57
|
**既存アプリに合流したときは、作る前に現状を読む:**
|
|
58
58
|
|
|
@@ -105,10 +105,10 @@ vantage add skill # 配置済みの skill(このファイルの仲間)と、そ
|
|
|
105
105
|
## Step 4 — 仕上げ
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
bun run check # エラーが残っていないか(exit 1 なら残っている)
|
|
109
|
+
bun run routes # 公開される URL の最終確認
|
|
110
|
+
bun run build # dist/ に client(+ server)+ vantage-manifest.json
|
|
111
|
+
bun run preview # 本番ビルドをローカルで動かす
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
`vantage-manifest.json` の `mode` は `server/` の有無から自動で決まる(手で書かない)。
|
package/base-template/AGENTS.md
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
# AGENTS.md — Vantage アプリの地図
|
|
2
2
|
|
|
3
3
|
このファイルは、**Vantage(`@squadbase/vantage`)アプリを作るコーディングエージェント**が
|
|
4
|
-
最初に読むための地図です。アプリ作者(= `index.tsx` を書く側)
|
|
5
|
-
|
|
6
|
-
正しく組めます。
|
|
4
|
+
最初に読むための地図です。アプリ作者(= `index.tsx` を書く側)が守るべき規約・不変条件を
|
|
5
|
+
1 ページに集約し、種類ごとの詳しいレシピは `agents/` 配下の知識ファイルに分けています。
|
|
7
6
|
|
|
8
|
-
>
|
|
9
|
-
>
|
|
10
|
-
>
|
|
7
|
+
> このファイルと `agents/*.md` は、いずれも **Vantage フレームワークが所有する正本**の
|
|
8
|
+
> コピーです。手で書き換えても、`vantage upgrade` を実行するとフレームワーク同梱の正本から
|
|
9
|
+
> 再同期されて上書きされます。アプリ固有のメモは別ファイル(例: `README.md`)に書いてください。
|
|
11
10
|
>
|
|
12
11
|
> 手順を伴う踏み込んだワークフローは、同梱の Claude Code Skill に分かれています。このファイルは
|
|
13
|
-
>
|
|
14
|
-
>
|
|
12
|
+
> 「地図」、`agents/*.md` は「種類ごとの静的リファレンス」、Skill は「手順書」という役割分担です。
|
|
13
|
+
> **配置済みの Skill を先に探す**手順は末尾の「さらに詳しく(同梱 Skill)」にあります。
|
|
15
14
|
|
|
16
15
|
## Vantage とは
|
|
17
16
|
|
|
@@ -39,8 +38,8 @@ UI キット・開発サーバー・API サーバー・ビルドはすべて Van
|
|
|
39
38
|
- **色はセマンティックトークンで書く。** `text-foreground`・`text-muted-foreground`・`bg-card`・
|
|
40
39
|
`border-border`。トークンがライト / ダークの両方を持つので `dark:` を並べる必要が無い。
|
|
41
40
|
素のパレット + `dark:`(`text-slate-900 dark:text-slate-100`)を混ぜると、その 1 か所だけ
|
|
42
|
-
手動で 2 モードを管理することになる(
|
|
43
|
-
`--secondary`・`--border` は背景・境界用で、文字色に使うと読めない。
|
|
41
|
+
手動で 2 モードを管理することになる(→ `agents/page.md` の「ダークモードは opt-in」)。
|
|
42
|
+
`--muted`・`--accent`・`--secondary`・`--border` は背景・境界用で、文字色に使うと読めない。
|
|
44
43
|
- **`.vantage/` と `dist/` は生成物。** 編集しない・読みにいかない(gitignore 済み)。任意の CLI
|
|
45
44
|
コマンド、または `vantage upgrade` で再生成される。
|
|
46
45
|
- **`definePage` の値はリテラルで書く。** title/description/navLabel はビルド時に静的抽出される
|
|
@@ -93,6 +92,8 @@ root/
|
|
|
93
92
|
| `@squadbase/vantage/query` | `useApiQuery`・`useApiMutation`・`apiJson`・`apiFetch`・`apiUrl`・`ApiError`、ほか `useQuery`/`useMutation` など TanStack Query の再エクスポート |
|
|
94
93
|
| `@squadbase/vantage/ui` | shadcn/ui(Base UI バリアント)プリミティブ(`Button`・`Loading`・`ErrorState`・`Empty` ほか) |
|
|
95
94
|
| `@squadbase/vantage/components` | 複合パーツ(`PageShell`・`DashboardCardPreset`・`DataTablePreset`・`EChart` ほか) |
|
|
95
|
+
| `@squadbase/vantage/table` | `FilePageView`・`TableViewer`(データファイルページの表ビューア) |
|
|
96
|
+
| `@squadbase/vantage/slide` | `SlideDeck`・`Slide`・`Steps`・`Step`・`MorphElement`・`useSlideNumber`・`useIsActiveSlide`(スライド専用。1920×1080 の固定キャンバス) |
|
|
96
97
|
| `@squadbase/vantage/markdown` | `MarkdownRenderer`(Shiki を隔離するための専用サブパス) |
|
|
97
98
|
| `@squadbase/vantage/server` | `ApiContext`・`ApiHandler`・`HttpError`・`isHttpError`・`json`(server/ 側でのみ使う) |
|
|
98
99
|
|
|
@@ -101,207 +102,24 @@ root/
|
|
|
101
102
|
`server/` ディレクトリがあれば **fullstack**、無ければ **SPA**。`vantage-manifest.json` の
|
|
102
103
|
`mode` はここから自動で決まり、手で書く設定は無い。**SPA から始めて fullstack へ「昇格」する
|
|
103
104
|
必要はない** ― テンプレートから始めた場合は最初から `server/` があり、その時点で fullstack。
|
|
104
|
-
下の 2
|
|
105
|
-
|
|
106
|
-
- `server/` が**ある** → 「API を持つ(fullstack モード)」を見る。データは自前の `/api/*` から
|
|
107
|
-
`useApiQuery` で取る。
|
|
108
|
-
- `server/` が**無い** → 「最小アプリ(2 ファイル)」の構成。外部 API を直接叩くなら `useQuery`。
|
|
109
|
-
自前の API が要るようになったら `server/api/*.ts` を足すだけでよい(設定変更は不要)。
|
|
110
|
-
|
|
111
|
-
## 最小アプリ(2 ファイル)
|
|
112
|
-
|
|
113
|
-
`package.json` と `index.tsx` の 2 ファイルだけで動く。
|
|
114
|
-
|
|
115
|
-
`package.json`:
|
|
116
|
-
|
|
117
|
-
```json
|
|
118
|
-
{
|
|
119
|
-
"name": "my-dashboard",
|
|
120
|
-
"private": true,
|
|
121
|
-
"type": "module",
|
|
122
|
-
"scripts": {
|
|
123
|
-
"dev": "vantage dev",
|
|
124
|
-
"build": "vantage build",
|
|
125
|
-
"preview": "vantage preview",
|
|
126
|
-
"check": "vantage check",
|
|
127
|
-
"routes": "vantage routes"
|
|
128
|
-
},
|
|
129
|
-
"dependencies": {
|
|
130
|
-
"@squadbase/vantage": "^0.5.0",
|
|
131
|
-
"react": "^19.2.7",
|
|
132
|
-
"react-dom": "^19.2.7"
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`index.tsx`(ルートのデフォルトエクスポートが `/` ページになる):
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
export default function Dashboard() {
|
|
141
|
-
return (
|
|
142
|
-
<main className="p-6">
|
|
143
|
-
<h1 className="text-2xl font-semibold">Dashboard</h1>
|
|
144
|
-
</main>
|
|
145
|
-
)
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
pnpm install
|
|
151
|
-
pnpm dev # → http://localhost:5173(HMR)
|
|
152
|
-
pnpm check # 静的診断(エラーがあれば exit 1)
|
|
153
|
-
pnpm routes # ページ/API の URL マップ
|
|
154
|
-
```
|
|
105
|
+
下の 2 つは段階ではなく、いま自分がどちらにいるかを確かめるための地図として読む。
|
|
155
106
|
|
|
156
|
-
`server/`
|
|
157
|
-
`
|
|
158
|
-
|
|
107
|
+
- `server/` が**ある** → データは自前の `/api/*` から `useApiQuery` で取る(→ `agents/api.md`)。
|
|
108
|
+
- `server/` が**無い** → 外部 API を直接叩くなら `useQuery`(→ `agents/page.md`)。自前の API が
|
|
109
|
+
要るようになったら `server/api/*.ts` を足すだけでよい(設定変更は不要)。
|
|
159
110
|
|
|
160
|
-
##
|
|
111
|
+
## 何を書くか → どのファイルを読むか
|
|
161
112
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`MISSING_DEFAULT_EXPORT`)。以下の「ファイル」列はページルートからの相対パス。
|
|
113
|
+
**書こうとしている種類のファイルだけを開けばよい。** まず該当する 1 ファイルを readFiles で
|
|
114
|
+
読んでから書き始める。
|
|
165
115
|
|
|
166
|
-
|
|
|
116
|
+
| 書こうとしているもの | 読むファイル |
|
|
167
117
|
| --- | --- |
|
|
168
|
-
|
|
|
169
|
-
| `
|
|
170
|
-
|
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `_404.tsx` | Not Found ページ |
|
|
174
|
-
| `_error.tsx` | ルートが throw したときのエラーページ |
|
|
175
|
-
|
|
176
|
-
`components/`・`hooks/`・`lib/`・`server/`・`public/` はどの階層でもルート走査の対象外
|
|
177
|
-
(ページにならない)。それ以外のディレクトリ名は URL のセグメントになる(→「ディレクトリ構造」)。
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
import { definePage } from "@squadbase/vantage"
|
|
181
|
-
|
|
182
|
-
// title は document.title、navLabel は useRoutes() で組むナビの表示名(既定は title)
|
|
183
|
-
export const page = definePage({ title: "Monthly Analysis · Acme", navLabel: "Monthly" })
|
|
184
|
-
|
|
185
|
-
export default function MonthlyAnalysis() {
|
|
186
|
-
return <main className="p-6">…</main>
|
|
187
|
-
}
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### ナビはルート一覧から組む
|
|
191
|
-
|
|
192
|
-
`useRoutes()` がページルート一覧(スキャン順)を返すので、リンク配列を手で持たない。
|
|
193
|
-
`useCurrentRoute()` は現在のルート(404 なら `undefined`)。
|
|
194
|
-
|
|
195
|
-
```tsx
|
|
196
|
-
import { Link, useCurrentRoute, useRoutes } from "@squadbase/vantage/router"
|
|
197
|
-
|
|
198
|
-
// 動的ルートは URL が定まらないので外す。label は navLabel → title → path の順
|
|
199
|
-
const routes = useRoutes().filter((r) => !r.dynamic)
|
|
200
|
-
const current = useCurrentRoute()
|
|
201
|
-
|
|
202
|
-
routes.map((r) => (
|
|
203
|
-
<Link key={r.path} to={r.to} activeClassName="font-semibold">
|
|
204
|
-
{r.label}
|
|
205
|
-
</Link>
|
|
206
|
-
))
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
`RouteInfo`: `path`(`/sales/:id`)・`to`(`/sales/$id`)・`params`・`dynamic`・`index`・`label`・
|
|
210
|
-
`title`・`description`・`navLabel`。
|
|
211
|
-
|
|
212
|
-
### フィルタ状態は URL に置く
|
|
213
|
-
|
|
214
|
-
リロードで消えず、URL をそのまま共有できる。`useState` と同じ形。
|
|
215
|
-
|
|
216
|
-
```tsx
|
|
217
|
-
import { useSearchParam, useSearchState } from "@squadbase/vantage/router"
|
|
218
|
-
|
|
219
|
-
const [region, setRegion] = useSearchParam("region", "all") // 常に string
|
|
220
|
-
const [segments, setSegments] = useSearchState<string[]>("segments", []) // JSON になる値
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
デフォルト値(または `null`)を書くとキーは URL から消える。履歴は既定で `replace`
|
|
224
|
-
(`{ replace: false }` で push)。
|
|
225
|
-
|
|
226
|
-
### 動的パラメータの「3 つの綴り」を同期させる
|
|
227
|
-
|
|
228
|
-
崩すと静かにマッチしなくなる不変条件:
|
|
229
|
-
|
|
230
|
-
- ファイル名 `sales/[customerId].tsx`
|
|
231
|
-
- 表示ルート `/sales/:customerId`
|
|
232
|
-
- リンクトークン `to="/sales/$customerId"` + `params={{ customerId }}`
|
|
233
|
-
|
|
234
|
-
```tsx
|
|
235
|
-
import { Link, useParams } from "@squadbase/vantage/router"
|
|
236
|
-
|
|
237
|
-
<Link to="/sales/$customerId" params={{ customerId: row.id }}>{row.name}</Link>
|
|
238
|
-
|
|
239
|
-
// 詳細ページ側で取り出す
|
|
240
|
-
const { customerId } = useParams()
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## データ取得(server を持たない fetch)
|
|
244
|
-
|
|
245
|
-
外部 API を叩くだけなら `server/` は不要。`@squadbase/vantage/query` の `useQuery` を使う:
|
|
246
|
-
|
|
247
|
-
```tsx
|
|
248
|
-
import { useQuery } from "@squadbase/vantage/query"
|
|
249
|
-
import { Loading, ErrorState } from "@squadbase/vantage/ui"
|
|
250
|
-
|
|
251
|
-
const q = useQuery({ queryKey: ["stats"], queryFn: () => fetch("/…").then((r) => r.json()) })
|
|
252
|
-
if (q.isPending) return <Loading />
|
|
253
|
-
if (q.isError) return <ErrorState message={(q.error as Error).message} />
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
`QueryClient` は Vantage が 1 つだけ管理する(staleTime 30s・retry 1・
|
|
257
|
-
refetchOnWindowFocus false・networkMode "always")。挙動を変えたいときはクエリ側のオプションで
|
|
258
|
-
上書きする。
|
|
259
|
-
自分の `server/api` を叩くときは `useQuery` ではなく `useApiQuery`(→「API を持つ(fullstack
|
|
260
|
-
モード)」)。
|
|
261
|
-
|
|
262
|
-
## API を持つ(fullstack モード)
|
|
263
|
-
|
|
264
|
-
**`server/` ディレクトリがあれば fullstack モード**(無いアプリに足せば、その時点で切り替わる)。
|
|
265
|
-
`server/api/**` の各ファイルが API ルートになる。
|
|
266
|
-
|
|
267
|
-
`server/api/monthly-analysis.ts` → `GET /api/monthly-analysis`:
|
|
268
|
-
|
|
269
|
-
```ts
|
|
270
|
-
import type { ApiContext } from "@squadbase/vantage/server"
|
|
271
|
-
import { HttpError } from "@squadbase/vantage/server"
|
|
272
|
-
|
|
273
|
-
export async function GET({ params, env }: ApiContext) {
|
|
274
|
-
if (!env.API_KEY) throw new HttpError(500, "API_KEY missing")
|
|
275
|
-
return Response.json({ ok: true })
|
|
276
|
-
}
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
- API モジュールは**大文字の HTTP メソッド**(`GET`/`POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`)を
|
|
280
|
-
エクスポートする。それ以外の名前は `INVALID_API_EXPORT` エラー。
|
|
281
|
-
- 動的 API も `[id].ts` 記法: `server/api/customers/[id].ts` → `GET /api/customers/:id`。
|
|
282
|
-
`params.id` で取り出す(`noUncheckedIndexedAccess` が効くので narrowing が要る)。
|
|
283
|
-
- **クライアントに見せたいエラーは `HttpError(status, msg)` を throw する。** それ以外の throw は
|
|
284
|
-
ログに記録され汎用の 500 に丸められる。
|
|
285
|
-
- **シークレットは `ApiContext.env` にだけ届く**(クライアントには決して届かない)。
|
|
286
|
-
|
|
287
|
-
クライアント側からは `useApiQuery` で `/api/*` を叩く。ベース URL の解決・JSON パース・
|
|
288
|
-
非 2xx の `ApiError` 化・クエリキー(`["api", url]`)が入っている:
|
|
289
|
-
|
|
290
|
-
```tsx
|
|
291
|
-
import { useApiQuery, useApiMutation } from "@squadbase/vantage/query"
|
|
292
|
-
|
|
293
|
-
const q = useApiQuery<Customer>(`/api/customers/${customerId}`)
|
|
294
|
-
if (q.isError) return <ErrorState message={q.error.message} /> // HttpError のメッセージ
|
|
295
|
-
|
|
296
|
-
// クエリ文字列は search で。undefined の項目は落ちる
|
|
297
|
-
const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
298
|
-
|
|
299
|
-
// 書き込み。変数がそのまま JSON ボディになる
|
|
300
|
-
const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST" })
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
`ApiError` は `message`・`status`・`body`・`requestId` を持つ。hook が使えない場所では
|
|
304
|
-
`apiJson(path, init)`、生の `Response` が要るときは `apiFetch`。
|
|
118
|
+
| ダッシュボード / 通常ページ(`.tsx`) | `agents/page.md` |
|
|
119
|
+
| API(`server/`) | `agents/api.md` |
|
|
120
|
+
| スライド(`.slide.tsx`) | `agents/slide.md` |
|
|
121
|
+
| `.xlsx` ページ | `agents/xlsx.md` |
|
|
122
|
+
| `.csv` ページ | `agents/csv.md` |
|
|
305
123
|
|
|
306
124
|
## 環境変数
|
|
307
125
|
|
|
@@ -309,30 +127,6 @@ const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST
|
|
|
309
127
|
のみ。** `VITE_` 系の公開 API は無い。
|
|
310
128
|
- サーバー側のシークレットは `ApiContext.env.MY_SECRET` で読む(`server/` 内のみ)。
|
|
311
129
|
|
|
312
|
-
## 組み込み UI / コンポーネントの入口
|
|
313
|
-
|
|
314
|
-
- **プリミティブ**は `@squadbase/vantage/ui` から import する(`Button`・`Loading`・
|
|
315
|
-
`ErrorState`・`Empty`・`Select`・`Checkbox` ほか)。
|
|
316
|
-
- **複合パーツ**は `@squadbase/vantage/components` から(`PageShell`・`DashboardCardPreset`・
|
|
317
|
-
`DataTablePreset`・`EChart` ほか)。
|
|
318
|
-
- **どの名前が import 可能か / props の詳細は `vantage docs` で引く。** ガイドとコンポーネント
|
|
319
|
-
リファレンスはパッケージに同梱されていて、オフラインでも読める(→「ドキュメントを引く」)。
|
|
320
|
-
**名前が分からないとき**はやりたいことで `vantage search` する(→ 同節)。
|
|
321
|
-
- **UI は import して使うのが既定。取り出す(eject)必要はない。** `vantage add ui|block` は
|
|
322
|
-
ソースを手元にコピーして**改造したいとき専用**のコマンドで、取り出せるのは
|
|
323
|
-
`ui: data-table` と `block: sales-overview` の 2 つだけ。それ以外の名前は import 専用で
|
|
324
|
-
`add` の対象ではない(未知名で実行すると候補が一覧表示される)。
|
|
325
|
-
|
|
326
|
-
### ダークモードは opt-in
|
|
327
|
-
|
|
328
|
-
ダークのトークンが効くのは、祖先に `.dark` か `[data-theme="dark"]` が付いているときだけ。
|
|
329
|
-
**OS / ブラウザの設定(`prefers-color-scheme`)は見ない。** `dark:` ユーティリティも同じ
|
|
330
|
-
スイッチに繋いであるので(`theme.css` の `@custom-variant dark`)、自分でクラスを付けない限り
|
|
331
|
-
アプリは常にライトで描かれる ― `dark:` を書いてもそこだけダークになることはない。
|
|
332
|
-
|
|
333
|
-
明暗を切り替えたいときは、レイアウトのルート要素などに `.dark` / `data-theme="dark"` を
|
|
334
|
-
自分で付ける。
|
|
335
|
-
|
|
336
130
|
## ドキュメントを引く(`vantage docs` / `vantage search`)
|
|
337
131
|
|
|
338
132
|
```bash
|
|
@@ -378,6 +172,7 @@ body・レスポンスの status と形)まで出る。`vantage check --json` /
|
|
|
378
172
|
|
|
379
173
|
- **`vantage-app`** — アプリを一から作る / 構成を広げるときの進め方と検証の順序
|
|
380
174
|
- **`vantage-add-feature`** — 既存アプリに page / api / ui を 1 つ足す定型
|
|
175
|
+
- **`vantage-slide`** — `.slide.tsx` でスライドデッキを書く(キャンバスの予算・段階表示・pptx 書き出し)
|
|
381
176
|
- **`vantage-pitfalls`** — Base UI(≠ Radix)の癖など、静かに壊れる落とし穴のリファレンス
|
|
382
177
|
- **`project-storage`** — Squadbase の Project Storage(アップロード済みファイル)をブラウザから読み書きする
|
|
383
178
|
|
|
@@ -399,6 +194,9 @@ vantage add skill --all --dir .claude/skills # 置き場所を指定(既定は
|
|
|
399
194
|
配置済みのコピーを新しいバージョンに更新したいときだけ `--force` を付ける(見つかった場所を
|
|
400
195
|
そのまま書き換える)。
|
|
401
196
|
|
|
197
|
+
**役割分担:** Skill = 手順書(踏み込んだワークフロー) / `agents/*.md` = 種類ごとの静的
|
|
198
|
+
リファレンス / `AGENTS.md`(このファイル) = 地図。
|
|
199
|
+
|
|
402
200
|
---
|
|
403
201
|
|
|
404
202
|
# テンプレート固有の規約(Squadbase テンプレート)
|
|
@@ -515,4 +313,22 @@ const res = await fetch(`${baseUrl}/queries/${QUERY_ID}?since=2026-01-01`, {
|
|
|
515
313
|
`ErrorState` は見出しを `div` / `p` で描くのでそのまま使ってよい。
|
|
516
314
|
- **データ取得の失敗は各ページが `ErrorState` で出す。** `BuildRecovery` が拾うのは
|
|
517
315
|
「レンダリングが throw した」場合だけで、`useApiQuery` の `isError` はページの責任
|
|
518
|
-
(→
|
|
316
|
+
(→ `agents/page.md` の「データ取得」)。
|
|
317
|
+
|
|
318
|
+
## 依存の追加とスクリプトの実行は bun で
|
|
319
|
+
|
|
320
|
+
このプロジェクトの package manager は **bun** です(`squadbase.yml` の `package_manager: bun`、
|
|
321
|
+
lockfile は `bun.lock`)。Squadbase のサンドボックスは bun と依存のキャッシュを持っており、
|
|
322
|
+
`bun install` はキャッシュだけで終わります。上のフレームワーク規約に出てくる
|
|
323
|
+
`pnpm install` / `pnpm dev` / `pnpm check` は、そのまま `bun install` / `bun run dev` /
|
|
324
|
+
`bun run check` に読み替えてください。
|
|
325
|
+
|
|
326
|
+
### 追加の不変条件
|
|
327
|
+
|
|
328
|
+
- **依存を足すときは `bun add <pkg>`(開発用は `bun add -d <pkg>`)。** `npm install` や
|
|
329
|
+
`pnpm add` を使わない — `package-lock.json` / `pnpm-lock.yaml` が生えて `bun.lock` と別の断面に
|
|
330
|
+
なり、次回起動時の install が lockfile を作り直す。
|
|
331
|
+
- **`bun.lock` を消さない・手で編集しない。** `package.json` の依存を直接書き換えたときは
|
|
332
|
+
`bun install` を一度走らせて `bun.lock` を追従させ、両方を同じコミットに入れる。
|
|
333
|
+
- スクリプトは `bun run <script>`(`bun run dev` / `bun run build` / `bun run check` /
|
|
334
|
+
`bun run routes`)。`npm run <script>` でも動くが、install に npm を使わないこと。
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# API(server/)
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`server/api/**`
|
|
4
|
+
に API ルートを書くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## API を持つ(fullstack モード)
|
|
8
|
+
|
|
9
|
+
**`server/` ディレクトリがあれば fullstack モード**(無いアプリに足せば、その時点で切り替わる)。
|
|
10
|
+
`server/api/**` の各ファイルが API ルートになる。
|
|
11
|
+
|
|
12
|
+
`server/api/monthly-analysis.ts` → `GET /api/monthly-analysis`:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import type { ApiContext } from "@squadbase/vantage/server"
|
|
16
|
+
import { HttpError } from "@squadbase/vantage/server"
|
|
17
|
+
|
|
18
|
+
export async function GET({ params, env }: ApiContext) {
|
|
19
|
+
if (!env.API_KEY) throw new HttpError(500, "API_KEY missing")
|
|
20
|
+
return Response.json({ ok: true })
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- API モジュールは**大文字の HTTP メソッド**(`GET`/`POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`)を
|
|
25
|
+
エクスポートする。それ以外の名前は `INVALID_API_EXPORT` エラー。
|
|
26
|
+
- 動的 API も `[id].ts` 記法: `server/api/customers/[id].ts` → `GET /api/customers/:id`。
|
|
27
|
+
`params.id` で取り出す(`noUncheckedIndexedAccess` が効くので narrowing が要る)。
|
|
28
|
+
- **クライアントに見せたいエラーは `HttpError(status, msg)` を throw する。** それ以外の throw は
|
|
29
|
+
ログに記録され汎用の 500 に丸められる。
|
|
30
|
+
- **シークレットは `ApiContext.env` にだけ届く**(クライアントには決して届かない)。
|
|
31
|
+
|
|
32
|
+
クライアント側からは `useApiQuery` で `/api/*` を叩く。ベース URL の解決・JSON パース・
|
|
33
|
+
非 2xx の `ApiError` 化・クエリキー(`["api", url]`)が入っている:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { useApiQuery, useApiMutation } from "@squadbase/vantage/query"
|
|
37
|
+
|
|
38
|
+
const q = useApiQuery<Customer>(`/api/customers/${customerId}`)
|
|
39
|
+
if (q.isError) return <ErrorState message={q.error.message} /> // HttpError のメッセージ
|
|
40
|
+
|
|
41
|
+
// クエリ文字列は search で。undefined の項目は落ちる
|
|
42
|
+
const rows = useApiQuery<Row[]>("/api/customers", { search: { segment } })
|
|
43
|
+
|
|
44
|
+
// 書き込み。変数がそのまま JSON ボディになる
|
|
45
|
+
const save = useApiMutation<Customer, Payload>("/api/customers", { method: "POST" })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`ApiError` は `message`・`status`・`body`・`requestId` を持つ。hook が使えない場所では
|
|
49
|
+
`apiJson(path, init)`、生の `Response` が要るときは `apiFetch`。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# csv ページ
|
|
2
|
+
|
|
3
|
+
フレームワーク所有の知識ファイルで、`vantage upgrade` で再同期されます。`.csv` を
|
|
4
|
+
ページとして置くときに読んでください。不変条件・ディレクトリ構造は `AGENTS.md` を
|
|
5
|
+
先に読んでいる想定です。
|
|
6
|
+
|
|
7
|
+
## `.csv` を置くだけでページになる
|
|
8
|
+
|
|
9
|
+
**`.csv` を `src/` に置くだけで、他のページと同格のルートになります。** URL の作り方は
|
|
10
|
+
`.tsx` と同じ(`src/sales-export.csv` → `/sales-export`、`index.csv` はそのディレクトリ)で、
|
|
11
|
+
ナビにも `vantage routes` にも並びます。開くとフレームワーク同梱の表ビューアが描き、
|
|
12
|
+
元ファイルをダウンロードできます。ビューアは**表計算ソフトの見た目**です —— 列は A / B / C、
|
|
13
|
+
左に行番号、ファイルの 1 行目はヘッダとして固定。読み取り専用で、編集もソートもできません
|
|
14
|
+
(セルを選んで `Cmd/Ctrl+C` でコピーは可)。
|
|
15
|
+
|
|
16
|
+
- **タイトルはファイル名から導かれる**(`sales-export.csv` → 「Sales Export」)。データファイルに
|
|
17
|
+
`definePage` は書けません。名前を変えたいときはファイルをリネームします
|
|
18
|
+
- **ページにしたくないファイルは `_` を前置する**(`_sales-export.csv`)。`components/`・`hooks/`・
|
|
19
|
+
`lib/` に置いたものも同じくページになりません
|
|
20
|
+
- **既定はファイルをそのまま置く(tsx を書かない)。** 自分でタイトルや説明を付けたいときだけ、`_` を
|
|
21
|
+
前置してルート化を止め、tsx から描きます:
|
|
22
|
+
```tsx
|
|
23
|
+
import { FilePageView } from "@squadbase/vantage/table"
|
|
24
|
+
import src from "./_sales-export.csv?url&no-inline"
|
|
25
|
+
export const page = definePage({ title: "売上エクスポート" })
|
|
26
|
+
export default () => <FilePageView src={src} kind="csv" fileName="sales-export.csv" />
|
|
27
|
+
```
|
|
28
|
+
- 数式・グラフ・セル書式といった概念は csv には無いので、値がそのまま読めます。ブラウザで
|
|
29
|
+
パースするので 25MB を超えるファイルはそのページにエラーが出ます —— 大きいデータは
|
|
30
|
+
`server/api/` から配って `DataTable` で描いてください
|
|
31
|
+
- **ビューアの無い拡張子(`.tsv` など)はルートになりません。** `vantage check` の
|
|
32
|
+
`UNSUPPORTED_PAGE_FILE` 警告が知らせます
|