OmniAICreator/Qiita-1.07M huggingface dataset:
サクッとMockup向けAppBarを作成してみた

# MUIで実装するAppBarの基本と実践的Tips

React + MUI を使って Web アプリケーションのヘッダー（AppBar）を構築する方法と、実装時に気をつけたいポイントについてまとめました。プロジェクト名や変数名は仮のものですが、技術的な知見の共有を目的とした記事です。

## 🔧 使用技術
- React 18+
- TypeScript
- MUI（@mui/material, @mui/icons-material）
- React Router DOM（v6以降）

## 🎯 実装するAppBarの要件
- 左側にロゴ（クリックでトップページに遷移）
- 右側にアイコンボタンを並べる（検索 / 記事生成 / 通知 / プロフィール）
- MUIの`AppBar`と`Toolbar`をベースに構成
- 見た目の統一性（アイコンの背景色、ホバーなど）

## 🧱 実装コード全体（Header.tsx）
```tsx
import React from "react";
import {
  AppBar,
  Toolbar,
  IconButton,
  Box,
  Button,
} from "@mui/material";
import { useNavigate } from "react-router-dom";

import SearchIcon from "@mui/icons-material/Search";
import AutoStoriesIcon from "@mui/icons-material/AutoStories";
import NotificationsIcon from "@mui/icons-material/Notifications";
import AccountCircleIcon from "@mui/icons-material/AccountCircle";

const HEADER_HEIGHT = 64;
const HEADER_COLOR = "#f5f5f5";
const ICON_BG = "#e0e0e0";

export default function Header() {
  const navigate = useNavigate();

  return (
    <AppBar
      position="fixed"
      style={{ height: HEADER_HEIGHT, backgroundColor: HEADER_COLOR }}
      elevation={1}
    >
      <Toolbar style={{ display: "flex", justifyContent: "space-between" }}>
        {/* ロゴエリア */}
        <Button onClick={() => navigate("/")}>
          <img
            src="/logo.svg"
            alt="logo"
            style={{ width: "50px", height: "auto" }}
          />
        </Button>

        {/* アイコン群 */}
        <Box display="flex" gap="8px">
          <IconButton style={{ backgroundColor: ICON_BG }}>
            <SearchIcon />
          </IconButton>
          <IconButton style={{ backgroundColor: ICON_BG }}>
            <AutoStoriesIcon />
          </IconButton>
          <IconButton style={{ backgroundColor: ICON_BG }}>
            <NotificationsIcon />
          </IconButton>
          <IconButton style={{ backgroundColor: ICON_BG }}>
            <AccountCircleIcon />
          </IconButton>
        </Box>
      </Toolbar>
    </AppBar>
  );
}
```

---

## ✅ 実装時のポイント

### 1. **背景色・高さ・ホバーのスタイル設計**
AppBar はデフォルトで濃い色なので、アプリのデザインに合わせて明るくすることが多いです。高さや影（elevation）も調整すると印象が変わります。

### 2. **ロゴをクリックしてトップに戻る導線は必須**
ユーザーが直感的に戻れるよう、ロゴクリックで`navigate('/')`できるようにします。

### 3. **アイコンボタンに共通スタイルをつける**
アイコンが目立たない場合は背景色で補完します。`IconButton` に `style={{ backgroundColor: '#e0e0e0' }}` を指定することで全体の統一感が出ます。

### 4. **アクセシビリティへの配慮**
各ボタンに `aria-label` をつけることで、スクリーンリーダー対応も可能です。

```tsx
<IconButton aria-label="search" style={{ backgroundColor: ICON_BG }}>
  <SearchIcon />
</IconButton>
```

### 5. **各ボタン処理は専用ファイルへ切り出し可能にする設計**
ボタンが増えてロジックが複雑になる場合は、以下のように責務を分離して整理しましょう。

```
src/
├── components/
│   └── presentation/
│       ├── HeaderSearch.tsx
│       ├── HeaderGenerate.tsx
│       ├── HeaderNotification.tsx
│       └── HeaderAccount.tsx
```

---

## 💡 応用アイデア
- ダークモード切り替えボタン
- ログイン状態で表示内容を切り替える
- モバイル表示ではドロワー（Drawer）に変換
- AppBar をページ毎に出し分けたい場合はルート階層で制御

---

## 📌 まとめ
AppBar はアプリの「顔」となる重要な UI パーツです。シンプルに見えて、ロジックやデザイン性、ユーザー体験など様々な工夫が詰め込まれます。共通レイアウトとして何度も目にする場所だからこそ、整っていて、押しやすく、迷わない作りを意識しましょう。
内定者アルバイトー振り返り 

2024年9月から2025年3月まで某IT企業で内定者アルバイトとして働かせてもらっていました。軽く振り返ろうと思います。

## 感想
プロダクトの概要を簡単に説明すると、社内向けのツールで、さまざまなユーザー属性をもとに条件を追加し、最終的にその条件に合致するセグメントに対してキャンペーンなどを配信できるプロダクトです。
今回参加したプロジェクトでは主にフロントエンド開発を任せてもらいました。そもそもバックエンドエンジニアとして働くつもりだったが、いきなりReact/Typescriptをやることになりかなり焦っていました。
とにかく動くものを作って成果を出さなきゃと思うばかりで、設計などがうまくできず後になってあーすればよかったと痛感することが多かったです。さらに追い討ちでプロダクトリリース日に近づくと、k8sやらGrafana/Prometheusなどのモニタリングに関しても学ぶ必要が出てきました。界隈ではネガティブな意見を持つ人が多いですが、フルスタックエンジニアもキャリアとして悪くないなと感じました。

## これから
半年内定者アルバイトとして働いたわけですが、新卒研修やる必要あるか？ってたくさんの人に言われました笑。同期と繋がる以外に理由はないですね。
配属先チームにもとても満足しています。ピーク時に14万QPS/320podsでリクエストを捌くプロダクトも作っているチームです。人間関係でもとても良い人が多くアルバイト身分の自分にも意見を求めてくれて、チームとして働いてる感を感じれました。成長を感じられて、未来の自分にワクワクできるチームです。

## 課題
- コミュニケーション能力をもっと伸ばしたいなと感じてます。AIが強すぎて自分のエンジニアとしての存在価値があるのかわからない毎日ですが、だからこそもっと人間としてのスキルを上げようと感じました
- 得意な領域を作る。ジュニアなので当たり前なのかもですが、まだまだ浅く広いって感じです
- もっとユーザーのことを考えられるエンジニアになりたいです。今回の反省点を活かして、ユーザーの満足度を高めらるよう頑張っていきたいです
- 世界情勢にも詳しくなりたいです。内定者アルバイトの最終日昼ご飯の時に共産主義の話になって、自分の無知を痛感しました(恥)
Laravel・Inertia・Reactで作ったページにmetaタグをいれる

# はじめに

こんにちは、エンジニアのkeitaMaxです。

今回はLaravel11とInertia.js・Reacrを使用して作成したページにmetaタグをつけたいと思います。

# app.tsx

`app.tsx`のtitleを以下のようにします。（インストールした時に自動で入っているかもしれません）


```tsx:app.tsx
const appName = import.meta.env.VITE_APP_NAME || 'application'
createInertiaApp({
    title: (title) => `${title} | ${appName}`,
```

`.env`ファイルにVITE_APP_NAMEが設定されていればその名前がappNameに入ります。

titleはこの後記述しますが、各ページで設定したtitleが入ります。

# 各ページ

例えばTopページがあったとして以下のように`Head`を入力します。

```tsx:top.tsx
export const Top = React.memo(function Top() {
    return (
       <Head>
       　　<title>TOP</title>
          <meta name="description" content="TOPページです" />
       </Head>
    )
})
```

こうすると`app.tsx`のtitleに`TOP`が入ります。

# 実際にどうついているのか

この状態でbuildしてどのようになるのかみてみます。

`.env`のVITE_APP_NAMEには`test-app`を入れます。


![スクリーンショット 2025-03-29 10.11.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/10743f0c-0627-46a0-ab2d-3866cbae9400.png)
![スクリーンショット 2025-03-29 10.13.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/0bfe249a-ca1b-41d8-bcaa-40868ba04fe7.png)


すると上の画像のように
descriptionには「TOPページです」
titleには「TOP | test-app」
と入ります

# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！

# 参考

https://inertiajs.com/title-and-meta
個人用備忘録：CloudFrontの403エラーに遭遇し、少し困ったのでアウトプットしてみた

