OmniAICreator/Qiita-1.07M huggingface dataset:
ProxmoxVEにRustゲームサーバーを構築してみる

前回までの内容

https://qiita.com/shimeji_k/items/1f4fc0222243587fd5fb

## 前回までは？
前回、ProxmoxVEにTrueNASを入れて便利さを実感！
では、いまサーバーに直接入れているインストールしている
LinuxとRustゲームサーバーをProxmoxVE上に構築してみる。

## 機材を選ぶ
転がっている機材でやるよりちゃんとしたサーバーに入れる
HP DL380 Gen10をメンテ

この記事の第2弾の構成のままProxmoxVEを入れたサーバーに入れ替えよう。

## サーバーの設定
* ProxmoxVE SAS 1.5kのHDD*2をRAID1してOS用に
* VMを入れるストレージは少し早いほうがいいかな？と思い512GのSATA接続SSDを6台でRAID5
* 上記をSmartArrayのBIOS画面にて設定

さてProxmoxとゲームサーバーをインストール！
（そして省略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/af9bb829-56fb-47d8-985b-a2f72ae598a9.png)

もう一つサーバー見えているけどこれは後で追加したものなので割愛w
ギリギリのメモリなのでお金溜まったらなんとかする予定で稼働開始。
メモリの割当 16GByte→24GByte→32GByte→48GByte
　どんどん足りなくなってくる・・・・

### ゲームサーバーはSteamCMDではなくLinuxGSMを利用してインストール
CentOSにしようかRockeyLinuxにしようかAlmaLinuxにしようか迷ったけど
最終的にはAlmaLinux9.4を採用


## そして6シーズン過ごしてみて（Monthly）
### そして稼働していて気づいたこと
* サーバーでiLOを完全放置していた
  iLOってネットワーク経由で色々と操作できるものなんだけどどうせ家にいるからいいか？とネットワークケーブル繋いでいないしIPも割り振ってない
* サーバー追加してみたけどマイグレーション（他のサーバーに移動）しようとしたけど時間かかりすぎ（50分程度）
* マイグレーションはiSCSIとかCephを利用するとライブマイグレーションができるとの情報が？？？
* 追加したProxmox01が256GByteのメモリなのでサーバー移動してProxmox02のメンテをしたい！

じゃぁ、iSCSIかCephを導入しないとねというところで
どうせならサーバー圏や自宅内ネットワークも見直しを行いたい！

ネットワークの勉強かねてネットワークの改造をこれからすすめていこう！



そしてストレージに関してはiSCSIかCephにする
とはいっても分散という言葉や複数ノードという言葉に惹かれてCephにすることは確定しているんですけどね。


次回

https://qiita.com/shimeji_k/items/8f90bd038b21be816727
【EC-CUBE4.3】作ったプラグインのE2Eテストを書いてみる

## 動機
- 仕事をしていくうえでも、全くテストコードというのを書いたことがなかった。
- これを機にテストコードというものはどういうものなのか勉強したい。

## やったこと
- プラグイン開発のテストコードの記事があったのでそちらを参考にChatGPTに聞きながら書いてみる。

## 手順
### 1. playwright のセットアップ
- windows のコマンドプロンプトで
```
npm init playwright@latest
```
- TypeScript を選択。
- 質問は、全部 yes。

### 2. テストコードを書いてみる
- `C:\Users\username>`上に、`tests`フォルダが作成されていた。
- その中の、`example.spec.ts`というファイルを編集する。

```javascript
import { test, expect } from '@playwright/test';

test('OrderInquiryPluginTest', async ({ page }) => {
  // EC-CUBE のトップページへ
  await page.goto('http://localhost:8080/');

  // 右上の「ログイン」リンクをクリック
  await page.getByRole('link', { name: 'ログイン' }).click();

  // URLがログインページであることを確認
  await expect(page).toHaveURL(/\/mypage\/login/);

  // メールアドレスとパスワードを入力
  await page.getByPlaceholder('メールアドレス').fill('1745300553.7138.ynagisa@example.org');
  await page.getByPlaceholder('パスワード').fill('1745300553.7138.ynagisa@example.org');

  // 「ログイン」ボタンをクリック
  await page.getByRole('button', { name: 'ログイン' }).click();

  // トップページに遷移できているか確認
  await expect(page).toHaveURL(/\/$/);
  
  // 「マイページ」リンク
  await page.getByRole('link', { name: 'マイページ' }).click();
  
  // マイページに遷移できているか確認
  await expect(page).toHaveURL(/\/mypage\/$/);
  
  // 「詳細を見る」ボタンをクリック
  await page.getByRole('link', { name: '詳細を見る' }).click();
  
  // 注文履歴に遷移できているか確認
  await expect(page).toHaveURL(/\/mypage\/history(\/\d+)?$/);

  // 「受注問合せ」ボタンをクリック
  await page.getByRole('link', { name: 'この注文について問い合わせる' }).click();
  
  // お問い合わせに遷移できているか確認
  await expect(page).toHaveURL(/\/contact\?order_no=\d+$/);
  
  // お問い合わせ内容を入力
  await page.getByLabel('お問い合わせ内容').fill('ダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキストダミーテキスト');

  // URL から order_no を取得
  const url = page.url();
  const urlObj = new URL(url);
  const orderNoFromUrl = urlObj.searchParams.get('order_no');

  // order_no が存在することを確認
  expect(orderNoFromUrl).not.toBeNull();

  // input[name="order_no"] の値を取得して比較
  const inputValue = await page.locator('input[name="contact[order_no]"]').inputValue();
  expect(inputValue).toBe(orderNoFromUrl);
  
  // 「確認」ボタンをクリック
  await page.getByRole('button', { name: '確認ページへ' }).click();

  // お問い合わせに遷移できているか確認
  await expect(page).toHaveURL(/\/contact/);
  
  // 「送信」ボタンをクリック
  await page.getByRole('button', { name: '送信する' }).click();

  // お問い合わせ完了に遷移できているか確認
  await expect(page).toHaveURL(/\/contact\/complete/);

});
```
---
#### ※追記
`Playwright には、E2Eテストのコードを自動生成する機能があります。`
- ↑ ちゃんと読んでなかった。。

```
npx playwright codegen http://localhost:8080
```
- とすると、ブラウザと検証ツールみたいなのが起動するので、そこでブラウザを操作すると録画機能のような感じで一連の操作を、コード化してくれるみたい。
---

### 3. テストコードを実行
```
npx playwright test example.spec.ts --headed
```
- をすると、ブラウザが起動して一連の操作をやった後に終了する。
- `--headed` なしで実行すると、処理にかかった時間等だけが表示される。

## 参考記事
https://zenn.dev/nanasess/articles/ec-cube-plugin-e2etesting-in-10mins
Linucレベル１勉強メモ　＃３

＃ 第一章　Linuxのインストールと仮想マシン・コンテナの利用

練習問題1.3
仮想マシンおよびコンテナの説明として誤っているものを２つ選択してください。

A.  仮想マシンよりもコンテナの方がシステムリソースをより多く消費する傾向がある

B.  仮想マシンのゲストOS上でコンテナを実行することができる。

C.  ゲストOSのカーネルがクラッシュするとホストOSもクラッシュする。

D.  ハイパーバイザーとは仮想マシンが動作する基盤となる仮想化管理機構である。

（解答）A. C.

（解説）
　仮想マシンとコンテナの違いに関する問題です。仮想マシンとコンテナを同列に比較することは難しいですが、仮想マシン内ではホストOSとは異なるOSが動いていますので、その分システムリソースの消費は大きくなると考えられます。仮想マシン内で動作するゲストOS上でDocker等のコンテナを実行することはできますので、選択肢Bは適切です。ゲストOSとホストOSはは分離されていますので、たとえゲストOSのカーネルが空ラッシュしても、ホストOSni影響は及びません。

 仮想化のメリット
*複数の仮想ましんを１台の物理サーバーに統合っすることができ、サーバーのリソース（CPUの処理能力やメモリなど）を柔軟に管理し、トータルの運用コストを削除できる。

仮想化のデメリット
* 仮想マシンのホストに障害が発生した場合、複数の仮想マシンに影響が出てしまう。
* ハードウェア上で直接OSを作動させるのに比べて、パフォーマンスが低下してしまう。
パフォーマンスの低下の対策として、最近のCPUの多くには仮想化支援機能を搭載しており、仮想化にまつわるオーバーヘッドを低減するようにしている。

コンテナについて
　アプリケーションの動作に必要な環境がパッケージングされたもので、サーバー上で独立して動かすことができる
コンテナのメリット
*　素早く環境をセットできる
*　同じような環境をあちこちで利用できる
*　ホストOSとカーネルを共有するためシステムリソースの消費が少なくてすむ
*　サービス起動までの時間がコンテナの方が短くて済む。

仮想化支援機能の種類
*　intel社製のVT-x
*　AMD社製のAMD-V

（わからなかった単語解説）
*　オーバーヘッド
　プログラムの本来できな処理に必要なリソース（時間やメモリなど）以外に、間接的に必要となるリソースのこと
 
