Next.js × GCPで最強の給料管理システムを作ってみた

image

はじめに

どうも!プログラミングの沼にどっぷり浸かっているエンジニアです。 今回は「毎月の給料計算、マジでめんどくさい...」と遠い目をしていた自分を救うべく(あわよくば「すげー!」って言われたい一心で)、「アルバイト給料管理システム」 を爆誕させました。

手作業での管理?Excel?そんなのもう古い!これからはWebアプリの時代ですよ社長! というわけで、開発中に起きた涙あり笑いありのトラブルと、こだわりの技術スタックについて、備忘録も兼ねてブログに残しておきます。

作ったもの

  • システム名: アルバイト給料管理システム(そのまんま)
  • ミッション: 勤怠入力から給料明細の発行までを全自動化し事務作業を解放する
  • 主な機能:
    • 従業員管理(時給が変わっても大丈夫なように履歴管理も完備!)
    • 勤怠入力(スマホでポチッとはいかないけど、Webからサクサク入力)
    • 給料計算(ボタン一つで計算完了。もう電卓はいらない)
    • 給料明細PDF生成(紙で渡す時代は終わりました)

「俺の考えた最強の技術スタック」

せっかく作るなら、モダンでイケてる技術を使いたいですよね。「流行ってるから」という理由で選んだものもありますが、結果的に大正解でした。

フロントエンド & バックエンド

  • Next.js 15 (App Router): 最新すぎてドキュメント少なくて泣いたけど、サーバーコンポーネントを使ってみたかったんです。
  • TypeScript: 型がないと生きていけない体になりました。安全性最高。
  • Tailwind CSS: CSS書くのが面倒な僕らの救世主。クラス名で殴るスタイル。
  • Prisma: SQL書かなくてもDB操作できる神ORM。
  • NextAuth.js v5: 認証周りは自前で書きたくないので、Google先生にお任せ。

インフラ (GCP)

  • Cloud Run: コンテナをポイっと投げれば動く。スケーリングも勝手にやってくれる。神。
  • Cloud SQL (PostgreSQL): DBはやっぱりリレーショナルでしょ。
  • Secret Manager: パスワードとかをコードに直書きして怒られたくないので使いました。

開発の軌跡(という名の苦闘)

Phase 0: 形から入るタイプ

まずは環境構築。「CI/CDパイプライン?なんかカッコいい響きだ」と思って、最初からGithub ActionsとかGCPのプロジェクト設定をガチガチにやりました。 ここでDockerの設定に手こずり、3日くらい溶かしたのは内緒です。

Phase 1: 地味だけど大事な土台作り

従業員登録とか勤怠入力とか、地味な画面を作っていきます。 「時給って途中で変わるじゃん?」ということに気づき、履歴管理機能を実装した自分を褒めてあげたい。ここでDB設計の重要さを痛感しました。

Phase 2: ラスボス「給料計算」

このシステムの肝です。「15分単位で切り捨て?」「深夜割増?」など、世の中の給料計算がどれだけ複雑かを思い知らされました。 でも、ボタン一つで「計算完了!」って出た時の快感はヤバいです。脳汁出ました。 あと、jsPDFを使ってPDFを生成するところは、座標指定との戦いでした。「あと1ピクセル右...いや左...」みたいな職人芸をしてました。

Phase 3: セキュリティは大事

「個人情報漏洩とか絶対やだ」と思ったので、監査ログ(誰が何をしたか記録するやつ)を実装しました。 あと、本番環境へのデプロイ。これが一番緊張する瞬間。

やらかした失敗と解決策(ここテストに出ます)

開発中、何度もPCを窓から投げ捨てそうになりましたが、なんとか乗り越えました。

1. 新しもの好きが裏目に... (Tailwind CSS v4)

「v4出たらしいぜ!使うしかねぇ!」と意気揚々と導入したら、設定周りが全然動かない。 エラーログと睨めっこすること数時間...。
解決策: 素直にv3に戻しました。枯れた技術(安定版)を使うの大事。マジで。
安定稼働のために書いたv3用の設定がこちら。シンプル・イズ・ベスト。

// tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx,mdx}", // ここをちゃんと書かないとスタイルが当たらない罠
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {
      colors: {
        background: "var(--background)",
        foreground: "var(--foreground)",
      },
    },
  },
  plugins: [],
};
export default config;

2. M1 Macの罠 (Cloud Runアーキテクチャ問題)

ローカル(M1 Mac)でビルドしたDockerイメージをCloud Runにデプロイしたら、「Exec format error」とか言われて起動しない。 なんで!?と思ったら、M1チップはARMアーキテクチャ、Cloud RunはAMD64アーキテクチャだったんですね...。
解決策: buildxを使って、「AMD64向けにビルドしてね!」と命令する必要がありました。

# これを忘れるとCloud Runくんが食べてくれません
docker buildx build --platform linux/amd64 \
  -t asia-northeast1-docker.pkg.dev/kamoit-system/payroll-app/payroll-app:latest \
  --push .

3. セキュリティ意識高い系 (監査ログ)

「誰かが勝手にデータ消したらどうすんの?」という恐怖心から、操作ログを残すことにしました。 Prismaを使えば意外とサクッと書けました。

// lib/audit.ts
// 悪いことしたらバレるよ?という機能
export async function createAuditLog({
  userId,
  action,
  tableName,
  recordId,
  oldValues = null, // 変更前の値も残す執念深さ
  newValues = null,
  ipAddress = null,
}: CreateAuditLogParams) {
  try {
    await prisma.auditLog.create({
      data: {
        userId,
        action,
        tableName,
        recordId,
        oldValues: (oldValues as Prisma.InputJsonValue) || Prisma.JsonNull,
        newValues: (newValues as Prisma.InputJsonValue) || Prisma.JsonNull,
        ipAddress,
      },
    });
  } catch (error) {
    console.error("ログ保存失敗したけど、メイン処理は止めないよ:", error);
  }
}

