スプーキーズのちょっとTech。

SPOOKIES社内のより技工的な、専門的なブログページです。

Full Weak Engineer CTF 2025参加しました!

こんにちは!Spookiesに入ってもう少しで3ヶ月、こまさんです!!
CTFは、入社する3年ぐらい前に一度参加してからずっとノータッチだったんですが、SpookiesにCTF部がある!という事で最近はボチボチ頑張ってます💪

という事で、今回はSpookiesのCTFチームspookiesFull Weak Engineer CTF 2025に参加してきました!

まずは結果から!

今回は一緒に参加してた方がめちゃくちゃ頑張ってくれて17位でした! 結構すごいのでは?!

私が解いた問題は4問だけですが、ちょっとその中から面白かったのをピックアップして話していきたいと思います!

まずはみんなの活躍を紹介~

  • Nemoola
    • Poison Apple (100pts./444solves/Misc)
    • AED (127pts./232solves/Web)
    • regex-auth (100pts./450solves/Web)
  • Huzuni
    • Welcome (100pts./522solves/Welcome)
    • strings jacking (100pts./447solves/Rev)
    • I_HATE_DEBUGGING (395pts./25solves/Rev)
    • Mystery Zone (227pts./97solves/Rev)
    • No need Logical Thinking (132pts./219solves/Rev)
    • NativeKotlian (497pts./2solves/Rev)
    • Pwn Me Baby (153pts./178solves/Pwn)
    • Flagcraft (277pts./67solves/Misc)
    • GeoGuessr1 (100pts./404solves/OSINT)
    • GeoGuessr2 (100pts./320solves/OSINT)
    • GeoGuessr3 (100pts./318solves/OSINT)
    • datamosh (106pts./294solves/OSINT)
    • RSA Phone Tree (124pts./240solves/OSINT)
    • GeoGuessr4 (133pts./217solves/OSINT)
    • QR (211pts./110solves/OSINT)
    • Osaka Expo Pavilion Quiz! (256pts./78solves/OSINT)
    • EXIT (147pts./189solves/OSINT)
    • MYAKUMYAKU TOWER (260pts./76solves/OSINT)
    • git predator (277pts./67solves/OSINT)
  • Komasan_ (私じゃ!)
    • baby-crypto (100pts./563solves/Crypto)
    • base🚀 (101pts./316solves/Crypto)
    • unixor (324pts./47solves/Crypto)
    • A (459pts./10solves/Rev)
  • mattyatea
    • Adversarial Login (230pts./95solves/Misc)

こうやって見るとそこまで活躍はできなかったですね、、😅 まぁ反省会は置いといて、、、

この中の「A」という問題がなかなかインパクトあって、面白かったので紹介してみますね!

まずは見てみよう

まぁまず添付ファイルが「main.py」と、、Pythonですね!(Python大好き人間なので嬉しい!!) とりあえずダウンロードしてコードを見てみましょう。

もういかつい

うひゃ~~、なんかとんでもないコードが出てきてしまいましたね。。(画像かなりちっちゃくて見づらいかも、、😨)

という事で、パッと見た感じ、Pythonの特殊メソッドを使って、演算子オーバーロードがたくさんされているみたいですね。。 で、とりあえず実行してみたのですが、流石にどこか弄られていて動きませんでした。(動いたらまだデバッガとにらめっこしてもよかったのですが、、)

じゃあ気合で難読化を解除していきます。

気合で解読

まず、最初はclassが2つ定義されていて、片方はメタクラスA、もう片方はAを継承したクラスA、という構造になっていますね。

演算子オーバーロードだらけ

まずできそうなことは、base64でエンコードされた文字列がたくさんあるので、ここをデコードしてみましょうか。

なんか作者からのメッセージがある。。(確かにSHA-256はだるいなぁ)

なんか、メソッド名とかクラス名とか色々ありますね。。ここから取ってきてメソッドとか実行しそうな感じ。

ここからは、まずクラスAの中身をほぐしていきます。。もう気合しかありませんね。

⌛⌛⌛作業中⌛⌛⌛

とまぁ、そんな感じで、各メソッドを気合で解きほぐしたらこんな感じになりました。

3分クッキングを彷彿とさせる差し替え術

どうやら、簡易的なスタックマシンが作られているみたいですね。 (なおスタックにはリストとかのオブジェクトも突っ込める現代仕様)

このスタックマシン的構造でコードを実行するようだ。。

そんで本題の下のコードの処理も展開していくと、、、

ダイエット大成功