## はじめに
CloudFrontを使った静的ウェブサイトやAPI配信の際に「403 ERROR」に遭遇することがあります。これはアクセス拒否のエラーで、構成ミスやアクセス制限などが原因のことが多いです。

:::note info
**個人の備忘録程度の走り書きとなっておりますが、温かい目で見守っていただければ幸いです。**
:::

本記事では、自分が再び同じ状況に陥ったときのために、原因や対処法を備忘録としてまとめておきます。

---

## 実際のエラーメッセージ

```
403 ERROR
The request could not be satisfied.
Request blocked. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
Generated by cloudfront (CloudFront)
```

---

## よくある原因（運用者向け）

- オリジンサーバーへの接続不可  
  例：CloudFrontがS3やALBにアクセスできない構成ミス。

- バケットポリシーやOAIの設定不足  
  S3がCloudFrontのオリジンアクセスアイデンティティ（OAI）を許可していない。

- WAF（Web Application Firewall）によるブロック  
  特定のIPやUser-Agent、URIなどにマッチしている可能性。

- CloudFrontのキャッシュポリシーの影響  
  不正なクエリやCookieによってアクセスが拒否されるケース。

- リクエスト数の急増（トラフィック過多）  
  一時的にバックエンドがリクエスト処理できていない状態。

---

## 解決方法（開発・管理者側）

- CloudFrontのログ（CloudWatchまたはS3出力）を確認。
- CloudFrontのオリジン設定（URL・ポート・プロトコル）を再確認。
- S3を使用している場合は、OAIに適切なアクセス権限があるか確認。
- バケットを公開しているなら署名付きURLやCookieの使用も検討。
- CloudFrontに適用されているWAFルールを確認。
- キャッシュを一度削除し、TTLの設定も見直す。

---

## 対応方法（利用者側）

- ページをリロードする。
- 時間を置いてから再度アクセスしてみる。
- ブラウザのキャッシュをクリアしてからアクセス。
- 他のネットワーク（例：スマホの4G）からアクセスしてみる。
- サイトの運営者または管理者に問い合わせる。

---

## まとめ
CloudFrontの403エラーは、構成ミス・アクセス制限・セキュリティルールなど複数の原因が絡みます。

:::note warn
***まずはログ確認から始め、S3やWAF、キャッシュ設定を順に確認するのが有効です。***
:::

今回のように、問題にぶつかったタイミングで備忘録を残しておくことで、次回以降のトラブルシューティングがスムーズになるので試してみてください！
再帰を使用した最大公約数を求めるアルゴリズム

## 最大公約数
「ユークリッドの互除法」というアルゴリズムがあります。それは、２つの整数 a, b (a >= b)があり、a = b*q + r  ( q, r は整数 かつ b > r)。要するに割り算をします。そのあと a, b を b, r に置き換えて同じことを、r が０になるまで繰り返します。そのときの b が最大公約数です！

## 再帰
再帰とは、ある仕組みや定義などにそれ自身を含むものです。ここで扱うのは関数やメソッドの再帰です。うまく利用することでwhile文やfor文よりも効率的にコードを書くことができます。

## 実際のコード（Java）
```java:Main.java
import java.util.Scanner;

class Main {

    static int d;

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        int r;
        if(x >= y){
            r = gcd(x,y);
        }else{
            r = gcd(y,x);
        }
        System.out.println(r);
    }

    static int gcd(int a, int b){
        d = a % b;
        if(d == 0){
            return b;
        }else{
            return gcd(b,d);
        }

    }
}
```
gcd(a,b)というメソッドで再帰が利用されていることが分かります。

## 終わりに
記事をお読みいただきありがとうございました。最大公約数や再帰について理解できたでしょうか？感想お待ちしています！
windows11で、sketchup6 その16

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
FunShapes.rb、見つけたのでやってみた。

# 写真
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/e491d4ec-815b-4752-93b3-a035c9627eca.png)

# サンプルコード

```
def pisot_triaxial
	prompt = ["# Iterations : "]
	params = [5]
	result = inputbox(prompt, params, "Imput Pisot Triaxial Parameters")
	if result
		it = [2, result[0]].max
	else
		return
	end
	entities = Sketchup.active_model.entities
	group = entities.add_group
	group_ents = group.entities
	mesh_pt = Geom::PolygonMesh.new
	indexes = [0]
	aux_vect = []
	for ind_u in (0..2 * it - 1)
		u = 2 * Math::PI * ind_u / (2 * it)
		for ind_v in (0..2 * it - 1)
			v = 2 * Math::PI * ind_v / (2 * it)
			x = 0.655866 * Math::cos(1.03002 + u) * (2 + Math::cos(v))
			y = 0.754878 * Math::cos(1.40772 - u) * (2 + 0.868837 * Math::cos(2.43773 + v))
			z = 0.868837 * Math::cos(2.43773 + u) * (2 + 0.495098 * Math::cos(0.377696 - v))
			pt = Geom::Point3d.new(1 * x, 1 * y, 1 * z)
			index = mesh_pt.add_point(pt)
			indexes.push(index)
		end
	end
	for ind_u in (1..2 * it - 1)
		for ind_v in (1..2 * it - 1)
			aux_ind = 2 * it * (ind_u - 1) + ind_v
			aux_vect = [indexes[aux_ind], indexes[aux_ind + 1], indexes[aux_ind + 2 * it]]
			mesh_pt.add_polygon(aux_vect)
			aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2 * it]]
			mesh_pt.add_polygon(aux_vect)
		end
		aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 1 + 2 * it]]
		mesh_pt.add_polygon(aux_vect)
		aux_vect = [indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 2], indexes[aux_ind + 1 + 2 * it]]
		mesh_pt.add_polygon(aux_vect)
	end
	for ind_v in (1..2 * it - 1)
		aux_vect = [indexes[ind_v], indexes[2 * it * (2 * it - 1) + ind_v + 1], indexes[ind_v + 1]]
		mesh_pt.add_polygon(aux_vect)
		aux_vect = [indexes[ind_v], indexes[2 * it * (2 * it - 1) + ind_v], indexes[2 * it * (2 * it - 1) + ind_v + 1]]
		mesh_pt.add_polygon(aux_vect)
	end
	aux_vect = [indexes[2 * it * (2 * it - 1) + 1], indexes[2 * it], indexes[4 * it * it]]
	mesh_pt.add_polygon(aux_vect)
	aux_vect = [indexes[1], indexes[2 * it], indexes[2 * it * (2 * it - 1) + 1]]
	mesh_pt.add_polygon(aux_vect)
	group_ents.add_faces_from_mesh(mesh_pt)
end

```

以上。
windows11で、sketchup6 その15

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
FunShapes.rb、見つけたのでやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/3c3b392a-617b-413c-82fe-bc6cedf421e4.png)

# サンプルコード

```
def jet_surface
	prompt = ["# Iterations : "]
	params = [5]
	result = inputbox(prompt, params, "Imput Jet Surface Parameters")
	if result
		it = [2, result[0]].max
	else
		return
	end
	entities = Sketchup.active_model.entities
	group = entities.add_group
	group_ents = group.entities
	mesh_js = Geom::PolygonMesh.new
	indexes = [0]
	aux_vect = []
	for ind_u in (0..2 * it)
		u = Math::PI * ind_u / (2 * it)
		for ind_v in (0..2 * it - 1)
			v = 2 * Math::PI * ind_v / (2 * it)
			x = (1 - cos_hip(u)) * Math::sin(u) * Math::cos(v) / 2
			y = (1 - cos_hip(u)) * Math::sin(u) * Math::sin(v) / 2
			z = cos_hip(u)
			pt = Geom::Point3d.new(1 * x, 1 * y, 1 * z)
			index = mesh_js.add_point(pt)
			indexes.push(index)
		end
	end
	for ind_u in (1..2 * it)
		for ind_v in (1..2 * it - 1)
			aux_ind = 2 * it * (ind_u - 1) + ind_v
			aux_vect = [indexes[aux_ind], indexes[aux_ind + 1], indexes[aux_ind + 2 * it]]
			mesh_js.add_polygon(aux_vect)
			aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2 * it]]
			mesh_js.add_polygon(aux_vect)
		end
		aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 1 + 2 * it]]
		mesh_js.add_polygon(aux_vect)
		aux_vect = [indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 2], indexes[aux_ind + 1 + 2 * it]]
		mesh_js.add_polygon(aux_vect)
	end
	group_ents.add_faces_from_mesh(mesh_js)
end
```