*　AMD社
　アメリカの半導体製造会社
 
*　ハイパーバイザー
　物理的なサーバー上で複数の仮想マシン（VM)を同時に実行・管理するためのソフトウェアのこと。
 これにより、１つの物理サーバーで複数のOSやアプリケーションを並行して動作させることができます。
 リソースの効率的な利用と運用コストの削減に貢献します。
FlutterでWebサイトを作るときに注意すること

# はじめに
久しぶりすぎてFlutterでWebサイトをiOS/Androidアプリと一緒に作るときの注意点を洗い出ししてみました。ChatGPTに聞いてみました。
自分用のメモです。

# 更新履歴
2025.4.22 初回投稿

## ローカルやサーバで画面が真っ白になる問題
1. MAMPで試してみる
URLが
    ```bash
    http://localhost:8888/sample_project/
    ```
であれば、以下のようにビルドします
 ```bash
 flutter build web --base-href /sample_project/
 ```

2.　MAMPの htdocs に配置
ビルドされた /build/web フォルダの中身を、次のようにコピーします
```bash
/Applications/MAMP/htdocs/sample_project/
```
中に index.html, main.dart.js, assets/ フォルダなどがある状態になります。

3.　ブラウザでアクセス
```bash
http://localhost:8888/sample_project/
```
* サーバでも一緒です

## URL内に#が付いてしまう
Flutter Webを使ってると、**URLに # が勝手に入る問題（例：https://example.com/#/home）に悩まされることありますよね。これは Flutter のデフォルトが「Hash URLルーティング」**になっているからです。

### 手順
1.url_strategy パッケージを追加
 ```bash
 flutter pub add url_strategy
 ```
 もしくは pubspec.yaml に直接追加
 ```yaml
 dependencies:
   url_strategy: ^0.3.0
 ```
2.main.dart に以下を追加
```dart
import 'package:flutter/material.dart';
import 'package:url_strategy/url_strategy.dart'; // ← 追加

void main() {
  setPathUrlStrategy(); // ← 追加
  runApp(MyApp());
}
```
 これで # が消えます！
 3.ビルドしてデプロイ
 ```bash
 flutter build web
 ```
 アップロードすれば、もう #/ のないキレイなURLで動きます

## 日本語の漢字が中国語のフォントになってしまう
Flutter Web はデフォルトで「Roboto」などを使いますが、
日本語を表示しようとしたときに指定フォントがなければ、システムのフォールバックフォントになります。

特に Web だと 中華系の「Noto Sans SC（Simplified Chinese）」などが使われてしまうことがあるとのこと。
1. google_fontsパッケージを追加
    ```bash
    flutter pub add google_fonts
    ```
    または
    ```yaml
    dependencies:
      google_fonts: ^6.2.1
    ```
2. main.dartに以下を追加
    ```dart
    import 'package:google_fonts/google_fonts.dart';
    ```
2. MaterialAppのthemeに以下を入れる
    ```dart
    MaterialApp(
      theme: ThemeData(
        textTheme: GoogleFonts.sawarabiGothicTextTheme(
          Theme.of(context).textTheme
        ),
      ),
    );
    ```
3. ビルドしてデプロイ
     ```bash
     flutter build web
     ```

 # 参考サイト
 https://zenn.dev/enoiu/articles/596078e878145d
.sort()でハマらない方法：Set×BigIntは比較関数必須！

Paizaの`Set`問題で、数値が昇順にならないバグに直面しました。原因は `.sort()` の仕様と `BigInt` の特性にあった！

## <br>🧪 問題の概要
2つの数列`A`, `B`与えられ、それぞれの値を重複なく昇順で出力せよ。

<br>入力例:
```
3
1 2 3
3 4 5
```
出力例:
```
1 2 3 4 5
```
<br>

https://paiza.jp/works/mondai/data_structure/data_structure__set_boss



## <br>💥 NGコード：文字列としてソートされる罠
```js
const arrA = lines[1].split(' ');
const arrB = lines[2].split(' ');
const seen = new Set([...arrA, ...arrB]);
console.log([...seen].sort().join(' '));
```
→ 出力が `10 2 3` みたいに崩壊。

なぜ？→ `.sort()` のデフォルトは文字列ソートだから。

## <br>✅ OKコード：BigInt＋比較関数
```js
const arrA = lines[1].split(' ').map(BigInt);
const arrB = lines[2].split(' ').map(BigInt);
const seen = new Set([...arrA, ...arrB]);

const sorted = [...seen].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
console.log(sorted.join(' '));
```

### ✔ 解説
✅`BigInt`型で巨大な数にも対応

✅`.sort()` に比較関数が必須（デフォは文字列比較）

✅`a - b` はNG → `BigInt - BigInt = BigInt` なので戻り値が 、
　 `Number` じゃなくて型エラー

## <br>📌 技術メモ

- `new Set([...])` は重複除去に便利
- `.sort()` は数値比較を明示しないとバグる
- `BigInt` 使うなら `map(BigInt)` + 比較関数必須


<br><br>[僕の失敗談と解決話！](https://paizabeginner.wordpress.com/2025/04/22/paiza%e3%81%a7%e5%9f%ba%e6%9c%ac%e3%83%9e%e3%82%b9%e3%82%bf%e3%83%bc-setxbigint%e3%81%a7%e3%82%bd%e3%83%bc%e3%83%88%e3%81%8c%e3%83%90%e3%82%b0%e3%82%8b%e7%90%86%e7%94%b1/)
オブジェクトストレージとは

## オブジェクトストレージ
　オブジェクトストレージは、画像や動画、メールなどの非構造型データをオブジェクトと呼ばれる単位で格納・管理する記憶方式である。データの大きさに柔軟に対応可能なことが特徴とされる。
VIVE Hubを捨ててALVRを使おうシリーズ　Ultimateトラッカー編

2025Apr27
設定に抜けがあったので追記しました。
　

**ALVRはVirtual Desktopのようなストリーミングソフトです**

HTC VIVE系のヘッドセットでVD（Virtual Desktop）を使うとフルフェイストラッキングが使えません。そこで私はVIVE XR EliteでALVRを使用しています。

今回はALVRでHTC VIVE Ultimateトラッカーを使用する方法です。ヘッドセットはVIVE XR Eliteを使用しています。
ALVRでは残念ながらUltimateトラッカーを扱えません。VIVE Hubを使う必要があります。ただ、そのままALVRとVIVE Hubがヘッドセットと通信している状態ではよろしくないです。

　 
VIVE HubをALVRの前に使用していたのであれば、PCに接続されこの状態になっているかと思います。
![Hub1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/5531618f-b02d-4209-b219-a5777e057faf.png)

ここでヘッドセットアイコンの上で右クリックし、「接続の解除」を選びます。
![Hub2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/2c057cc9-0513-4fa7-9e39-45baef3e2a7d.png)

アイコンを右クリックしてもメニューが出ない場合はヘッドセット内でPCの接続を切ります。
接続PC名を選択すると解除メニューが出るので「接続を解除」を選びます。
![Screenshot_20250427_213134.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/c1726da8-3e14-4fc1-8d54-f52255d48c84.png)
![Screenshot_20250427_213159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/028fc1dd-3845-45d5-9f38-93cb29a1feed.png)


次にALVRの「Settings]>「Extra」の「Driver Launch action」を「Unregister ALVR at shoutdown」に変更します。
![ALVR_Add1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/4e1db841-1b43-4cb8-a7c2-ddbd1839d819.png)




これでVIVE HubでUltimateトラッカーだけを扱い、ヘッドセットの通信はALVRという切り分けが行えます。

※トラッカーのドングルはPC側に接続する必要があります！

![full.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/f4aa5fee-80a4-45c0-b248-0917eca15414.png)
ストアドプロシージャとは

## ストアドプロシージャ
　ストアドプロシージャとは、複数のSQL命令からなる処理手続き（プロシージャ）をDBMSに格納したもの。クライアントは、本来複数命令が必要な処理を、プロシージャの呼び出し１回で行うことが出来る。この技術により、ネットワークを介したアクセスの場合には、通信回数を減らすことが出来る。
IaC(Infrastructure as Code)とは

## IaC(Infrastructure as Code)
IaCとは、サーバーやネットワークなどのインフラの設定をプログラムとして管理する手法である。以前は手順書に基づいて手作業で行っていた内容をソフトウェアで自動実行出来るので、作業時間の短縮やミスの削減に繋がる。
WSLでDebianの新しいバージョンを入れたい

Microsoftのオンライン ストアからDebianをダウンロードしてインストールできるのですが、2025/4現在も、ストアから入手可能なのは2022/3付けのDebian 11 "bullseye" だけです。