めっちゃシンプルになりましたね!!!(苦笑)

本当に初動のコードが嘘みたい。

それでコードを読むと、、

「要はflagを入力して、その文字列の文字毎のコードの総和をシードとして、ランダム値を生成してそれと入力をxorしたものがコード中にあるlistに合致すれば正しいフラグだよ」

という感じですね。

あと49文字だという事も分かるので、seedの取りうる範囲での総当たりで解読できそうですね。

ここまでくれば、もうちゃちゃっと行けるかな(この問題の本題はRevであってCryptoじゃないのでね)

あー楽しかった🚩

Javaに演算子オーバーロード、、、、、だめです!!!!もっと難化しちゃう。

感想

今回はちょっとインパクトがあったRev問を一つWriteup的に書いてみました。 (といっても実質的に作業が地味すぎるからほぼ差し替えですが。。)

楽しかった!!この調子で、すこしずつCTF部も盛り上げていきたい!!

あとPwn問を練習したいなぁと思っていたり。。 日々精進ですね。頑張ります。

Claudeの可能性を探ってみた

この記事は人間が書いています

こんにちは。

まっちゃんです 👋

現在、SpookiesではAIの導入を進めています。

導入を進めているAIはAnthropicという会社が開発している、ClaudeというAIです。

そのAIをどのように活用していけば良いかを書いていきたいと思います。

開発者が執筆しているので、開発者的な目線での解説が多いかと思いますが、ご了承ください 🙏

Claude、何ができるんだ

現状、AIには得意不得意がありますが、Claudeくんは、プログラミングが得意です。

実際に説明させてみましょう。

Claudeって何がするのが得意なの?

Claudeは以下のような分野が得意です:

文章作成・分析
長文の要約、技術文書の作成、メールの下書き、創作活動など、様々な文章タスクを高品質でこなせます。複雑な内容も分かりやすく説明するのが得意です。

プログラミング・技術サポート
コードの作成、デバッグ、リファクタリング、技術的な質問への回答など。多くのプログラミング言語に対応しており、アーキテクチャの設計相談なども可能です。

データ分析・可視化
CSVやExcelファイルの分析、グラフ作成、統計的な洞察の提供など。アップロードされたデータから意味のある情報を抽出できます。

問題解決・論理的思考
複雑な問題を段階的に分解し、論理的なアプローチで解決策を提案します。ブレインストーミングや意思決定のサポートも得意です。

学習・教育サポート
概念の説明、例題作成、学習計画の立案など。難しいトピックも理解しやすく噛み砕いて説明できます。

クリエイティブな作業
アイデア出し、ストーリー創作、デザインコンセプトの提案など、創造的な思考をサポートします。

何か特定の作業でお手伝いできることはありますか?

めちゃくちゃ長いレスポンスが帰ってきたので、要約させます

要約してください

Claudeが得意なことを簡潔にまとめると: - 文章・コミュニケーション - 要約、執筆、説明が得意 - プログラミング - コード作成・デバッグ・技術相談 - データ分析 - ファイル分析・グラフ作成・洞察提供 - 問題解決 - 複雑な課題を論理的に分解・解決 - 学習サポート - 概念説明・教育コンテンツ作成 - クリエイティブ - アイデア出し・創作活動

つまり、文章から技術まで幅広い知的作業をサポートできる汎用的なAIアシスタントです。

幅広いらしいです(ほんまか)

というのはさておき、実際に何ができるかみてみましょう。

使うときに大切なこと

なるべく、タスク化をさせて、そのタスクの詳細などに、やりたいことを詳細に書いてもらいましょう。

それを私たち人間が精査して、修正して、Claude CodeなどのAIに取り掛かってもらうことで、「思ってたのと違うが??」が発生しにくくなります。

また、コーディングのフローで言うと、

  1. タスクが切られる
  2. タスクを作業者が精査する
  3. 精査した情報を元に、作業する
  4. 作業者がPRを作成する
  5. レビューしてもらう
  6. 作業者がレビューから修正、返答などを行う
  7. マージする

のようなフローですが、その中で作業者の部分がClaude Codeになって、レビュー者が人間になるようなイメージが一番わかりやすいです。

なので、Claude Codeなどが生成したコードをレビューするのが我々の役目です。

それでレビューをし、おかしな点などをどんどんプロンプトに入れて、修正してもらいます。

また、その時にルールとして定義させて、起こらないようにするなどのことも必要です。

プログラミング

マジで、めちゃくちゃ得意です。

後述するClaude Codeくんがとてもすごいです。