今後の野望

とりあえず動くものはできましたが、まだまだやりたいことはあります。

  • 深夜・休日割増の完全自動計算: 計算ロジックをもっと賢くしたい。
  • スマホ対応: スタッフが自分のスマホから「今着きました!」って打刻できるようにしたい。
  • LINE連携: 給料日が来たらLINEで「振り込まれたよ!」って通知が来たら最高じゃない?

さいごに

今回の開発で、Next.jsとGCPの便利さに感動しつつ、「動かないコードはただの文字の羅列」 という真理に到達しました。 エラーと戦い続けた日々でしたが、動いた時の感動があるからプログラミングはやめられませんね。

もし同じようなシステムを作ろうとしている人がいたら、僕の屍(失敗談)を越えていってください! それでは、また次の開発で会いましょう👋

お知らせ

可茂IT塾ではFlutter/Reactのインターンを募集しています!(募集停止中)

可茂IT塾ではFlutter/Reactのインターンを募集しています!(募集停止中)

可茂IT塾ではFlutter/Reactのインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More

タグ

Flutter (124)初心者向け (32)イベント (19)Google Apps Script (17)可茂IT塾 (12)Nextjs (12)AI (8)React (8)riverpod (7)デザイン (7)Firebase (7)Figma (6)VSCode (6)JavaScript (6)ChatGPT (5)新卒 (4)就活 (4)Slack (4)Dart (4)TypeScript (4)お知らせ (4)FlutterWeb (3)Prisma (3)NestJS (3)アプリ開発 (3)tailwindcss (3)ワーケーション (3)インターン (3)Web (2)Obsidian (2)設計 (2)線型計画法 (2)事例 (2)Git (2)CSS (2)Freezed (2)Image (2)File (2)Material Design (2)経験談 (2)画像 (2)iOS (2)React Hooks (2)社会人 (2)大学生 (2)RSS (1)Google (1)CodeRunner (1)NotebookLM (1)個人開発 (1)Android (1)Unity (1)WebView (1)Twitter (1)フルリモート (1)TextScaler (1)textScaleFactor (1)学生向け (1)supabase (1)Java (1)Spring Boot (1)shell script (1)正規表現 (1)table (1)テーブル (1)hooks (1)パワーポイント (1)ブックマーク (1)Pocket (1)ブクマク (1)MCPサーバー (1)OpenAI (1)Supabase (1)ベクトル検索 (1)趣味 (1)モンスターボール (1)SCSS (1)Swift (1)MapBox (1)Cupertino (1)gpt-oss (1)生成AI (1)llama.cpp (1)LLM (1)ListView (1)secretmanager (1)postgresql (1)nextauth (1)prisma (1)typescript (1)cloudrun (1)gcp (1)nextjs (1)kamoit (1)就活浪人 (1)既卒 (1)保守性 (1)iPad (1)シェアハウス (1)スクレイピング (1)PageView (1)画面遷移 (1)flutter_hooks (1)Gmail (1)GoogleWorkspace (1)ShaderMask (1)google map (1)Google Places API (1)GCPコンソール (1)Google_ML_Kit (1)Vercel (1)Google Domains (1)DeepLeaning (1)深層学習 (1)Google Colab (1)Firebase Analytics (1)Gemini AI (1)コード生成 (1)GitHub Copilot (1)GitHub Actions (1)gemini (1)オンラインオフィス (1)html (1)オブジェクト指向 (1)クラスの継承 (1)ポリモーフィズム (1)LINE Messaging API (1)LINE Notify (1)LINE (1)Bitcoin (1)bitFlyer (1)コミュニティー (1)文系エンジニア (1)build_runner (1)ヒーター (1)作業効率 (1) (1)Flutter実践開発 (1) (1)permission_handler (1)flutter_local_notifications (1)markdown (1)GlobalKey (1)ValueKey (1)Key (1)アイコン (1)go_router (1)FireStorage (1)debug (1)datetime_picker (1)Apple Store Connect (1)FlutterGen (1)デバッグ (1)Widget Inspector (1)VRChat (1)API (1)検索機能 (1)ローディング (1)Skeletonizer (1)Simmer (1)Shader (1)SharedPreferences (1)オフラインサポート (1)Navigator (1)メール送信 (1)FlutterFlow (1)Firebase App Distribution (1)Fastlane (1)Dio (1)CustomClipper (1)ClipPath (1)video_player (1)IMA (1)カスタム認証 (1)アニメーション (1)Arduino (1)ESP32 (1)フリーランス (1)会社員 (1)mac (1)csv (1)docker (1)GithubActions (1)Dialog (1)BI (1)sora2 (1)Gemini CLI (1)Claude Code (1)LifeHack (1)ショートカット (1)Chrome (1)高校生 (1)キャリア教育 (1)非同期処理 (1)生体認証 (1)BackdropFilter (1)レビュー (1)Antigravity (1)getAuth (1)クローズドテスト (1)PlayConsole (1)Algolia (1)コンサルティング (1)Symbol (1)

お知らせ

可茂IT塾ではFlutter/Reactのインターンを募集しています!(募集停止中)

可茂IT塾ではFlutter/Reactのインターンを募集しています!(募集停止中)

可茂IT塾ではFlutter/Reactのインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。

Read More
U30可茂ITインターンハッカソン

U30可茂ITインターンハッカソン

12月28,29日開催。2日間でアプリ開発の企画から完成までを目指す!U30可茂ITインターンハッカソンを開催します。

Read More