これは 2025 年度冬ハッカソンにて制作された作品です。サイボウズ株式会社 様より企業賞をいただきました。
作品概要
私たちが制作したのは、traP の部内経済基盤「Plutus」です。
部内で作成されたゲームやサービス内の通貨を、比較的簡単にサービスを超えて使えるようにするためのプラットフォームの創造を目指しました。
サークル内独自通貨「コピア」による決済サービスを実装した他、取引履歴や残高ランキングなどを可視化するダッシュボードである「Pteron」も実装されています。

メンバー紹介
今回のハッカソンでは誰かひとり偉い人を作るのではなく、全員が責任者としての自覚を持てるような配置となっています。
やくわり (表)
@uni_kakurenbo: リーダー
@howard127: キャプテン
@rurun: 取締役
@mikannkann: エース
@mamo: 監督
@quarantineeeeeeeeee: CTO
@o_o: ブレイン
やくわり (裏)
@uni_kakurenbo: フロントエンド, デザイン
@howard127: バックエンド
@rurun: フロント, デザイン
@mikannkann: 社内環境整備, フロント
@mamo: バックエンド
@quarantineeeeeeeeee: フロント, デザイン
@o_o: バックエンド 飽きたらフロント
Plutus とは

部内経済基盤「Πλοῦτος (Plutus)」は「πτερόν (Pteron)」と「cornūcōpiae (Cornucopia)」から構成されています。cornūcōpiae(Cornucopia) は取引を管理する金融サーバーであり、πτερόν (Pteron)を通して、取引や履歴の確認を行うことができます。
πτερόν(Pteron) のクライアントは React、サーバーは Kotlin で作られています。
cornūcōpiae (Cornucopia) は Go で作られており、πτερόν (Pteron) と gRPC により通信を行います。
また、今回実装した通貨「コピア」を活用するプロジェクトのサンプルとして、「Ἑρμῆς (Hermes)」「Δημήτηρ (Demeter)」を制作しました。こちらはNext.jsで実装されています。
デプロイは traP 内製の作品公開プラットフォーム NeoShowcase にて行いました。
アプリ詳細
cornucopia
まず今回のプロジェクトではなぜか(その必要が無いにも関わらず)実際に通貨のデータを持ったり残高を持つ口座の管理を行うシステムをWebのバックエンドサーバーから独立させる意思決定が行われました。
しかもなんとバックエンドサーバーではKotlinを採用しているにもかかわらず、「より基盤感がある」ためGoが採用されました。
さらにバックエンドサーバーとの通信は「名前の響きがかっこいい」のでgRPCで行うことになりました。
その結果、まともにクエリが投げれない低機能データベースが完成しました。
うーん...
今のなってはなんでこんな技術選定をしたのかは思い出せないですが、結果としてgRPCを採用したことが企業賞に選ばれた理由の一つになったのでギリギリ良かったなと思います。

↑ @o_o 作のアイコン
Pteron サーバー
PteronのAPIサーバーです。言語はKotlinになりました。理由は @howard127 がマイクラ好きだからです。
これはこのプロジェクト全体に言えることなのですが、この班にはtraPに革命を起こしたいロックなメンバーが集まっているので基本的にtraPの標準から外れた技術選定がなされています。
このプロジェクトではKotlinでAPIサーバーを作るためのフレームワークとしてKtorを採用しました。Kotlinの開発元であるJetBrains社が公式に作っているので安心して使えました。
他にはDIコンテナとしてKoin、テストフレームワークとしてKotest、SQLライブラリとしてExposedを採用したりしました。かなりイマドキなKotlinを書けた気がします。
正直、開発期間が始まってから数日間の内に機能の7割ぐらいが完成した(と思っていた)ので「班員の教育に力を入れるぞ~💪」などと余裕ぶっていたのですが次々に考慮し忘れていた要件が発覚し、結局

こうなって

こうなりました。ごめん...
またこのサーバーはtraP内製PaaSのNeoShowcase上にデプロイしているのですがGradleによるビルドが重すぎてNeoShowcase上でのビルドが失敗するという問題が発生しました。結局Github ActionsでビルドしたイメージをNeoShowcase側で使うことで事なきを得たのですが、標準から外れたことをするとどんな問題が起きるか分かんないもんですね。反省します。
ぷてろんクライアント
クライアントは @uni_kakurenbo の独裁強い希望により、Reactで実装することになりました。他のメンバーはみんなVue.jsの方が使えるはずなのに不思議ですね。
traP に React の風を起こそう
コンポーネントライブラリには、@rurun が使ってみたかったMantineを使いました。少し癖はあるものの、コンポーネントの種類が豊富で使いやすかったです。これのおかげでハイペースで開発を進めることができました。
ちゃんと動くかっこいいダッシュボードができてよかったです。