実際にCloudflareのテンプレートをもとに、MCPサーバーテンプレートを作成したり、GitHub連携のMCPサーバーなどもClaude Codeに作らせています。

でも、難しいんでしょう?????????

ちなみに、そんなことはないです。

人間と同じで、なるべく具体的に指示をしてあげることが重要です。

基本的には、

  • 何を使って
  • 何をできる
  • 何を作る

  • 何を使って
  • 何を処理する

などのプロンプトで十分です。

様々な場面があると思うので何個か、私がプロンプトをどの場面にどうやって組んでいるかを解説していきます。

新規開発

Claude Codeで、

  • どうして
  • 何を使って
  • 何をできる
  • 何を作る
  • 作る時のルール

のように指示します。 また、この際に仕様書的な感じでたくさん詳細に入力してあげると良いでしょう。

これは私が新しいアプリケーションを作成しようとした際のプロンプトの例です。

# きっかけ
AIを使う際に、ルールを使いまわしたい時があります。
その時に使用できるような、CLIツールのBackendを開発してください。
Cloudflare Workers を使用して、Cloudflare D1にメタデータ、R2に実際のMarkdownを保存する様なサーバを作ってください。

# 技術仕様
- サーバレス: Cloudflare Workers
- DB: Cloudflare D1
- Storage: Cloudflare R2
- API: Restful API
- Deploy: GitHub Actions
- Authenticate Method: JWT

# 要件
- なんかたくさん

# 開発のルール
- 複数人で開発するので、詳細にコーディングルールを明文化すると良いでしょう。
- 最初はClickUpにタスクを作って、詳細にやりたいことのタイトルの最初に[Task]をつけて、タスク化してください。
- そのタスクの詳細には、やることをチェックリストで保存してください。
- また、設計などで困ったこともClickUpで タイトルの最初に[QA]をつけて、起票してください。
- 何かしらのタスクに手をつけたり、終わったりした際には、状態の更新を忘れないでください。
- また、指示をされたがClickUpに存在しないタスクの場合は、タスクを新規作成するべきです。
- タスク周りの処理は絶対に怠らないでください。

実際は、新規開発の場合、もっとコンテキストを与えてあげると良いです。

既存のものに追加の機能をつけるとか

Claude Codeで、下のような感じでプロンプトを構築しています。 - 何をできる - 何を作る - 作る時のルール

例えば、前あった社内のツールの改善タスクでは、

# 目的
タスクの概要

# 具体例
何が、どのようになるべきか

のようにタスクを投げます。

次に、動作確認をして、動かなかったりコンパイルでエラーが発生した際には、

エラー内容 のように出て動かないので修正して

のようにぶん投げます。

最終的に動作確認ができたら、

PRを作りたいので、下記のテンプレートにまとめてください。

# 概要

# できること

# テスト内容
- [ ] テストの内容
- [ ] テストの内容1
...

と指示し、PRの概要を作らせて、PRを作ります。

事務作業とか

あんまり例が思いつかないですが、例として、領収書をまとめさせてみましょう。

├── 未処理/
│   ├── 未処理の領収書.pdf
│   ├── 未処理の領収書2.pdf
│   └── 未処理の領収書.png
└── 処理済み/

のようなファイルがあるとします。

Claude Codeで、次のように指示します。

未処理のファイルに入っているpdfやpngファイルを読んで、YYYY/MM/DD-事業者名-¥値段 のような形で、処理済みに移動させてください

そうするとおそらくいい感じになります。(検証できていない)

MCPと組み合わせる

新しい単語が出てきたと思いますが、こちらは別途、解説する予定です!

AIはMCPと組み合わせることで、何倍も強くなります。

例えば、GitHubやClickUpのMCPを使えば、GitHubのIssueやClickUpのチケットから、作業内容を作成して、ClickUpに具体的なチケットに起こして、それをClaude Codeに作業させることができたりします。

その作業内容をEsaにまとめるようにさせれば、作業ログも取れますね。

【開発合宿in那須塩原】成果物発表~~~!!後編

こんにちは!アルバイトのガマ🐸です!!
開発合宿 in 那須高原(2泊3日) の後編をお届けします!

前回のブログでは、Aチーム・Bチームの成果をご紹介しましたが、 今回はいよいよ Cチーム・Dチーム・Eチーム の成果物をご紹介します!!

どのチームも、テーマである

「定量化が難しいものを、定量化・可視化する」

に真正面から挑んだ力作ぞろいです💪


 

各チームの成果物紹介(後編)