以上。
windows11で、sketchup6 その14

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
FunShapes.rb、見つけたのでやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/059f0cd0-c2b7-4530-94f6-a66381ee3f76.png)


# サンプルコード

```
def misc_torus
	prompt = ["# Iterations : ", "c Value : "]
	params = [5, 1.5]
	result = inputbox(prompt, params, "Imput Misc Torus Parameters")
	if result
		it = [2, result[0]].max
		c = result[1].abs
	else
		return
	end
	entities = Sketchup.active_model.entities
	group = entities.add_group
	group_ents = group.entities
	mesh_mt = Geom::PolygonMesh.new
	indexes = [0]
	aux_vect = []
	for ind_u in (-it..it - 1)
		u = Math::PI * ind_u / it
		for ind_v in (-it..it - 1)
			v = Math::PI * ind_v / it
			x = Math::cos(u) * (c + Math::sin(v) * Math::cos(u) - Math::sin(2 * v) * Math::sin(u) / 2)
			y = Math::sin(u) * (c + Math::sin(v) * Math::cos(u) - Math::sin(2 * v) * Math::sin(u) / 2)
			z = Math::sin(u) * Math::sin(v) + Math::cos(u) * Math::sin(2 * v) / 2
			pt = Geom::Point3d.new(1 * x, 1 * y, 1 * z)
			index = mesh_mt.add_point(pt)
			indexes.push(index)
		end
	end
	for ind_u in (1..2 * it - 1)
		for ind_v in (1..2 * it - 1)
			aux_ind = 2 * it * (ind_u - 1) + ind_v
			aux_vect = [indexes[aux_ind], indexes[aux_ind + 2 * it], indexes[aux_ind + 1]]
			mesh_mt.add_polygon(aux_vect)
			aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 2 * it], indexes[aux_ind + 1 + 2 * it]]
			mesh_mt.add_polygon(aux_vect)
		end
		aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2 - 2 * it]]
		mesh_mt.add_polygon(aux_vect)
		aux_vect = [indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2]]
		mesh_mt.add_polygon(aux_vect)
	end
	for ind_v in (1..2 * it - 1)
		aux_vect = [indexes[ind_v], indexes[ind_v + 1], indexes[2 * it * (2 * it - 1) + ind_v + 1]]
		mesh_mt.add_polygon(aux_vect)
		aux_vect = [indexes[ind_v], indexes[2 * it * (2 * it - 1) + ind_v + 1], indexes[2 * it * (2 * it - 1) + ind_v]]
		mesh_mt.add_polygon(aux_vect)
	end
	aux_vect = [indexes[2 * it * (2 * it - 1) + 1], indexes[4 * it * it], indexes[2 * it]]
	mesh_mt.add_polygon(aux_vect)
	aux_vect = [indexes[1], indexes[2 * it * (2 * it - 1) + 1], indexes[2 * it]]
	mesh_mt.add_polygon(aux_vect)
	group_ents.add_faces_from_mesh(mesh_mt)
end
```

以上。
windows11で、sketchup6 その13

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
FunShapes.rb、見つけたのでやってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/5f3449e8-4143-4175-91a4-d2eaa9b1bf87.png)

# 

```
def horn_shape
	prompt = ["# Iterations : "]
	params = [5]
	result = inputbox(prompt, params, "Imput Horn Shape Parameters")
	if result
		it = [2, result[0]].max
	else
		return
	end
	entities = Sketchup.active_model.entities
	group = entities.add_group
	group_ents = group.entities
	mesh_hs = Geom::PolygonMesh.new
	indexes = [0]
	aux_vect = []
	for ind_u in (0..2 * it)
		u = ind_u/(2.0 * it)
		for ind_v in (0..2 * it - 1)
			v = 2 * Math::PI * ind_v / (2 * it)
			x = (2 + u * Math::cos(v)) * Math::sin(2 * Math::PI * u)
			y = (2 + u * Math::cos(v)) * Math::cos(2 * Math::PI * u) + 2 * u
			z = u * Math::sin(v)
			pt = Geom::Point3d.new(1 * x, 1 * y, 1 * z)
			index = mesh_hs.add_point(pt)
			indexes.push(index)
		end
	end
	for ind_u in (1..2 * it)
		for ind_v in (1..2 * it - 1)
			aux_ind = 2 * it * (ind_u - 1) + ind_v
			aux_vect = [indexes[aux_ind], indexes[aux_ind+1], indexes[aux_ind + 2 * it]]
			mesh_hs.add_polygon(aux_vect)
			aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 1 + 2 * it], indexes[aux_ind + 2 * it]]
			mesh_hs.add_polygon(aux_vect)
		end
		aux_vect = [indexes[aux_ind + 1], indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 1 + 2 * it]]
		mesh_hs.add_polygon(aux_vect)
		aux_vect = [indexes[aux_ind + 2 - 2 * it], indexes[aux_ind + 2], indexes[aux_ind + 1 + 2 * it]]
		mesh_hs.add_polygon(aux_vect)
	end
	group_ents.add_faces_from_mesh(mesh_hs)
end

```

以上。
#0085（2024/03/29）データベース設計の「ビジネスルール」

# データベース設計における「ビジネスルール」とは？

データベースを設計する際に重要となる概念が「ビジネスルール」です。本記事では、ビジネスルールの意味や具体例、データベース設計においてどのように役立つかを解説します。

---

## 🔹 ビジネスルールとは？

ビジネスルールとは、業務やシステムにおける「ルール」「制約条件」「データ間の関係性」を具体的に明確化したものです。

- 業務上の決まりごと
- データ同士の関連性
- データ整合性のための条件

これらをはっきりさせることで、設計や運用がスムーズに進みます。

---

## 🔹 ビジネスルールの具体例

具体的なビジネスルールには次のようなものがあります。

### 業務上の制約
- 「ユーザーは必ずメールアドレスを持っている必要がある」
- 「商品の価格は0円以下にはならない」
- 「在庫以上の数の商品を注文することはできない」

### データ間の関係
- 「1つの注文には複数の商品を含めることができる」
- 「顧客は複数回注文できる」
- 「商品は1つのカテゴリに属する」

### データの整合性
- 「同じユーザーが重複して登録されてはいけない」
- 「注文完了後はデータを変更できない」

---

## 🔹 ビジネスルールの重要性

ビジネスルールを明確にすると、以下のようなメリットがあります。

- **データ整合性の維持**：不正なデータの登録を防げます。
- **要件の明確化**：開発者間で要件を明確に共有でき、スムーズな開発を促進します。
- **バリデーションの実施**：入力データがルールを守っているかをシステム側で検証できます。

---

## 🔹 データベース設計への反映方法

ビジネスルールをデータベースに反映する具体的な方法は以下の通りです。

### 制約条件（Constraint）の設定
- **NOT NULL制約**：必須項目を設定
- **UNIQUE制約**：重複データを防ぐ
- **CHECK制約**：条件を満たしたデータのみ登録
- **FOREIGN KEY制約**：関連するデータの関連性を定義

### ER図を用いたデータ構造設計
- エンティティ（テーブル）間の関係を明確化
- ルールを視覚的に設計書に反映

---

## 🔹 ビジネスルールの記述例（設計書）

| エンティティ | 属性 | データ型 | ビジネスルール |
|------------|------|--------|----------------|
| ユーザー | メールアドレス | VARCHAR | 必須、重複不可 |
| 商品 | 単価 | INT | 0以上の整数のみ |
| 注文 | 注文日 | DATE | 現在日時以前の日付 |

---

## 🔹 ビジネスルールの注意点

- **現場業務との整合性**：実際の業務に即して慎重に設定
- **変更可能性の考慮**：業務は変化するため、柔軟に対応可能な設計を目指す

---

## 🔹 まとめ

ビジネスルールはデータベース設計において、業務ルールやデータの制約を明確化し、設計・運用上の重要な基準となります。明確に定義することで、システムの品質向上や運用安定性につながります。設計段階で十分に検討しましょう。
71. Simplify Path 解答例・ポイント

# 問題内容
与えられた絶対パスを決められたルールに従って書き直す

# 解答例
```python:sample
class Solution:
    def simplifyPath(self, path: str) -> str:
        components = path.split("/")
        st = []

        for comp in components:
            if comp == "" or comp == ".":
                continue
            
            if comp == "..":
                if st:
                    st.pop()
            else:
                st.append(comp)
        
        return "/" + "/".join(st)
```