でーめーてーる
copiaのやり取りのデモで、シンプルなポイントの受け取り、請求の実装をしています。
ポイント残高表示
プロジェクトが保有するポイント残高をトップページに表示
ポイント受け取り
「ポイント獲得」ボタンを押すと、プロジェクトからログインユーザーへ10ポイントが送金
ポイント請求(決済)
プロジェクトがユーザーに対して支払いを請求。請求を作成するとPlutusダッシュボードの決済ページへリダイレクトし、ユーザーが承認または拒否した後、指定したURLに戻る。
へるめーす
Plutus API(Pteron)を使用したアプリケーション実装のデモのための、
スロットマシンのサンプルアプリケーションです。
以下の機能があります:
- ユーザーのポイント残高の取得
- スロットゲームを通じたポイントの増減(送金・決済フローの活用)
ぼくのコピア
Plutusを使って @howard127 の口座に送金をすることができるだけのWebアプリです。

最終発表中に発表まで時間があったので半分冗談として作ったのですが、思ったよりウケが良かったので正式にデモ用とアプリとして整備して公開することにしました。遊びで作ったのに多分DemeterやHermesより使われてて、コミーを推したいのになぜかスピキが流行ってしまったトリッカルの代表と同じ気分です。
インフラ
ポリレポで関心の分離
レポジトリ構成は @uni_kakurenbo が設計してくれました。
Plutusは複数のサービスで構成されるシステムですが、git submoduleを使って階層構造を表現しています。これによって関心の分離が実現でき、例えば、フロントのメンバーは基本pteron-clientの中だけで作業することができます。
plutus (親リポジトリ)
├── system/
│ ├── pteron/
│ │ ├── client/ → traP-jp/pteron-client (React)
│ │ └── server/ → traP-jp/pteron-server (Kotlin)
│ └── cornucopia/ → traP-jp/cornucopia (Go, 金融サーバー)
├── specs/ ← API仕様(OpenAPI, Protobuf)
└── docker/ ← 本番用Dockerfile(ghcr.ioイメージを参照)
// これの他に、あと3こくらいデモアプリのレポジトリもある
Issueドリブンで開発
基本Issueドリブンで開発しました。並行作業が効率的に行え、進捗の可視化ができて良かったです。またissueテンプレートも作りました。
ハッカソンのスピード感を殺さないように、以下の流れで運用していました。
- 気付いた人が雑にissueを立てる
- 要件を話し合ったり、適切な粒度までissueを分割する
- 作業ができる状態になったら、
need/triageラベルを剥がす