ここからは、Cチーム・Dチーム・Eチームの成果物をご紹介します!

Cチーム

日報作成ツール「にぽ」

「にぽ」は全く新しい形での日報作成を提案するアプリケーションです。一見すると怪しげな名前ですが、これはチームメンバーが毎回の日報入力時に「にぽ」と times に呟くところから命名されたものです(「日報を書く」->「日報」->「にっぽう」->「にぽ」)。

さて、日報の入力はただただ面倒くさいという潜在的な問題を抱えていました。そしてその割には、社内であまり活用されておりません。長期的に見れば、形骸化した日報は意味のないルーティンだけを残し、日々の積み重ねによって決して小さくない損失を生み出していました。

我々のチームはこれらを同時に解決すべく、全く新しい入力インタフェースを供えた日報作成ツールを開発しました。

詳細

今回の合宿のテーマは「定量化しにくいものを定量化し、可視化する」でした。定量化しにくいものには、例えば感情や文章があります。我々はここに着目し、そして前から社内で指摘されていた日報の問題を組み合わせてプロダクトを開発することにしました。

我々はまず日報が抱えている問題を整理し、次のような問題が挙がりました。

  • 入力が面倒くさい
  • 日報が社内ナレッジベースである esa に統合されてしまっているためノイズが大きい
    • 意味のない(中身の薄い)日報がナレッジを汚染し、検索性の低下やデータの無為な肥大化を起こしている
  • 日報が活用されていない
    • 本来であれば、週次報告や四半期に一度開催される 1on1 に生かされているべきである

これらの問題から、我々は日報の入力を極限まで簡単にし、さらに日々の感情を数値化した上でトラッキングを行い、メンバー及びマネージャ双方がグラフィカルに閲覧できるツールにしていくことを決定しました。

最終的には、本ツールの 1on1でのフィードバックや自己マネジメント能力の養成への活用を目指していきます。

使用技術

フロントエンド

  • React + React Router DOM の SPA
    • Web 上で快適なページ操作性を実現するには SPA が最適との判断から
    • ページ遷移にかかるストレス、遷移の瞬停を避けたい意図
    • メンバーが React に慣れている
  • SCSS によるスタイリング
    • ロードの遮蔽や心地よい遷移を実現するため、アニメーションを多用している
    • アニメーションと tailwind などのユーティリティ志向 CSS フレームワークとの相性はあまり良くない

バックエンド

  • Bun + ElysiaJS でのRestAPI
    • APiを作成するうえで、一番簡潔に書きやすく開発しやすいTypeScript(JavaScript)を使用した
      • その中でも、Bunを使用したのは特にHttpサーバーとしてのパフォーマンスが良いため
      • ElysiaJSを使用したのはBunのAPIフレームワークの中でも有名で、情報が得られやすいため
  • OpenAPIによるAPI仕様の策定
    • 事前にOpenAPIで定義しておくことで、フロントエンドとバックエンドとのクリティカルパスを極力抑えれる
    • フロントエンドはOpenAPI-typescriptなどで簡単にAPI部分を作成できる
    • バックエンドはAPI仕様に合わせて処理を作成すればよい
      • win-winである

まとめ

他のチームはプロダクト志向が強かったものの、我々の成果物はツール志向だったため成果発表時にはやらかした...と思いました。しかし、成果物のコンセプトとデザイン、チームメンバーの見事なプレゼンによって見事投票によって優勝をいただくことができ、チーム一同大変嬉しく思います。

今後とも社内運用に向けて引き続き開発を進めてまいります!


Dチーム

まず、何を作ったの?

声のdBをスコアにするChrome拡張機能を作りました。 そのスコアを閲覧するためのウェブサイト、保存するためのBackendも作成しています。 実はサイト自体は見れます。

emolyze.nanasi-apps.xyz

作ったもの

  • Google Chrome 拡張機能
  • Website
  • Backend

もっと詳しく

アイデア

30分くらいでまっちゃんとまるさんとWeb3の方で構想を練りました。 最初に出たアイデアが声をスコアにするという物でした。 しかし実装の難易度的に終わる気がしなかったので、3案用意しました。 実装難易度順で - 声をスコアに (1番難しい) - Slack のリアクションからスコア算出 - SlackやChatwork のチャットからスコア算出 の3つが出ました。 しかし、3社合同ということでもし使うなら全社で使いたいという話になり、声をスコアにすることに決まりました。

Chrome 拡張機能

ほぼ本体です。

機能

  • 音声の録音機能
  • 音声をdBにする
  • しゃべってるユーザーを紐付け

