OmniAICreator/Qiita-1.07M huggingface dataset:
個人アプリ備忘録：勤怠管理システムのLDAP認証フローについて、体系的にまとめてみた

## はじめに
勤怠管理システムのログイン時に、LDAP (Active Directory) を使った認証を行うフローについて整理します。

システムを設計・実装する際の参考として、備忘録を残します。

## 書こうと思ったきっかけ
LDAP認証を導入するにあたり、認証フローや実装方法を明確にする必要がありました。

また、運用やトラブル対応時にも役立つ情報を整理しておきたいと考え、この備忘録を作成しました。

## こんなイメージを想定しています

勤怠管理システムのログイン時に、LDAP (Active Directory) を使った認証を行うフローの備忘録となります。

```
[1] ユーザーが勤怠管理システムにアクセス  
    ↓  
[2] ログイン画面でユーザー名・パスワードを入力  
    ↓  
[3] システムがLDAPサーバー (Active Directory) に認証リクエストを送信  
    ↓  
[4] ADが認証情報を照合し、結果をシステムに返す  
    ├── OKなら → [5] セッションを作成し、ユーザーをダッシュボードにリダイレクト  
    │           ↓  
    │   [6] システムがユーザーの権限情報を取得 (例: 従業員 or 管理者)  
    │           ↓  
    │   [7] ユーザー権限に応じた機能・データが表示  
    │           ├── **従業員** → 勤怠打刻、勤務時間確認、有給申請  
    │           └── **管理者** → 従業員の勤怠データ管理、シフト作成、承認作業  
    ↓  
    └── NGなら → [エラーメッセージ表示: IDまたはパスワードが違います]  
```

**参考サイト**

https://it.impress.co.jp/articles/-/23320

## 認証フロー

1. **ユーザーが勤怠管理システムにアクセス**
2. **ログイン画面でユーザー名・パスワードを入力**
3. **システムがLDAPサーバー (Active Directory) に認証リクエストを送信**
4. **ADが認証情報を照合し、結果をシステムに返す**
    - OKなら → **セッションを作成し、ダッシュボードへリダイレクト**
        - **ユーザーの権限情報を取得 (従業員 or 管理者)**
        - **権限に応じた機能・データを表示**
            - 従業員: 勤怠打刻、勤務時間確認、有給申請
            - 管理者: 従業員の勤怠データ管理、シフト作成、承認作業
    - NGなら → **エラーメッセージを表示 (IDまたはパスワードが違います)**

## LDAP認証の実装ポイント

### LDAPサーバーの接続情報
- **ホスト名/IPアドレス**: `ldap.example.com`
- **ポート番号**: `389 (LDAP)` or `636 (LDAPS)`
- **認証方式**: 平文 or LDAPS (暗号化)
- **Base DN**: `ou=Users,dc=example,dc=com`

### 認証処理
- ユーザー情報の検索 (`sAMAccountName`, `userPrincipalName` など)
- 認証後に `memberOf` で権限取得
- セッション管理

### エラーハンドリング
| ケース | 対応 |
|--------|------|
| ID/PW 誤り | 「IDまたはパスワードが違います」と表示 |
| AD接続失敗 | システムエラーを通知、ログを記録 |
| アカウントロック | 「アカウントがロックされています」と通知 |

## 実装手順

### LDAP認証のセットアップ
**Python の場合 (`ldap3` ライブラリを使用)**
```python
from ldap3 import Server, Connection, ALL

server = Server('ldap.example.com', get_info=ALL)
conn = Connection(server, user='cn=admin,dc=example,dc=com', password='password', auto_bind=True)
```

### セッション管理
- 認証成功後に `session` にユーザー情報を保存
- 期限付きトークンを利用

### 権限に応じた画面制御
```python
if 'Administrators' in user_groups:
    redirect_to_admin_dashboard()
else:
    redirect_to_employee_dashboard()
```

## テスト項目
### 正常系
- 正しいID/PWでログインできるか
- 権限ごとに正しい画面が表示されるか

### 異常系
- 間違ったパスワードでログインできないか
- ADサーバーがダウンした場合の動作は適切か

## 運用ポイント
- **ログの記録**: 認証エラーの原因を特定しやすくする
- **パフォーマンス監視**: LDAP認証の応答速度を定期確認
- **運用マニュアル作成**: 障害発生時の対応手順をまとめる

## まとめ
LDAP認証を導入することで、セキュリティを向上させつつ、組織内でのアカウント管理を統一できます。

実装にはサーバー設定や適切なエラーハンドリングが必要なため、事前に十分な準備を行うことが重要です。テストと運用監視を徹底し、安全に運用できるようにしたいです！

今後も運用しながら、改善点があれば追記していく予定です。
個人的Tips

個人的Tipsまとめ。PHP多め

## PHP Unitの実行コマンド忘れちゃった
```
// 全テストを実行
./vendor/bin/phpunit

// 特定ファイルのpathの指定ができる
./vendor/bin/phpunit {path}

// filterでメソッドの指定もできる
./vendor/bin/phpunit --filter={method name} {path}
```

<br>

## PHP Unitの実行時に「MySQL server has gone away in」のエラーが出る
Fixtureの容量が大きすぎてSQLが実行できていない可能性がある
Mysql側で許容しているパケットの最大値を確認して、増やそう
```
// 確認
show variables like 'max_allowed_packet';

// 変更　↓は16MB
set global max_allowed_packet = 16777216;
```

<br>

## ローカル環境でDBコンテナに接続できない
これはもうやらない？
```
// mysqlコンテナのIPAddressを確認する
// "IPAddress"を控える
docker inspect mysql

// ソース内の接続ホストを書き換える
'host' => env('MYSQL_PORT_3306_TCP_ADDR', 'XXX.XX.X.X'),
```

<br>

## phpunittestの実行がno such file or directoryとなり表示されない
vender/配下のファイルの改行コードがCRLFになっているのが問題？
解決策としては一旦、vender配下の削除をして、インストールし直せば解決する
```
rm -rf vendor/
composer install
composer update
```

<br>

## Jenkins実行時にサーバのスペースが足りない
対象のサーバで下記のコマンドを実行
下記のコマンドで使用していないdockerのイメージ、コンテナ、ボリューム、ネットワークの削除をすることができる
```
docker system prune -af
```

<br>

## VM内でスペース容量が足らなくて困ったら
ゲストOS内で下記のコマンドを実行
```
docker system prune -af
```

<br>

## Mysqlの暗号化・復号化のSQLってなんだっけ
```
// 暗号化
update {table} SET {column} = HEX(AES_ENCRYPT('{value}', '{key}')) where XXXX;

// 復号化
select convert(AES_DECRYPT(UNHEX({column}), '{key}') USING utf8) from {table} where XXXX;
```

<br>

## Mysqlをdumpしたい
```
mysqldump --single-transaction -u {user} -p -h {host} {db} -P {port} > {出力先}
```

<br>

## シンボリックリンクを貼ったり、削除したりしたい
```
// 作成
ln -s {貼る元} {貼る先}
 
// 削除
unlink
```

<br>

## Mysqlで1ヶ月後や、1ヶ月前にデータを更新したい
```
// 1ヶ月後
UPDATE
    Table
SET
    date_at = (date_at + INTERVAL 1 MONTH)
 
// 1ヶ月前
UPDATE
    Table
SET
    date_at = (date_at - INTERVAL 1 MONTH)
```
Web APIシリーズその4(全5回)：一歩先行くHTTP・ヘッダを知ろう


## HTTPのURLとメソッド以外の要素

- ボディ
- ヘッダ：とんでもなく多彩
  HTTPを深く知るには必須の、実に楽しい要素

----
## HTTPヘッダとは
- リクエストとレスポンスそれぞれに存在する
- クライアントからは、リクエストのヘッダで様々な情報を伝える
- サーバからは、レスポンスのヘッダで様々な情報を伝える

----
## ブラウザの挙動
- ブラウザはHTTPレスポンスのヘッダを見て、どう動作するかを判断している
   他のURLにリクエスト投げ直し
   ローカルキャッシュを表示
   ブラウザでは処理できないのでファイルとしてダウンロード
   など・・・

----
## 実際の通信のヘッダ内容を見る
- F12ツールのNetworkタブ
  超！重要！

----
## よく見るヘッダ：content-type
- ボディのデータの形を伝える
- リクエストにもレスポンスにも使う
- APIでは```application/json```を使うのがデファクト
- たまに```multipart/form-data```や```application/x-www-form-urlencoded```を見かける（特にリクエスト）

----
## よく見るヘッダ：X-Api-Key
- APIキーを設定する場合によく用いられる
- content-typeと共に、プログラマが頻繁に設定するHTTPヘッダ

----
## キャッシュに関するヘッダ：ETag
- Etagの値が同じの場合はコンテンツに変化がない！
  →初回はボディと共にETagを返してもらう
  →２回目以降はETagの値のみ要求
  →値が変わっていなければキャッシュを使ってよいということになる
  →値が変わっていれば改めてコンテンツを取得「

----
## 大きなファイルを扱う際：Range
- コンテンツの何バイト目から何バイト分欲しい、というリクエスト
- 対応していないサーバもある
- 動画のストリーミング再生で有用

事例）iOSアプリでのローカルWebサーバ
Rangeに対応しているライブラリでないと動画再生が出来なかった！

----
## 圧縮アルゴリズムの指定：Accept-Encoding

- content-typeに指定された形式のデータを圧縮してボディに収めることが出来る
- gzipが一般的な気がする

----
## 最後に
- HTTPヘッダは非常に多彩でとてもではないが語りきれない
- APIを呼び出すときに、ヘッダに要件がある場合がある
  ヘッダについて少しでも知識があると、呼び出しがうまくいかない場合の解決の糸口になるケースがある
VS CodeでFreeBSDにリモート接続

