【初めてのAWS】チームの勤怠管理システムを作ってみた（その１）

# 1. 初めに
「AWSを触りたい！」と心に決め、前々から若干必要かなと思っていたチーム内の勤怠管理システムをAWSを使って作ってみようと思った。気づいたら行動に移していた。

勤怠管理システムの全貌としては以下の3つである。3本に分けて残していく。
その１：名前を選択して「出勤」or「退勤」ボタンを押し、記録する
その２：勤怠記録のデータを可視化する
その３：過去の勤怠を編集できるようにする

**本Qiitaの内容**
* どうやってAWSの世界へ入っていったか
* 初めてのLambda
* Chat GPTとの協働
* WebのJSからAPI呼び出し

# 2. AWSを学ぶ
「AWSって美味しいの？」ってレベルの知識から勤怠管理システムを作るにあたって、いいチュートリアルを探していた。そこで、[AWS Hands-on for Beginners 〜Serverless #1〜](https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-Serverless-1-2022-confirmation_422.html)を見つけた。このハンズオンは今世紀で一番役に立った。

下図のような、API Gatewayを使ってLambdaを呼び処理を行うという基本的な構成をハンズオン形式で学ぶことができるので非常におすすめ！私のような初めてAWSを触る人でもとてもわかりやすかったと思う。
```mermaid
graph LR
  User([User])-->B[API Gateway]
  B-->C[Lambda]
  C-->B
  B-->User
```

ただ、このハンズオンが公開されたのが2019年ということもあり、若干動画内のサイト構成と変わっているところがあるからその点だけ気をつける必要がある。

# 3. 勤怠をつけるLambdaを作る
今回は、DynamoDBを使って勤務時間を管理するLambda関数を作成するようにした。web側で開始ボタンor終了ボタンを押して、押されたボタンによってLambda側の処理を変えた。
DynamoDBではパーティションキーをName（文字列）、ソートキーをTimeStamp（文字列）として作成した。
### DynamoDBの構成
* Name
* TimeStamp
* EndTime: 開始時はNull, 終了ボタンを押したときに記録される
* WorkingHour: 開始時はNull, 終了ボタンを押したときに記録される

### Lambdaコード
if文で開始と終了を分け、処理を変えている。
**簡単にコードの説明**
こちらのコードは開始ボタンを押された時用のコードである。引数であるEventがどんな形になるか想定しながら、入力される名前を取得する。まず、前回の勤怠が終了できてることを確認する。前回終了できてないのに開始できるようになったら、二重払いに繋がるから気をつけよう！！前回終了してたらDynamoDBに名前とTimeStampを記録する。
```python:Kintai_Add_start.py
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('TableName')#テーブルの名前を入れる
def lambda_handler(event, context):
    action = event['action']
    name = event['name']

    if action == 'start':
        # 最新の勤務記録を取得
        response = table.query(
            KeyConditionExpression=Key('Name').eq(name) & Key('Timestamp').begins_with('202'),
            ScanIndexForward=False,
            Limit=1
        )

        if response['Items']:
            last_record = response['Items'][0]
            if last_record.get('workinghour') is None:
                return {
                    'statusCode': 400,
                    'headers': {
                        'Content-Type': 'application/json',
                    },
                    'message': '前回の勤務を終了していません。'
                }

        timestamp = datetime.now(timezone.utc).isoformat()
        response = table.put_item(
            Item={
                'Name': name,
                'Timestamp': timestamp,
                'EndTime': None,
                'WorkHours': None
            }
        )

        return {
            'statusCode': 200,
            'headers': {
                'Content-Type': 'application/json',
            },
            'message': "仕事開始！！",
            'timestamp': timestamp
        }
```
終了ボタンが押された時も同じようにelifで作動するようにしよう。
終了の時はworkhourも記録できるようにコードを書かないといけないけど、Chat GPTに頼めばすぐ作ってくれる。

# 4. ChatGPT(or Claude)にweb（HTML, CSS, JS）を作ってもらおう
この辺については大体知っててただの作業になりそうだったのでChat GPTに全部振った。
プロンプトとしては以下を使ったと思う（若干忘れてる）
``` prompt.txt
##背景
勤怠管理のhtml, css, jsで作ろうとしてるから手伝って欲しい
htmlではドロップダウンで名前を指定できて、勤務開始と勤務終了というボタンを押してJSからAPIを実行する

##ユーザーストーリー
1. index.htmlでドロップダウンでAさんを指定する。勤務開始ボタンを押したら、apiでdynamodbに記録。
2. 勤務終了する時にindex.htmlで勤務終了ボタンを押す。dynamodbを参照して、その名前の人が直前に出勤しているか確認。出勤記録があれば、出勤開始した時間から勤務時間を計算する。直前の記録が退勤だったら、出勤していませんというアラートを出す。

＃その他
名前と勤務開始時間、勤務終了時間、勤務時間のカラムがある。
この流れが適切か確認して、よければ、index.htmlとcssとjsを書いてほしい
```
もっといいプロンプトがあったらぜひ教えて欲しい

**HTML. CSS, JSはちょっと知っておいた方がIIKAMO**
HTML, CSS, JSの基本構文とかはある程度理解してないと、APIを繋げたり、ちょっとだけデザイン変えたりみたいなことができなくなるので、おおかたChatGPT等に作ってもらい、それをありがたく編集するという立場がいいと思う。

**Web作るならClaudeの方がIIKAMO**
HTML, CSS, JSは意外と合計すると量がある。Chat GPTよりもClaudeの方がいいかもしれない。だいぶ個人的ではあるが、Claudeの方が各ファイルの連携ってところでは勝ってる気がする。かつ、意外と各ファイル長いからClaudeの方が出力断然早くてサクサク進められる。

# 5. API Gatewayの設定
ハンズオンである程度できると思う。
注意点はステージとデプロイをしっかりすることを忘れないように。
私がハンズオンで見逃してただけかもしれないけど、APIとしてPOSTしたりGETしたりするみたいな説明はなかったと思う。WEBからはPOSTとかGETとかPUTとかするからその辺で設定は若干必要になる。

**特に悩んだところ**
* CORS
後でJSからPOSTするとき、コンソールでCORSのエラーがずっと出てて、CORSって何やねんってなった。CORSの設定のボタンば全然見つけられず、しばらくここで苦労した。!この画像からだとすぐに見つけられると思うが、webに転がってるレイアウトと若干変わっていたのか見つけるまで本当に苦労した。「APIをデプロイ」ボタンの下でCORSを有効にできるからこれをする。

* ステージ・デプロイ
CORSを有効にした後もここで苦労した。webで転がってる情報によるとCORSを有効にした後に「APIをデプロイ」を押すとデプロイできると書いてあったが、一生できなかった（変なことをしてただけかも）。新しいステージを作成からステージを作り、作ったステージにデプロイする。そうするとやっと使える。

# 6. JSからのAPI使用
この点は、`# 2. AWSを学ぶ`に含まれていなかったので、若干苦戦した。エンドポイントをどのように使ったらいいかわからなかった。Chat GPT大先生に聞くとすぐわかるから聞いてみるといい。エンドポイントはLambda関数の設定->トリガーからエンドポイントのURLが取れるのでコピペする。
あと、Lambda関数が要求する形でデータを上げなきゃもちろん動かない。
Lambda関数に合うように変更しよう。私はここでChat GPTに裏切られて、ずっと違う形でデータを渡すJSを教えられ困った。困った時はClaudeとかも使おう（自分を信じるのもすごい大切）。

JSスクリプトを一部抜粋
``` Javascript script.js
function recordTime(action) {
    const url = 'https://endpoint'; // LambdaのAPI Gateway Endpoint URLを設定
    const nameSelect = document.getElementById('ドロップダウンの選択のhtml id');
      const errorField = document.getElementById('Errorを表示するid');
      const name = nameSelect.value;
      }
    fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ 
        action: action,
        name: name 
    })
})
```

# 最後に
この流れで勤怠管理システムのデータを入力するシステムが完了した。私はUIとか凝るとモチベに繋がるのでその後UIをChat GPTと相談しながら作った。
これができた後、チームでこのデータちゃんと可視化できるようにしたいということになり、データ可視化ページに取り組むことになった。

次回：データ可視化するってよ