などの機能があります。 ChromeのTabCaptureという機能を使用して録音しています。 また、Gather完全対応という話をしたように、Gather上の通信を引き抜いて、playerActivelySpeaksイベントを拾い、話している人を抜き出しています。 地味に一番頑張った部分です。 その機構を地道に実装して、Google Meet等対応させていこうという計画です。

まっちゃん
  • 全てを実装。
  • Cursorくんありがとう。

反省点

  • めちゃくちゃコードが汚い。
  • 読めない。
  • AIを使うのが下手で、最低限動くものしかできなかった。
    • 上手く使えていればブラッシュアップできたのに...
  • 全ての責務がこの拡張機能にある。
    • 音声の処理がCloudflareではできないので、拡張機能にやらせていた。
    • 最悪ではある。
    • しかし最善ではあった。
    • ただし判断が遅かった。

Frontend

Cloudflare Pagesを使用しています。 まるさんに作ってもらいました。 BackendからAPIを適当に繋いで、適当に繋ぎ込みをしました。 デザインの案を適当に紙に書いて、これがいい!と言っただけで完成していて本当にびっくりしました。

まるさん
  • モックデータを表示する、ベースとなるフロントエンド
まっちゃん
  • ベースを使用して
    • 残りのAPIの繋ぎ込み
    • デザインの微調整

反省点

  • データが1つしかなくて映えなかった。
    • モックデータを突っ込むべきだった。

Backend

Cloudflare Workers と Cloudflare D1を使用して、いい感じにスコアを保存するBackendを作成しました。 無料です。 まじでただ保存するだけなので、特筆すべき点は特にありません。

まっちゃん
  • 全て。
  • Cursorくんに感謝

反省点

  • PrismaなどのORMを使用していません!
  • SQL直書き!!!!!!!
    • これが良くなかった.....

プレゼン資料

Web3の方とまるさんがめちゃくちゃ良い感じに作ってくれました。

まっちゃん
  • 実際のところ、私はほぼやっていないので特にないですが、作ってくれたものがとても良かったです

何を意識したの?

まっちゃん

特に時間は意識しました。(まっちゃん比) アイデアは比較的にすぐ出ましたし、実装もすぐ始めましたが、見積もった8時間を超えないように、色々なペース配分を頑張りました。 また、実現可能かを入念に調べることで、時間を有効的に使うことができました。

反省

  • 上で時間を意識したと書いたものの、実際は見積もった時間をオーバーしてしまった
    • その分、別のところで巻き返したりできたから良かったですが、できていなかったら危なかった。
  • 細かいことが気になりすぎて、大変でした
    • 大変でした。
    • 多少目を瞑るということが大切なことを知りました。
    • 大半これで時間を潰してしまいました。

まとめ

上の反省で時間がどうのと書いたものの、実際のところ全ての工程を含め、8.5時間で品質はどうであれ、難易度が高い課題をこなすことができたと思っています。 しかし、細かいことに目を瞑ることも大切ということがわかりました。


Eチーム

私たちのチームは「会議の無駄を可視化するシステム」の開発に取り組みました。

背景

普段の会議で以下のような問題を感じることがありました。

  • 会議の目的から逸れた話をずっとしている
  • 自分に関係のない会議に参加させられる

そこで、会議内容を分析し「有意義」と「無駄」をグラフ化したり、誰がどのくらい話しているかを可視化するシステムを開発することで、効率的な会議や参加者適正化を実現することを目指しました。

使用技術

  • バックエンド:PHP
  • UI:Tailwind CSS
  • 字幕抽出:FFmpeg
  • AI分析:OpenAI API
  • データ可視化:Chart.js
  • 開発支援:Cursor

仕組み

開発したシステムは以下の流れで動作します。

  1. データ入力:議題や参加者情報(名前、関係する議題)の入力、Google Meetの録画ファイルのような、発言者情報付きの字幕が含まれた動画のアップロード
  2. 字幕抽出:FFmpegを用いて動画から字幕を抽出し、「いつ、誰が、何と発言したか」というデータのリストを生成
  3. AI分析:抽出した発言データと議題や参加者情報をOpenAI APIに送信し、会議内容を分析
  4. データ可視化:分析結果から以下の内容を表示
    • Chart.jsによる各人の発言割合を表す円グラフ
    • Chart.jsによる有意義な発言と無駄な発言の割合を表す円グラフ
    • 会議の要約と改善提案

今後実装したい機能

