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

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

【開発合宿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 ファイルの読み込み処理で困っている方の参考になれば幸いです!

NuxtのコーポレートサイトをNext.jsに置き換えたら、GithubCopilotに仕事を奪われかけた話

こんにちは。Spookies歴3か月のエンジニア、鈴木です。

この度、Nuxt.jsで作られていた弊社のコーポレートサイトをNext.jsに移植しました。

新年一発目の技術ブログは、本件についてまとめようと思います。

リプレイスに至った経緯

Reactのポートフォリオがない

Spookiesでは、今までJavaScriptフレームワークにvue.jsが採択されがちでした。

もちろんReactの経験値がゼロだったわけではなく、最近に入って一部の小さなプロジェクトや業務等で利用されることはあったようなのですが、ナレッジ量的に無難な選択肢としてVue.jsやNuxt.jsが使われてきた経緯があるようです。

しかし、Spookiesの新たな挑戦の一つとして、VueだけでなくReactも大々的に取り扱うという目標ができました。 とはいえ、大々的に取り扱うにはまず実績があるべき。

一番手っ取り早く、自社のReactの実力を表現する方法はないか。

そうだ、まずはコーポレートサイトをReactベースにしてしまおう。

僕のスプーキーズチュートリアル

この仕事、スプーキーズにおける僕の初仕事でした。

この社内プロジェクトでスプーキーズのプロジェクト運営になれて、 以降のプロジェクトでエンジニアとしてアサインできるようになる必要がありました。

社内で完結する業務で水合わせってワケです。

リプレイスのキモ

NuxtとNextjsみたいな超有名フレームワーク間の移行なんて、ドキュメントがネットに無限に転がっており、具体的にやり方を今更書いてもしゃーないのでキモだけ書きます。

アーキテクチャの変更点

従来はNuxtでSSGした静的サイトをGithub Pagesでホストするという構成でした。

この部分をNextjsのSSGに置き換えたので、そのほかのインフラに大きな変更はありません。 RouterにはPage RouterではなくApp Routerを使いました。

nuxtからの移行作業という点だけで言えばPage Routerの方がやりやすくはあったのですが、 今後はAppRouterを扱う案件が増加すると思われることと、 Page Routerが将来的に破棄されるんじゃないかという漠然とした不安もあったため、上司と相談の上App Routerを採用することになりました。

GithubCopilotを使おう

Github Copilotを使いましょう。

単純な移植ならGithub Copilotは優秀です。 VS CodeのCopilot Chatに貼り付け、「これをnextjsに移行してください」と書くだけです。 これだけで、作業の七〜八割を終わらせてくれます。

残り生成ミスによるエラーの修正等ですが、これも大体Copilotに修正させることができます。 人間はCtrlとCとTabとクリックさえ押せればいいのです。

こういった、やりたいことが明確に定義されているが知識理解を要する単純作業は、我々人類はAIにかてっこないです。

感想

結局、Next.jsが良いか、Nuxt.jsが良いか

今回の移行では、スプーキーズの戦略的意図があったためNuxt.jsではなくNext.jsが選択されましたが、この戦略的意図がなければ、Next.jsとNuxtどちらが良いのでしょうか。

コーポレートサイトというプロジェクト単体で考えればNext.jsにこだわる必要はなく、Nuxt.jsで十分でしょう。

ただ、個人的な意見を述べると、社内の技術スタックをReactに統一するメリットは、Nuxt.jsやVue.jsの迅速な開発というメリットよりも大きいと考えます。 Vue.jsだと苦戦するけどReactであれば容易に対応できる実装というのは、やはり多数あるように感じるためです。

仮にコーポレートサイトのようなVue.jsで十分なプロジェクトであったとしても、ブログ・プレスリリース機能をつけてSSGするだとか、絞り込みや検索機能を持たせたうえでSSGするだとか、そういったちょっと捻った実装をする場合はReactのほうがわかりやすく書けるように僕は思います。

また、今回は使いませんでしたがNext.jsにはISRという機能があるので、SSGとSSRのいいとこ取りができるのもコーポレートサイトにNext.jsを利用するメリットです。

AIの使い方と未来

タイトルにもあるように、この仕事でやりたいロジックが明確なコーディングであればほぼGithubCopilotに任せられることを肌で感じました。

ただ、最終的に生み出したコードに責任を持つのが人間であることは、どれだけAIが進歩しても変わらないでしょう。

「プログラマーはいらなくなる。が、エンジニアという職業は必要であり続ける。」

「だからこそ、エンジニアのキャリアや成長の仕方が大きく変わる」

というのが、僕のAIとの初仕事の感想でした。

SECCON Beginners CTF 2024 参加記

こんにちは。CTF部に入部したてほやほやのみーさんです。

実は5月の末金会後にCTF勉強会をやったこともあり部員が2人増えました!🎉

ちょうど良いタイミングで初心者向けのコンテストがあるとのことで、2024/6/15-16 に開催されたSECCON Beginners CTF 2024に参加してきました!

spookiesチームとしての参加メンバーは4名、個人参加・他チームでの参加をしているメンバーもいました。 それぞれ予定の合間を縫っての参加でしたが、spookies全体としてかなり盛り上がったコンテストでした。

spookiesチームとしては個人参加している部長を超えることを目標に頑張りました。 そしてもう一人の新入部員もなんと個人参加!ガッツがありますね!

結果は全体237位! まだまだ伸び代があります...。ありすぎます...!

そしてなんと我がCTF部部長はソロ参加で3位! 流石すぎます。

ちなみに 2024/6/21-23 は Wani CTF 2024 に参加もしていました。 まずは部長を目指して、部員同士、切磋琢磨していきたいですね。

以下、各メンバーの参加記まとめです。

続きを読む