---
# System prepended metadata

title: koji 課題4

---

# 課題4 デジタル名刺

勉強会で名刺交換をする中で、書いてある内容がそれぞれ違うため話題が生まれにくく、持っている人持っていない人がいることに目をつけて誰もがその場で登録できるオンライン名刺システムを開発することにしました

オンライン名刺はその日まで有効で、次の日にはみれなくなるようにしようと考えました

**実装はスマホの画面サイズで行ってください**

# MVP1 5/27完了

アプリ開発の準備をする
ユーザーはアプリをスマホからみることができる

## TODO
- [x] React+TypeScriptの開発環境をViteで用意する
- [x] Fireabseにデプロイする(新規プロジェクトを作成)
- [x] Makefileを作成(make deployでデプロイできる)
# MVP2 5/27完了

開発者はCI/CDを利用して快適に開発を行うことができる

## TODO
- [x] Jestとreact-testing-libraryを導入する
- [x] サンプルのテスト(関数とコンポーネント)が動く
    - [x] src/\_\_tests__/sampleComponent.spec.ts
- [x] Makefileでテストを実行できる(make test)
- [x] Github ActionsでPushでパイプラインが動くように設定する
- [x] ビルドステップが実行される
- [x] 自動テストが実行される
- [x] 自動デプロイが実行される

# MVP3 期限5/29まで

ユーザーは名刺をみることができる

## TODO
- [x] ChakuraUIを導入する(ボタンをみれればOK)
- [x] 以下のテーブルを作成する(前回作ったプロジェクトでOK)

### userテーブル

table: users

|Name|Type|option|
|---|---|---|
|user_id |varchar|non-null|
|name|varchar|non-null|
|description|text|non-null|
|github_id|varchar|null|
|qiita_id|varchar|null|
|x_id|varchar|null|