今回は基本的な機能の実装に留まりましたが、今後以下の機能を実装したいと考えています。

  • 同じことを何度も言っていないかの検出
  • 無言が続いている時間の算出
  • 無駄と判定した箇所の表示
  • 参加者が会議と関係あるかの判定
  • ブラウザ上での字幕抽出と発言データ生成(動画アップロードの代替)
  • OpenAI APIを利用した、動画からの発言データ生成(発言者情報付きの字幕が含まれない動画のサポート)

直面した課題

開発中に最も時間を要したのは、OpenAI APIとの連携でした。チームメンバー全員がOpenAI APIを利用した経験がなく、正常なレスポンスが得られるようになるまでかなりの時間がかかってしまいました。

具体的には、429 - You exceeded your current quota, please check your plan and billing detailsというエラーが発生し続けていました。この課題に対して、チーム全員で協力して調査し、試行錯誤を重ねることで解決にたどり着きました。

解決のきっかけは、あるメンバーが貼ってくれた、正常なレスポンスが得られるcurlのログでした。curlとプログラムのリクエストボディを見比べたところ、モデルになぜかgpt-3.5-turboが指定されていることが判明。これをgpt-4o-miniに修正することで問題が解決しました。

感想

今回の開発合宿を通じて、多くの学びを得られました。

技術面では、Cursorによる開発効率向上の効果を体験することができました。

プロジェクト管理面では、時間制約の中での優先順位付けや軌道修正の重要性と、進捗共有の大切さを学びました。特に、行き詰まった時こそ積極的に状況報告を行い、チーム全体で解決策を探ることの価値を実感しました。

最も印象深かったのは、オフィスや勤務形態の違いで普段顔を合わせることのないメンバーと、協力して開発に取り組めたことでした。この過程で、技術的な学びと同じくらい貴重な交流を深めることができました。


 

最後に

「定量化が難しいものを、定量化・可視化するサービスを考え、制作する」という
難易度の高いテーマでしたが、 各チーム面白いアイディアが沢山出てきましたね!!

今回の開発合宿を通じて得た学びや経験は、今後のプロジェクトにも活かしていきたいと思います!

また次回、さらに面白いテーマで合宿ができることを楽しみにしています!

参加メンバーの皆さん、本当にお疲れさまでした!
そして、ここまで読んでいただきありがとうございました!

【開発合宿in那須塩原】成果物発表~~~!!前編

こんにちは!アルバイトのガマ🐸です!!
今回は、先日開催した開発合宿 in 那須高原(2泊3日)での各チームの成果物を発表します!!
今回の合宿では、

「定量化が難しいものを、定量化・可視化するサービスを考え、制作する」

というテーマのもと、A〜Eの5チームに分かれて開発に取り組みました!

チームは、あえて普段あまり接点のないメンバー同士で組まれました!
初めてしっかり話すような相手とも協力しながら、
限られた時間の中でひとつのアイデアを形にしていくという、合宿ならではの濃い体験になりました!


 

各チームの成果物紹介 (前編)

前編ではAチーム、Bチームの成果物を紹介します!!


Aチーム 1f4a9

 なにかの文字コードらしいです。調べてみましょう!

作ったもの

 私たちチーム・1f4a9では排便予測アプリ・unkastを作成しました。

 このアプリでは身体情報・食事・運動量などを入力することで排便のタイミングを予測します。予想結果は天気予報のような形で表示します。
アプリ画面

開発

 排便予測アプリ・unkastはFlutterを使って開発しました。メンバー全員がFlutter未経験でしたが、エージェント型生成AIツールを使うことで動くものはできました。

 使用したツールはメンバーによって異なりますが、CursorとCodexを使っています。

 Cursorは.cursor/rulesディレクトリの下にあるファイルを見て要件やコーディングルール等を把握しますが、CodexはAGENTS.mdを見て把握します。つまり、プロジェクトによって見るディレクトリ・ファイルが異なります。

 そこでAGENTS.md.cursor/rulesを見るように指示を書いておくことで異なるツールを使っているメンバー間でAIに参照させるファイルを共有させました

使用した絵文字

 排便確率によって表示するアイコンは以下のような処理になっていますが、絵文字やコメントも生成アプリが作ったものになります。(しっかりと排便予報アプリを理解した上でボケてきていてすごい...)

// 確率に応じた顔文字を返す
String getFaceEmoji(int percent) {
  if (percent < 20) {
    return '😄'; // 好調
  } else if (percent < 50) {
    return '😐'; // 怪しい
  } else if (percent < 80) {
    return '😣'; // 厳しい
  } else {
    return '💩'; // もう無理
  }
}