# この問題のポイント
この問題では、決められたルールに従うため複数の条件を設定しなければならず、その方法を考えるのが難しさにつながっている。
解答例では、最初から戻り値を作っていくのではなく、一度リストに保管しながら条件に照らし合わせて調整し最後に結合して戻り値とする方針で処理している。この方針により、使ってはいけない文字列の削除や親ディレクトリにさかのぼる処理を分かりやすいコードで実装することができる。
Agent APIのまとめ


# 設定方法:エージェントAPIを使い始める

+ ステップ1: Agentforceを有効にしてエージェントをアクティブ化する
+ ステップ2: 接続されたアプリを作成し、OAuth設定を有効にする
+ ステップ3: 接続されたアプリケーションをエージェントに追加する
+ ステップ4: コンシューマーキーとコンシューマーシークレットを取得する
+ ステップ5: トークンを作成する

エージェント API は、同期メッセージとストリーミング メッセージの両方の処理をサポートしています。同期メッセージは、1 回の呼び出しで完全な応答が必要なユースケースに最適ですが、ストリーミング メッセージは、チャット会話などのリアルタイムのやり取りに適しています。


### 考慮すべきこと

+ データ使用量:エージェント API への各呼び出しは、Einstein リクエストを消費します。使用されるリクエストの数は、API 呼び出しのサイズと大規模言語モデル (LLM) 使用タイプの乗数によって異なります。
+ API タイムアウト:エージェント API には 120 秒のタイムアウトがあります。呼び出しがタイムアウトすると、HTTP 500 応答が返されます。

# 投稿から

+ [セットアップエージェントに「接続」タブがないのはなぜですか](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000MYI2x)

:::note
エージェント API は、「Agentforce (デフォルト)」タイプのエージェントではサポートされていません。

これには、セットアップ タイプのカスタム エージェントが含まれますが、これらは API ではサポートされていません。他のタイプのエージェントを作成する必要があります。 
:::

https://trailhead.salesforce.com/content/learn/modules/agent-api-quick-look/build-custom-ai-agents-with-agent-api


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/cddc9d9a-f11a-4513-8d00-c668bf1fd9e6.png)


+ [APIを通じて作成されたエージェントワークはエージェントの容量を占有しません](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PWytV0AT)
HeliScriptでWeb APIを使用するときの設計ポイント

# 概要
Web APIを使用する設計でつまずきやすいポイントとその対応策をまとめました。