WordPressを設置することになり、SFTPのアカウントを作ってもらったのでVS Codeでリモート接続しようとしたら繋がらない。Terminalでsshすると接続できるのだけど、VS Codeのリモート接続だとエラーが出てしまう。

```
[12:10:43.585] WARN: $PLATFORM is undefined in installation script output.  Errors may be dropped.
[12:10:43.586] Failed to parse remote port from server output
[12:10:43.586] Terminating local server
[12:10:43.587] > 40099
[12:10:43.590] Resolver error: Error: 
	at y.Create (/Users/[username]/.vscode/extensions/ms-vscode-remote.remote-ssh-0.117.1/out/extension.js:2:739050)
	at t.handleInstallOutput (/Users/[username]/.vscode/extensions/ms-vscode-remote.remote-ssh-0.117.1/out/extension.js:2:737131)
	at e (/Users/[username]/.vscode/extensions/ms-vscode-remote.remote-ssh-0.117.1/out/extension.js:2:789804)
    ....
[12:10:43.597] ------

[12:10:43.597] No hints found in the recent session.
[12:10:43.600] Local server exit: 15
```

$PLATFORMが怪しいのではないか、ログイン後のシェルの設定がおかしいのではないか、などとGPTは言うのでssh越しに.profileや.shrcを編集してみたがどうにもうまく動かない。

結論から言うとVS CodeのRemote SSHは単なるクライアントではなくて、VS Codeサーバーをインストールするものなので、VS CodeがサポートしていないFreeBSDでは動作しないということなのだ。

