在庫管理ってけっこう大変だよね

この記事は異世界行ったら本気だすぴょこりんクラスタ Advent Calendar 2021のために書いたものです。このアドベントカレンダーそのものに関しては、主催者による紹介記事を見てください。

はじめに

ここ2年くらい、消耗品はいくつもまとめて買うようになった。 そうなると困るのは数の管理であり、買い物のたびにあれ買うんだっけとか、 そろそろこれが切れそうとかを覚えておくのも大変になったので、 まずは数だけでも管理できるようにした。

完成品

ソースコード

github.com

README作ってないので、代わりに

  • 道具
  • 立ち上げ方
    • Makeでビルド
    • できたバイナリを実行すると、デフォルト12000番ポートで立ち上がる。-port <port#>をつけるとport#で立ち上がる。

動作イメージ

トップ画面はこんな感じで、最終更新日が古いものから順に品名と数がひたすら並ぶ。 プラスボタン/マイナスボタンでそれぞれインクリメント/デクリメントを行い、 ゴミ箱ボタンでエントリそのものを消す。 メニューボタンは数を大幅に変えたり名前を変えたいときに使うが、基本使わない。

f:id:nbisco:20211128234520p:plain
トップ画面

カテゴリごとにフィルタもできる。 filterを押すとメニューが出てきて、一旦全部見えなくなる。 チェック入れたものだけ見られるようになっている。

f:id:nbisco:20211128234553p:plain
フィルタ画面

追加はシンプルにフォーム。

f:id:nbisco:20211128234610p:plain
追加画面

設計

以降、作るときに意識したことを書いていく。

要件

要件は以下とした。品数のメンテがだるいのはともかく避けたかったので、 手軽というかまあ許せるくらいに簡単なもので、かつそんなに作るのに苦労しないものをめざした。

# 要件 対応方針
1 ぱっと見で何がどれくらいあるかわかる 品名と数だけ表示し、更新日時等は出さない
2 スマホでもPCでも使える Webアプリとし、レスポンシブに動くようにする
3 品数メンテ時に文字入力させない インクリメント/デクリメントボタンで増減できるようにする
4 探しやすくする カテゴリでフィルタをかける

アーキテクチャ

いくつかAPIを用意し、それをブラウザから適宜叩くようにする、 (たぶん)よくある感じのウェブアプリとした。

UI

問題なのはレスポンシブに動くようにするところ、画面に合わせてデータを取得したりすることだった。 前者はCSSフレームワークにVanilla Frameworkを使ったら実現できてしまったので、 特に考えることはなかった。 後者は、特にフレームワークに頼らずともJavaScript使うだけでなんとかなってしまった。 async/awaitのおかげで素人でもあまり困らずにこの辺なんとかできてしまいますね。

APIモデル

consumable-itemオブジェクトが1個あるだけ。全部リクエスト同期で処理する。 インクリメント/デクリメントはPATCHとかPUTとかとはちょっと性質が違うのではと 思って、オブジェクトにくっついてる特殊操作扱いにした。 これでよかったかは謎だが、特に困ってはいない。

# HTTP Methodとendpoint 概要
1 GET /api/v1/consumable-items 管理品一覧取得
2 GET /api/v1/consumable-items/:id id指定で管理品取得
3 POST /api/v1/consumable-items 管理品新規作成
4 POST /api/v1/consumable-items/actions/plus-one/invoke id指定で管理品の数をインクリメント
5 POST /api/v1/consumable-items/actions/minus-one/invoke id指定で管理品の数をデクリメント
6 PATCH /api/v1/consumable-items/:id id指定で管理品情報修正
7 DELETE /api/v1/consumable-items/:id id指定で管理品情報削除

データモデル

品名、数、カテゴリを1つエントリで持つ。 カテゴリに関してはテーブルを分けようかとも思ったが、 使っていると結構気軽に分類を変えることがわかった(最初はキッチンでまとめていたが、出し入れが激しいので別枠を作って管理するとか)ので、 1つにして、テーブル間の同期を考えないようにした。 大した量もないので、これでも問題ないはず。

type Consumable struct {
   Id          uint32    `gorm:"primaryKey" json:"id"`
   CreatedAt   time.Time `json:"created_at"`
   UpdatedAt   time.Time `json:"updated_at"`
   Name        string    `json:"name"`
   Count       uint32    `json:"count"`
   Category    string    `json:"category"`
   SubCategory string    `json:"subcategory"`
}

おわりに

けっこう便利に使っているが、結局日々のメンテがいちばん大変なのであった。 次は数のメンテが楽になる何かを作りたいですね。