(特にハッカソン中は、全ての欄を埋めるわけではないので、_No response_というテキストが残って見にくいです。そこで、不要な部分を自動でHTMLコメントアウトするワークフローを書きました。視覚的なノイズを減らすのにとても便利でした。.github/workflows/comment-no-response.yml)
ラベル設計
ラベルは大きく以下の5つのカテゴリに分け、管理しました。
特に、must,shuold,couldの3つに優先度を分けることで、開発をより効率的に進めることができました。
| カテゴリ | 説明 | 例 |
|---|---|---|
type/ |
何の種類か | type/enhancement, type/bug, type/refactoring, type/chore |
area/ |
どこを触るか | area/client, area/server, area/server-finance, area/infra, area/design, area/docs |
priority/ |
優先度 | priority/critical, priority/must, priority/should, priority/could |
need/ |
必要なアクション | need/attention, need/triage, need/discussion, need/help |
status/ |
課題の状態 | status/blocked, status/invalid |
(親レポジトリの.github/label.ymlをマスターとして、全リポジリに自動同期するワークフローを書きました。UIぽちぽちしなくていいので、めっちゃ便利でした。)
submoduleの運用の工夫
code-workspaceの利用
submoduleで分離すると、開発時に複数リポジトリを行き来するのが煩雑になってしまいます。そこで、VSCodeのマルチルートワークスペースで全サービスを一画面にしました。
さらに、git submodule update --init --recursiveで全サブモジュールを取得した後、plutus.code-workspaceを開けば全体を見ながら開発できます。
子レポジトリの反映問題への対処
gitのsubmoduleは、子の更新が自動で親に反映されるわけではありません。そこで、子のmainにpushすると、親にrepository_dispatchを送信し、親が自動でsubmodule更新するようになっています。
[子] push to main
-> dispatch-update.yaml (or docker-publish.yml)
-> curl で traP-jp/plutus に event_type: "update" を送信
[親] repository_dispatch を受信
-> update-submodule.yaml
-> submodule更新
-> 自動commit & push
(pteron-serverでは、dispatch-update.yamlを削除してdocker-publish.ymlに統合。
「Dockerイメージのビルド完了後にdispatchする」設計にすることで、イメージ公開が確実に完了してから親に通知されるようになっています。)
PRの自動化
PRもci関係だけでなく、開発の流れを止めないような自動化も行いました。
例えば、ブランチ名にissue番号がある場合は、PRのdescriptionに Closes #123 と自動追加されます。これにより、ハッカソン中に時間に追われて無言でPRを出しても、issueと自動関連付けされ、PRのcloseと一緒にissueが自動で閉じます。余計な手間をなくしつつ、issueの閉じ忘れも未然に防ぐことができます。他にも、issueラベルの自動付与や、assigneeを設定するのを忘れていたら、PRを作った人を自動で指定されたりもします。
みんなの感想
@uni_kakurenbo
Pteron のクライアント書いてました.
ずっとおんなじ技術スタックばっかり触れててもつまらないし,部内のローカルなデファクトスタンダードが根を張りすぎるのもあんまり健全ではない気がしたので,今回は班員のみんなには React を使ってもらうようにしてみました.まあ冬墓だし,ガチ初心者はいないし.いいかなって.
Hermes とか手伝っていて思ったのですが,個人的には短期開発に Next.js は悪くないかなと思います.
P.S. なんか気付いたら班員のみんながブログを書いてくれていました.ありがとう.
@howard127
Cornucopia と Pteron のサーバーとぼくのコピアを作りました。
技術選定で適当に聞いたことのある技術を言っていたらなんと全部採用されてしまいました。悪ノリって怖いですね。
僕がServer-Side Kotlinをごり押しして採用したので責任を取って同じくバックエンドチームの@mamoと@o_oにKotlin教えるぞ~と意気込んでいたのですがそもそも1週間しかない上、初心者がいるにも関わらず無駄に設計を凝ってしまったため最終的にほとんどタスクを振ることができませんでした。:gomen:
技術選定や設計の際はプロジェクトの規模や開発期間、メンバーなどをちゃんと考慮しましょう。(自戒)
ちなみにCornucopiaはコードの9割、Pteronサーバーはコードの7割、ぼくのコピアに関してはコードのほぼすべてがAIによって生成されています。AIの進化って怖いですね。
@quarantineeeeeeeeee
Pteronのクライアントの実装を行いました。初のReactでしたが、普段触っているVue.jsとの共通点や違いについて実践的に学ぶことができました。未経験のUIライブラリにハッカソンで挑戦する不安もありましたが、ダッシュボードらしいデザインを素早く作成することができたので、結果的には大正解だったと思います。やはり適切に手を抜くことは大切だと実感しました。最高に強くて面白いメンバーに恵まれて、とても楽しく開発することができました!
@rurun
UIのラフと、PlutusのOpenAPI定義と、Pteronのクライアントを主に担当しました。
予定があって作るものを決めるミーティングに遅れて参加したのですが、Discordの通話に入った途端 「traPの経済を作ります」 と言われ訳のわからない名前を5個くらい羅列されました。懐かしいです。
Reactを使うのは初めてだったのですが、チュートリアルなども整備されていてよかったです。今回はReactのReactらしい部分をあまり触らなかったので、機会があればまた使ってみたいと思います。OpenAPIのyamlは人間が書くものじゃないですね。苦しかったです。ハッカソンの終盤ではかなりGitHub Copilotを使っていたのですが、改めてAIの進化を感じました。
これまでのハッカソンでは開発が終わらないがちだったので、最初に書いたラフにかなり近く、ちゃんと動くものが完成して、感動しました。このチームで開発できてよかったです。とても楽しいハッカソンでした!
@mikannkann
インフラ関係をいじったり、タスク管理したり、Pteronのクライアントやったり、いろいろしてました。実は今までのtraPのハッカソンでは、時間切れになってしまい、少しやり切れない気持ちがありました。しかし今回は、初めて完成まで持って行けた作品になりました。強くておもろいメンバーと一緒に全力で走り切れて、本当に楽しかったです!!!!!
@mamo
バックエンドは力になるというより:@howard127:からずっと教えてもらっていました。設計について特に教えてもらって、とっても面白かったです:dekadekaarigatou:実際にコードを書きフィードバックをもらって、とてもためになりました。
そのあとはdemeterをAIに書かせるという仕事をしていました。フロントをほぼ書いたことがなかったので、AIの仕事を見ながら勉強していました。AIってすごいですね。ただデザインがAIぽいとほかのメンバーに突っ込まれました:gomen:
ほかのメンバーが強くて刺激になるハッカソンでした!このチームに参加できてよかったです!とても楽しかったです!
@o_o
主に Pteron クライアントとアイデア出しを行いました。今回こそバックエンドやります!と自己紹介で意気込んだものの、バックエンドは Kotlin の勉強を冬墓前にやったことと、中途半端なコミット一つで終わってしまいました。なんでだろう。
Pteronクライアントでは初めての React でしたが、個人的にはVue.js よりも書きやすくとても気に入りました。いつか traP の標準にしていきたいですね。ハッカソンで納得のできるものを完成させることができたのは今回が初めてだったのでとても達成感があります。最高のチームメンバーに囲まれて、おふざけ半分、真面目半分で開発期間は毎日のように笑っていました。本当に楽しかったです!ありがとうございました!
ほんとに次こそはバックエンドをちゃんとやりたい