皆様こんにちは、最近銀髪になったTatsuroです🧑🦳。
題名に表記しています通り、コミュニティ内でハッカソンを企画・開催しました。
開催に至った経緯
年末のテックブログにも掲載しましたが、11月にAbemaタワーで開催された東京Flutterハッカソン2024に僕・yo・Ayato・kochaの4人で参加し、株式会社ゆめみ様( https://www.yumemi.co.jp/ )のスポンサー賞をもぎ取りました。
賞品の内容はというと、審査員兼・ゆめみ様で技術取締役をされている、よーたん(渡辺陽太)さんが「願いを1つ叶えてくれる」というものでした。(玉を7つ集めると出てくる的な🐉)

そこで、賞品を使って「弊コミュニティPlayGroundでハッカソンやりたいです、審査員やってください!!」と思いつきでお願いしてみたところ、なんと快く了承して頂き開催に至ることになりました。
有難い事この上ない!
開会式
というわけで3/6に開会式を開催しました。
なんと審査員には、よーたんさんの他にゆめみ様の「CTOの大城さん」「CDOのリリーさん」にお引き受け頂くことができました(凄すぎて何で来てくださったのか未だによくわかってない)。
また、今回のハッカソンのテーマは「ライフ」に決定しました。
よーたんさんにテーマを決めて頂きましたが、決定理由に関しては「大人と学生との間でライフスタイルの違いがあるんじゃないかうんぬんかんぬん」とのことでした。


チーム数は4(6人×4チーム)でレギュレーションは以下のように設定しました。


開発スタート
さて、20日間の開発が始まりました。
以下コミュニティ内のMastodonサーバです、気合い入ってますね。

ここからは僕のチームのアプリ開発についてお話しします。
他チームが開発したアプリに関しては、後日別記事で上がるかも?ご期待ください。
早速ですが、僕たちTeam3が開発したアプリはこちら「wa-live」です!!
某チャットアプリのようなローカルコミュニティ内で大喜利を行うアプリです。
僕たちのチームは、
デザイナー1名・フロントエンドエンジニア3名・バックエンドエンジニア1名(僕)の5名で開発を行い、
開発の流れは、全員でアイデア出し → 仕様決め → デザイン → 実装 のお決まりの流れでした。
デザイン
デザイナーのMioさんには稼働時間が取れない中、無理を言ってデザインを作製して頂きました。
マジで感謝🙏
アーキテクチャ
フロントエンドエンジニアのLuck, Ren, Ryuの3人はReact&Viteで開発を行い、OrvalでAPIクライアントのコード自動生成を行ったり、TanstackRouterでルーティングを実現したりとモダンな技術構成に挑戦して頑張ってくれました。
バックエンド・インフラは僕が担当しましたが、terraformでAWSサービスの構成管理を行い、フロントエンドはAmplifyでデプロイ・認証機能はCognitoで実装・バックエンド部分はLambda・APIGatewayのサーバレス構成で実装しました。
苦労した実装ポイント
以下の機能を実装しました。
- グループ作成
- ユーザー招待、参加
- リアルタイムチャット、大喜利テーマ投稿
- 回答、いいね
- ランキング集計
この中で特に苦労したのはチャット画面でリアルタイムに投稿を行う機能ですね(僕が)。
自前でWebSocketを実装するのが面倒そうだったので、
開発に慣れているAWSサービスの中からAPIGateway WebSocketAPIの存在を知り選定してみました。
WebSocket接続時にConnectionをDynamoDBに保存、切断時に削除します。
メッセージはDynamoDBに保存したあと、ブロードキャストで他の接続Connectionに送信します。
実装自体はさほど難しくありませんが、httpと違ってws通信の概念を理解するのが大変だったかも。
// lambda_functions/websocket/connect.py
def lambda_handler(event, context):
try:
# 接続IDをイベントから取得
connection_id = event["requestContext"]["connectionId"]
# クエリパラメータからユーザーIDとグループIDを取得
query_params = event.get("queryStringParameters", {}) or {}
user_id = query_params.get("userId", "")
group_id = query_params.get("groupId", "")
# 現在のタイムスタンプを取得
current_time = int(datetime.now().timestamp() * 1000)
# 接続情報をDynamoDBに保存
connections_table.put_item(
Item={
"connectionId": connection_id,
"userId": user_id,
"groupId": group_id,
"createdAt": current_time
}
)
print(f"接続が確立されました: connectionId={connection_id}, userId={user_id}, groupId={group_id}")
return {
"statusCode": 200
}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {
"statusCode": 200
}
// lambda_functions/websocket/disconnect.py
def lambda_handler(event, context):
# 接続IDの取得
connection_id = event["requestContext"]["connectionId"]
# 接続情報をDynamoDBから削除
connections_table.delete_item(
Key={
"connectionId": connection_id
}
)
return {"statusCode": 200}
// lambda_functions/websocket/send_message.py
def lambda_handler(event, context):
# 接続IDの取得
connection_id = event["requestContext"]["connectionId"]
# API Gateway Management APIクライアント
api_endpoint = f"https://{event['requestContext']['domainName']}/{event['requestContext']['stage']}"
api_gw = boto3.client("apigatewaymanagementapi", endpoint_url=api_endpoint)
try:
// 割愛(S3に画像アップロード、DynamoDBにアイテムを登録等)・・・
# クライアントに送信するメッセージを作成
send_data = {
"messageId": message_id,
"groupId": body["groupId"],
"messageType": body["messageType"], # CHAT, THEME
"messageText": body["messageText"],
"messageImage": message_image_url,
"createdBy": user_info, # 送信者の情報
"createdAt": created_at,
"prizeText": body.get("prizeText", ""),
"deadline": body.get("deadline", "")
}
# 同じグループ内の全接続に送信
# 送信するグループのユーザーのコネクションを取得
group_connections = connections_table.query(
IndexName="GroupIdIndex",
KeyConditionExpression=Key("groupId").eq(body["groupId"])
)
# 送信者以外の全接続にメッセージを送信
for connection in group_connections.get("Items", []):
try:
api_gw.post_to_connection(
ConnectionId=connection["connectionId"],
Data=json.dumps(send_data)
)
except Exception as e:
# 無効な接続は削除
if "GoneException" in str(e):
connections_table.delete_item(
Key={"connectionId": connection["connectionId"]}
)
return {"statusCode": 200}
except Exception as e:
print(f"エラー: {str(e)}")
return {"statusCode": 500, "body": str(e)}
こんな感じで実装して本番でデモを行うことができました。
徹夜でフロントチームと繋ぎ込んだ甲斐がありました。(ほぼLI○Eやないか)

成果発表
そんなこんなで3/27に成果発表を行い、審査員御三方に厳正なる審査及びFBをして頂きました。
優勝チームは、Team4のゲテモノ版クッ○パッド「Cook Wild」でした🏆
実装内容もさることながら、フィールドワークを通したアイデアの作り込みが凄まじかったです。
(Team4含め、他チームのアプリに関しては別記事にて紹介して頂く予定です)




総括
この度は、株式会社ゆめみ様から審査員として御三方をお招きしてこのようなイベントを開催することができました(学生一同、感謝してもしきれません🙏)。
本イベントを通じて、コミュニティ内の開発意欲が格段に高まったことも言うまでもありませんし、ハッカソンで技術力やチーム開発の素養を身につけることができた学生が大半だと思われます。
この勢いのままコミュニティの活気が更に増して欲しいなと切に願います🔥


審査員としてお越しくださった、よーたんさん・リリーさん・大城さん、本当にありがとうございました。
それではまた、どこかでお会いしましょう😎 さようなら!!(他チームの開発記事もお楽しみに)