反省点

 今回作成したアプリはフロントだけで、表示されているデータはモックデータでした。  しかし、サーバーサイドも実装してそこでモックデータを返しておけばよかったと思いました。


Bチーム Factimes

概要

Bチームは、人の心の距離が可視化されるSNSを作成しました。その名もFactimes 機能はシンプル。

1. コア機能

1.1 心理的距離マップ

ユーザー間のコミュニケーションの活発さを基に、組織内の心理的な距離や影響度を2Dマップ上にリアルタイムで可視化します。

  • ユーザー配置: ユーザーを円形のアイコン(ノード)としてマップ上に表示します。
  • 距離の表現: ユーザー間の距離が近いほど、アイコン同士が近くに配置されます。
  • 影響度の表現: ユーザーの影響力が高いほど、アイコンのサイズが大きくなります。
  • リアルタイム更新: ユーザー間のインタラクションに応じて、座標やノードサイズが動的に更新されます。

1.2 タイムライン

一般的なSNSと同様に、投稿が時系列で表示されるタイムライン機能です。

  • 表示: 投稿を時系列順に表示し、無限スクロールに対応しています。
  • フィルタリング: 特定のユーザーや期間で投稿を絞り込むことができます。

2. SNS機能

2.1 投稿機能

ユーザーはテキストや画像を投稿し、他のメンバーと情報を共有できます。

  • テキスト投稿: 最大500文字までのメッセージを投稿できます。
  • 画像添付: 1投稿あたり最大4枚まで画像を添付できます。
  • メンション: @username 形式で特定のユーザーに通知を送ることができます。
  • ハッシュタグ: #tag 形式で投稿を分類・検索しやすくします。

2.2 インタラクション機能

投稿に対して、さまざまな方法でリアクションやコミュニケーションが可能です。

  • いいね: 投稿をワンクリックで評価します。
  • 絵文字リアクション: 😀, 👍, ❤️ など、複数の絵文字で感情を表現できます。
  • リツイート: 他のユーザーの投稿を自分のタイムラインで共有します。
  • コメント: 投稿に対して返信や議論ができます。
  • 投稿編集・削除: 自身の投稿を後から修正・削除できます。

3. ユーザー管理機能

3.1 認証・認可

セキュアな利用環境を提供するためのユーザー管理機能です。

  • 組織ドメイン制限: 特定の組織ドメインを持つメールアドレスでのみ登録・利用が可能です。
  • セッション管理: 安全なログイン状態の維持と管理を行います。
  • ロールベースアクセス制御 (RBAC): 管理者や一般ユーザーなどの役割に応じた権限を付与します。

3.2 プロフィール管理

ユーザーが自身の情報を管理・公開するための機能です。

  • 基本情報: 名前、部署、役職などを登録できます。
  • アバター画像: プロフィール画像を設定できます。
  • 自己紹介: フリーテキストで自己紹介を記述できます。

技術スタック詳細

コアテクノロジー

カテゴリ 技術 バージョン/詳細
言語 TypeScript v5.x
フレームワーク Next.js v15.3.1
UIライブラリ React v19.0.0
データベース PostgreSQL - (要件定義ではv17を推奨)
ORM Prisma v6.9.0
認証 NextAuth.js v5.0.0-beta.28

主要ライブラリ (フロントエンド)

ライブラリ 用途
date-fns 日付・時刻の操作
zod スキーマ定義とデータ検証
CSS Modules コンポーネント単位でのCSSスタイリング

主要ライブラリ (バックエンド)

ライブラリ 用途
@auth/prisma-adapter NextAuth.jsとPrismaを連携させるアダプタ
bcryptjs パスワードのハッシュ化処理

開発ツール・環境

ツール 用途
開発環境 Docker / Dev Container
リンター ESLint
フォーマッター Prettier
Gitフック Husky, lint-staged
DBマイグレーション Prisma Migrate
開発サーバー Next.js (Turbopack利用)
スクリプト実行 tsx (TypeScript実行)

徹底したバイブコーディング

Bチームの特徴は完成したプロダクトそのものというよりは、その過程

Bチームでは、今回人間が直接コードを編集していません

すべてCursorを使ったバイブコーディングで開発しました。

人間がやると200時間かかるとされた作業を、合宿内の8時間に短縮することに成功。

ただ、この作業圧縮は、

  1. 人間が最適なアーキテクチャを指定してあげて

  2. AIが得意とする技術に合わせて要件を調整してあげたから

できたことです。