- [ストアにあるDebian GNU/Linuxのページ](https://www.microsoft.com/store/apps/9MSVKQC78PK6)
- [ストアにあるDebian GNU/Linuxのアプリケーションパッケージの直リンク](https://aka.ms/wsl-debian-gnulinux)
- ストアから入手可能なディストリビューションの一覧: `wsl --list --online`
- コマンドラインでストアからDebianをインストールする: `wsl --install Debian`

ストアにないディストリビューションについては、ルートファイルシステムのtarファイルをインポートすることで導入できます。

- [WSL で使用する Linux ディストリビューションをインポートする](https://learn.microsoft.com/ja-jp/windows/wsl/use-custom-distro)
- コマンドラインでtarファイルをインポートする: `wsl --import <distro name> <target directory> <source tar file>`
  - tarファイルはgzやxzで圧縮されていてもOK

上記の説明ページでは、Dockerイメージから tar ファイルをエクスポートする方法が書いてあり、もちろんそれでもOKですが、手間ですよね？

Debianに関して言えば、Dockerイメージの元になっているルートファイルシステムのtarファイルをGitHubから入手できます。

- リポジトリ: https://github.com/debuerreotype/docker-debian-artifacts
    - amd64ブランチ: https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-amd64
       - bookworm 通常版: https://github.com/debuerreotype/docker-debian-artifacts/blob/dist-amd64/bookworm/oci/blobs/rootfs.tar.gz
       - bookworm slim版: https://github.com/debuerreotype/docker-debian-artifacts/blob/dist-amd64/bookworm/slim/oci/blobs/rootfs.tar.gz
    - arm64ブランチ: https://github.com/debuerreotype/docker-debian-artifacts/tree/dist-arm64v8
asciinemaでコンソール操作を記事に貼り付け


## 概要

**asciinema** はターミナルの操作をテキストベースで録画し、軽量な `.cast` ファイルとして保存・再生／埋め込みできるツールです。動画ではなくテキストなのでファイルサイズが小さく、Qiita やドキュメントへの埋め込みも簡単に行えます。

ここでは紹介しませんが、aggというツールでgifへの変換も行えます。詳細は公式ページをご覧ください。

[asciinema公式/Getting started](https://docs.asciinema.org/getting-started/)

---

## インストール

### Ubuntu / Debian系
```bash
sudo apt update
sudo apt install asciinema
```

### macOS（Homebrew）
```bash
brew update
brew install asciinema
```

### 汎用（pipx）
```bash
pipx install asciinema
```

---

## 録画の手順

1. ターミナルで録画開始
   ```bash
   asciinema rec session.cast
   ```
2. 通常の操作を行う  
3. 録画終了は `Ctrl+D` もしくは `exit`  

---

## 録画ファイルの公開

1. asciinema.org にアップロード（初回のみ認証が必要）
   ```bash
   asciinema auth
   asciinema upload session.cast
   ```
2. アップロード後に表示される URL（例：`https://asciinema.org/a/12345`）を開く
   Macなら⌘+URLクリック

---

## Qiita への埋め込み

Shareをクリックすると下部にあるEmbed the playerセクションに以下のようなスクリプトがあるので、これを記事中に貼り付けるだけでプレイヤーが表示されます。  
```html
<script src="https://asciinema.org/a/4ADo6PVjhi0kJtSd2vBKPYejo.js" id="asciicast-4ADo6PVjhi0kJtSd2vBKPYejo" async="true"></script>
```

<script src="https://asciinema.org/a/4ADo6PVjhi0kJtSd2vBKPYejo.js" id="asciicast-4ADo6PVjhi0kJtSd2vBKPYejo" async="true"></script>

---

## まとめ

1. パッケージマネージャー or pipx でインストール  
2. `asciinema rec` で録画、`Ctrl+D` で終了  
3. `asciinema upload`  
4. `<script>` タグを Qiita に貼り付けて完了  

これだけで、Qiita 記事内にターミナル操作のライブ記録を埋め込めます。

***注意：プロンプトが出てしまうので、ユーザー名やホスト名など重要な情報を録画して公開しないようにご注意ください。***
VIVE Hubを捨ててALVRを使おうシリーズ　フルフェイシャルトラック編

**ALVRはVirtual Desktopのようなストリーミングソフトです**

HTC VIVE系のヘッドセットでVD（Virtual Desktop）を使うとフルフェイストラッキングが使えません。そこで私はVIVE XR EliteでALVRを使用しています。

今回はALVRでアイトラッキングとフェイシャルトラッキングを使用する方法です。ヘッドセットはVIVE XR Eliteを使用しています。


VRCFaceTrackingを以下からダウンロードしインストールします。
https://docs.vrcft.io/docs/intro/getting-started

![フェイス１.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/82e1f542-2038-4ca8-8274-5e936f67a39e.png)

起動し「Module Registry」を押します。
![フェイス２.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/2a65f08f-4fc7-4834-90ba-e8c2b1743fc4.png)

ALVR Moduleを選び「Install」を押します。![フェイス３.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/0208e7fb-dd49-455f-9a60-79936c2b3499.png)

「Home」を押してALVRのロゴが表示されていればOKです。
![フェイス４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/59936ef8-25fe-4c47-b7e7-26d04df3c361.png)

　
ALVRの「Settings」で「Eye and face tracking」を「VRCFaceTracking」にします。
![フェイス６.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/3022613c-5e26-4d49-8bd5-e3e37636edef.png)

　
ヘッドセットでVIVE XR Eliteでは左コントローラーのシステムボタンを押してメニューを出し「ギアマーク」>「入力」で「フェイストラッキング」と「アイトラッキング」をオンにします。

![Screenshot_20250422_170442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/deb53078-4838-47cc-b967-bd3ab64cc03a.png)


VRChatでOSCを有効にします。
ラディアルメニューで「オプション」
![Screenshot_20250422_171647.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/3a40af69-908e-44c9-96a4-830469e18db8.png)

「OSC」
![Screenshot_20250422_171652.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/689b0282-c299-4005-9247-3aba3253d164.png)

「有効」をオンにし、「設定をリセット」を行っておきます。
![Screenshot_20250422_171710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/77129db0-bdc1-4ae6-bcba-09d99b9ae21e.png)

ここで一旦アバターを他のものに着替え、再度フルフェイシャルトラッキングしたいものに着替え直します。
OSCの通信が上手くいっていればVRCFaceTrackingに、アバターに設定されているパラメータ数が表示されます。
![フェイス５.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201026/f23afde0-16c2-466b-990d-ecc98eee7e0e.png)

この状態であればフルフェイシャルトラッキングが行えています。
URLを中心に考えるとLaravelが楽になった話(自分のための備忘録も含めて)

## ルーターのweb.phpを中心に考える。

web.phpはurlを作っている。

controllerはURLで使う関数を作っている。

web.phpはcontrollerで作ったどの関数かを指定し、このurlに対して指定の関数を発火させている。

## CRUD処理について

post[]は新しくサーバーに投稿し新規作成する。(Create)

get[]は作成されているものをサーバーに表示を求める。(Reade)

put[]は作成されているものの編集を行う。(Update)

delete[]はサーバーにあるデータ削除を行う(Delete)



### URLとは何か？初心者エンジニア向けに解説します【Webの仕組み解説シリーズ#3】のシリーズを#3~#6まで見るといいです。(余裕があれば#1~#6まで見ることをお勧めします。)↓

https://www.youtube.com/watch?v=tG7FG1gPjLA&list=PL3PnJ18ZwZnfu6Gd8lbvIIcMsdYHsujsG&index=3&ab_channel=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%A2%E3%82%AB%E3%83%87%E3%83%9F%E3%83%BC

http通信↓

https://www.youtube.com/watch?v=b_apIgHNqtk&t=350s&ab_channel=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB

これを見たうえで↓
### Laravel入門：MVC完全攻略 POST保存処理【プログラミング初心者向け】
https://www.youtube.com/watch?v=q3vQKCmytz0&ab_channel=%E3%82%86%E3%81%8D%E3%81%B2%E3%82%8D%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E6%95%99%E5%AE%A4

を見るとLaravelとurl(webサーバー)のつながりがよくわかると思います。

udemyの各Laravelまとめ

https://www.udemy.com/course/laravel9/learn/lecture/31437980#content

APIの説明も簡単に(httpメソッドにも関係している。)

https://www.youtube.com/watch?v=rEGmSRZ-dWY&ab_channel=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB


さらには

余裕がある方は
「webを支える技術」を読むといい。

https://www.amazon.co.jp/Web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-HTTP%E3%80%81URI%E3%80%81HTML%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6REST-WEB-PRESS-plus/dp/4774142042/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1TBH8L36U5B9J&dib=eyJ2IjoiMSJ9.vyj0oG9baMuEZ_ddcog6rp6qU4doVy-b7jM5Qk2s-ZzOD8Ksu4hnv0x0K5nX3pa3W4dS8ZDrVXE4_vCeT0Fz4ehZLTCPFRETixouI286hXNiIszZXJ0ViOKqF-0v2esBT5D64ktPuR86QY-JJsFEgOvbD4b5NtvXXwg2lttyqURJ_GekMaEUf4PkYR85XyLYMc2iVoWgu-qpHyTJNuotZCoIoljiV82TKRy9aXGmt8YBOGSLzqG0hsDXOczC0W6Si1ayXFkClOR75WFGtYhRmYd2M4Jh2ljq3soCalml0jo.hxvIrO4IY0K_FtGQAh8JDzAZ4rGoy3el0Eo2qqN8xX4&dib_tag=se&keywords=web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93&m=ANNLLU4HTZVX9&qid=1745305456&s=warehouse-deals&sprefix=web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93%2Cwarehouse-deals%2C141&sr=8-1-catcorr

まだ上手く自分も言語化できていないので
後ほどうまく解説します。
初めてのポートフォリオ開発で「開発タスクの洗い出し」の大切さを知った話

### 初めてのポートフォリオ開発で「開発タスクの洗い出し」の大切さを知った話
----



こんにちは。
この記事は、初めてポートフォリオ用のWebアプリを開発し始めた初学者の備忘録です。 
ざっと、CRUD操作を知った！とりあえず、Railsでアプリを作ろう！と動き出してみたものの、「まず何をすればいいのか分からない」という状態から始まりました。

結論として、**開発をスムーズに進めるためには、実装の前に「やること（タスク）を細かく洗い出すこと」がとても大切**だと学びました。

---

## 開発の進め方で最初にぶつかった壁

私の場合、Railsの教材や書籍では「コードの書き方」は学べても、  
実際にポートフォリオアプリを1から作ろうとすると「どこから手をつけていいのかわからない」状態になりました。

- 画面は作りたいけど、何から着手すればいいのか
- DBってどうやって設計するのか
- そもそも「設計」って何よ

初学者のため、右も左もわかりません。
疑問が一気に押し寄せてきます。

---

## 「タスクの洗い出し」の考え方を知った

そこで様々な情報を受けて、**「開発タスクの洗い出し」から始める**ことを学びました。

----

### どんなことを書き出すのか？

- ユーザーはどう動くのか（ユーザーストーリー）
- 作るべき機能は何か（ログイン、一覧表示、登録ボタンなど）
- 必要な画面やページは何か
- どんなデータを保存する必要があるのか
------

### ユーザーストーリー形式で書くとイメージしやすいらしい
- ユーザは、メールアドレスとパスワードでログインできる
- ユーザは、登録した内容をマイページで確認できる

-----

### そこから機能タスクに落とし込むらしい
- Deviseをインストールする
- Userモデルを作成する
- ログイン中のユーザー名を表示する

----


### 「段階的にやるべきこと」があると知った

開発は「とりあえず作ってみよう」ではなかなか進まないことも多いです。  
そこで、**段階を踏んで考えていくことが大切**みたいです。

-----

### 私が知ったステップ

1. アプリのイメージを考える（画面・機能）
2. やるべきタスクを洗い出す（ユーザーストーリー形式や機能形式）
3. 登場する「情報の種類（データ）」を整理する（例：ユーザー、投稿など）
4. 各データに必要な項目（カラム）を考える
5. データのつながり（リレーション）を考える
6. ER図を書く
※現段階的には、ほぼ手をつけられていません
---

## 初学者だからこそ、タスクを「細かく」「小さく」してみる

「画面を作る」  
「DBを設計する」  
というのは抽象的すぎて、初学者には難しいと感じました。

**最初はタスクを細かく、できるだけ小さく分けることが大事**だということでした。
看護師として患者と関わる時と似ているなと感じました。

------

### 私が学んだ「細かく分ける考え方」は以下（ほぼ、未着手ですが）

- 画面に出てくるものを紙に書き出す
- それぞれに「名前」「説明」などどんな項目があるかを考える
- それぞれの項目が「文字」「数字」などどんなデータの種類かをメモする
- どの情報がどの情報とつながっているかを線でつないで関係を図にする
- ターミナルでモデルを1つずつ作っていく

-----

「そんな細かくやるの？」と思いましたが、やってみると頭の中が整理されて、  
**「とにかくコードを書き始める」よりずっと安心して取り組める**なあと実感しました。事前の準備ってとても大事ですね。

---

## 設計とタスク管理の大切さを知った

初学者にとって「設計」や「タスク管理」はとても地味に見えるかもしれません。  
やってみて感じたのは
#### 「いきなり実装」に飛び込まず、段階を分けて考えることで、迷いが減って、進め方に自信が持てるようになる。

ということだと思います。

---

## 使っているツール

- **Notion**：タスクを「ToDo / 進行中 / 完了」で整理できて視覚的にわかりやすい
- **Canva**：画面遷移を図にする際に使用しました。
（Figmaも触ったことがあるのですが、今後操作できるようにしていきたい。）
---

## 今後やる予定のこと

- ER図をちゃんと描く
mermaidを使用する予定
- seedでお試しデータを入れる  
- 表示画面と連携させて、データが見えるようにする
　

## 学び

同じように「何から手をつければいいか分からない」初学者の方がいたら、  
まずはタスクを洗い出すところから始めてみるとイメージしやすい。

ここまで読んでいただきありがとうございました。
引き続き、頑張ります。
Microsoft ランタイムのインストール

ついつい忘れるランタイム。インストール方法を都度調べているのでまとめ。

# Visual C++ 再頒布可能パッケージ

以下のページの 2025/4/22 時点の情報によると
https://learn.microsoft.com/ja-jp/cpp/windows/latest-supported-vc-redist?view=msvc-170

vc_redist.x64.exe (AMD64の場合) をインストールすれば、Visual Studio 2015、2017、2019、および2022 はカバーされるらしい。
最新バージョンは 14.42.34433.0 。

Visual Studio 2013 (VC++ 12.0) 以前はサポートされなくなっているがダウンロード、インストールはできる。


- Visual Studio 2013 (VC++ 12.0)
- Visual Studio 2012 (VC++ 11.0) Update 4
- Visual Studio 2010 (VC++ 10.0) SP1
- Visual Studio 2008 (VC++ 9.0) SP1
- Visual Studio 2005 (VC++ 8.0) SP1

# .Net Framework

このサイトによると、
https://learn.microsoft.com/ja-jp/dotnet/framework/install/versions-and-dependencies#remarks-for-version-45-and-later
4.5 以降の .Net Framework をインストールすると Net Framework 4 以降のものを置き換えるらしい。
同様に、3.5 をインストールすると 2.0,3.0 の代わりとして動作するらしい。

1.0 および 1.1 は ?

## .Net Framework 4.8/4.81
ダウンロードはここから Windows のバージョンに合わせて行うのがいいかな？
https://learn.microsoft.com/ja-jp/dotnet/framework/install/versions-and-dependencies#remarks-for-version-45-and-later


## .Net Framework 3.5

2025/4/22 時点では提供はランタイムのみ

Windows8以下の場合はこちらから
https://dotnet.microsoft.com/ja-jp/download/dotnet-framework/net35-sp1


Windows10以降の場合はコントロールパネルから「Windowsの機能の有効化または無効化」
あるいは OptionalFeatures.exe で呼び出す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/51b8690e-2259-4356-9066-a936da002a4f.png)

# その他

DirectX ランタイム、Access ランタイムなど
スマホで縦書きと誤認される日本語レイアウトを防ぐ——等幅10文字グリッドの罠とCSS処方箋

スマートフォン閲覧では「等幅フォント＋10 文字折り返し」によって正方形グリッドが形成され、日本語の縦書き紙面に酷似した見た目が生じます。読者は無意識に縦書きだと錯覚し、読み進めづらくなる――これはモバイル特有の可読性課題です。本稿では **(1) 書字方向の宣言**、**(2) フォント幅の揺らぎ**、**(3) 右端を揃えない段組み** という三つのアプローチを組み合わせ、横書きメタファを強化する実装ガイドを示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84965/dedfad95-2e56-465a-b991-4fa2944e3a39.png)


---

## 1. なぜ「縦書き」に見えてしまうのか  

### 1‑1. 正方形グリッド現象  
スマホ幅（約 320 px）に 1 em×10 文字を置くと行長＝行高の正方形ブロックが並びます。等幅フォントは全文字幅が一定のためグリッド感が増幅し、縦罫線が浮き上がるため縦書き誌面に見える。  

### 1‑2. 日本語特有の認知バイアス  
日本語は古くから縦書き文化を持つため、正方形レイアウトに対して「縦読みかも」と瞬時に連想しやすいことが指摘されています。  

---

## 2. 誤認を防ぐ三つの処方箋  

### 2‑1. 書字方向を明示する  
CSS `writing‑mode: horizontal-tb;` をルート要素に指定すれば、UAは横書きレイアウトを優先レンダリングします。主要ブラウザは Chrome 48／Safari 16 以降でフルサポート済み。  

### 2‑2. フォント幅に“揺らぎ”を入れる  
- **ベース**：等幅（例 “M PLUS 1mn”）  
- **アクセント**：助詞・欧文・記号のみ可変ピッチ（例 “Noto Sans JP Variable”）  

可変ピッチが行内に混在すると字幅差が横方向のリズムを生み、「縦罫」の錯視を崩せます。  

### 2‑3. 右端を揃えない段組み  
`max-width: 20em;` で折り返し位置を変動させ「ギザギザ」のラグを作る、または `column-count: 2; column-gap: 1em;` で段組みを行うと、整列感が弱まり横書きを連想しやすくなります。  

---

## 3. 推奨スタイルガイド  

| 指針 | 推奨値・設定 | 理由 |
|---|---|---|
| 書字方向 | `writing-mode: horizontal-tb;` | 横書きをUAに宣言|
| ベースフォント | `"M PLUS 1mn", monospace` | 等幅で整列を維持|
| アクセントフォント | `"Noto Sans JP Variable", sans-serif` | 幅の揺らぎ  |
| 行間 | `line-height: 1.7` | 視認性改善|
| 折り返し幅 | `max-width: 20em;` | ラグ生成  |
| 段組み | `column-count: 2;` | 横感を強調  |

---

## 4. コードサンプル（抜粋）

```html
<style>
html { writing-mode: horizontal-tb; }

p {
  font-family: "M PLUS 1mn", monospace;
  font-size: 16px;
  line-height: 1.7;
  max-width: 20em;          /* ≈10–12文字で折返し */
}

p span.hz {
  font-family: "Noto Sans JP Variable", sans-serif;
}

@media (min-width: 480px) {
  article { column-count: 2; column-gap: 1em; }
}
</style>

<article>
  <p><span class="hz">この</span>スタイルはスマホでも...</p>
</article>
```

---

## 5. 運用チェックリスト  

1. 行長が 8–12 文字で収まるか  
2. 右端が揃い過ぎていないか  
3. 可変ピッチを挿入する規則をドキュメント化しているか  
4. `writing‑mode` のブラウザ互換を検証済みか  
5. フォント・CSS変更時に Lighthouse で再テストしたか  

---

## まとめ  

- **横書きを確実に認識させる鍵**は、書字方向宣言・字幅の揺らぎ・右端ラグの三点を組み合わせること。  
- 追加コストは CSS 数十行と Web フォント 1 種のみ。  
- これらを実装すれば、最小幅スマホでも「縦書きと誤認される」可読性リスクを大幅に減らせます。  

---

> **読了ありがとうございます！**  
> 実装サンプルの改良例や検証結果など、ぜひコメント欄で共有してください。
【非エンジニア向け】既存のDatabuttonアプリにMCPサーバーを導入する方法


Databuttonで構築したアプリを「AIエージェントと連携できるサービス」に変えるには、MCP（Model Context Protocol）対応が不可欠です。

しかも、**導入はボタンを押すだけ。**

---

## ✅ 対象者

- エンジニアでないが、既存アプリを拡張したい  
- GPT系エージェントに自社アプリをつなげたい  
- MCPって聞いたことあるけど、何から始めればいいか分からない  

---

## 🎯 やるべきこと

すでにアプリがあるなら、たった1ステップで完了：

📍 `Settings` → `Production` → **「Enable MCP in your app」**

これで、AIからアクセス可能なMCPサーバーが即時に有効化されます。

---

## 🌍 MCPって何に使える？

- AIによる自動要約・翻訳・分析  
- DBへの書き込みや外部API連携  
- AIエージェントとの「自然な会話による処理実行」

---

## 🔗 関連リンク

- [Databutton公式](https://databutton.com?via=takahiro19)  
- [MCPガイド（英語）](https://docs.databutton.com/databutton-mcp-build-tools-for-ai)

---

## ✅ まとめ

非エンジニアでも業務アプリにAIを組み込む時代です。  
**「Enable MCP」ボタンひとつ**で、その入り口に立てます。  
社内DXの第一歩として、ぜひ導入を検討してみてください。
MLflow TracingのOpenAI Responses API対応をDatabricksで試してみる

こちらを見たら、MLflow 2.22.0で、OpenAI Responses APIのトレーシングがサポートされていました。

https://mlflow.org/docs/latest/tracing/integrations/openai#responses-api

以前書いたこちらを改めてトレーシングしてみます。

https://qiita.com/taka_yayoi/items/9fb6faa4c296d922682c

```py
%pip install -U openai
%pip install mlflow==2.22.0rc0
%restart_python
```

```py
import os
os.environ['OPENAI_API_KEY'] = dbutils.secrets.get(scope="demo-token-takaaki.yayoi", key="openai_api_key")
```

# 基本的な使用法

```py
import openai
import mlflow

# Enable auto-tracing for OpenAI
mlflow.openai.autolog()

openai_client = openai.OpenAI()

response = openai_client.responses.create(
    model="gpt-4o-mini", input="フランスの首都は"
)
```

トレースできました。

![Screenshot 2025-04-22 at 15.45.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/890629e5-d669-406f-aef0-41cd9c3c8bc2.png)

# 画像の分析

```py
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-4o-mini",
    input=[
        {"role": "user", "content": "この画像に写っているチームは何ですか？"},
        {
            "role": "user",
            "content": [
                {
                    "type": "input_image",
                    "image_url": "https://upload.wikimedia.org/wikipedia/commons/3/3b/LeBron_James_Layup_%28Cleveland_vs_Brooklyn_2018%29.jpg"
                }
            ]
        }
    ]
)

print(response.output_text)
```
![Screenshot 2025-04-22 at 15.46.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/4a0426f1-8f2e-4b86-9514-14d4578227eb.png)

# Web検索

```py
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-4o-mini",
    tools=[{"type": "web_search_preview"}],
    input="今日のポジティブなニュースストーリーはなんですか？"
)

print(response.output_text)
```
![Screenshot 2025-04-22 at 15.47.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/21dd3bd3-01b2-4d6a-a10c-af528f3b0ed0.png)

# 会話の履歴

```py
from openai import OpenAI
client = OpenAI()

response = client.responses.create(
    model="gpt-4o-mini",
    input="こんにちは。弥生 隆明と言います。"
)

print(response.output_text)
```
![Screenshot 2025-04-22 at 15.47.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/bb04a664-1676-44f0-95f4-aa4add26253d.png)
![Screenshot 2025-04-22 at 15.47.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0a1766f6-4e68-4ae7-9b05-b390847a744c.png)

```py
response = client.responses.create(
    model="gpt-4o-mini",
    input="私の名前は",
    previous_response_id=response.id,
)

print(response.output_text)
```
![Screenshot 2025-04-22 at 15.48.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ef7f4570-4ae5-452b-b18e-39d5828b6fdc.png)
![Screenshot 2025-04-22 at 15.48.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a5b1dc6a-9244-485e-943d-36c08f28400d.png)

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
Gradle の Version Catalogs を使っているプロジェクトをローカル参照する

:::note info
実行環境
- gradle-8.11.1
:::

Android アプリ開発で Gradle の [Version Catalogs](https://docs.gradle.org/current/userguide/version_catalogs.html) を使用していると、同じく Version Catalog を使用している Android のプロジェクトをローカルで参照したときにエラーが発生します。

```shell
e: file:///Users/[user.name]/AndroidStudioProjects/[application]/build.gradle.kts:3:24: Unresolved reference: [library.name]
e: file:///Users/[user.name]/AndroidStudioProjects/[application]/build.gradle.kts:7:24: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: 
```

これは例えば、アプリを開発しているプロジェクトから、別のプロジェクトで開発されているライブラリをローカル参照したときに発生します。

# 対応策

対応策として、プロジェクトごとに Version Catalog の参照名を変更します。

まず、参照元のプロジェクトでは以下の資料を参考に `libs.versions.toml` ファイルで依存バージョンを管理しているとします。

https://developer.android.com/build/migrate-to-catalogs

この場合、参照先のプロジェクトでも `libs.versions.toml` ファイルで依存バージョンを管理しようとすると、ローカル参照したときに参照名が競合して上記のエラーが発生します。

そこで、toml ファイルを任意の名前（ここでは `sample.versions.toml` とします）に変更し、以下の変更を追加します。

```settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        // 参照名を toml ファイルの名称と同じにする必要は無いが、同じであるほうがわかりやすい。
        create("sample") {
            from(files("gradle/sample.versions.toml"))
        }
    }
}
```

```app/build.gradle.kts
plugins {
    // 参照名をすべて libs.~ から sample.~ に変更する
    alias(sample.plugins.android.application)
    ...
}
```

これで Version Catalog の参照名が競合することは無くなりました。

ただし、`sample.versions.toml` でバージョン管理しているプロジェクトをローカル参照する場合は、以下の設定を「**参照元**」のプロジェクトに追加する必要があります。

```settings.gradle.kts
dependencyResolutionManagement {
    versionCatalogs {
        create("sample") {
            from(files("../[参照するプロジェクト名]/gradle/sample.versions.toml"))
        }
    }
}
```
depcheckを使った未使用パッケージのチェックと.depcheckrc.jsonによる除外設定

# ✅ はじめに

プロジェクトが大きくなると、依存パッケージがどれだけ使われているかを把握するのが難しくなってきます。  
特に `package.json` に記載された依存の中で、「実際に使っているもの」と「すでに不要になっているもの」を見分けるのは手間がかかります。

そんなときに便利なのが [`depcheck`](https://www.npmjs.com/package/depcheck) です。

`depcheck`は、プロジェクトにインストールされたパッケージの中で、使われていないもの(未使用の依存)を検出してくれます。

# 🚀 `depcheck` の基本的な使い方

まず、`npx`を使って簡単に実行できます。

```bash
npx depcheck
```

これで、`package.json`に記載されている依存のうち、コード上で使用されていないものをリストアップしてくれます。

# ⚠️ 注意点：実際は使っているのに「未使用」と判断されるケース

`depcheck`は静的解析に基づいてチェックを行うため、以下のようなケースでは**誤検出**されることがあります：

- 動的な`require()`や`import()`
- 設定ファイルの中でのみ使用されているパッケージ

こういった**「使ってるのに未使用扱いされる」**パッケージを除外したいときに便利なのが、`.depcheckrc.json` です。

# 🛠 `.depcheckrc.json` で除外設定を行う

プロジェクトのルートに `.depcheckrc.json` を作成し、以下のように記述します：

```json
{
  "ignores": [
    "express",
    "dotenv"
  ]
}
```

この設定により、`express`や`dotenv`などの依存が、未使用であっても`depcheck`の出力から除外されます。

# 📝 まとめ

- `npx depcheck`で未使用パッケージをチェックできる  
- `.depcheckrc.json`で、実際は使っている依存を除外可能  
- 静的解析の限界を補うために、手動での除外設定が重要
文字列存在チェック

文字列内に指定文字列が存在するかチェックする
# 文字列存在チェック
## 引数情報指定
~~~
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' 文字列存在チェック
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' 文字列存在チェック（引数情報指定）
'------------------------------------------------------------------------------
Public Function F_String_Check_Inf( _
        ByRef aArgInf As T_STRING_ARG_SEARCH_INF) As Boolean
    Dim wkRtn As Boolean
    
    Dim wkTmpAryAry As Variant
    
    F_String_Check_Inf = F_String_GetSearchInfArray_Inf(wkTmpAryAry, aArgInf)
End Function
~~~
## 引数指定
~~~
'------------------------------------------------------------------------------
' 文字列存在チェック（引数指定）
'------------------------------------------------------------------------------
Public Function F_String_Check( _
        ByVal aTarget As String, _
        Optional ByVal aSearch As String = "", Optional ByVal aSrchSpec As E_STRING_SPEC = E_STRING_SPEC_MATCH_MID, Optional ByVal aSrchPtn As String = "") As Boolean
    Dim wkArgInf As T_STRING_ARG_SEARCH_INF: wkArgInf = G_String_InitArgSrchInf()
    
    With wkArgInf
        .Target = aTarget
        
        .Search = aSearch
        .SrchSpec = aSrchSpec
        .SrchPtn = aSrchPtn
    End With
    
    F_String_Check = F_String_Check_Inf(wkArgInf)
End Function
~~~
## 単語存在チェック（引数指定）
~~~
'------------------------------------------------------------------------------
' 単語存在チェック（引数指定）
'------------------------------------------------------------------------------
Public Function F_String_CheckWord( _
        ByVal aTarget As String, _
        Optional ByVal aSearch As String = "", Optional ByVal aSrchSpec As E_STRING_SPEC = E_STRING_SPEC_MATCH_MID, Optional ByVal aSrchPtn As String = "", _
        Optional ByVal aChkPtn As String = D_STRING_MATCH_CHECKWORD, Optional ByVal aChkSpec As E_STRING_SPEC = E_STRING_SPEC_MATCH_ALL) As Boolean
    Dim wkTmpAryAry As Variant
    
    F_String_CheckWord = F_String_GetSearchInfArrayWord(wkTmpAryAry, aTarget, aSearch:=aSearch, aSrchSpec:=aSrchSpec, aSrchPtn:=aSrchPtn, _
                                                        aChkPtn:=aChkPtn, aChkSpec:=aChkSpec)

End Function

~~~
個人的備忘録：Next.js × App Routerの基本構成とよく使うファイルたちを整理してみた

## はじめに
本記事では、Next.js を使用したフロントエンドプロジェクトの典型的なディレクトリ構成について解説します。

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

DockerやTypeScript、ESLintなどを活用した、実用的なプロジェクト構成をもとに、それぞれのファイルやフォルダが担う役割について整理していきます。

## 書こうと思ったきっかけ
チーム開発や学習の中で「この構成ってどんな意味があるの？」と疑問を持つことが多かったため、自分自身の理解の整理と、これからNext.jsを始める方に向けた備忘録としてまとめようと思いました。

## ディレクトリ構成
```
frontend
├── docker-compose.yml
├── Dockerfile
├── eslint.config.mjs
├── Makefile
├── next-env.d.ts
├── next.config.ts
├── node_modules
├── package-lock.json
├── package.json
├── postcss.config.mjs
├── public
│   ├── file.svg
│   ├── globe.svg
│   ├── next.svg
│   ├── vercel.svg
│   └── window.svg
├── pull_request_template
├── README.md
├── src
│   └── app
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx
│       └── page.tsx
└── tsconfig.json
```

## 各ファイル・ディレクトリの役割

### ルート直下のファイル
- **docker-compose.yml**: 複数サービスを同時に立ち上げるDocker構成ファイル
- **Dockerfile**: アプリケーションのビルド手順を定義
- **eslint.config.mjs**: コードスタイルチェック用の設定
- **Makefile**: 開発用コマンドをまとめたファイル（例：make build）
- **next-env.d.ts**: Next.js固有の型補完用ファイル（自動生成）
- **next.config.ts**: Next.jsのカスタマイズ設定
- **node_modules/**: インストール済みのnpmパッケージ
- **package.json / package-lock.json**: パッケージ管理ファイル
- **postcss.config.mjs**: PostCSSの設定ファイル（Tailwindなど）
- **pull_request_template**: GitHubのPRテンプレート
- **README.md**: プロジェクト説明用ドキュメント
- **tsconfig.json**: TypeScriptのコンパイル設定

### public/
- 静的ファイル（画像、アイコンなど）を格納する場所。URLで直接アクセス可能。

### src/app/
- **favicon.ico**: サイトアイコン
- **globals.css**: 全体スタイルを定義
- **layout.tsx**: 全ページ共通のレイアウト
- **page.tsx**: トップページのエントリーポイント

## 特徴
| 特徴             | 内容                                           |
|------------------|------------------------------------------------|
| TypeScript対応    | `.ts`や`.tsx`の使用                         |
| App Router構成   | `src/app/` 配下に `page.tsx` と `layout.tsx` |
| Docker対応        | `Dockerfile` と `docker-compose.yml`         |
| ESLint + PostCSS | `.config.mjs` による設定                     |
| Makefile活用      | コマンド簡略化のためのスクリプト定義         |

## まとめ
このような構成は、開発・テスト・本番環境を見据えたNext.jsプロジェクトとして非常に実践的だと思っています。

:::note warn
特にDockerやMakefileが組み込まれている点は、チーム開発やCI/CD導入にも適しており、保守性・再現性の高い開発基盤を構築できるのでおすすめです...！
:::

今後プロジェクトを始める際や、他のリポジトリを参考にする際の判断材料になれば幸いです。
CI-03T 声紋認識

#### 初めに
M5Stack Unit ASR から取り出したCI-03Tで色々試してみます。
CI-03T では声紋登録も可能ということなので試してみました。

#### プログラム作成
CI-03Tでは容量オーバーでエラーとなりました。
そこで、４M FLASHの CI-33T で作成します。
中国語版を参考に日本語で作成しました.
しかし CI-03Tしか手元ににないので ASRPRO 4M版に書込むことにします。
（CI-03T実装のCI-1302とASRPRO 2Mチップが同等と思われる為）
問題なく書込み完了で 早速、動作確認してみました。
声紋認識する単語は"明かりを点けて"、"明かりを消して"、"こんにちは"の
３語としました。
まずは、この３語の声紋登録を行います。
同じ単語を指示に従って３回言って登録します。
登録完了するまでは、この３語は音声認識対象とはなっていません。
登録後に登録本人がワードを言うと認識されます。　
認識には少し間があります。
他の人で試したいのですが いないので VOICEVOXで音声出力してみます。
男女の声で試しましたが応答なしです。　その後、本人が言うと応答します。
声紋登録していない他のワードは男女関係なく普通に認識されます。
どの程度、厳密に判別されるのかは不明ですが とりあえず動作確認できました。

#### 動作確認の動画
https://youtu.be/7FR37OXAsrw

#### 最後に
一応、動作確認はできましたが この機能（声紋認識）は別途 ライセンス購入が必要なようで、５分毎にリセットがかかります。
試用以外で使用される場合は、メーカーに問い合わせてください。
また、正規の CI-33T（CI-1303）を使用してください。

#### メーカーサイト
チュートリアルとサンプルファームウェア
https://help.aimachip.com/docs/tutorials-and-sample-firmware/tutorials-and-sample-firmware-1ga9t3gqldbts
声紋認識
https://help.aimachip.com/docs/question/question-1fu2u6b408fn6

#### 音声認識モジュールの入手先
CI-03T （2㎜ → 2.54㎜ピッチ変換基板もあり）
https://www.aitendo.com/product-list/1259
ASRPRO  
https://ja.aliexpress.com/w/wholesale-ASRPRO.html?spm=a2g0o.home.search.0
Laravelの「@verbatim」って何

# `@verbatim`ディレクティブとは
Laravelの公式リファレンスは以下の通り

> テンプレートの大部分でJavaScript変数を表示している場合は、HTMLを@verbatimディレクティブでラップして、各Bladeエコーステートメントの前に@記号を付ける必要がないようにできます。

```php
@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim
```
https://readouble.com/laravel/8.x/ja/blade.html

# どこで使うん？
bladeの構文と被る可能性のあるVue.jsとかの構文（特に`{{ }}`）を使うために使う。

Vue.jsなどのjsフレームワークでは、bladeでも使う`{{ }}`を、変数の表示で使う。
bladeテンプレートにVueで`{{ }}`を書いたりすると、Vueが解釈する前に（HTMLの要素になる前に）これをbladeの処理で解釈しようとして、意図しない挙動やエラーが起きたりする。
ここで`@verbatim`の出番。
`@verbatim`で囲まれた部分はbladeテンプレートの処理が無効になるので、そのままHTMLとして出力される。
で、ブラウザに渡された後、Vue.jsが`{{ }}`の部分を解釈して正しく表示する、という流れになる。

例：
```php
@verbatim
  <p v-for="message in errorMessages" class="error">
    {{ message }}
  </p>
@endverbatim
```


# ついでに
こういう、ピンと来ない・見たことない言葉に出会ったら意味を調べるようにしている。
言葉の意味がわからないと一生覚えられないので。
暗記はしないけど、こんなのあったなーって頭の片隅に置いておきたい派です。

https://eow.alc.co.jp/search?q=verbatim

### 「verbatim」の意味
> 一語一語、逐語的に、文字どおりに

という意味らしい。へぇ〜

### 読み方
「ヴァーベイタム」らしい。へぇ〜
個人的備忘録：git pull の出力メッセージ、ちゃんと読めたらちょっと成長できた気がした

## はじめに
この記事では、Git 初学者向けに「`git pull` コマンドを使った際に表示されるメッセージ」の意味について、具体的な例を交えて解説します。

## 書こうと思ったきっかけ
チーム開発中に「`git pull` をしたけど何も変わらなかった」という場面に遭遇し、その理由がわからず戸惑うケースがよくあります。

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

そのような初心者の方に向けて、出力内容の読み解き方をわかりやすくまとめました。

## 実行したコマンド
```bash
git pull origin main
```
このコマンドは、リモートリポジトリ（`origin`）の `main` ブランチから最新の変更を取得し、自分のローカルの `main` ブランチに反映させるものです。

## 実行結果の解説
```text
Warning: Permanently added 'github.com' (ED25519) to the list of known hosts.
```
- 初めて `github.com` にアクセスしたときに出る警告です。
- GitHub のホスト鍵を信頼済みリストに追加したことを意味します。
- 通常、1回だけ表示されます。

```text
From github.com:2025SpringTeamA/frontend
 * branch            main       -> FETCH_HEAD
Already up to date.
```
- `github.com` 上の `2025SpringTeamA/frontend` リポジトリから `main` ブランチの内容を取得しています。
- `Already up to date.` は、ローカルの内容がすでにリモートと一致しており、**新しい変更がない**ことを示します。

## まとめ
- `git pull` をしても "Already up to date." と出た場合、リモート側に新しい更新がないことを意味します。
- このメッセージはエラーではなく、**最新の状態を保っている**という安心のサインです。
- 今後、他のメンバーが `main` に変更を加えた場合に再度 `git pull` をすると、差分が取り込まれます。

初めのうちは出力メッセージに戸惑うこともありますが、一つ一つの意味を理解していけば、自信を持って Git 操作ができるようになるかと思います...！
生成AIで作成する5G システム関連ドキュメント

生成AIを活用して作成された、5Gモバイル通信ネットワークおよび3GPP仕様に関する一連の技術ドキュメントです。

## 📘 1. 生成AIで作成する5Gシステムの説明  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/a58f779ffa64c803d519)  
5Gシステムの全体像、構成要素（UE, gNB, 5GC）について、生成AIを用いて体系的に説明した記事です。

## 📘 2. 生成AIで作成する3GPPの詳細説明  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/1a832e5103a6bf6d308a)  
3GPPとは何か、標準化の流れとその役割、リリース構造について生成AIを用いて解説する内容です。

## 📘 3. 生成AIで作成する3GPP 5G NR技術仕様の読解ガイド  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/2128507c6b5181ce6df8)  
5G NR仕様書をどう読解すべきか、仕様間の関係性や読み解く際のポイントを生成AIを用いてガイド形式で紹介します。

## 📘 4. 生成AIで作成する3GPPの技術仕様書から5Gシステム装置を開発する困難性の説明  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/78480ae99cf488657211)  
仕様書からの直接開発における課題、自然言語の曖昧さ、解釈の差異について生成AIを用いて詳しく記述しています。

## 📘 5. 生成AIで作成する5GシステムへのAIの適用と開発環境へのAIの導入の推測と説明  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/6d6b103db3b852d9cd21)  
AIが5G開発工程（設計・テスト・運用）にどう適用されつつあるのか、今後の方向性について推測を交えた内容です。

## 📘 6. 生成AIで作成する5Gインフラ装置の汎用ハードウェア利用状況の推定  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/3aa0f24a15c023e4dc03)  
5Gネットワーク機器における汎用ハードウェア（PC、サーバーなど）利用の現状と傾向を、生成AIを通して読み解きます。

## 📘 7. 生成AIで作成する5GシステムのUEとgNBのインターフェースの概要  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/20e2000a3033ef8df7f0)  
UEとgNBのインターフェース利用の現状と傾向を、生成AIを通して読み解きます。

## 📘 8. 生成AIで作成する5GシステムのNG-RANと5GCのインタフェース概要  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/e63285b1380f1266b777)  
NG-RANと5GCのインタフェース利用の現状と傾向を、生成AIを通して読み解きます。

## 📘 9. 生成AIで作成する5Gシステムと監視・管理・運用システムのインタフェース概要  
[🔗 記事を読む](https://qiita.com/InvisibleSmartphone/items/8462e39b66e8a2697684)  
5Gシステムと監視・管理・運用システムのインタフェース利用の現状と傾向を、生成AIを通して読み解きます。

---

今後もこのシリーズは継続してアップデート予定です📡✨

---
ProxmoxVEというサービスに出会う


前回までの内容

https://qiita.com/shimeji_k/items/8677daa0b06ec16d4454


そもそも当人の知識が浅い！！

## サーバーやネットワークの知識
そもそも、自宅サーバーの知識なんて全然ないしネットワークの知識もなにもない。

仮想環境で知っていることといえば、
VirtualBoxでLinux入れて遊んだり
ローカルのWSL2にGitbucketを入れてソース管理したり
MacのParallelsにWindows7いれたり
DockerでMySQLたててSlowQuery解消の練習したり

ネットワークもVPNはかろうじて薄くしってる
自宅のルーターでVPN設定して外から入ってファイルを取り出すとか？
L3スイッチでポートVLANがわかるくらい？

そんな程度

## Linuxに対する知識
ものすごく昔VineLinux（Kernel2.2時代）で遊ぶ
その後Fedora（Kernel2.4）でファイル共有サーバーを作る。

あとは、CentOS6～7で遊んだり
AWSのAmazonLinunxで遊ぶ程度の知識

あとはHighPointのRocketRAIDを動かすためにmake installしてきただけ

かろうじてミドルウェア入れたり設定できたりコマンドがわかるかな？程度

## ハードウエア知識
昔オーバークロックにハマっていたときに
PCIクロックに依存してATAデータが吹っ飛んだりしないように
SCSIカードに依存していたのでレガシーSCSIはわかる（U2W160？）SmartArray6404
普通の人が作らない環境で自作PCを作る
TyanのマザボでDualCPU環境を構築
でもしばらく自作もしていなかったので現在の志向がわからない

## なぜProxmoxを知った？
どっかの現場で
ESXiとかOpenStackとか聞いたことあったからちょっと検索してみようかと検索してProxmoxVEというものが引っかかる
ちょっと使ってみようという気になる

## Proxmox面白いかも？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/b40bbd8c-e40f-40e9-9f1e-c237f4260546.png)
NASがほしいけどお金がない！
じゃぁProxmoxVEにTrueNASをインストール
仮想環境にインストールするのこんなに楽になっているか！と感動

## よくわからない用語があるぞ？
ZFSとかCephってよくわからない用語がでてくる
なんだコレ？
LVMはLogical Volume Managerだから普通の記憶領域ということなのね

## ZFSってなんだろう
そもそもZFSとはなんだ？
TrueNASにもあったけど
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/933e1306-0c6f-4be1-b427-6dc5b47bb58e.png)

https://ja.wikipedia.org/wiki/ZFS
ファイルシステムということが初めて分かる
これって作成画面だとRAID構築するということはソフトウェアストレージコントローラー？
なるほど、ハードウェア依存しなくてもいけるとはこれはお買い得かも

でも、BBUとかないしキャッシュは？？？
レガシー脳だとどうしてもハードウェアRAID最強説になってしまう。

## ProxmoxVEインストール
いろいろな箇所でインストールメディア（USBメモリ）の作り方書いているので割愛
Rufusにて作成
https://rufus.ie/ja/

やった設定
* ProxmoxVEのOS領域　1.5kのSAS HDD*2 をRAID1で構築
* LVM領域を1.5kのSAS HDD*6 にてRAID5にて構築
* インストール後、アップデートを無償リポジトリにする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/54b8ba8d-a48f-45f6-bc35-bdd6cd3dc8c8.png)
* LVM用の記憶領域を追加（RAID5で構築したやつ）

## ProxmoxVEでなんか動かしてみる
ノードのProxmoxにlocalというものがあるのでここにインストール用のISOイメージを置くことができてマウントできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/656fe47a-7319-4b74-9ff5-61a38b7be5bf.png)

作成を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/6ffbc378-9b69-4560-b3e3-d80cf70359fe.png)
OSの設定とISOを選んで
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/e51f5cf8-bae0-425f-908e-38abcb594369.png)
基本システムはそのままで良いと思う

インストール無事終了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/5e686f98-4fa1-4bb3-934c-373db0efdbdf.png)

CPUのコアやメモリの割当も自由にできるのでこれは便利

そして、RustゲームサーバーもProxmoxVE上でつくってみる！

次回

https://qiita.com/shimeji_k/items/13f45d4556ca028e51a6
インフラエンジニアでもなんでもない人がゲームサーバーを立てて遊ぶ

## なぜ至ったのか？
Rustというゲームを始めたのがきっかけ。
PvEでしばらく遊んでいたけど、なんかRustじゃない気がして公式に行くんだけどやっぱりなんにもできない！

コミュニティサーバーは数あれど、
NPCが弱かったり、取れる資材が多いなど
不便を楽しむって感じではなかった。

あるサーバーで遊んでいると家の周りにボスが湧いて何もできずに殺されまくって萎え。。。

## じゃぁどうするの？
自分でサーバー立てればいいんじゃない？
じゃぁやってみよう！の思いつき

機材も色々転がってる。


## いまどんなかんじ？
ゲームサーバー立てて今に至るが
構成を変えたいとか考え始めたので現状の整理からやっていこうと思う。

やってきたこと
* Linuxサーバーを立てる
* ローカルで遊ぶ
* 適当に公開してみる（ただし人ふやしたくないから内緒で）

## やってきた問題点
管理しづらい
落ちやすい
別サーバーへの移行がめんどい

## 理想
ネットワーク間を整理したいのと、監視を充実させたい。
転がっている機材を有効活用したい！


なお以下は自分用の記憶と記録、日記。
## 第1弾（ローカル）
とにかく、周りに邪魔されないバニラな環境をローカルにつくる。
* 転がっているサーバーに4台HDDを入れる
* 家に転がっていたサーバーにCentOS8を入れる
* LinuxGSMを利用してゲームサーバーをインストール
* client.connect 192.168.10.200:28015
うごいた！
![第一弾.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/f5f751b7-060d-4336-990f-9244661f854c.png)


## 第2弾（外部から接続をやってみよう！）
* 固定IPを持っているのでRTX1200で独立したネットワークを作成
* HDDを8台RAID5にして余裕をもたせた構成
* OS再インストールしてLinuxGSM（割愛）。。
* client.connect xxx.xxx.xxx.xxx:28015
![第一弾-第二弾.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/db007279-0b63-4ea4-a116-03adf5367cf1.png)

じつはこの時点でコミュニティサーバー一覧に表示されているが本人は気づいていない。 

## 第3弾（外部から誰か入ってきてる？）
* 外部からの接続なのにサーバー一覧に出てこないから安心してそのまま2週間ほど遊ぶ。
* 一人のハズなのになぜか？自分の知らない家が建ってる？？

ようやく、外部に公開されていると気づくw
まぁ、このまま少し遊んでみるか。。。

## 第4弾（Proxmoxとはなんぞや？）
* サーバー何故かNODEがふたつあるのにNODE1台稼働もったいない。。。
* ProxmoxVEという面白そうなものがある！
* インストール
* これはおもしろいかも？
![第一弾-第四弾.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4067323/6a404047-49cb-46db-a802-014aa9041c2a.png)

Proxmoxって最強じゃない？
ここからサーバー勉強の泥沼に嵌まる


次回

https://qiita.com/shimeji_k/items/1f4fc0222243587fd5fb
PythonでQRコード認証(TOTP)を実装する

# はじめに
Pythonを使ったwebアプリにQRcodeを使用したTOTP「Time-based One-Time Password（時間ベースのワンタイムパスワード）」認証を導入する手順を簡潔にまとめてみました。
まだ実装したことがない方の参考になれば嬉しいです。
（ユーザー登録・パスワード認証は実装されている前提で進めさせていただきます）




# 1.　必要なライブラリをインストール
`pip install pyotp`　（ワンタイムパスワードを生成・検証するためのライブラリ）
`pip install qrcode`　（QRコードを生成するライブラリ）


「requirements.txt」を使用する場合は、
```python:requirements.txt
pyotp
qrcode
```

```python:Dockerfile
COPY requirements.txt .
RUN pip install -r requirements.txt
```



# 2.　カスタムユーザーモデルにtotp用フィールドの追加
Django には標準で User モデルが用意されています（django.contrib.auth.models.User）が、
認証周りを細かくカスタマイズしたい場合、AbstractBaseUser を継承して自分で定義する必要があります。

```python:accounts/models.py
from django.contrib.auth.models import AbstractBaseUser

class User(AbstractBaseUser):

    # TOTP用のシークレットキーを保存するフィールドを追加
    totp_secret = models.CharField(max_length=32, blank=True, null=True)  

    # TOTP用のシークレットキーを生成する関数
    def generate_totp_secret(self):
        self.totp_secret = pyotp.random_base32()
        self.save()

    # ユーザーのTOTPコードを検証する関数
    def verify_totp(self, totp_code):
        if not self.totp_secret:
            return False
        totp = pyotp.TOTP(self.totp_secret)
        return totp.verify(totp_code)
```




# 3.　QRcodeを表示する
各ユーザーがパスワード認証を突破したタイミングで、そのユーザーが持つシークレットキーから生成されたQRcodeを表示します。
```python:accounts/views.py

from django.contrib.auth import get_user_model

User = get_user_model()

def generate_qr(request, username):
    user = User.objects.get(username=username)

    # まだTOTPが設定されていない場合、新しいシークレットを生成
    if not user.totp_secret:
        user.generate_totp_secret()

    totp = pyotp.TOTP(user.totp_secret)
    totp_uri = totp.provisioning_uri(name=user.username, issuer_name="YourAppName")

    # QRコードを生成
    qr = qrcode.make(totp_uri)
    buffer = BytesIO()
    qr.save(buffer, format="PNG")
    buffer.seek(0)

    return HttpResponse(buffer.getvalue(), content_type="image/png")
```


```python:accounts/urls.py
from django.urls import path
from . import views

app_name = "accounts"

urlpatterns = [
    path('generate_qr/<str:username>/', views.generate_qr, name='generate_qr')
]
```


```html:qrcode.html
<img id="qrCodeImage" src="" alt="Scan this QR code with Your MFA App">
```


```js:myLogin.js
let qrImage = document.getElementById("qrCodeImage");
let qrUrl = `/accounts/generate_qr/${username}/`;
qrImage.src = qrUrl;
```



# 4.　入力codeのバリデーション

入力フォームなどから受け取ったcodeを検証し、認証が成功すればログイン処理に進めます。

```python:accounts/views.py
def totpLogin(request):
    username = request.POST.get("username")
    user = User.objects.get(username=username)

    totp_code = request.POST.get("totp_code")
    totp_code = int(totp_code)

    if not user.verify_totp(totp_code):
        return HttpResponseForbidden("Invalid TOTP code")  # 認証失敗

    login(request, user)
```








# おわりに
今回はTOTPの実装部分だけをぎゅっとまとめて紹介しました。
意外と少ないコードで実装できるんだなと驚きました。

実際に認証機能として実装する際は、
・フォーマットのバリデーション/エラーハンドリングの追加
・ユーザーが設定画面からTOTP機能をON/OFFできるようにする
・上記のタイミングでtotp_secretをリフレッシュする
・MFA App（認証端末）側でtotp_secretを削除してしまった場合のバックアップ方法
などが必要になるかと思います。


認証まわりに関連して、JWT(JSON Web Token)を導入する記事も書きましたので、ぜひそちらも合わせて御覧ください！
[PythonでJWT認証を実装する](https://qiita.com/j-yasukawa/items/3695e15071594e95c9d6)