:::note warn
この内容はVket CloudでのWeb API使用方法を理解していることが前提です。不明点がある場合は[こちらのガイド](https://vrhikky.github.io/VketCloudSDK_Documents/latest/WorldMakingGuide/JsUpload_FetchCurrentWeather.html) を参照してください。
:::

# リポジトリでなくクライアントでJsonをパースする
## 問題点: リポジトリでJsonをパースできない
一般的にWeb APIから取得したデータはインフラ層のリポジトリでパースします。しかしHeliScriptには「コールバック関数の引数としてカスタムクラスを使用できない」という制約があるため、リポジトリでデータを成形するとクライアントにデータを渡せなくなります。

:::note warn 
**コールバック関数の引数としてカスタムクラスを使用できない**
```c#
// 〇: 基本の組み込み型とJsValは使用可能
delegate void fStringCallback(string);
delegate void fJsValCallback(JsVal);

// ✕: カスタムクラスは使用できない
// delegate void fCustomDataCallback(CustomData);
// class CustomData { }
```
:::

## 対応策: クライアントでパースする
上記制約があるため、クライアント側でデータをパースする必要があります。

## 実装例

```c#
// リポジトリ。
// 処理をもたないため、I(インターフェイス)をプレフィックスしています。
class IEventRepository{
    public void FetchEventList(fJsValCallback callback){
        // JSファイル側で実装します
        customJS.fetchEventList(callback);
    }
}

// クライアント
component SomeGimmick_Component{
    IEventRepository _Repository;
    list<Event> events;
    
    public SomeGimmick_Component(){
        _Repository = new IEventRepository();
        _Repository.FetchEventList(FetchEventCallback);
    }

    void FetchEventCallback(JsVal jsVal){
        // todo: JsValをパースする
    }
}
```

# リポジトリから複数回データを取得する場合の対応
## 問題点: 複数回リポジトリにアクセスする必要があるケース
クライアントでパースする場合に問題になるのは、一つのオブジェクトを成形するために複数回リポジトリにアクセスする必要があるケースです。HeliScriptにはasync/awaitなどの非同期処理構文がないため工夫が必要です。

## 対応策
この制約に対応するため、以下の方法をおすすめします:

### ①JS側でデータをまとめる
JS側では非同期処理（async/await構文など）が使えるため、JS側であらかじめデータをまとめておく方法です。

### ②API単位でクラスを分ける
APIのデータ取得単位でオブジェクトを分割する方法です。

:::note info
**[Vket Cloudのエントランスワールドのイベント掲示板の例](https://hikkyofficial.cloud.vket.com/worlds/entrance/main.html?worldid=entrance)**
下記UIでは、イベントページとページステータスボタンを同じ概念にまとめるのが自然です。しかし、APIの取得単位が異なるため、別概念・別クラスとして分離することで実装がシンプルになりました。

![d07d5918-587b-4383-be97-b615802d3c5e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14345/0c436b6a-3ac0-4120-84fa-1b42a242bc6f.png)

:::
Mattermostで特定ユーザーのユーザー名を変更する方法（管理者向け）

こんにちは！
 今回は **Mattermostの管理者が特定ユーザーのユーザー名（例：@john_doe → @john）を変更する方法**について解説します。

## :dart: 目的

Mattermostの管理者が、ユーザーに代わってユーザー名を変更したいときに使える手順です。
 対象は**自社運用しているMattermostサーバー**で、**`mmctl`（CLIツール）を使った方法**になります。

## :white_check_mark: 前提条件

- MattermostサーバーにSSHなどでアクセスできる
- `mmctl` が使える（v6.7以降で動作確認）
- サーバー上で **Mattermostと同じユーザー権限** で操作できること

## :hammer_and_wrench: ユーザー名変更手順

`mmctl`がある以下のディレクトリに移動します。

```bash
cd /opt/mattermost/bin
```

### ① `mmctl` をローカルモードで実行する

まずは Mattermost サーバー上にログインし、`mmctl` をローカルモードで使用して対象ユーザーを検索します：

```bash
sudo -u mattermost ./mmctl --local user search john_doe
```

実行例：

```
id: 2fg4xjjzof88jj4qa5yo3je7ow
username: john_doe
email: johndoe@example.com
```

### ② `user username` コマンドでユーザー名を変更

上記で取得したユーザーIDを使って、以下のコマンドでユーザー名を変更します：

```bash
sudo -u mattermost ./mmctl --local user username 2fg4xjjzof88jj4qa5yo3je7ow john
```

成功すると：

```
User john updated successfully
```

### :white_check_mark: 補足：`--local` モードとは？

Mattermostサーバーと**同じホスト上で `mmctl` を使う場合に限定して、認証なしで直接操作できるモード**です。

もし次のようなエラーが出たら：

```
Error: failed to create client: socket file "/var/tmp/mattermost_local.socket" doesn't exist
```

以下の2つを確認してください：

1. `config/config.json` で `"EnableLocalMode": true` になっているか
2. サーバーを再起動したか

さらに、次のエラーが出た場合：

```
Error: failed to create client: owner of the file must be the same user running mmctl
```

これは `mmctl` を実行しているユーザーが `mattermost` と違うためです。
 その場合は以下のように実行しましょう：

```bash
sudo -u mattermost ./mmctl --local ...
```

## 🧪 確認

変更後は以下のコマンドで正しく変更されているか確認できます：

```bash
sudo -u mattermost ./mmctl --local user search john
```

## :memo: まとめ

| 操作           | コマンド例                                             |
| -------------- | ------------------------------------------------------ |
| ユーザー検索   | `mmctl --local user search <旧ユーザー名>`             |
| ユーザー名変更 | `mmctl --local user username <user-id> <新ユーザー名>` |

## ✨ おわりに

MattermostではGUIからはユーザー名を変更できない場合もあるため、CLI操作を覚えておくと非常に便利です。
 チーム内の命名ルールの統一やユーザー管理にも役立ちます。

質問やトラブルがあればぜひコメントください！
paizaラーニングレベルアップ問題集の「1はどこにある？」をやってみた。

paizaラーニングレベルアップ問題集の[1はどこにある？](https://paiza.jp/works/mondai/loop_problems2/loop_problems2__seq_one)をやってみました。
- - -
###### 問題
https://paiza.jp/works/mondai/loop_problems2/loop_problems2__seq_one
- - -
###### 参考
[数列の中に何個ある?](https://qiita.com/anonymously115/items/2f04abcfe1d3f154c464)
- - -
###### C
```c
#include <stdio.h>

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		int a;
		scanf("%d", &a);
		if (a == 1) printf("%d\n", i);
	}
	return 0;
}
```
- - -
###### C++
```cpp
#include <iostream>
using namespace std;

int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a;
		cin >> a;
		if (a == 1) cout << i << endl;
	}
	return 0;
}
```
- - -
###### C#
```cs
using System;

class Program
{
	public static void Main()
	{
		int n = int.Parse(Console.ReadLine());
		int[] A = Array.ConvertAll(Console.ReadLine().Split(), int.Parse);
		for (int i = 0; i < n; i++) if (A[i] == 1) Console.WriteLine(i + 1);
	}
}
```
- - -
###### Go
```go
package main
import "fmt"

func main() {
	var n int
	fmt.Scan(&n)
	for i := 1; i <= n; i++ {
		var a int
		fmt.Scan(&a)
		if a == 1 {
			fmt.Println(i)
		}
	}
}
```
- - -
###### Java
```java
import java.util.*;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		for (int i = 1; i <= n; i++) if (sc.nextInt() == 1) System.out.println(i);
		sc.close();
	}
}
```
- - -
###### JavaScript
```js
const [N, A] = require("fs").readFileSync("/dev/stdin", "utf8").trim().split('\n').map((s, i) => i ? s.split(' ').map(Number) : Number(s));
for (var i = 0; i < N; i++) if (A[i] == 1) console.log(i + 1);
```
- - -
###### Kotlin
```kotlin
import java.util.*

fun main() {
	val sc = Scanner(System.`in`)
	val n = sc.nextInt()
	for (i in 1..n) if (sc.nextInt() == 1) println(i)
	sc.close()
}
```
- - -
###### PHP
```php
<?php
	$n = intval(fgets(STDIN));
	$A = array_map("intval", explode(' ', fgets(STDIN)));
	for ($i = 0; $i < $n; $i++) if ($A[$i] == 1) echo $i + 1, PHP_EOL;
?>
```
- - -
###### Perl
```pl
my $n = int(<STDIN>);
my @A = map { int($_) } split ' ', <STDIN>;
for (my $i = 0; $i < $n; $i++) {
	if ($A[$i] == 1) {
		print $i + 1, $/;
	}
}
```
- - -
###### Python3
```py
N = int(input())
A = list(map(int, input().split()))
for i in range(N):
	if A[i] == 1:
		print(i + 1)
```
- - -
###### Ruby
```rb
N = gets.to_i
A = gets.split.map(&:to_i)
N.times do |i|
	if A[i] == 1
		p i + 1
	end
end
```
- - -
###### Scala
```scala
import java.util._

object Main extends App{
	val sc = new Scanner(System.in)
	val n = sc.nextInt()
	for (i <- 1 to n) if (sc.nextInt() == 1) println(i)
	sc.close()
}
```
- - -
###### Swift
```swift
let n = Int(readLine()!)!
let A = readLine()!.split(separator: " ").compactMap { Int($0) }
for i in 0..<n {
	if A[i] == 1 {
		print(i + 1)
	}
}
```
tableの列幅の指定とtbodyの自動補完と。

## はじめに
HTMLでテーブルを作成する際、列幅の指定等に使う \<colgroup> と、データを格納する \<tbody> の配置を適切に行わないとうまく反映されません。最近少し手こずったので、記事にして忘れないようにしたいと思います。

## テーブルの正しい構造と自動補完の注意点
HTMLでテーブルを記述する際、\<colgroup> で各列の幅やスタイルを指定できる。仕様に沿って正しい順序で記述しなければ、レイアウトがうまく設定されない。

以下のコードが適切な構造。
```html
        <table>
            <colgroup> <!--列幅の指定--> </colgroup>
            <tbody>
                <!--テーブルの中身-->
            </tbody>
        </table>
```


このように、\<table> タグ直後に \<colgroup> を記述し、その後に \<tbody> で中身を囲むのが正しい。

一方、次の例のように \<tbody> の前に \<colgroup> を記述せず、\<tbody> 内に \<colgroup> を配置してしまうと、スタイルが反映されなくなる。（ブラウザが自動補完してくれる可能性もあるのかも？）
```html
        <table>
            <tbody>
            <colgroup> <!--列幅の指定--> </colgroup>
            <!--テーブルの中身-->
            </tbody>
        </table>
```



また、以下の例はテーブルの中身が \<tbody> で囲われていない。ブラウザは自動補完機能により内部的に \<tbody> を挿入する。が、その際に意図しない配置となることもあるかも。
```html
        <table>
            <colgroup> <!--列幅の指定--> </colgroup>
            <!--テーブルの中身-->
        </table>
```

自動補完機能は記述ミスを補ってくれるありがたい仕組みだけど、開発者ツールなどで生成されたHTMLの構造を確認し、意図通りに \<colgroup> と \<tbody> が配置されているかどうかを確認した方がよいかも。


## おわりに
最近、少し手こずってました。こうやってまとめる簡単なんですが、サーバーサイドでの動的な挿入など、コードが複雑になってしまっていました。自動補完されるのも知らなかったので勉強になりました。
【C#】MSTestでテスト用に別のDBを用意して接続する方法


DB アクセスにかかわる部分の単体テストについて MicroSoft 公式では、テスト用にローカルに新しく DB をたててテストすることを推奨しています。

https://learn.microsoft.com/ja-jp/ef/core/testing/choosing-a-testing-strategy

https://learn.microsoft.com/ja-jp/ef/core/testing/testing-with-the-database

公式では XUnit を使用した例で実装していたため、MSTest を使用した実装方法を紹介します。

## DB の初期化クラス追加

MSTest のプロジェクトに DB の初期化クラスを追加します。
このクラスでは既存のテスト用 DB があればクリア、最新の情報でテーブルを作成、データの追加を行います。

コードは下記です。

```Csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace Example.Server.Tests;
public class TestDatabaseInitializer
{
    private const string ConnectionString = @"Server=(localdb)\mssqllocaldb;Database=Temp-TestDB;Trusted_Connection=True;ConnectRetryCount=0";
    private static readonly object _lock = new();
    private static bool _databaseInitialized;

    static TestDatabaseInitializer()
    {
        lock (_lock)
        {
            if (!_databaseInitialized)
            {
                using (var context = CreateContext())
                {
                    context.Database.EnsureDeleted();
                    context.Database.EnsureCreated();

                    context.Temp.Add(new Temp { Id = 0, Text = "TestData1" });
                    context.Temp.Add(new Temp { Id = 0, Text = "TestData2" });
                    context.Temp.Add(new Temp { Id = 0, Text = "TestData3" });
                    context.Temp.Add(new Temp { Id = 0, Text = "TestData4" });
                    context.Temp.Add(new Temp { Id = 0, Text = "TestData4" });

                    context.Users.AddRange(users);
                    context.SaveChanges();
                }
                Console.WriteLine("Database initialized");

                _databaseInitialized = true;
            }
        }
    }
    public static ExampleDbContext CreateContext()
        => new ExampleDbContext(
            new DbContextOptionsBuilder<ExampleDbContext>()
            .UseSqlServer(ConnectionString)
            .Options);
}
```

`ConnectionString`に接続先を保持しているため、この値をローカルのテスト用 DB に設定することでテスト用 DB を使用することができます。

## テストクラス側のコード

テストクラス側のコードは以下のように記述します。

```Csharp
[assembly: ClassCleanupExecution(ClassCleanupBehavior.EndOfClass)]

namespace Example.Server.Controllers.Tests
{
    [TestClass()]
    public class TempControllerTests
    {
        private static ExampleDbContext _context;

        public TempControllerTests()
        {
        }

        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            _context = TestDatabaseInitializer.CreateContext();
        }

    }
}
```

このようにすることで DBContext を使用することができます。

## 処理の解説

初期化クラスでは DB のテーブル作成と初期データ投入を行います。
複数のクラスから同時アクセスされても良いように`lock`による排他とフラグによる制御を入れます。

またコンテキストを生成するメソッドが静的に定義されているため、コンストラクターも静的にしています。
ただし静的コンストラクターは１度しか実行されないため、`lock`による排他とフラグの部分は不要かもしれません。

## おわりに

これで、MSTest でテスト用 DB に接続する事ができます。ぜひ参考にしてみてください。

この記事が皆様のコーディングライフの助けになれば幸いです。

## 参考

https://learn.microsoft.com/ja-jp/ef/core/testing/choosing-a-testing-strategy

https://learn.microsoft.com/ja-jp/ef/core/testing/testing-with-the-database
家計簿アプリを作る＃２４

![スクリーンショット 2025-03-29 084047.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4012588/02c78d55-b96c-4cdc-8216-b6cd74b3f179.png)
![スクリーンショット 2025-03-29 084154.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4012588/38be0d62-f098-4b0e-9eff-6bead5adbed8.png)
ヘッダーの下に、SideBarコンポーネントを加えて、インポートします。

![スクリーンショット 2025-03-29 084238.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4012588/98b45d8a-a6ae-4274-a66b-05a44df346b8.png)
これらは、親コンポーネントで定義されているので、エラーが出ています。
なので、親コンポーネントから、SideBarコンポーネントにプロップスとして渡していきます。

＊プロップスとは？
コンポーネントにデータを渡すとき、そのデータを属性として指定することで、コンポーネントに対して必要な情報を送ることができます。
例えば、Card1コンポーネントに title と text 、Card2コンポーネントには number と onClick という自分で作った属性のようなものを使ってデータを渡しています。 これらの属性のようなものをReactではPropsと呼びます。
erbファイル - 自動formatter設定（vsCode）

久々にrailsチュートリアルを再度勉強しているのですが、erbファイルの自動フォーマットをしたいと思い、vsCodeの拡張機能を利用した設定を行いました。
その手順を備忘録として記載します。

参考記事

https://qiita.com/h-taro/items/74a3522382f17d2d8662

# 1. 拡張機能インストール
`ERB Formatter/Beautify` という拡張機能をインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/15b07223-bc2a-4267-93cc-01bc362c9032.png)

# 2.必要gemをインストール
ターミナルで以下を実行します。
```terminal
$ gem install htmlbeautifier
```

完了後、プロジェクトのgemFileに以下を記載し、bundle installします。
develop環境でのみで利用するため、その中に記載しています。
```ruby:Gemfile
group :development do
  ~ 略 ~
  gem 'htmlbeautifier'
end
```
```terminal
bundle install
```

ここで、後程の設定でhtmlbeautifierのpathが必要になるため、確認しておきます。
```terminal
$ which htmlbeautifier
/path/to/your/htmlbeautifier
```

# 3.設定ファイルを作成する
プロジェクト配下の `.vscode`ディレクトリに、`extensions.json`ファイルと`settings.json`ファイルを作成します。ディレクトリがなければ手動で作成して大丈夫です。
※`extensions.json`は必須でないですが、もし別環境でも作業するなどの場合にアテンションしてくれるので、念の為作成しておきます。また、特にチーム開発をする場合は共通フォーマッタを利用することでコードのばらつきが減ると思います

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2704095/7a422008-f801-44d9-a785-f2905e6cfd02.png)

中身を記載していきます。
※setting.jsonの`vscode-erb-beautify.executePath`には、先ほど確認したパスを入れます。コピペをする際はご注意ください。
```json:extensions.json
{
  "recommendations": [
    "aliariff.vscode-erb-beautify"
  ]
}
```

```json:settings.json
{
  "files.associations": {
    "*.html.erb": "erb"
  },
  "[erb]": {
    "editor.defaultFormatter": "aliariff.vscode-erb-beautify",
    "editor.formatOnSave": true
  },
  "vscode-erb-beautify.executePath": "path/to/your/htmlbeautifier",
  "vscode-erb-beautify.customEnvVar": {
    "LC_ALL": "en_US.UTF-8"
  }
}
```

これで完了です。
ctrl + sなどで保存すると、綺麗erbファイルが自動で綺麗な見た目に修正されると思います。
Supabaseで日時を保存しようとしたらエラーになった【React】

学習記録を保存するアプリを React と Supabase で作成中、`created_at` に関するエラーに遭遇したので記録として残しておきます



## 開発環境

- フロントエンド: React (TypeScript)
- バックエンド: Supabase
- 状態管理: useState（React標準）
- UIライブラリ: Chakra UI


## 目的

学習した内容と時間、日時を Supabase に保存する
フォーム入力から `title`, `time`, `created_at` を Supabase に送信する設計です
![スクリーンショット 2025-03-29 8.19.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3977506/e68d6613-7e96-4603-9c0b-2d0c8fcc687c.png)


## 発生した問題

フォームで `created_at` を `type="time"` で入力していたが、Supabase に送信すると以下のエラーが発生

- "The specified value '11:00' does not conform to the required format"
- `400 Bad Request`

原因は、**React 側で取得された値が時間だけ（"11:00"）だったのに対し、Supabase 側が ISO 形式の日時（"2025-03-28T11:00" など）を要求していた**ため
`type="time"` と Supabase の `timestamp` 型が合っていなかった



## 対応

### 入力形式の変更

React 側のフォームで、`type="datetime-local"` を使用するように変更

```tsx
<Input
  type="datetime-local"
  value={createdAt}
  onChange={(e) => setCreatedAt(e.target.value)}
/>
```

### 送信形式の変換

入力された文字列はそのままでは Supabase に適さないため、`Date` オブジェクトに変換し、`toISOString()` で整形してから送信する。

```ts
const newRecord = {
  title,
  time: Number(time),
  created_at: new Date(createdAt).toISOString(),
};
```

## 参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
Einstein Enhanced Botのエラーのまとめ



+ [最初のスクリーンショットには、「Sim, quero saber!」というテキストが表示されています。これは WhatsApp のボタンとして表示されるはずですが、なぜ機能しないのかわかりません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000MYFQ7)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/6270d8b5-1d67-4e6a-b9a8-23199067d483.png)

:::note
PrimeiroNome 変数値が null の場合、{!PrimeiroNome} が表示されます。BOT で null チェックを行ってください。 

ボタンの問題は既知の制限です。 
https://ideas.salesforce.com/s/idea/a0B8W00000GdoxVUAR/add-einstein-bot-like-buttons-on-whatsapp-ui
:::

+ [I can't manage make the generative answers feature work on my Enhanced Einstein bot](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000PYExI)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/231886b3-5601-4cb5-82e7-23625f8e8d4e.png)

:::note
I got an update on this. Turns out I was missing a step on Data Cloud Setup. I got a clue about that because whenever I tried using an Agentforce Data Library or all the knowledge articles as grounding for the bot I got the same blank answer, so I checked the steps to enable Data Cloud Correctly on my sandbox and found that my connection was not active. 

これについて最新情報をいただきました。データクラウドの設定手順が抜けていたことが判明しました。Agentforceデータライブラリやナレッジ記事をボットの基盤として使用しようとした際に、同じ空白の回答が返ってきたため、その原因が分かりました。そこで、サンドボックスでデータクラウドを正しく有効化する手順を確認したところ、接続がアクティブになっていないことが判明しました。 
:::


# 未解決

+ [ボットで選択リストの値を表示する](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ajlJN)

+ [Error During Adding Channel to Agent](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000MZ48r0AD)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/d6e6c81d-40fa-43d4-8a05-024815be5e0e.png)


# 制限

+ [Route from AgentForce to an Enhanced BOT](https://trailhead.salesforce.com/trailblazer-community/feed/0D5KX00000MbMvV)

:::note
By default, Salesforce Omni-Channel + Enhanced Bot handoff is one-way. 

There is no native "return to bot" after Agent chat ends unless you implement a custom "handoff" strategy.

デフォルトでは、Salesforce Omni-Channel + 拡張ボットのハンドオフは一方向です。 

カスタムの「ハンドオフ」戦略を実装しない限り、エージェント チャットの終了後にネイティブの「ボットに戻る」機能はありません。
:::
go言語のお勉強1

# 経緯
転職活動してたらgoの求人が多い
元々興味はあったし、dockerとかterraformはgo製らしいし、AWSでもGCPでも使えるしで良さげ
第２言語として習得を目指す

# 調査から
go言語をひたすら書いて実行するだけなら
https://go.dev/tour

dockerhubにあるコンテナ確認
https://hub.docker.com/_/golang/tags

使うなら現時点での最新だと golang:1.24.1-alpine かな？

コンテナ内の状況確認
/go直下に/binと/srcあるけど中身何もない
もちろんだけどgoコマンドは動く

```
$ docker run -it golang:1.24.1-alpine sh
/go # ls -lah *
bin:
total 8K     
drwxrwxrwt    2 root     root        4.0K Mar  4 22:01 .
drwxrwxrwt    4 root     root        4.0K Mar  4 22:01 ..

src:
total 8K     
drwxrwxrwt    2 root     root        4.0K Mar  4 22:01 .
drwxrwxrwt    4 root     root        4.0K Mar  4 22:01 ..

/go # go version
go version go1.24.1 linux/arm64

/go # vi main.go
package main
import "fmt"
func main() {
	fmt.Println("hello world")
}

/go # go run main.go
hello
```

# 最低限実行環境を目指す
hello worldを出力するwebサーバを作りたい

``` ディレクトリ構造
dir ━━ app
    ┃  ┗ main.go
    ┃  ┗ hoge.go...
    ┃
    ┗ docker-compose.yml
    ┗ Dockerfile
    ┗ Makefile
```

# ファイル
``` makefile:Makefile
clean:
	docker compose down --rmi all --volumes
upd:
	docker compose up -d
logs:
	docker compose logs -f --tail=20
```

``` docker-compose.yml
services:
  go-web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8080:80
```

``` dockerfile:Dockerfile
FROM golang:1.24.1-alpine as golang
WORKDIR /app
COPY app .
RUN go build -o server main.go
CMD ["./server"]
```

``` app/main.go
package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "hello world")
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":80", nil)
}
```

# webサーバ動かす
```
$ make upd
$ docker ps
CONTAINER ID   IMAGE                COMMAND      CREATED         STATUS         PORTS                                   NAMES
73248aa3cb3c   go_practice-go-web   "./server"   6 minutes ago   Up 6 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   go_practice-go-web-1
```

http://localhost:8080 にアクセスして「hello world」出ればok！

次はwebサーバ以外の用途とか、フレームワーク利用しながらgo言語の仕様を勉強していきたい
【Teams電話】モバイルアプリから利用できる代理人機能

# はじめに

Teams 電話の代理人機能では、委任者が代理人に通話関連の操作を委任することができます。Teams のモバイルアプリの場合、代理人が行える操作にいくつかの制限があります。この記事では、モバイルアプリから利用できる代理人の機能についてまとめました。

※ 関連記事

https://qiita.com/atsmin77/items/77f869629a2e660cd801

# モバイルアプリから利用できる代理人機能

代理人の機能のうち、モバイルアプリから利用できる機能は以下の表のとおりです。

※ 2025/3/28 時点
| 機能 | 説明 | モバイルで利用可 |
|:-:|:-:|:-:|
| 通話の発信 | 委任者の電話番号を使用して発信できる | 〇 |
| 通話の受信 | 委任者宛て通話を受話できる | 〇 |
| 通話設定の変更 | 委任者の通話設定を変更できる | 〇 |
| 通話履歴の共有 | 委任者の通話履歴を閲覧できる  | × |
| 保留解除 | 委任者の保留中の通話を保留解除できる  | × |
| 通話への参加 | 委任者の進行中の通話へ参加できる | × |

::: note warn
モバイルアプリからは、代理人が委任者の通話履歴を確認することができません。
:::

::: note
利用できる機能についても、デスクトップクライアントと操作方法が異なります。
:::

(参考：Microsoft Teams での共有回線の外観)
https://learn.microsoft.com/ja-jp/microsoftteams/shared-line-appearance

# モバイルアプリから利用できる機能

## 通話の発信 / 受信

モバイルアプリにおいても、代理人は委任者の電話番号から通話を発信することができます。

また、委任者が代理人の同時呼び出しや通話転送を設定していれば、通話は代理人のモバイルアプリにも着信します。

* デスクトップクライアント
デスクトップクライアントでは、通話タブに委任者の名前のタブが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/f67f4371-c174-4868-919f-92a008be86c9.png)

* モバイルアプリ
モバイルアプリでは、通話を発信する際に委任者の電話番号から発信するかどうかを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/5f1642b3-ce2a-4b39-9b96-da607a4a214f.png)