なので、妥協した箇所、もっと良くできる箇所がめちゃくちゃあります。 とはいえ、実際にSNSとして動き使えるものが出来上がりました。

今回証明できたのは、AI使役者がシステム開発に精通している場合のバイブコーディングの実用性。

今後の課題は、

  1. これを弊社の実際の業務オペレーションに落とし込み、実際に開発サービスとして提供できるようにすること

  2. AI使役者がシステム開発に精通していない場合でも製品になるものを作れるようにしていくこと

でしょうか。

チームの目標とモチベーション

Tech という点からはすこし話がそれますが....... Bチームのチームリーダーを務めた人間が技術者上がりではなくスタートアップ界隈出身だったため、 Bチームの目標は優勝だけではなくその先、「もしプレシードだったら1000万調達できるようなプロダクトを作る」でした。

なので、僕らだけハッカソンというよりはビジコンみたいなプレゼンをしてしまったわけですが....... ただそういうだけあって、ちゃんと裏でしっかり市場分析や戦略策定もしたりしたので、スプーキーズからいつかプロダクトとして世に出るかも? でたらいいな。


 

前編はここまで!

C・D・Eチームの成果物も、かなりユニークなものばかり!
次回の後編では、それぞれのアイデアや工夫をたっぷりご紹介しますので、お楽しみに🥳

CSV文字コード変換アプリのエンコーディング判定

こんにちは、spookies歴2か月目の下釜です!
今回は、CSVファイルの文字コード自動判定処理で発生した問題と、その対策について共有します。特に、jschardet を使っている方や、CSVの文字コードでハマった経験がある方に参考になれば嬉しいです。

問題内容

jschardet を使ってCSVファイルの文字コードを自動判定していたが、以下のようなケースでエラーが発生した:

  • 文字コードの confidence が低すぎて undefined になる

  • ファイルの内容が英数字中心で判定が困難(ASCIIと誤認識)

  • 結果として "xxx の文字コードを特定できませんでした" という例外が発生

原因

jschardet は、文字数が少なかったり、内容が英数字ばかりのCSVなどは正しく判定できない
UTF-8でもShift_JISでも解釈できるようなファイルだと、confidenceが低くなりやすい

対応内容

元のコード(変更前)

const detected = jschardet.detect(buffer);
const encoding = detected?.encoding?.toLowerCase();
if (!encoding || detected.confidence < 0.3) {
  throw new Error(`${file.name} の文字コードを特定できませんでした`);
}
const supportedEncodings = ['utf-8', 'ascii', 'shift_jis', 'windows-1252'];
if (!supportedEncodings.includes(encoding)) {
  throw new Error(`${file.name} は未対応の文字コードです(推定: ${encoding})`);
}
const decodedText = iconv.decode(buffer, encoding);

変更後のコード(修正後)

const detected = jschardet.detect(buffer);
let encoding = detected?.encoding?.toLowerCase() || '';
// 英数字のみか判定
const asciiOnly = /^[\x00-\x7F]*$/.test(buffer.toString('binary'));
// encoding 不明 or confidence 低い or 英数字だけなら shift_jis にフォールバック
if (!encoding || detected.confidence < 0.2 || asciiOnly) {
  encoding = 'shift_jis';
}
const supportedEncodings = ['utf-8', 'ascii', 'shift_jis', 'windows-1252'];
if (!supportedEncodings.includes(encoding)) {
  throw new Error(`${file.name} は未対応の文字コードです(推定: ${encoding})`);
}
const decodedText = iconv.decode(buffer, encoding);

修正内容の要点

  • confidence の判定閾値を緩和 0.3 → 0.2 に変更

  • エンコーディング未判定時に、shift_jisにフォールバックする

  • 英数字だけのファイル対策でASCII文字だけか判定し、同様に shift_jis へフォールバック

  • iconv-lite による変換処理自体は変更なし、判定部分のみ修正で済ませた

検証結果

  • マイナビのCSVなど、これまで読み込み時にエラーになっていたファイルもすべて取り込み可能になった

  • 日本語や記号の文字化けも発生せず、変換後はBOM付きUTF-8として正しくダウンロードされる

まとめ

CSVの文字コードは「なんとなくUTF-8でしょ」で済まないことが多く、特に日本語圏では Shift_JIS や Windows-1252 の混在がよくあります。 jschardet は便利ですが過信せず、フォールバック戦略を用意しておくことが安定運用のカギだと痛感しました。

同じように CSV ファイルの読み込み処理で困っている方の参考になれば幸いです!