株式会社WR

株式会社WR

WEB TOTAL CONSULTING

Laravel + PostgreSQLで作る顧客管理システムの設計パターン
ブログ一覧へ
技術ブログ

Laravel + PostgreSQLで作る顧客管理システムの設計パターン

弊社が複数のクライアント向けに開発してきた顧客管理システム(CRM)の設計パターンをまとめます。再利用性と保守性を重視した設計で、業種を問わず応用できます。

顧客管理システムに共通する要件

業種は違っても、顧客管理システムに求められる要件は共通しています。

  1. 顧客基本情報の登録・編集・検索
  2. 来店/取引履歴の記録
  3. メモ・タグ機能
  4. CSV出力
  5. 権限管理(スタッフ別アクセス制限)

データベース設計

-- 顧客テーブル
CREATE TABLE customers (
    id          BIGSERIAL PRIMARY KEY,
    name        VARCHAR(100) NOT NULL,
    name_kana   VARCHAR(100),
    email       VARCHAR(200),
    phone       VARCHAR(20),
    birthday    DATE,
    memo        TEXT,
    created_at  TIMESTAMP DEFAULT NOW(),
    updated_at  TIMESTAMP DEFAULT NOW()
);

-- 来店・取引履歴
CREATE TABLE customer_histories (
    id          BIGSERIAL PRIMARY KEY,
    customer_id BIGINT REFERENCES customers(id),
    type        VARCHAR(50),    -- 来店 / 購入 / 問い合わせ etc.
    amount      INTEGER,        -- 利用金額
    note        TEXT,
    occurred_at TIMESTAMP NOT NULL
);

Laravelモデルの実装

class Customer extends Model
{
    protected $fillable = [
        'name', 'name_kana', 'email', 'phone', 'birthday', 'memo'
    ];

    // 来店履歴
    public function histories()
    {
        return $this->hasMany(CustomerHistory::class);
    }

    // 来店回数
    public function getVisitCountAttribute(): int
    {
        return $this->histories()->where('type', '来店')->count();
    }

    // 累計利用金額
    public function getTotalAmountAttribute(): int
    {
        return $this->histories()->sum('amount');
    }
}

検索機能の実装

// CustomerController::index()
public function index(Request $request)
{
    $customers = Customer::query()
        ->when($request->q, fn($q, $keyword) =>
            $q->where(function($q) use ($keyword) {
                $q->where('name', 'like', "%{$keyword}%")
                  ->orWhere('name_kana', 'like', "%{$keyword}%")
                  ->orWhere('phone', 'like', "%{$keyword}%");
            })
        )
        ->withCount(['histories as visit_count' => fn($q) =>
            $q->where('type', '来店')
        ])
        ->orderByDesc('updated_at')
        ->paginate(30);

    return view('admin.customers.index', compact('customers'));
}

まとめ

このパターンをベースに業種ごとの固有機能(例:ネイルサロンなら施術記録、ガソリンスタンドなら車両情報)を追加することで、効率よく高品質なCRMが構築できます。

Category 技術ブログ

Related Posts

関連記事

開発・技術のご相談はお気軽に

お見積りは無料です。まずはお気軽にご相談ください。

お問い合わせ →