## 通話設定の変更

モバイルアプリにおいても、代理人は委任者や他の代理人の通話設定を変更することができます。

* デスクトップクライアント
デスクトップクライアントでは、[設定] - [通話] に委任者の名前のタブが追加されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/54e6126b-d647-41c9-b379-7026bfa84820.png)

* モバイルアプリ
モバイルアプリでは、[設定]-[代理人の管理] から委任者をタップすると、委任者の設定を変更することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/fee60d0c-b71a-4832-9838-63d837b09166.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/8447d0f2-558e-403b-a65b-45ea42ccc542.png)

# モバイルアプリから利用できない機能

## 通話履歴の共有

モバイルアプリでは、代理人に委任者の通話履歴が表示されません。

* デスクトップクライアント
デスクトップクライアントでは、[通話] タブに委任者の通話履歴が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/e95f10d5-7405-499a-b2c7-9e3775d55221.png)

* モバイルアプリ
モバイルアプリにも [共用回線] タブが表示されますが、委任者の通話履歴は表示されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/0582ee4e-6b89-4d07-b0ca-d0557752a5b4.png)

## 保留解除/通話への参加

モバイルアプリでは、代理人に委任者の通話状況が表示されません。そのため、代理人が委任者の通話保留を解除したり、進行中の通話に参加することはできません。