![upload_1b6f6a9a10e9a62f6287437107790663](https://hackmd.io/_uploads/H1lVvLxV0.png)


テストデータを1件入れる

|Name|Value|
|---|---|
|user_id|sample_id|
|name|テスト太郎|
|description|\<h1>テスト太郎の自己紹介\</h1>|
|github_id|あなたのgithubのID|
|qiita_id|あなたのQiitaのID|
|x_id|あなたのXのID|

RLSを無効にする


### user_skillテーブル
ユーザーIDとスキルIDを結ぶ中間テーブル

table: user_skill

|Name|Type|Option|
|---|---|---|
|id|int8||
|user_id|varchar|non null|
|skill_id|int8|non null|

RLSを無効にする

![image](https://hackmd.io/_uploads/ByrPvLeNR.png)


テストデータを追加する

|Name|Type|Option|
|---|---|---|
|user_id|sample-id|
|skill_id|1|

### skillテーブル

table: skills

プログラミングの技術を保存しておくテーブル

|Name|Type|Option|
|---|---|---|
|id|int8||
|name|varchar|non null|

![image](https://hackmd.io/_uploads/r16DPUeVC.png)

RLSを無効にする

テストデータを追加する

NameをReact,TypeScript,Githubで3つ作る

![image](https://hackmd.io/_uploads/H1pdvUx4R.png)

## 中間テーブルについて

ユーザーに好きな技術を選択させて名刺では表示を行う
現在のテストデータではuserのIDがsample-id
user_skillテーブルではsample-idに紐づくのはskill_id 1であるので

skillテーブルのID1をみると、「React」であることがわかる

このように中間のテーブルを用意することでユーザーにスキルを紐付けることが可能

userテーブルのカラムにskillカラムをもっても実現できるが、仮に3つ好きなスキルを選べるとしたときにユーザーテーブルにカラムが増えてしまう

user_skillを使うことによってuserテーブルにカラムを入れる必要がなくなった
- [x] Routerを設定する
    localhost:5132/cards/:idでidに入力した文字列を画面に表示できる(例えば/cards/helloならhelloと画面に表示される)
![image](https://hackmd.io/_uploads/B1dtw8eNR.png)


- [x] supabaseを使えるようにセットアップする
    ファイル名はsupabase.tsにしないとインポートできないので注意
- [x] 登録した情報を表示する(/cards/sample-idでアクセスしたらそのIDに紐づくユーザーデータを表示する
    - [x] ユーザーデータ取得中はローディング画面を出す
    - [x] ユーザー情報を取得する
    - [x] ユーザーIDからuser_skillテーブルのuser_idと一致するレコードをみつけてそのレコードのskill_idでskillsテーブルを検索する
    - [x] ユーザーとスキルをあわせてUserとして表示
    idがundefinedまたはユーザーがいないならローディングのまま
    vite.config.jsでprocessを読み込めるように設定するのも忘れずに
![image](https://hackmd.io/_uploads/Hyg5vLgEA.png)


- [x] Github, Qiita, Xはクリックすると飛べるようにする
GithubなどはIDしか登録していないのでファクトリーメソッドをUserに作成することでインスタンス作成時にURLの形にしてデータを持っておくとよい


こうすることでURLの形式にして持つことが可能
同じように実装する必要はないが参考にすること

![image](https://hackmd.io/_uploads/SyUcw8eN0.png)


- [x] ChakraUIを使ってスタイルを整える
スマホ利用がほとんどのためスマホレイアウトで作成すること
デベロッパーツールからiphoneSEのレイアウトで開発する
SNSは任意登録なのでない場合は表示しない

![image](https://hackmd.io/_uploads/Sk3cvUlVC.png)

- [x] 紹介文はHTMLで表示する
https://qiita.com/hiromoon/items/f3ed77abd338139ba97b

ただしこれは注意が必要。紹介文にあるHTMLをそのまま実行するのでそこにjsで悪意のある分仕様が埋め込まれたら実行されてしまう。今回はサンプルアプリなのでこれを使うがサービスリリースするなら別の方法を使う

![image](https://hackmd.io/_uploads/BJMjPIe4R.png)


# MVP4 期限6/1まで 6/6完了

ユーザーは自己紹介カードを登録できる

## TODO

- [x] routerに登録のパス`/cards/register`を登録してページが表示できるようにする
- [x] タイトルをつける(名刺新規登録など)
- [x] レイアウトを当てながらID、名前、自己紹介、好きな技術、GithubId、QiitaId, TwitterIdの入力欄を作る(見た目だけで良い)
ここで技術は先程supabaseのskillsテーブルで用意したレコードの中から選択できるようにする
    - [x] skillsを取得する関数を作成する
    - [x] 関数で取得したskillsをmapでoptionに設定する 

IDはユーザーに適当な英単語をいれてもらう想定にする
あとでユーザーは英単語(ID)を入力してそのユーザーの名刺を見れる。ここでuuidを使うのもできるが入力が大変であり、連番では他の人の自己紹介カードをみれてしまうので、英単語をIDにすることに今回はした(重複してしまう問題は考えない)
- [x] 登録ボタンがある
![image](https://hackmd.io/_uploads/ByTiwLeER.png)


- [x] 必須項目にバリデーションエラーを設定する
react-hook-formでバリデーションエラーを表示する
idは英語文字列だけ
- [x] 項目を登録することができる
supabaseに実際に登録するように実装してください
登録できたらusersテーブル、user_skillテーブルにデータが追加されたかを確認
実際にidを使って/cards/idをみて自己紹介が見れるかを確かめる
※ なぜかSelectのところだけバリデーションエラーがでないのでわかる方は教えて(今回は本質でないのでスキップしたよ)
- [x] 登録に成功したらlocalhost:5173/にページ遷移する
useNavigateを使うと良い

![image](https://hackmd.io/_uploads/r1NhDLlN0.png)

# MVP5 期限6/3まで 6/6完了
ユーザーはトップ画面でIDを入力して別のユーザーの名刺をみることができる

## TODO
- [x] タイトルがある
- [x] IDの入力フォームがある
- [x] ボタンをクリックすると/cards/入力したIDページに遷移する
- [x] IDがないときにバリデーションエラーが出る(項目が少ないのでhook-formを使わなくても良い)
- [x] /cards/idのページに戻るボタンを追加する
戻るをクリックするとホームにページ遷移する

![image](https://hackmd.io/_uploads/B19hPIl4R.png)


# MVP6  期限6/6まで
それぞれのページにテストを実装して安心してCDができるようにする

ページごとにテストのファイルは分けること

## TODO
- [x] 名刺カードのテストを書く
    - [x] 名前が表示されている
    - [x] 自己紹介が表示されている
    - [x] 技術が表示されている
    - [x] Githubアイコンが表示されている
    - [x] Qiitaのアイコンが表示されている
    - [x] Twitterのアイコンが表示されている
    - [x] 戻るボタンをクリックすると/に遷移する
    react-routerのモックをすると検証できる
https://qiita.com/shiva_it/items/48e92101a31e4a2ba50d

- [x] 名刺登録ページのテストを書く
    - [x] タイトルが表示されている
    - [x] 全項目入力して登録ボタンを押すと/に遷移する(useNavigateのパスが/であることをみる)
    supabaseFunctionはモックをすること
    モックしないと本番のDBに影響してしまうため
 https://zenn.dev/aidemy/articles/62720a7cab9115
    - [x] IDがないときにエラーメッセージがでる
    - [x] 名前がないときにエラーメッセージがでる
    - [x] 紹介分がないときにエラーメッセージがでる
    - [x] (スキルはエラーメッセージが出ないので割愛)
    - [x] オプションを入力しなくても登録ができる

- [x] トップページのテストを書く
    - [x] タイトルが表示されている
    - [x] IDを入力してボタンを押すと/cards/:idに遷移する(useNavigateのパスをみる)
    - [x] IDを入力しないでボタンを押すとエラーメッセージが表示される
    - [x] 新規登録はこちらを押すと/cards/registerに遷移する

# MVP7 期限6/8まで

ユーザーの情報を次の日にすべて削除するバッチ処理をGithubActionsのクーロンジョブを使って実現することにしました

朝6時に前日のusersとuser_skillを削除するようにします

## TODO

- [x] tsファイルを実行すれば前日作成したusersとuser_skillを削除できるようにする

```
 npx ts-node --esm ./batch/index.ts 
```
このコマンドを実行したら削除ができるようにする

- [x] 毎朝6時にクーロンジョブが実行されるパイプラインを作成する
GithubActionsで新たなファイルを作成すること。その中では上のコマンドを実行するようにする

前日のデータをsupabaseで手動で作成する。GithubActionsを手動で実行して消えればOK
次の日の朝も一応確認すること


# MVP8 期限6/10まで

- [ ] 記事を書く
- [x] READMEを書く

時間があればやりたいこと
- [ ] 404ページ
- [ ] 自己紹介サニタイズ
- [ ] ユーザー登録フォームバリデーション（）
- [ ] user登録時にIDがテーブルにあったらエラー、"register"も登録できないようにする
- [ ] selectを複数選択可能にする

# 見本アプリ
https://degital-meishi.web.app/
id: sample-id