- [Remote Development using SSH](https://code.visualstudio.com/docs/remote/ssh) VS Code公式Webサイト

標準がダメならサードパーティー、というわけで探してみるといいものを見つけた。

- [SSH FS](https://marketplace.visualstudio.com/items?itemName=Kelvin.vscode-sshfs) Visual Studio Market Place

Fuseを使うfuse-sshfsではなく、sshの出力をVS Codeで利用するプラグイン。VS Codeが対応していなかったり、ポートフォワーディングが動かなかったりするサーバーに繋ぐときは有効だと思う。少なくともFreeBSDに繋ぐのには役に立った。これは後から見つけたんだけど、チュートリアルを日本語で書いてくださる方もいた。

- [Visual Studio CodeでSSHごしにファイルを編集する](https://qiita.com/informationsea/items/5c9f05c81a41fb885460)
プランニングポーカーで見積りする

## はじめに
現場でプランニングポーカーを利用して、工数を出していたのでやり方をまとめてみます。
<br>

## プランニングポーカーとは
wiki( https://en.wikipedia.org/wiki/Planning_poker )によると

Planning poker, also called Scrum poker, is a consensus-based, gamified technique for estimating, mostly used for timeboxing in Agile principles. In planning poker, members of the group make estimates by playing numbered cards face-down to the table, instead of speaking them aloud. The cards are revealed, and the estimates are then discussed. By hiding the figures in this way, the group can avoid the cognitive bias of anchoring, where the first number spoken aloud sets a precedent for subsequent estimates.

プランニングポーカーは、スクラムポーカーとも呼ばれ、コンセンサスに基づく、ゲーミフィケーションによる見積もり手法である。プランニングポーカーでは、グループのメンバーは、声に出す代わりに、数字の書かれたカードを伏せてテーブルに出して見積もりを行う。カードが公開され、見積もりが議論される。このように数字を隠すことで、グループは最初に声に出して話した数字がその後の見積もりの前例となる、アンカリング（一番最初に受け取った情報にその判断を大きく影響されてしまうこと）の認知バイアスを避けることができる。

<br>

## 詳しくは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942091/ac2fb315-32cb-43bd-9f26-8b5ac68bb2b0.png)
<出典元> https://kawaguti.hateblo.jp/entry/20120218/1329524230

<br>

## 前提・事前準備
1\. どこの部分を扱っているのか
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3942091/1dfeeea5-5098-4865-a25b-73ad39f19c28.png)
<br>
2\. 基準となる作業を決める
プランニングポーカーは基準となる作業に対して、相対的にどれぐらいになるかを議論していくのでまずは基準となる作業を決める。
現場では新しい画面を作成する際の工数を"2"として、チームの共通認識にしていました。
<br>
3\.タスクの洗い出し
議論をしている最中にタスクが増えることもあるので、ざっと全体的なタスクの洗い出しをする。このタスク単位でカードを出して話する。
<br>
4\.参加者への連絡
参加者へプランニングポーカーを実施することを共有。
テックリーダーと非エンジニアのマネージャなどを含めて4人くらいでやると複数の観点が得られると思います。

## どう進めていたのか
### 1\. 案件・タスクの概要説明
関係者に案件全体と洗い出した各タスクの概要を説明する。
ファシリテーター（進行役）はタスクを洗い出した人がやるとスムーズ
実装レベルの話になると細かい話が多くなるので、全体を俯瞰してみることを意識すること。

### 2\. 各タスクに対して、各々の情報共有
カードを出す前に持っている情報を出し合う。
各々が持っている前提知識・情報は異なるのでここで言葉の扱いや粒度、知識レベルをできるだけ揃えておく。

### 3\. カードを出して、相対的なポイントをきめる
洗い出された情報をもとにカードを出す。使うカードは「1,2,3,5,8,13」あたりまで。
「21」以上になる場合は、そもそもタスクを分けたほうが扱いやすい。
個人的には上記の数字にとらわれず、「5.5」とか細かくすると割とうまくまとまる印象だった。

基準となるのはチームとしてポイントを「2」として認識している作業。
これを基準にどれくらい倍のポイントになりそうか、カードを出す。

### 4\. 上記を繰り返す
1-3までの作業を3回ほど繰り返し、全タスク分の工数のすり合わせを行っていく。
全員の数字が合えばそこで終了。
揃わない場合は、そろわない人同士の間あたりのポイントにしておくと雰囲気も悪くならない。

### 5\. 工数を出す
全タスクのポイントが出たと思うので、基準となるポイント「2」にどれくらいの人日がかかるかを算出して、各ポイントにその工数をかけていく。
新人など、経験によってより時間がかかりそうであれば、最後にバッファ工数を積んで調整する。


## 所感
### メリット
・ゲーム感覚で工数を決められるので楽しい。コミュニケーションをとる機会にもなる。

・参加者の知識を共有できるのでタスクの抜け漏れ防止や、思ったよりも工数がかかりそうなこと、レビューの事前知識など重要なことがあらかじめわかるため、説明の工数を省ける。

・みんなで工数を決めるので延期などが生じた場合に、実装者の責任だけになることを避けることができる。もちろんまじめに作業していた場合の話だけど……

・機械的に工数を出せるので、技術者レベルによって工数について悩まなくてよい。

### デメリット
・小さめの案件には向かなそう。むしろ時間がかかりすぎて無駄になる。なんにでも適用すればいいってものではなかった

・案件が多いとその分だけ実施に時間がかかるのでかなり時間がとられる。共通して参加するであろうテックリーダーや非エンジニアのマネージャなどはかなり時間をとられている感じだった。

・ゲーム感覚で楽しいのでみんなこの手法でやりたがるため、プランニングポーカーをやることが目的化する空気があった。あくまで見積りをすることが目的なので間違えないように。
wekan (1999) on ubuntu server 24.04

## ubuntu server を建ててみました。
デスクトップ環境だけでなく、オンプレミスで動く歴としたサーバが欲しくなったのです。

## wekan もやってみよう。

https://wekan.github.io/

ただサーバを建てるだけでなく wekan サービスもきちんと入れてみます。FreeBSDとは違うので細いところは戸惑いますがデスクトップで慣れてきたので大丈夫でしょう。

## wekan ってなに？
製造業では猫も杓子もカンバン・・・トヨタ生産方式（かんばん方式）。これのオンラインバージョンということですが、このてのトラッキングシステムの類は、ぼっちマン一筋ではほとんど外形管理くらいですね。

## snap でインストールする

ubuntu server ですと最初からインストールされて動いていたりしますが、設定をどうするの？　となりますので以下の手続きを見つけました。

- snap install wekan

- snap set wekan root-url='https://wekan.example.com'

設定はしたのですが・・・
```
12010 ?        Sl     0:03 mongod --dbpath /var/snap/wekan/common --logpath /dev/null --journal --bind_ip 127.0.0.1 --port 27019 --quiet
  12057 ?        Sl     0:04 /snap/wekan/1999/bin/node --stack-size=65500 main.js

```
127.0.0.1 でリッスンしてます。デスクトップじゃないので、困りましたね・・・

## さらに設定する

```
$ snap set wekan port='3001'

$ systemctl restart snap.wekan.wekan
```

## アクセスできるようになりました・・・

![Screenshot 2025-03-05 at 13-24-41 .png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/8f73dd1b-df80-4f1d-9f07-118776c480db.png)

![Screenshot 2025-03-05 at 13-29-36 パソコン管理 -.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91470/04d68413-3587-4118-9d11-667599989b71.png)

## もう少し踏み込むには

* nginx の認証つきリバースプロキシ＋DNS設定

実用の環境についてはまたいずれ。
元ヤフーエンジニア社長が思うこと、「エンジニアほど魅力的な仕事はない！」

## 自己紹介
株式会社PRUMという会社の代表をしています。岩本です。  
[https://prum.jp/](https://prum.jp/)  
SES企業でエンジニアとして就業したのち、ヤフーでもエンジニアとして働いておりました。  
2019年、PRUMを創業し、組織を5期目の途中で70名の組織まで成長させました。  
エンジニアの成長について、誰よりも考え抜いてきた自信があります。  

## エンジニアという仕事の魅力
エンジニアという仕事について、あなたはどのようなイメージを持っていますか？  
難しい、専門的、敷居が高い…そんな印象を抱いている人もいるかもしれません。  
しかし、それ以上にエンジニアは非常に魅力的で、将来性も抜群の仕事です。  
本記事では、エンジニアという職業の素晴らしさをいくつかの視点からお伝えします。

**エンジニアは、めちゃめちゃめちゃめちゃ良い仕事です！！**

### 1. スキルの見える化が可能
エンジニアの最大の特徴のひとつは、スキルが非常に明確であるという点です。  

例えば、「営業が得意」と言われても、その具体的なスキルを明確に説明するのは難しいことが多いですよね。  
しかし、エンジニアの場合は違います。  

- **「Javaを5年間使っていました」**  
- **「データベース設計を担当し、このプロジェクトを成功させました」**  

このように、スキルと経験が具体的かつわかりやすい形で示せます。  

また、自分自身の成長もはっきりと実感できます。  
新しい言語を習得したり、複雑なプロジェクトを完遂したりするたびに、「できることが増えた」という達成感を得ることができます。  
このスキルの可視性と成長実感は、他の職業ではなかなか得られないエンジニアならではの魅力です。  

さらに、エンジニアは努力次第で誰でも優秀になれる職業でもあります。  
必要なのは、**地道に学び続ける姿勢** です。  
特に日本人は、**真面目でコツコツ積み上げることが得意な国民性** を持っています。  
その特性が、エンジニアという仕事と相性抜群なのです。  

### 2. 安定した需要と働きやすさ
IT業界は、近年急速に発展してきた業界です。  
そのため、比較的若い企業が多く、**働きやすい環境** が整っているケースが多いです。  

特にエンジニアは**慢性的な人手不足** であり、技術力を身につければ多くの企業から求められる存在になります。  
しかも、IT企業の多くは年功序列のような古い文化がなく、**実力主義やフラットな組織文化** を持つところが多いのも特徴です。  
このような環境は、やりがいを感じながら働けるエンジニアにとって大きな魅力です。  

また、近年では**リモートワーク** も普及し、家庭と仕事の両立がしやすくなっています。  
子育て中の友人が、育児をしながらリモートで仕事をこなしている例もあります。  
エンジニアは **「真面目でコツコツ頑張る人」** が多い職業だからこそ、こうした柔軟な働き方が許容されやすいのかもしれません。  

### 3. キャリアの広がり
エンジニアとしての経験は、**将来のキャリアにも大きなアドバンテージ** となります。  

エンジニアは、システム開発やサービス構築などを通じて、**実際に「作る力」** を身につけます。  
このスキルは他職種にも応用が効きます。  
例えば、エンジニアから **コンサルティングや企画職へキャリアチェンジ** する人も多くいます。  
また、**ディレクターやプロジェクトマネージャー** といったポジションに進むことも可能です。  

さらに、エンジニアはプログラミングスキルだけでなく、**問題解決能力や論理的思考力** を培うことができます。  
これらのスキルは、どんな職業でも価値を発揮するものです。  

### 4. 堅実な成長が見込める
エンジニアには、一発逆転というような派手さはないかもしれません。  
しかし、その代わりに**堅実に成長できる職業** です。  

1年目の新人が10年目のベテランに簡単に追いつけることはありませんが、  
逆に言えば、**地道に学び続ければ着実にスキルアップし、市場での価値を高めていける** のがエンジニアです。  
努力が報われやすい環境にあるという点も、エンジニアの大きな魅力と言えるでしょう。  

## まとめ
エンジニアは「手に職」を持つだけでなく、**働きやすい環境** や **豊かなキャリアパス**、**成長実感** といった多くの魅力を持っています。  
そして、それらは**コツコツと努力を続けられる人なら誰でも手に入れることが可能** です。  

これからの時代、IT技術の需要はますます高まるばかりです。  
もしあなたが「挑戦してみようかな」と思ったなら、ぜひ一歩を踏み出してみてください。  

**エンジニアほど魅力的な職業は、そう多くありません。**

---
PRUMのエンジニアの95%以上は、未経験からの採用です。
ぜひ、求人をチェックしてみてください！

▼ Wantedly求人
https://www.wantedly.com/projects/626662

▼ コーポレートサイト
https://prum.jp/

VISION 『日本で一番エンジニアが成長する会社を創る』

ご応募お待ちしておりますー！
EMQX: Username と Password を使う

## EMQXの管理ダッシュボードにアクセス

```text
http://example.com:18083
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0da1a349-0e00-404a-86e8-57b81dc31372.png)

次でログインできます。
>ユーザー名: admin
>パスワード: public

左のメニューから　Authentication に入ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/32794639-fb34-479f-bfa3-e9fb988dd284.png)

データベースの選定

私は、　Built-in Database　を選びました。

Mechanism の選択

Password-Based を選びます。

ユーザーの作成
>user: scott
>paswword tiger123
で作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/7e624af7-6150-4692-a15a-c46585866897.png)

## テスト

サブスクライブ

```bash
mosquitto_sub -d -h example.com -t topic_aa \
	-u scott -P tiger123
```

パブリッシュ

```bash
mosquitto_pub -d -h example.com -t topic_aa \
	-u scott -P tiger123 \
	-m "こんにちは PM 13:25"
```
High Frequency Trading (HFT)の専用インフラストラクチャ


## 1. ハードウェアインフラ

### コロケーション
- 取引所の近くに専用サーバーを設置
- 物理的な距離によるレイテンシ削減
- 専用の高速ネットワーク接続

#### 具体的な構成
- カスタムCPU（超高速処理）
- FPGA（Field Programmable Gate Array）
- 低レイテンシネットワークカード
- 専用高速メモリ（DDR5/HBM）

### ネットワークインフラ
- 超低レイテンシネットワーク
- マイクロ波通信
- 光ファイバー直接接続
- レイテンシ: 数マイクロ秒

## 2. ソフトウェアインフラ

### 取引アルゴリズム
- C++による超高速実装
- ゼロコピーメモリ管理
- ロックレスプログラミング
- リアルタイムOSの利用

### データ処理
- RDMA（Remote Direct Memory Access）
- ゼロ遅延メモリ転送
- カーネルバイパス技術
- Direct Memory Access

## 3. 金融データインフラ

### リアルタイムデータフィード
- FIX（Financial Information eXchange）プロトコル
- 超高速メッセージキュー
- マルチキャストデータ配信

### データストレージ
- オンメモリデータベース
- KDB+
- MemSQL
- Apache Ignite

## 4. リスク管理インフラ

### リスクエンジン
- 超高速リスク計算
- 並列処理
- マイクロ秒単位のリスク評価

### コンプライアンス
- リアルタイム取引監視
- アルゴリズム検証
- 自動レポーティング

## 5. 具体的な技術スタック例

```
ハードウェア:
- Intel Xeon Platinum CPU
- NVIDIA Tesla V100 GPU
- Mellanox ConnectX-6 ネットワークカード

ソフトウェア:
- Linux リアルタイムカーネル
- C++20
- CUDA
- Intel MKL

データインフラ:
- KDB+
- Apache Kafka
- gRPC
```

## 推定コスト
- サーバー: $50,000 - $500,000
- ネットワーク: $10,000 - $100,000/月
- ソフトウェアライセンス: $100,000 - $1,000,000/年

## 最新トレンド
- AI/機械学習の統合
-量子コンピューティング
- 5G/6Gネットワーク
- エッジコンピューティング

## 重要な最適化ポイント
1. レイテンシ最小化
2. スケーラビリティ
3. リアルタイム処理
4. リスク管理
5. コンプライアンス

## 結論
HFTインフラは、従来のITインフラとは全く異なる、極めて特殊で高度な技術領域です。
モデルについて色々調べてみた（ついでにLaravelとDDD）

最近色んな「モデル」という言葉に出会ったので、まとめてみました。

## データモデルの種類

データモデルは、用途に応じて以下の3種類に分類されます。

### 概念データモデル
現実世界の事象やプロセスを抽象化して、データの構造を表現するモデル。

### 物理データモデル
データがデータベース管理システム（DBMS）内でどのように格納され、アクセスされるかを定義するモデル。

### 論理データモデル（諸説）
こちらは特に定義が揺れがちなモデルでした。
基本的には、データの構造や関係を定義するモデルですが、データベースを巻き込むかどうかの考え方が分かれていました。

ネットで調べた感じ
- **データ総研の系記事**では、「論理データモデルはデータベースの構造や操作を定義する」とされている。
- **NTTデータの記事**では、「論理データモデルはビジネスのデータ構造のみを表現し、DBMSに依存しない」としている。

という風に、データベース巻き込み型と、巻き込まない型の論理データモデルがあります。

**AWSの解説**では、論理データモデルには中間テーブルの概念がなく、物理データモデルには存在するため、データベース巻き込まない派のようです。

共通で、論理データモデルはエンティティクラスの立ち位置といえそうでした。

参考: [AWSの論理データモデルと物理データモデルの違い](https://aws.amazon.com/jp/compare/the-difference-between-logical-and-physical-data-model/)

---

## LaravelのEloquentモデル

最近触る機会があったLaravelでは、内部にEloquentが提供してくれるModelがあります。これはどんなモデルでしょうか。

Laravel公式の説明では、
> Laravelには、データベースとの対話を楽しくするオブジェクトリレーショナルマッパー(ORM)であるEloquentが含まれています。Eloquentを使用する場合、各データベーステーブルには対応する「モデル」があり、そのテーブルとの対話に使用します。

とされています。

つまり、Eloquentのモデルは「データベース巻き込み型の論理モデル」と言えそうです。

---

## DDD（ドメイン駆動設計）におけるモデル

『ドメイン駆動設計モデリング実践ガイド』によると、

> モデルにはさまざまな種類があり、目的によって使い分けられます。DDDの文脈で頻出し、混乱しやすいのは次の2種類のモデルです。
・ドメインモデル：ドメインの間題を解決するためのモデル
・データモデル：データの永続化方法を決める（永続化方法の効率化という問題解決
を行う）ためのモデル

これを3種のデータモデルに当てはめて整理すると、

- **データモデル** ＝ 物理データモデル or データベース巻き込み型の論理データモデル
- **ドメインモデル** ＝ 概念データモデル かつ 問題解決のロジックを持った論理データモデル

という形になりそうです。

---

## 論理データモデルとデータベース知識の漏れ

ここまで調べた感じ論理データモデルの解釈は、データベースの知識が漏れるかどうかが大きなキーになりそうでした。

- **ドメイン駆動・ユースケース駆動等（現実世界・概念寄り）**
- **データベース駆動（データベース構造に影響を受ける）**

という違いとも捉えられると思います。
（データベース駆動という言葉は自分が気に入って使っている言葉です。）

またプロジェクトで使い分けをするならば、
例えば、
**既存のビッグデータを利活用するシステム** → データベース巻き込み型の論理モデルでエンティティを定義するのは納得感ある。
**現実世界のユースケースを重視するシステム** → 概念・ドメイン駆動のアプローチが適している。（こちらが一般的）

というパターンが考えられると思います。

私の意見としては、
一般的なシステムにおいて、データベースを操作することは当然ありますが、**現実世界のユースケースを実現するために最終的に操作するためのものとして認識**しています。
リポジトリパターンを採用するなどして、データベースの知識は、特定のクラスに閉じ込め、
**インターフェイスやユースケースの層には、データベースの知識は漏れ出さない**形が、一般的には理想になると言う認識を持っています。

（とはいえ、論理データモデルとテーブル構造が一致してしまうことも多いイメージです）

### データベースの知識漏れの注意
仮にデータベース巻き込み型の論理データモデルを採用したとしても、インターフェース層やコントローラまで、このモデルを持ち込むのは危険です。

サービスのユーザーやAPIを利用するフロントエンドが、実現したいユースケースの中で、データベースの構造を知る必要は当然ありません。

APIレスポンスとして、ユーザーやフロントエンドに対して必要なデータを返したいときに、データベースの構造がレスポンスに影響する必要も当然ありません。

Laravelの場合だと、テーブルと紐付くResourceクラスがありますが、これをレスポンスとして使うのは、上記の理由で個人的には避けた方が良いと思います。

## さいごに

メモ書きからAIにまとめて貰って、そこからたくさん自分で加筆したので、文体がやや乱れている気がします。

英語としてのモデルは「型。模型。」
modelの語源は「modus」で「型・適量・様式」などみたいです。

「モデルさん」は、型とかお手本になるみたいな意味？模型みたいって意味？なんですかね。

「アイドル」は、「偶像、崇拝される人や物」で、空想上のもの感がありますね。

それで言うとアイドルの方が格上な感じしますが、昨今は地下アイドルって言葉もあり、今の自分の感覚としてはモデルの方が格上です。
はい。余談失礼しました。
【イベントレポート】技術参謀たちの戦略図 〜リーダーシップという選択肢と彼らが選んだ企業の魅力〜 #StaffEngineer_findy

いつも記事を読んでいただきありがとうございます！
モブエンジニア（[@mob-engineer](https://qiita.com/mob_engineer))です！

今回は2025.03.05（水）に開催した**技術参謀たちの戦略図 〜リーダーシップという選択肢と彼らが選んだ企業の魅力〜**へ参加しましたのでアウトプットしてイベントレポートを執筆しました。

初学者でもサクッと読めるように平易な表現で執筆しているため、お気軽に読んでいただければ幸いです。

# 目次
- 『事業を差別化する技術を生み出す技術』
- 『困難を「一般解」で解く』
- パネルディスカッション
- まとめ

## 『事業を差別化する技術を生み出す技術』

#### 登壇資料

https://speakerdeck.com/pyama86/shi-ye-wochai-bie-hua-suruji-shu-wosheng-michu-suji-shu

- 自己紹介
    - Go所属のバックエンドエンジニアの方
    - 前職で技術参謀（スタッフエンジニア）ロールを担ってきた
- スタッフエンジニアとは
    - マネジメント対象（部下）を持たない技術専門職
    - **スタッフエンジニアの道**で分かりやすく示されている
    - 水見式アーキタイプ診断で分類分けできる
- 事業を差別化する技術
    - 前職（GMOペパボ）ではキャリアパスとして定義されている
    - 役割として**技術視点での事業方向性を支えていく**
    - 求められるスキルとして*技術理解**と**事業理解**がある
        - 特に事業理解は本当に重視したほうがいい
        - 自分の興味と企業が向かう姿を調整することが重要
    - 最新技術を導入することが目的ではない
        - 事業の特性を理解し、最適な技術を選定・実装すること
        - 具体的には仮想待合室、内製Kubernetes Engineなどがある
    - 単なる技術導入でなく事業戦略と連携させることが大切
    - メンバーとの協業も行うことが大切
        - シャドーイング・逆シャドーイングなどの取り組みが大切
    - 仲間と協力しながら事業を成長させていくことが大切

## 『困難を「一般解」で解く』

#### 登壇資料

https://speakerdeck.com/fujiwara3/findy-2025-03-05

- 自己紹介
    - さくらインターネット所属のエンジニアの方
    - ISUCON4回優勝されている方
- スタッフエンジニア
    - 基本的に4類型に分けられる
        - テックリード：チームを導く
        - アーキテクト：設計で方向性を示す
        - ソルバー：困難に立ち向かう
        - 右腕：事業をドリフトしていく
    - 振り返ってみたらソルバーの役割がしっくりくる
- そもそも困難な問題とは
    - システム開発の事例
        - パフォーマンスチューニング、障害対応などは当てはまる
        - コンポーネントの適切な使い方も含まれる
    - レバレッジの効く形で解決していくことがベター
        - 実例としてRedshiftを利用したデータ取り込み機能
        - Lambdaでスケール速度改善＋コスト削減事例
            - スパイク耐性が大幅にUpして処理性能が向上した
- まとめ
    - スタッフエンジニアはチームを超えた会社⇒業界全体の改善を行うこと
    - fujiwaraさんは最強のSREイネイブラー

## パネルディスカッション
- スタッフエンジニアになったきっかけは
    - Fujiwaraさん：成り行きでなっていった
    - P山さん：もともとはWeb開発を極めていったが、その中でスタッフエンジニアにいつのまにかなっていった
    - スタッフエンジニア=マネージャーではないため管理職のふるまいが必要なわけではない
    - そもそもスタッフエンジニアロールが定義されていないと厳しい
    - （個人的考察）困難を乗り越えつつスタッフエンジニアになっていくんだろうな～
- スタッフエンジニアのやりがい
    - P山さん：市民開発を通じてスタッフエンジニアの面白さを知っていった

## 質疑応答
- 高い技術力と事業理解を身につける方法
    - サービスを好きになることが大切
    - サービス開発者との接触を増やしていくことが大切
    - Xでエゴサするのがいいかもしれない
- プレイヤーからスタッフエンジニアへ転身したきっかけ
    - とりあえずサービスを触ってみたこと
- 事業部レベルで技術と営業が縦割りになっている場合の進め方
    - 何とも言えないが、組織風土による
    - 仲良くなっていくことが大切
    - ご飯いったりして信頼関係を築くことが重要
- シニア⇒Staffとなるために必要な能力は低レイヤーなのか
    - おっしゃる通りだと思う
    - 先端技術も深掘っていったらOSまわりの知識が必要になる
- 技術力の向上方法
    - とにかくコードを書きまくることが大切
    - 好きだからこそアウトプットし続けることが重要
    - コミュニティ活動に参加することで社外に目を向けられる
    - 自身が評価されるようなことを好きになっていくことが大切かもしれない
    - やはりアウトプットしていくことが大切

## まとめ

スタッフエンジニアについて**技術参謀**の書籍を通じてある程度キャッチアップは行えていましたが、**技術を用いて事業をどのようにドリフトしていくか**といった新たな視点は面白かったです。

そのうえで、自身がスタッフエンジニアとして活動していくうえで、**何が必要で、何が不足しているか**を考えていく必要があると思いました。

最後まで記事を読んでいただきありがとうございました！！
AWS Certified Cloud Practitioner ギリギリ合格体験記（2025/2/15）

# 1. はじめに
**AWS Certified Cloud Practitioner（AWS クラウドプラクティショナー**）を2025年2月15日に受験し、無事合格しました。
本記事では、受験の経緯や学習方法、試験の感想などをまとめます。これから受験を考えている方の参考になれば幸いです。

# 2. 受験の経緯
私自身、業務でAWSを扱う機会はあるものの、開発経験はありませんでした。しかし、業務を行う上で開発者と話す場面が多く、「AWSの基礎知識を身につける必要がある」と以前から感じていました。
そこで、AWSの基礎を学ぶきっかけとして、本資格の取得を目指しました。

# 3. 試験内容
AWS Certified Cloud Practitionerの試験は、AWS資格の中でも「初級・入門」に位置づけられ、比較的易しい試験とされています。

:::note alert
<font color="Red">**ただし、AWSのサービス名や内容を知らないと勘で正解するのは難しいため、まったく学習せず合格することは厳しいかと思います。**</font>
:::

試験では、クラウドの基本概念やAWSの主要なサービス、料金体系、セキュリティ、運用に関する内容が問われます。試験概要は以下の通りです。
|  |  |
|---- |----|
| 試験時間 | 90分 |
| 問題数 | 65問（選択式問題） |
| 合格ライン | 700点（1000点満点） |
| 試験範囲（割合） | ●クラウドのコンセプト（24％）<br>●セキュリティとコンプライアンス（30％）<br>●クラウドテクノロジーとサービス（34％）<br>●請求、料金、およびサポート（12％） |
| 受験料 | 100USD（筆者が受験した時は、16,500円） |
| 受験方法 | テストセンターもしくはオンライン受験|

:::note info
**採点対象外の設問**
試験には、スコアに影響しない採点対象外の設問が65問のうち15問含まれています。AWSではこういった採点対象外の設問での成績情報を収集し、今後採点対象の設問として使用できるかどうかを評価しているようです。ちなみに、どの設問が採点対象外かは受験者に分かりません。
:::

# 4. 学習方法
:::note warn
**筆者の前提知識**
筆者が持っているIT資格（知識）は下記となります。
・ITパスポート
・基本情報技術者
・G検定　など

ただ、これらの知識が試験に大きく役立ったとは感じませんでした。
<font color="Red">**やはり、しっかり学習しないと簡単には合格できません。**</font>
:::


**使用した教材**
- <font color="Green">AWS認定資格試験テキスト　AWS認定 クラウドプラクティショナー(改訂第３版)</font>
試験内容に沿った内容のテキストとなっており、AWSの基本概念を体系的に学ぶのに最適でした。練習問題も掲載されています。

- <font color="Green">AWS認定 クラウドプラクティショナー模擬試験 CLF-C02 試験問題集</font>
スマホの問題集アプリで、スキマ時間に活用し、短時間でも反復学習ができました。
※基本は無料ですが、課金をすることで解ける問題が追加されます。


**学習期間**
学習期間は、約２週間です。
- 1週目: テキストを一通り読み、基本概念を理解。
- 2週目: 問題集アプリを活用し、実践的な対策を実施。分からない問題は、テキストで復習。

平日は昼休みにスキマ時間学習、休日に集中学習を行いました。


# 5. 感想
![スコアシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3798098/ecc0a21e-f61f-44fe-886c-6c534618a8bb.png)

スコアは、合格基準点ギリギリでしたが、何とか合格することができました。
受験してみて、AWSの基本を体系的に学べたことが一番の収穫でした。ただし、試験費用が**16,500円**と高額な点は少し負担に感じました。また、試験では細かいサービスの仕様を問われる問題もあり、単なる暗記ではなく概念を理解しておくことが重要だと感じました。

<br>

## 受験時のポイント
- **試験結果について**
  - 試験終了後すぐに合否が画面表示されます。（テストセンターの場合はそうでした）
  - 詳細なスコアレポートは5営業日以内に受験申込ページで確認可能。
  私の場合、土曜日受験で翌日（日曜日）に結果を確認できました。
<br>

- <font color="Blue">**AWSの再受験無料キャンペーン**</font>
  - 受験申込時にキャンペーンコードを入力すると、1度目が不合格でも2回目の受験料が無料になります。（キャンペーンコードは、1度目の受験申込の際に必要です）
  - 受験申込前にキャンペーンをチェックするのがおすすめ。


# 6. おわりに
**AWS Certified Cloud Practitioner**は、クラウドの基礎を学ぶのに最適な試験です。特に初心者の方におすすめです。
また、<font color="Red">**AWS認定試験に合格すると、次回のAWS認定試験の受験料が50%割引になる特典**</font>があります。これを活用して、次のステップとなる認定試験の試験にも挑戦してみたいと思います。

加えて、**再受験無料キャンペーン**を利用すれば、万が一不合格でも再チャレンジしやすいため、試験のハードルが下がります。

これから受験する方の参考になれば幸いです！
Docker内のmongoDBのデータ削除方法

Docker内でmongoDBを建てて、その中のデータ削除に関する備忘録です。
WSL内でDockerを使用していて、どうやったらmongoDBのデータを削除できるのか分からない。データ削除方法を知りたい方のお役に立てるかなと思っています。

## 手順
### 1.コンテナに接続
```
docker exec -it reactdojou-mongo-1 /bin/bash
```
→root@　のように切り替わる

### 2.mongosh コマンドを実行する
```
mongosh
```
→test> のように切り替わる
### 3.データベースを選択   
```
use reactdojou
```
### 4.現在のデータベースを確認
```
db
```
### 5.コレクションの一覧を表示
```
show collections
```
### 6.データの削除
データベース全体を削除
```
db.dropDatabase()
```
特定のコレクションデータを削除
```
db.questions.deleteMany({})
```

これでデータが削除できました。
EMQX の使い方

emqx は、MQTT のブローカーソフトです。

## パッケージのダウンロード

```bash
wget https://www.emqx.com/en/downloads/broker/5.8.5/emqx-5.8.5-ubuntu24.04-amd64.deb
```

## インストール

```bash
sudo dpkg -i emqx-5.8.5-ubuntu24.04-amd64.deb
```

## 起動

```bash
sudo systemctl start emqx
```

起動していることを確認

```bash
sudo systemctl status emqx
```

## テスト

サブスクライブ

```bash
mosquitto_sub -d -t topic_aa
```

パブリッシュ

```bash
mosquitto_pub -d -t topic_aa -m "こんにちは Mar/05/2022"
```

## リモートからのテスト
example.com に EMQX ブローカーが立っているとします。

サブスクライブ

```bash
mosquitto_sub -d -h example.com -t topic_aa
```

パブリッシュ

```bash
mosquitto_pub -d -h example.com -t topic_aa -m "こんにちは Mar/05/2022"
```
Karpenterでノードのオーバーヘッドを見抜く方法！

# Karpenterでメモリのオーバーヘッドを見抜く方法！

Karpenterを使ってKubernetesクラスタのノードをプロビジョニングする際、どれだけのメモリがシステムのオーバーヘッドとして消費されているか、気になったことはありませんか？そんなときに大活躍するのが、`NodeClaim`リソースの`status`フィールドです！  
ここでは、`capacity`と`allocatable`のメモリ値を比較するだけで、事前に計算された静的なオーバーヘッドが分かります。  

## NodeClaimの基本をおさらい

Karpenterでは、各ノードのリソース情報が`NodeClaim`リソースに記録されています。特に注目すべきは以下の2点です：

- **capacity**: ノードが持つ総リソース量
- **allocatable**: Podに実際に割り当て可能なリソース

この2つの値の差が、システムやKubernetes自体の動作に必要なオーバーヘッドとなっています！

## メモリのオーバーヘッドをYAML例で確認

以下のYAMLは、メモリにフォーカスした`NodeClaim`の例です。

```yaml
apiVersion: karpenter.sh/v1
kind: NodeClaim
status:
  allocatable:
    cpu: 95590m
    ephemeral-storage: 88Gi
    memory: 173400Mi
    pods: "110"
    vpc.amazonaws.com/pod-eni: "107"
  capacity:
    cpu: "96"
    ephemeral-storage: 100Gi
    memory: 181862Mi
    pods: "110"
    vpc.amazonaws.com/pod-eni: "107"
```

この例では、ノードのメモリ総量（**capacity**）は **181862Mi** なのに対し、実際にPodに割り当て可能なメモリ（**allocatable**）は **173400Mi** です。  
つまり、**181862Mi - 173400Mi = 8462Mi** のメモリがオーバーヘッドとしてシステム用に確保されていることがわかります！

## 経緯

Karpenterの実装コードを読んだとき、EC2NodeClassで**systemReserved**を省略すると単純に**100Mi**のメモリのオーバーヘッドになると考えていました。
[karpenter-provider-aws/pkg/providers/instancetype/types.go at eff767c9754db6af33fce191e3d23fde65d7d11b · aws/karpenter-provider-aws](https://github.com/aws/karpenter-provider-aws/blob/eff767c9754db6af33fce191e3d23fde65d7d11b/pkg/providers/instancetype/types.go#L521)

**しかし、実際に検証してみると予想を大きく上回るオーバーヘッドが発生していたのです！**
ハッカソンでの学び #1 React

## React
フロントエンドの開発にReactを使用しました。私はReactを使ったことがなく，様々な知識を得ました。それについて私の理解の及ぶ範囲で解釈し整理しておきます。

### コンポーネント
Reactはコンポーネントという単位に分けて画面のUIを作っていくことを知りました。各ページにはメインのコンポーネントがあり，それを記述したファイルにほかのコンポーネントをインポートして一つの画面を完成させます。今回は基本的に，同じ画面内のコンポーネントは同じディレクトリに配置しました。ヘッダーや背景など，すべてのページに共通するコンポーネントは同じ階層に「components」というディレクトリを作成し，そこに配置しました。コンポーネントはどのファイルからでもインポートできるように常時エクスポートするようです。

### 状態管理「state」
Reactでは，画面上で状態が変化する変数にstateという状態管理をつけると，自動で画面が更新されます。変数にはそれを更新するための関数とセットでstateをつけます。（const [変数, 更新関数] = useState(初期値);）stateの概念は難しくてハッカソン中はわかりませんでしたが，後で調べて少しわかりました。

### JSX
Reactでは，JavaScriptのなかでHTMLを記述できます。したがって，HTMLファイルとJavaScriptファイルを分けて開発するよりも要素の変更や追加，管理などが容易になります。JavaScriptで関数を定義して，returnの中にHTMLを記述しますが，一番外の親要素は一つでなければならないということを教わりました。なので，二つになる場合は<></>で囲むという方法をとるのがよいらしいです。

### VSCodeの拡張機能
Reactでコンポーネントを作るときに，VSCocdの拡張機能「ES7+ React/Redux/React-Native snippets」をインストールすると素早くテンプレートが作成できます。空白のファイルで「rafce」と打つと候補が出てきてエンターでテンプレートを挿入できます。

### まとめ
Reactの基本的な知識を得られたのではないかと思います。propsなどわからない概念がまだありますが，引き続き学び続けたいと思います。
Flutterにおけるファイル保存について for iOS

## はじめに
現在参加しているプロジェクトで、データ保存に関する重要な点に気づくことがありました。ファイルがどこに保存されているかを正確に理解していないと、仕様に合った実装ができず、大きなミスにつながる可能性があると学びましt。この記事では、iOSでファイルがどこに保存されているのか、また、どのようなディレクトリ指定方法があるのかについて説明します。少しでも参考になれば幸いです。

:::note info
今回は「PathProvider」を使用してディレクトリパスの取得を実装しています。

PathProviderについては下記の記事を参考に理解を深めました。

https://qiita.com/haru-qiita/items/e564bc5ca3dd7d1ed0a8
:::

## 📌 目次

1. [iOSのディレクトリ構成](#3-iosのディレクトリ構成)
1. [データ保存のメリット・デメリット](#データ保存のメリットデメリット)
4. 2. [アプリの一時保存領域（getTemporaryDirectory()）](#1-アプリの一時保存領域gettemporarydirectory)
3. [アプリの永続保存領域（getApplicationDocumentsDirectory()）](#2-アプリの永続保存領域getapplicationdocumentsdirectory)
5. [まとめ](#まとめ)

## 1. iOSのディレクトリ構成

まずiOSのディレクトリ構成について説明します。

### **1. Documents/**
- ユーザーが作成したファイル（画像、動画、音声）や、ユーザーに見せても良いファイルを保存する場所
- iOSのファイルアプリから閲覧可能（アクセス許可のため `info.plist` の設定が必要）。
- **iCloudにバックアップされる。**

### **2. Library/**
- ユーザーに見せたくないファイルを保存する場所。
- `UserDefaults` に保存したデータもこのフォルダ内に格納される。
- **iCloudにバックアップされる（`Caches/` を除く）。**

### **3. Library/Caches**
- キャッシュ用のフォルダ。
- `tmp/` と似ているが、`tmp/` より長期間保存される。
- **定期的にシステムによって削除される。**
- **iCloudにバックアップされない。**

### **4. tmp/**
- 一時的なデータ保存用のフォルダ。
- アプリ終了時にファイルを削除することを推奨。
- アプリ再起動時にはファイルが削除される可能性があることを考慮する。
- **定期的にシステムによって削除される。**
- **iCloudにバックアップされない。**

### 🔗公式サイトリンク

https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html



## 2. アプリの一時保存領域（`getTemporaryDirectory()`）

### **用途**
- 一時的なデータ保存（アプリが閉じられると削除される可能性がある）
- iOSでは `tmp/` フォルダに格納される

### **パスの取得方法**

```dart
import 'package:path_provider/path_provider.dart';
import 'dart:io';

Future<Directory> getTempDir() async {
  return await getTemporaryDirectory();
}
```

###  **保存例**

```dart
import 'dart:typed_data';
import 'dart:io';

Future<void> saveTempFile(Uint8List audioData) async {
  final tempDir = await getTemporaryDirectory();
  File file = File('${tempDir.path}/audio.wav');
  await file.writeAsBytes(audioData);
}
```


## 3. アプリの永続保存領域（`getApplicationDocumentsDirectory()`）

### **用途**
- アプリが削除されるまでデータを保持する
- iOSでは `Documents/` フォルダに格納される

###  **パスの取得方法**

```dart
Future<Directory> getAppDocDir() async {
  return await getApplicationDocumentsDirectory();
}
```

###  **保存例**

```dart
Future<void> savePersistentFile(Uint8List audioData) async {
  final docDir = await getApplicationDocumentsDirectory();
  File file = File('${docDir.path}/audio.wav');
  await file.writeAsBytes(audioData);
}
```

## まとめ

- **一時的なデータ保存** ➝ `getTemporaryDirectory()`（アプリ終了やシステムにより削除される可能性あり）
- **永続的なデータ保存** ➝ `getApplicationDocumentsDirectory()`（アプリ削除までデータ保持、iCloudバックアップ対象）
- **キャッシュ用途** ➝ `Library/Caches`（`tmp/` よりも長期間保存可能、iCloudバックアップ対象外）
- **完全な一時保存** ➝ `tmp/`（アプリ終了時や再起動時に削除される可能性が高い）

アプリのデータ管理を適切に行い、ユーザー体験の向上を目指しましょう！
Docker内の通信で困った話

docker内で、backend、frontend、mongodbのコンテナを建ててそれぞれに通信を行おうとしたところ、404エラーが出ました。

私と同じように、Dockerを使う前は、frontendからbackendへの通信がうまくいっていたのに、Dockerにしたとたん、通信エラーが出たという方もいらっしゃるのではないでしょうか。
そんな方のお役に立つ記事になれば幸いです。

## 問題　通信が通らない

普通に考えると下記のようなURLでそれぞれに向けて通信すると通るはずなのですが、Dockerの中ではこれらは使用できません。
frontend: http:localhost:3000
backend: http:localhost:5000
mongodb: http:localhost:27017


## 解決策　サービス名で通信する
では、どうすればよいのかというと、
サービス名で指定してあげればよいのです。
サービス名とはyamlファイルに書いたこれ(frontend,backend,mongo)のこと

```yaml
services:
  frontend:　#←サービス名
    build:
      context: ./frontend
    volumes:
      - ./frontend:/app
    env_file:
      - ./frontend/.env
    ports:
      - "3000:3000"
    command: npm run dev
  backend:　#←サービス名
    build:
      context: ./backend
    env_file:
      - ./backend/.env
    depends_on:
      - mongo
    ports:
      - "5000:5000"
    volumes:
      - ./backend:/app
    command: ["node", "-r", "ts-node/register", "server.ts"]
  mongo:　#←サービス名
    image: mongo:latest
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db
    environment:
      GLIBC_TUNABLES: "glibc.pthread.rseq=0"
  seed:
    build:
      context: ./backend
    env_file:
      - ./backend/.env
    depends_on:
      - mongo
    command: ["node", "-r", "ts-node/register", "seed/seed.ts"]
volumes:
  mongo-data:

networks:
  default:
    name: net-todo
    external: false  # true にすると既存のネットワークを使用 
```

frontend: http://frontend:3000
backend: http://backend:5000
mongodb: http://mongo:27017

これでDocker内でそれぞれのサービスに通信が取れるようになりました。
【Marp】Markdown でスライドをサクッと作る ⚡️

## はじめに

みなさん、Lightning Talk してますか？
LT は準備も Lightning であるべき！⚡️
Markdown でスライドをサクッと作成することができる Marp というツールを紹介します。

## Marp を導入する

### 1. 拡張機能 Marp for VS Code をインストールする

https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode

### 2. vscode デフォルトの Markdown プレビューボタンを表示する

Marp for VS Code では vscode デフォルトの Markdown プレビュー機能を使います。
拡張機能 [Markdown Preview Enhanced](https://marketplace.visualstudio.com/items?itemName=shd101wyy.markdown-preview-enhanced) を入れていると、vscode デフォルトの Markdown プレビューボタンが非表示になっていることがあります。
`setting.json` に以下の設定を追加してあげると復活します。

```json:setting.json
{
  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons": false
}
```

### 3. `*.md` ファイルの先頭におまじないを書く 🪄

スライドの縦横比を指定したいときは `size` を指定してあげます。
「最近はスマホで発表を見てくれる人もいるから、『16 : 9』にするといいよ」と大学時代の指導教員に教わりました（余談）

```markdown:slide.md
---
marp: true
size: 16:9
---
```

プレビューボタンをポチっと押すと、スライドになっていることが確認できます 👀

![preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/568879c6-c142-4c18-b209-ef65811c8f3f.png)

## Marp の基本のキ ✍🏻

### 改ページしたい！

改ページしたい箇所に `---` を挿入します。
（`headingDivider` を指定すると、見出しごとに自動で改ページすることもできる）

![page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/4be815fa-f3dd-415d-ad3a-9f9711fe1f24.png)

### カスタムのスタイルを当てたい！

カスタムのスタイルは `*.css` で指定します。

```css:custom-theme.css
/* @theme custom-theme */

@import 'default';

h1 {
  color: red;
}
```

| コード                      | 意味                         |
| --------------------------- | ---------------------------- |
| `/* @theme custom-theme */` | カスタムテーマの名前をつける |
| `@import 'default';`        | default のテーマを継承する   |

`*.md` でカスタムテーマを指定します。

```diff_markdown:slide.md
  ---
  marp: true
+ theme: custom-theme
  size: 16:9
  ---
```

vscode にもカスタムテーマを教えてあげます 👨‍🏫

```diff_json:setting.json
{
  "markdown-preview-enhanced.hideDefaultVSCodeMarkdownPreviewButtons": false,
+ "markdown.marp.themes": ["./custom-theme.css"]
}
```

赤くなった！！！！！

![custom-theme.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/aaac0df6-9a25-4d13-a87d-c4cf670798ed.png)

### デカ文字を表示したい！

`<!-- fit -->` をつけると圧迫感を演出できます(?)

![fit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3848132/ce9b04e6-cfb7-4f18-bd41-af8a6dfe2c80.png)

## おわりに

充電ケーブルは Lighting じゃないほうが良い 🔪🍎
PowerAutomateからFetchを使用してDataverseのデータを取得する方法

# 記事作成の経緯
PowerAutomateを使用してDataverseからデータを取得する際に、依存関係にあるほかのテーブルからもデータを取得するような処理を今回実装しました。作業する際に関連する情報を見つけられないといったことがあったので、私自身の備忘録もかねてこの記事を投稿させていただきます。

# 実装について
今回はPowerAutomateを使用し、Dataverseの「行を一覧にする」のアクションとFetch Xmlクエリを活用しデータを取得することを想定しています。

## PowerAutomateでの実装
こちらではDataverseの「行を一覧にする」のアクションを使用します。
テーブル名にはデータの取得元となるテーブルを選択し、Fetch Xmlクエリの項目にはFetchの書き込みを行います。（取得方法については事項で記載）
![スクリーンショット 2025-03-05 102200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767329/2e6e2547-1b7d-4cfb-9e0d-4ea9567d6094.png)

## Fetch Xmlクエリ

### Fetch Xmlクエリの記載例
```xml
  <entity name="msdyn_aibdatasetfile">
    <attribute name="msdyn_aibdatasetfileid" />
    <attribute name="msdyn_name" />
    <order attribute="msdyn_name" descending="false" />
    <filter>
    <condition attribute="createdon" operator="lt" value="2025-03-04T20:19:43.5381258Z" />
    </filter>
        <link-entity name="account" from="accountid" to="Test_table">
            <all-attributes/>
        </link-entity>
  </entity>
</fetch>
```

基本的な文法は次の通りです。
・entryでテーブルの論理名を指定
```xml
<entity name="msdyn_aibdatasetfile">
```
・attributeで列の論理名を指定（ここで指定したデータのみ取得できます）
```xml
<attribute name="msdyn_aibdatasetfileid" />
<attribute name="msdyn_name" />
```

・all-attributesを使用すると列の指定をすることなくすべてのデータを取得できる
```xml
<all-attributes/>
```

・order attributeでデータの並び順を指定することができる
```xml
<order attribute="msdyn_name" descending="false" />
```

・filterを使用すると取得データの絞り込みを行うことができる
（こちらの記載例は作成日以前のデータの取得）
```xml
<filter>
<condition attribute="createdon" operator="lt" value="2025-03-04T20:19:43.5381258Z" />
</filter>
```

・Link-entryを使用するとリレーションのテーブルからデータの取得をすることができる
```xml
<link-entity name="account" from="accountid" to="Test_table">
<all-attributes/>
</link-entity>
```

・entry,fetchの文末には/で終了の記載を入れる
```xml
</entity>
</fetch>
```

### Fetch Xmlクエリの確認方法
確認方法は以下の2つがあります。
設定が少し手間にはなりますが2番目の方法がおすすめです。

#### 1.PowerPlatFormの詳細設定から確認
1．右上の歯車マークのクリック
2．Dynamics365の設定画面の右上のろうとのマークをクリック
3．検索欄から該当のテーブルを選択し右上の「Fetch Xmlのダウンロード」をクリック

こちらの方法は簡単な操作で確認をすることができ、保存されているビューをもとに該当する列の選択などがされた状態のFetchをダウンロードすることができます。
また選択のところから絞り込みの条件を指定することでフィルター条件も適用することができますが、リレーションが設定されたテーブルからのデータの取得が難しいかと思います。
![スクリーンショット 2025-03-05 110501.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767329/b2733402-968d-42d8-80d5-bb001029b4d2.png)
![スクリーンショット 2025-03-05 111131.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767329/c5a232b0-449a-4a44-9e08-7dd1bbf3fa6b.png)
![スクリーンショット 2025-03-05 111419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3767329/b8d54f72-57d5-4022-8b45-d935611ada58.png)

#### 2.FetchXML Builderから確認
1．XrmToolBoxをインストールしてMicrosoft365アカウントにログイン、環境へアクセスする
2．Tool LibraryからFetchXML Builderをインストールする
3．FetchXML Builderを開きテーブルや列、リレーションのあるテーブルを追加していく

こちらの方法を行う場合は、初期設定などが必要になりますがより細かく確認をすることができるので詳細な設定を行いたい方はこちらの方法がおすすめです。

## まとめ
こちらの記事ではFetchを使用したデータの取得方法をまとめていきました。
なるべくわかりやすく記載をしているつもりではありますが、情報が足りていない部分があるとは思うので補足して調べながら進めていただければと思います。
最後までこちらの記事を読んでいただきありがとうございました
塗装職人からエンジニアに？できらぁ！（Java-2）

## はじめに
Teyo3Mです。
エンジニアになるため、現在会社に所属しながら勉強をしています。
前回に引き続き、勉強して学んだことなどを備忘録として記載していきます。
[前回の記事はこちら](https://qiita.com/Teyo3M/private/d36604e54b53a9f3c5a4)


## 簡単な自己紹介
名前：Teyo3M
職歴：家庭教師のバイト、塗装職人
趣味：スキューバダイビング


## 実施していること
[初心者がJavaでTodo管理システムを作ってみるガイド！](https://qiita.com/Hemmy7/items/64c2e8e70e6b835628bf)
本記事の発展課題にある「タスクの優先度の設定」、「期限の設定」、「データの永続化」に取り組んでいる。

## 先入観が招いた学び
私は前回の記事で先入観から失敗しているのにも関わらず、ここでも学習の機会を生みました。
タスクを優先度順に並べ替えをしようと思った際に、勉強中の基本情報が頭をよぎりました。
「並べ替えならアルゴリズムの勉強でやった。バブルソートで終わりなのでは？」
結論からお話すると、sort()メソッドを利用すればハードコーディングはいらなかったです。
↓下記実際に記述したコード

```Java
import java.util.List;

public class Sorter {

    // Todoリストを優先度の降順にバブルソートするメソッド
    public static void sortTodos(List<Todo> todos) {
        int n = todos.size();
        for (int i = 0; i < n - 1; i++) {
            boolean swapped = false; //制御用
            for (int j = 0; j < n - i - 1; j++) {
                // getPriority() を使用して優先度レベルを取得
                if (todos.get(j).getPriority().getLevel() < todos.get(j + 1).getPriority().getLevel()) {
                    Todo temp = todos.get(j);
                    todos.set(j, todos.get(j + 1));
                    todos.set(j + 1, temp);
                    swapped = true;
                }
            }
            if (!swapped) {
                break; // 既に整列済みなら終了
            }
        }
    }
}
```

## エラーハンドリングのむずかしさ

入力を受け付けるコードを書いていた時の話です。
日付を入力する際に、自分で記述したにも関わらず、入力形式に疑問がわいてしまいました。
正しい形式が2025/01/01　の時、2025/1/1と入力した場合はどうなるのか。
答えは簡単でエラーでプログラムが止まってしまいました。
結局どちらもプログラムが受け入れられるような入力をしてもらえるまでループすることで解決しました。


実際に書いたコード
```java
import java.util.Scanner;

public class SelectPriority {
    private static final Scanner scanner = new Scanner(System.in);  // クラス変数として宣言

    public static Priority selecter() { 
        System.out.println("優先度を選択してください。 (1:低, 2:中, 3:高, 4:やばい)");

        while (true) { //エクセプションを使わないエラー処理
            String input = scanner.nextLine();
            if (input.matches("[1-4]")) {  // 正規表現で1〜4のみ許可
                return Priority.values()[Integer.parseInt(input) - 1];
            }
            System.out.println("1から4の数字を入力してください。");
        }
    }
}
```
こちらは、正規表現で1～4の数字のみ受け付けるプログラムです。
Todoリストの優先度設定に使用しました。
工夫した箇所として、「ecxeption」を使わないエラーハンドリングに挑戦しました。


## まとめ
コーディングに限った話ではないのですが、ゴールを見据えて何かをするのはとても大切だと思いました。
本記事で取り上げた2つのコードもそれぞれ失敗例と成功例をとらえることができると思います。
上のコードは「手段に固執するあまり不要なリソースを使ってしまった」パターン。
下のコードは「目的を達成するために、最小のリソースでコーディングができた」パターン。
勉強を振り返って自分を客観視した時に、「自分は何をしていたのか」と次回の進捗報告時に思わないよう、日々意識していきたいとおもいｍ
Terraform入門：シェルスクリプトで一括作成！AWSのEC2インスタンスとセキュリティグループをTerraformで構築する方法

## はじめに
Terraformを使用すると、AWS上のインフラをコードで管理できます。本記事では、**Terraformを用いてEC2インスタンスとセキュリティグループを作成**する方法を解説します。

https://qiita.com/free-honda/items/6b56b4dfa69c4ef4dd99#%E3%81%8A%E3%81%BE%E3%81%91%E4%B8%80%E6%8B%AC%E3%81%A7%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88


スクリプトを実行することで、Terraformの設定ファイルが自動的に作成され、簡単にAWS環境を構築できます。

## 1. Terraformで作成するAWSリソース
本記事で紹介するスクリプトを実行すると、以下のAWSリソースが作成されます。

### **1.1 EC2インスタンス**
- AMI ID: `ami-072298436ce5cb0c4`
- インスタンスタイプ: `t2.micro`
- キーペア: `my-key-pair`
- セキュリティグループ: `modules/security_group` にて作成
- タグ: `Terraform-EC2`

### **1.2 セキュリティグループ**
- VPC ID: `vpc-xxxxxxxx`（実際のVPC IDに置き換え）
- **許可する通信**
  - **Ingress (受信)**
    - **SSH (ポート 22)**: `0.0.0.0/0` からのアクセス許可
    - **HTTP (ポート 80)**: `0.0.0.0/0` からのアクセス許可
  - **Egress (送信)**
    - **すべての通信を許可**

## 2. Terraform構成ファイルの作成
スクリプトを実行すると、以下のTerraform構成ファイルが自動作成されます。

### **2.1 ディレクトリ構成**
```
terraform-project/
│── main.tf             # AWSプロバイダーの設定、EC2インスタンス、セキュリティグループのモジュールを定義
│── variables.tf        # 変数定義（VPC ID）
│── outputs.tf          # 出力定義（EC2インスタンスID）
│
└── modules/
    └── security_group/
        │── main.tf      # セキュリティグループの定義（SSH, HTTPの許可）
        │── variables.tf # セキュリティグループ用の変数定義（VPC ID）
        └── outputs.tf   # セキュリティグループの出力（SGのID）
```

### **2.2 各ファイルの説明**
| ファイル | 役割 |
|----------|------|
| **main.tf** | AWSプロバイダーの設定、EC2インスタンス作成、セキュリティグループのモジュールを定義 |
| **variables.tf** | 変数（VPC ID）を定義 |
| **outputs.tf** | 作成されたEC2インスタンスのIDを出力 |
| **modules/security_group/main.tf** | セキュリティグループの定義（SSH 22番、HTTP 80番の許可） |
| **modules/security_group/variables.tf** | セキュリティグループのVPC IDを変数として定義 |
| **modules/security_group/outputs.tf** | 作成されたセキュリティグループのIDを出力 |

## 3. Terraformの適用手順
Terraformを適用するには、以下のコマンドを順番に実行してください。

### **3.1 Terraformの初期化**
```sh
cd terraform-project
terraform init
```

### **3.2 Terraformの実行計画を確認**
```sh
terraform plan
```

### **3.3 Terraformを適用（リソース作成）**
```sh
terraform apply -auto-approve
```

## 4. 追加できる改善点
このスクリプトをさらに改良する方法もあります。

### **4.1 環境変数を利用**
- `VPC ID` や `AMI ID` を `terraform.tfvars` などで管理すると、スクリプトをより柔軟に運用可能。

### **4.2 EC2のセキュリティ強化**
- `SSH (22)` のアクセス許可を `0.0.0.0/0` から **特定のIPアドレスに制限** するとより安全。

### **4.3 変数の拡張**
- `instance_type` や `key_name` も `variables.tf` で定義すると汎用性アップ。

## まとめ

本記事では、Terraformを使ってAWS上にEC2インスタンスとセキュリティグループを作成する方法を紹介しました。

:::note info
***スクリプトを実行することで、自動的にTerraform構成ファイルが生成され、簡単に環境構築が可能になります。***
:::

Terraformを活用することで、インフラの管理が容易になり、再利用性も高まります。ぜひ実際に試してみてください！
非同期手続きの中でロックを掛ける

## 参考
この記事は、以下の動画を参考にしています。
詳しくは、動画をご覧ください。

<iframe width="560" height="315" src="https://www.youtube.com/embed/bmwtHCiUCg4?si=YN6uQ94K9l4FV29e" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

リファレンス

https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.semaphoreslim

## 非同期手続きの中ではlock文が使えない
`async`を使った非同期手続きの中で、`await`を付けた非同期呼び出しを含む文ブロックを、`lock`文を使ってロックを掛けようとすると、ビルドエラーになる。

```cs
private static readonly Lock _lock = new();

public async Task DoWorkAsync()
{
    lock (_lock)
    {
        // 
        await DoSubWorkAsync(); // ビルドエラー
        //
    }
}
```
`lock`文を使わず、`System.Threading.Lock`クラスのメソッドを使い、ロックの取得と解放をすると、ビルドエラーにはならない。

しかし、`Lock`クラスのロックはスレッドに掛けられるため、`await`の前後が異なるスレッドで実行される可能性のある非同期手続きでは、正常にロックが動作しない。（[参照](https://learn.microsoft.com/ja-jp/dotnet/api/system.threading.lock#remarks)）
```cs
private static readonly Lock _lock = new();

public async Task DoWorkAsync()
{
    _lock.Enter(); // ここを実行するスレッドと…
    
    try
    {
        // 
        await DoSubWorkAsync(); // ビルドエラーにはならない
        //
    }
    finally
    {
        _lock.Exit(); // ここを実行するスレッドが、異なる可能性がある
    }
}
```

## セマフォを使ってロックを掛ける
そこで非同期手続きでは、`System.Threading.SemaphoreSlim`クラスのオブジェクトを用いて、ロックを掛けるとよい。

```cs
private static readonly SemaphoreSlim _semaphore = new(initialCount: 1, maxCount: 1);

public async Task DoWorkAsync()
{
    await _semaphore.WaitAsync(); // ロックを掛ける
    
    try
    {
        // 
        await DoSubWorkAsync();
        //
    }
    finally
    {
        _semaphore.Release(); // ロックを解放する
    }
}
```

ロックを掛ける際、タイムアウトを指定することもできる。
```cs
var locked = await _semaphore.WaitAsync(timeout: TimeSpan.FromSeconds(1));
```
rex0220 印刷屋プラグイン 見積書の社印変更と位置調整

[rex0220 印刷屋プラグイン](https://qiita.com/rex0220/items/9be2d9b20a3a1f016c76)で、見積書の社印変更と位置調整をしてみます。

# 概要

少し大きめの社印を他の文字にかぶらないように配置してみます。
社印は、画像ファイルアプリに添付ファイルとして登録して、それを見積書で利用します。

![2025-03-05_10h52_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/56db77cb-5b24-4602-8ef7-fed66248bb80.png)

# テスト用社印の作成

今回は、[テスト用社印作成ツール作成メモ](https://qiita.com/rex0220/items/200c5f23dd4c31170f03)で、作成したpng画像を利用します。

![2025-03-05_10h25_59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/d83692d0-e402-47f0-b83c-b182ea315729.png)


# 画像ファイルアプリへの登録と fileKey の確認

レコードに社員の画像ファイルを登録します。

![2025-03-05_10h27_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/53053dcc-76cd-42b2-9749-8edf06276209.png)

ブラウザーの開発ツールで、登録した画像の fileKey を確認できます。

console タブで、「kintone.app.record.get()」を入力して実行し、レコードの内容を表示。
添付ファイルの値に fileKey があります。

![2025-03-05_10h30_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/14236b87-9613-4a11-b77f-83389922f2db.png)


# fileKey の変更

社印欄の fileKey を変更します。

#{&f(...)}

```js:
// 変更前
      VTAG("img", ATTR("class", "pcraft-inv-seal", "width", "250", "height", "120", "src", "#{&f(20250302031501227586874B104969A58F90E42C4C3C26073)}"))

// 変更後
      VTAG("img", ATTR("class", "pcraft-inv-seal", "width", "250", "height", "120", "src", "#{&f(20250305012652A3307F05B9B648E89C9751D72C67CF3D014)}"))

```

# 変更後の社印確認

社印が変更されたか確認します。

![2025-03-05_10h38_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c72a0b62-314b-4ef7-a271-5068b96bc2d7.png)


# 社印の位置調整

プレビュー画面の社印上で、右クリックしてメニューから「検証」を選択すると開発ツールで、社印の要素を表示できます。

![2025-03-05_10h40_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/f62cbf40-afd8-4f87-b765-60ab61b409d0.png)

位置を left, 大きさを width で変更して 真ん中あたりに配置します。
位置は、親要素の pcraft-inv-right (position: relative;指定)を基準にして指定します。

    left: -120px;
    width: 120px;

![2025-03-05_10h42_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b71e7a56-594d-4d3a-8a8c-09795bf2b2af.png)

# 印刷屋プラグイン設定で CSS の変更

先ほど調整した css をプラグイン設定で指定します。

![2025-03-05_10h48_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/5e0ebc4e-fde0-4973-b319-c521e30c2f15.png)


```css:
.pcraft-inv-seal {
    left: -120px;
    width: 120px;
}
```

# プレビュー画面で確認

プレビュー画面で、css の変更が反映されているか確認します。

![2025-03-05_10h47_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1011555f-8ed6-4f55-85d0-fb7d9627c7f3.png)

# PDF で確認

プレビュー画面通りに PDF が作成されるか確認します。

![2025-03-05_10h51_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1765600b-c6f6-4686-9668-ed9f0c2309ae.png)
Nextjsをvercelに上げたらでたエラーその3:  is possibly 'undefined'


この記事ではNextjsでvercelに上げたらでたエラーについて書いています。

## エラーコード

```tsx
./src/app/account/page.tsx:39:14
Type error: 'session.user' is possibly 'undefined'.
  37 |           <h1 className="text-3xl font-bold mb-4">
  38 |             {/* {session.user.name}さんのアカウント */}
> 39 |             {session.user.name}&apos;さんのアカウント
     |              ^
  40 |           </h1>
  41 |           <p>メールアドレス: {session.user.email}</p>
  42 |           <button
Static worker exited with code: 1 and signal: null
Error: Command "npm run build" exited with 1
```

# エラー内容
このエラーは、TypeScriptがsession.userがundefinedの可能性があるため
session.user.nameにアクセスする際に型エラーが発生していることを示しています。

useSession()から取得されるsessionオブジェクトは、認証されていない場合には
undefinedになる可能性があるため、このエラーが発生しています。

# エラー解決方法
sessionオブジェクトがundefinedでないことを確認してから
session.userにアクセスするようにします。
sessionが存在しない場合に備えて条件分岐を追加しました。

```tsx
if (status === "authenticated" && session?.user) {
  return (
    <div>
      <div>
        <h1>
          {session.user.name}&apos;さんのアカウント
        </h1>
        <p>メールアドレス: {session.user.email}</p>
        <button onClick={handleSignOut}>
          サインアウト
        </button>
      </div>
    </div>
  );
}
```
Nextjsをvercelに上げたらでたエラーその2:  is assigned a value but never used

この記事ではNextjsでvercelに上げたらでたエラーについて書いています。

# エラー内容
```sql
Failed to compile.
./src/app/page.tsx
9:17  Error: 'session' is assigned a value but never used.  @typescript-eslint/no-unused-vars
info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/app/api-reference/config/eslint#disabling-rules
Error: Command "npm run build" exited with 1
```

# エラー理由
このエラーは、sessionが変数として定義されているにも関わらず、その値がコード内で使用されていないために発生しています。ESLintの@typescript-eslint/no-unused-varsルールが、未使用の変数を警告しています。

エラーが発生した行を見ると、sessionが宣言されているけれども実際に利用されていない状態です。

# エラー解決方法

## sessionを使用する

```javascript
const { data: session, status } = useSession();

if (session) {
  console.log(session.user.name); // sessionの情報を使う例
}
```

## sessionの宣言を削除

```javascript
const { status } = useSession(); // sessionを削除
```

## 強引な方法

ESLintルールを無効化(警告を無視)したい場合、@typescript-eslint/no-unused-varsルールを無効化することもできます。next.config.jsに以下を追加して、ビルド時の警告を無視できます

```javascript
module.exports = {
  eslint: {
    ignoreDuringBuilds: true,
  },
}
```