* デスクトップクライアント
デスクトップクライアントでは、代理人に委任者の通話状況が表示されます。代理人は委任者の通話の保留解除や通話への参加が行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/9994669d-74ec-4de1-9fff-e71d16b9df2e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/ae811c40-214f-4865-80b8-9c616bf74bda.png)

* モバイルアプリ
デスクトップクライアントでは、代理人に表示されるのは委任者のプレゼンスのみです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2680397/5cbc5037-76e3-4c88-8110-18b4114a7082.png)
(ポエム)「タイトル詐欺」と「書きかけの下書き」についてかんがえる(個人的感想)(いろいろ、反省を込めて)


参考
----

https://dic.nicovideo.jp/a/%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E8%A9%90%E6%AC%BA


https://note.com/tukiweb/n/n831bf2299810


前説
----


    「タイトル詐欺」とは、

ニコニコ百科(仮)によると

「タイトル詐欺」

- ニコニコ動画をはじめとした動画共有サイトにおいて、タイトル（動画の表題）と本体のギャップが激しすぎる動画につけられるタグ。

- ドラマ、アニメなど、（結果的に）偽りがあるタイトル又はそのサブタイトル。

- 娯楽・スポーツなど特定の部門で表彰した選手に文句を言うアンチの常套手段。

瀬戸優理子によると

「書きかけの下書き」

ライティングでは、よく「数稽古」の大切さが説かれます。「書く」という行為を体に覚えさせ、しみこませ、書けば書くほどスラスラ言葉が出てくるようになる……という。


で、個人的な感想
----

そもそも、タイトル詐欺は、注目をあつめてアクセスによる資金稼ぎで「詐欺」の才能がないと出来ない。((人をだまして金品を得る)ほぼ、ネットワーク犯罪)

そもそも、完全完成を目指す人は、アップしないので、どんなに良くても作品が
よに出てこない。
タイトル詐欺では、ないが、俺の考えた最強のxxの人は、他人だよりなので後が続かない
例としては、俺の考えた最強の「お手伝いロボット(名前は、マルチなんとか(HMX-12))」、続きは、クラウドファンドで。
(個人的には、すごくほしい(ちょびっっも「なんの事?」))

それ個人的な感想(2chの創設者的)に言うと、俺の考えた最強のxx。も、嫌いじゃないが、現実だとウザイ

程度の問題でたまった「書きかけの下書き」をよにとうのは、非常に良い事だ。
(きれいにまとめておわる)
Pythonista 3でUTF-8ファイルopen時に出るUnicodeDecodeErrorへの対処法

## 概要

- Pythonista 3でUTF-8が含まれるファイルを迂闊に`open`するとエラーが出る
- Pythonista 3では`open`時に`encoding='utf-8'`の明示的指定が必要
- このエラーが発生するのはPython 3における`open`の仕様による
- Pythonista 3でもこの仕様によるエラーが発生する環境である

## 発生した環境

Pythonista 3 (バージョン3.4)

## 起きたこと

以下のコードをPythonista 3上で実行させ、
日本語ファイル(UTF-8)を読みこませようとするとエラーが発生する。

```python:test_code.py
file_name = 'japanese_utf-8_file.txt'
with `open`(file_name) as f:
    print(f.read())
```

> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 171: ordinal not in range(128)

0xe3とpositionの後の数値は読み込ませたファイルによって異なる。

## 原因

どうやらUTF-8ファイルをUS-ASCIIファイルと勘違いして、
無理にデコードしようとしてエラーになっている模様。

なおこの事象はPython 3における`open`の仕様である。
たまたまこの仕様がPythonista 3の環境でこうなったというだけである。

## 気付いた理由

エラー表示の変数(Vars)の項目で、ファイルオブジェクトのencodingが`'UTF-8'`ではなく
`'US-ASCII'`になっていたことで気付いた。

## 対策

以下のように、`open`の際に`encoding='utf-8'`を付けるとエラーが出なくなる。

```python:test_code_recovered.py
file_name = 'japanese_utf-8_file.txt'
with `open`(file_name, encoding='utf-8') as f:
    print(f.read())
```

## 結論

- `open`でのUnicodeDecodeError問題はPythonista 3でも発生する
- `open`の際は`encoding='utf-8'`を付ける

## 参考資料

直接参考にした資料のみ記載。
Python 3の文字コード関連についてはQiitaを探せばいろいろと出てくる。

- https://qiita.com/Doremi_chan/questions/108db8c500a1679bf979
  この現象に関する質問
- https://qiita.com/tell-k/items/9320338a7fbc7dcd52d4
  現象の背景及び解決法

## その他

今更だし車輪の再発明の気もするが、Pythonista 3で直接この件について
言及した記事が見つからなかったので作成してみた。
ESET Endpoint Antivirus for Linuxの設定変更

ESET Endpoint Antivirus for Linux (Linux版のESET) では、GUIの設定画面がありません。

設定ファイルをエクスポート、編集、インポートすることで、設定を変更できます。


```
sudo /opt/eset/eea/lib/cfg --export-xml=/tmp/eset.xml
```


```
sudo /opt/eset/eea/lib/cfg --import-xml=/tmp/eset.xml
```

ESETは非常に軽量と評判です。

しかしながら、ディストリビューションやハードウェアとの相性によって、パフォーマンスに大きく影響を及ぼす場合があります。

その場合、いくつかの設定をオフにすることで、パフォーマンスが改善する場合があります。

---

私の環境の場合、「タイピングが画面に反映されるまで数秒のタイムラグが生じる」というレベルで、パフォーマンスに影響がありました。

※あくまでも個人環境の相性によるもので、製品が悪いわけではありません

私のケースでは、以下の設定をオフにすることで、パフォーマンスが驚くほどに改善しました。

機能名 | 概要
---|---
アーカイブスキャン<br>(`ArchiveEnable`) | `.zip`、`.tar`、`iso`などのファイルの中身をスキャン
セクタスキャン<br>(`SectorEnable`) | MBRやディスクセクターなどの低レイヤー領域をスキャン

エクスポートした設定ファイル内の以下の項目を探し出し…

```xml
<NODE NAME="ArchiveEnable" TYPE="number" VALUE="1" />
```

```xml
<NODE NAME="SectorEnable" TYPE="number" VALUE="1" />
```

以下のように、 `1` -> `0` へ変更することで、設定をオフにすることが可能です。

```xml
<NODE NAME="ArchiveEnable" TYPE="number" VALUE="0" />
```

```xml
<NODE NAME="SectorEnable" TYPE="number" VALUE="0" />
```

これらの設定は複数ヶ所あり、スキャンの種類ごとにオン・オフを指定可能です。

代表的なスキャンの種類は以下の通りです。
生成AIに質問すると、他の種類についても教えてくれます。

セクション名 | 意味 | 対応する操作
---|---|---
ODScand | On-Demand Scanner Daemon | 手動スキャン／スケジュールスキャン
OAScand | On-Access Scanner Daemon | リアルタイム保護（常時監視）
NPScand | Network Protection Scanner | Webアクセススキャン（HTTP/HTTPSなど）

当然ながら、これによって保護されなくなるものがあるため、検討のうえ実施されると良いかなと思います。
※会社PCの場合は情シスにご相談ください

また、セキュリティソフトとの相性はどうしてもあると思うので、どうしても相性が悪い場合は、別のソフトへの乗り換えを検討するのもありだと思います。

---

加えて、スキャン対象の除外設定が可能です。

```xml
<ITEM NAME="DetectionExclusions" DELETE="1" />
```

この項目を、例えば以下のように指定することで、特定のディレクトリ配下のファイル変更をスキャン対象外にすることが可能です。

```xml
<ITEM NAME="ExclusionsManagement">
  <ITEM NAME="DetectionExclusions">
    <ITEM NAME="1"><NODE NAME="Path" TYPE="string" VALUE="/proc/*" /></ITEM>
    <ITEM NAME="2"><NODE NAME="Path" TYPE="string" VALUE="/sys/*" /></ITEM>
    <ITEM NAME="3"><NODE NAME="Path" TYPE="string" VALUE="/dev/*" /></ITEM>
    <ITEM NAME="4"><NODE NAME="Path" TYPE="string" VALUE="/tmp/*" /></ITEM>
    <ITEM NAME="5"><NODE NAME="Path" TYPE="string" VALUE="/var/log/*" /></ITEM>
    <ITEM NAME="6"><NODE NAME="Path" TYPE="string" VALUE="/run/*" /></ITEM>
  </ITEM>
</ITEM>
```

特に、`/var/log/`配下は、syslogなどの更新頻度が非常に高いファイルもあります。
これらがスキャン対象になっていると、常時スキャンが生じることになります。

除外設定をすることで、負荷軽減を図ることができます。
VS Code マークダウンでスクリーンショットをコピペしたい

# VS Code 左下の歯車マークをクリックし「Settings」を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83291/5b8dfa7b-39d9-490d-bdf3-fa88d31a57ba.png)

# 右上のsetting.jsonを開く
![setting.json](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83291/95d8a4b0-7e03-45e1-bd87-5c6a9faaa83c.png)

# setting.jsonを設定する
```json
{
    "markdown.copyFiles.destination": {
        "*": "./images/${documentBaseName}/${documentBaseName}.${fileName/^(.+)\\.([^.]+)/$2/}"
    }
}
```

# コピペすると設定した指定のフォルダにイメージ画像が配置される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83291/f825d806-3b9f-49d8-8a8b-8b004095b245.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83291/05b7ab7e-dc62-4fbf-ab06-485291375a8a.png)

:::note info
マークダウンのプレビューは、Ctrl + Shit + v となります
:::

# 参考
https://www.1ft-seabass.jp/memo/2024/04/26/vscode-current-markdown-copyfiles-destination-setting-ver2/
https://note.com/teaslife/n/nadfab4591bfb
windows11で、sketchup6 その12

# 概要
windows11に、sketchup6を入れてみた。
rubyで、3Dを書く。
練習問題やってみた。

# 練習問題
ぶどう園の雪害を表示せよ。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/4f2841f3-b2f8-482f-a6f8-c0d6e5442b79.png)

# サンプルコード

```

require 'sketchup.rb'

def cylinder(x, y, h)
	model = Sketchup.active_model
	entities = model.active_entities
	r = 5
	n = 8
	circleBase = entities.add_circle([x, y, 0], Z_AXIS, r, n)
	base = entities.add_face(circleBase)
	base.pushpull h * -1
end

def budouen
	h = [[180,180,180,180,180],#0
		[180,180,180,180,180],
		[180,180,180,180,180],
		[180,180,180,180,180],
		[180,180,180,180,180],
		[180,180,140,180,180],#5
		[180,180,180,180,180],
		[180, 90, 90,180,180],
		[140,180,180,180,180],
		[180,180,180,180,180],
		[180,180,180,180,180],#10
		[180,180,180,180,180],
		[180,180,140,180,180],
		[180,180,150,180,180]]
	(0..4).each { |y|
		(0..13).each { |x|
			cylinder x * 300, y * 300, h[x][y]
		}
	}
end


```

以上。