ClaudeCodeと作る消費税減税シミュレーター
はじめに
政治の焦点となっている消費税減税について、「10%から5%になったら実際どれくらい家計が楽になる?」という疑問を数値で可視化するため、政策議論支援ツール「消費税減税シミュレーター」を開発しました。
本記事では、WordPress子テーマとしての実装から、精密な消費税計算ロジック、リアルタイムUI制御まで、政策議論に活用できる実用的な計算ツールの構築手順を詳しく解説します。
本記事について
今回の開発および記事執筆は、Claude Code(Anthropic社のAI)との協業で進めました。AI時代の新しい開発スタイルの実践例として参考になれば幸いです。
自己紹介
ホネグミ代表、応用情報技術者の資格を持つエンジニア×マーケターです。これまでIT系の会社役員を4年、独立して4年目になります。クライアントワークでは「こうしたい」を技術で形にすることを専門としていますが、最近は思想駆動型サービス開発の第一人者として、AIを活用した様々なサービス開発を続けています。
サービス概要

主要機能
- 瞬時計算: 税込金額入力で即座に減税効果を算出
 - 複数減税パターン対応: 10%→5%, 8%→0%など政策案に対応
 - 精密な端数処理: Math.floor()による現実的な消費税計算
 - 例示ボタン: 食費・光熱費など生活支出例をワンクリック入力
 - 詳細分析表示: 税抜き金額、税額、減税効果を分解表示
 - SNS連携: Twitter/LINE対応の計算結果共有機能
 - 使用統計: WordPress連携による累計使用回数表示
 
技術スタック
フロントエンド
HTML5
├── セマンティック構造設計
├── レスポンシブフォーム実装
└── アクセシビリティ対応
CSS3
├── CSS Grid によるレイアウト
├── モバイルファーストレスポンシブ
├── グラデーション・アニメーション効果
└── カスタムラジオボタンUI
JavaScript (ES6+)
├── 税額計算エンジン
├── リアルタイムバリデーション
├── WordPress AJAX 連携
├── SNSシェア API
└── 非同期エラーハンドリング
バックエンド(WordPress連携)
PHP (WordPress)
├── 子テーマ functions.php
├── AJAX ハンドラー
├── 使用回数管理システム
├── セキュリティ対策
└── データベース最適化
実装手順
1. HTML構造設計
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>消費税減税シミュレーター</title>
    <meta name="description" content="消費税減税シミュレーター【無料】で家計の節約効果を計算!">
</head>
<body>
    <div class="tax-simulator">
        <!-- ヘッダー部 -->
        <h2>💰 消費税減税シミュレーター</h2>
        <p>あなたの支出がどれくらい安くなるかシミュレーションします</p>
        
        <!-- 使用統計表示 -->
        <div class="usage-stats">
            <p class="total-usage">累計使用回数: <span id="total-count">読み込み中...</span>回</p>
        </div>
        
        <!-- 例示ボタン群 -->
        <div class="example-buttons">
            <p>以下の例をクリックすると自動入力されます:</p>
            <div class="example-btn-container">
                <button class="example-btn" data-example="50000">月の食費 50,000円</button>
                <button class="example-btn" data-example="12000">電気代 12,000円</button>
                <button class="example-btn" data-example="8000">ガソリン代 8,000円</button>
                <button class="example-btn" data-example="15000">外食費 15,000円</button>
                <button class="example-btn" data-example="80000">家賃 80,000円</button>
            </div>
        </div>
        
        <!-- 入力フォーム -->
        <div class="input-section">
            <label for="tax-included-amount">現在の税込金額を入力してください:</label>
            <div class="input-wrapper">
                <input type="text" id="tax-included-amount" placeholder="例:50,000" maxlength="12">
                <span class="currency">円</span>
            </div>
            
            <!-- カスタムラジオボタン -->
            <div class="tax-rate-section">
                <label>現在の消費税率:</label>
                <div class="radio-group">
                    <label class="radio-option">
                        <input type="radio" name="current-tax-rate" value="8">
                        <span class="radio-custom"></span>
                        8%
                    </label>
                    <label class="radio-option">
                        <input type="radio" name="current-tax-rate" value="10" checked>
                        <span class="radio-custom"></span>
                        10%
                    </label>
                </div>
            </div>
            
            <div class="tax-rate-section">
                <label>減税後の消費税率:</label>
                <div class="radio-group">
                    <label class="radio-option">
                        <input type="radio" name="new-tax-rate" value="5" checked>
                        <span class="radio-custom"></span>
                        5%
                    </label>
                    <label class="radio-option">
                        <input type="radio" name="new-tax-rate" value="0">
                        <span class="radio-custom"></span>
                        0%
                    </label>
                </div>
            </div>
            
            <button id="calculate-btn">
                <i class="fas fa-calculator"></i> 減税効果を計算する
            </button>
        </div>
        
        <!-- 結果表示エリア -->
        <div class="result-section" style="display: none;">
            <!-- 動的に生成される計算結果 -->
        </div>
        
        <!-- 免責事項 -->
        <div class="footer">
            <p><strong>【免責事項】</strong></p>
            <ul class="disclaimer-list">
                <li>本ツールはシミュレーション目的で作成された計算機です。</li>
                <li>実際の税制改正とは異なる場合があります。</li>
            </ul>
        </div>
    </div>
</body>
</html>
2. 核心となる税額計算ロジック
/**
 * 消費税減税効果計算メイン関数
 * 現実的な消費税計算に準拠したMath.floor()端数処理を実装
 */
function calculateTax() {
    // 入力値の取得と正規化
    const amountStr = amountInput.value.replace(/[^\d]/g, '');
    if (!amountStr) return;
    
    const taxIncludedAmount = parseInt(amountStr);
    const currentTaxRate = parseInt(document.querySelector('input[name="current-tax-rate"]:checked').value);
    const newTaxRate = parseInt(document.querySelector('input[name="new-tax-rate"]:checked').value);
    
    // 【重要】現実的な消費税計算ロジック
    // 1. 税込金額から税抜き金額を逆算(端数切り捨て)
    const currentPretaxAmount = Math.floor(taxIncludedAmount / (1 + currentTaxRate / 100));
    const currentTaxAmount = taxIncludedAmount - currentPretaxAmount;
    
    // 2. 新税率での税額計算(端数切り捨て)
    const afterTaxAmount = Math.floor(currentPretaxAmount * newTaxRate / 100);
    const afterTotalAmount = currentPretaxAmount + afterTaxAmount;
    
    // 3. 減税効果の算出
    const reductionAmount = taxIncludedAmount - afterTotalAmount;
    const taxReductionRate = currentTaxRate - newTaxRate;
    
    // 4. 年間効果の概算(参考値)
    const annualReduction = reductionAmount * 12;
    
    // 結果をUIに反映
    displayCalculationResults({
        currentPretaxAmount,
        currentTaxAmount,
        taxIncludedAmount,
        afterTaxAmount,
        afterTotalAmount,
        reductionAmount,
        taxReductionRate,
        annualReduction
    });
    
    // 使用回数カウンター更新
    updateUsageCounter();
    
    // SNSシェアボタン設定
    configureShareButtons(taxIncludedAmount, currentTaxRate, afterTotalAmount, newTaxRate, reductionAmount);
}
3. WordPress AJAX連携システム
<?php
/**
 * WordPress子テーマ functions.php
 * 消費税減税シミュレーター用カウンターシステム
 */
class TaxReductionCounterSystem {
    
    /**
     * システム初期化
     */
    public static function init() {
        // AJAX ハンドラー登録
        add_action('wp_ajax_tax_reduction_counter', [self::class, 'handle_counter']);
        add_action('wp_ajax_nopriv_tax_reduction_counter', [self::class, 'handle_counter']);
        add_action('wp_ajax_tax_reduction_get_count', [self::class, 'get_count']);
        add_action('wp_ajax_nopriv_tax_reduction_get_count', [self::class, 'get_count']);
    }
    
    /**
     * カウンター更新処理
     * セキュリティと性能を考慮した実装
     */
    public static function handle_counter() {
        // リクエストバリデーション
        if (!check_ajax_referer('tax_reduction_nonce', 'nonce', false)) {
            wp_die('不正なリクエストです');
        }
        
        // IPベースの重複チェック(簡易実装)
        $user_ip = $_SERVER['REMOTE_ADDR'];
        $last_access_key = 'tax_reduction_last_' . md5($user_ip);
        $current_time = current_time('timestamp');
        $last_access = get_transient($last_access_key);
        
        // 5秒以内の連続アクセスを制限
        if ($last_access && ($current_time - $last_access) < 5) {
            echo get_option('tax_reduction_counter', 0);
            wp_die();
        }
        
        // カウンター更新
        $current_count = get_option('tax_reduction_counter', 0);
        $new_count = $current_count + 1;
        update_option('tax_reduction_counter', $new_count);
        
        // 最終アクセス時刻記録
        set_transient($last_access_key, $current_time, 300); // 5分間保持
        
        echo $new_count;
        wp_die();
    }
    
    /**
     * 現在のカウント数取得
     */
    public static function get_count() {
        echo get_option('tax_reduction_counter', 0);
        wp_die();
    }
}
// システム初期化
TaxReductionCounterSystem::init();
?>
4. 高度なUI制御とバリデーション
/**
 * リアルタイムUI制御システム
 * ユーザー体験を向上させる入力支援機能
 */
class TaxSimulatorUI {
    constructor() {
        this.amountInput = document.getElementById('tax-included-amount');
        this.calculateBtn = document.getElementById('calculate-btn');
        this.resultSection = document.querySelector('.result-section');
        this.isComposing = false; // 日本語入力状態管理
        
        this.initializeEventListeners();
        this.initializeExampleButtons();
        this.loadCurrentCount();
    }
    
    /**
     * イベントリスナー初期化
     * 日本語入力対応の高度な入力処理
     */
    initializeEventListeners() {
        // 日本語入力対応
        this.amountInput.addEventListener('compositionstart', () => {
            this.isComposing = true;
        });
        
        this.amountInput.addEventListener('compositionend', () => {
            this.isComposing = false;
            setTimeout(() => this.formatAndValidateInput(), 0);
        });
        
        // リアルタイム入力処理
        this.amountInput.addEventListener('input', () => {
            if (!this.isComposing) {
                this.formatAndValidateInput();
            }
        });
        
        // Enterキー対応
        this.amountInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && !this.calculateBtn.disabled) {
                calculateTax();
            }
        });
        
        // 税率変更時の動的更新
        document.querySelectorAll('input[name="current-tax-rate"], input[name="new-tax-rate"]')
            .forEach(radio => {
                radio.addEventListener('change', () => this.updateCalculateButton());
            });
    }
    
    /**
     * 入力値のフォーマットとバリデーション
     */
    formatAndValidateInput() {
        let value = this.amountInput.value.replace(/[^\d]/g, '');
        
        if (value) {
            // 数値フォーマット(カンマ区切り)
            this.amountInput.value = this.formatNumber(value);
            this.validateAmount(parseInt(value));
        } else {
            this.amountInput.value = '';
            this.resultSection.style.display = 'none';
        }
        
        this.updateCalculateButton();
    }
    
    /**
     * 金額バリデーション
     * @param {number} amount 
     */
    validateAmount(amount) {
        const maxAmount = 10000000; // 1000万円上限
        const minAmount = 1; // 1円下限
        
        if (amount > maxAmount) {
            this.showValidationError('金額は1000万円以下で入力してください');
            return false;
        } else if (amount < minAmount) {
            this.showValidationError('1円以上の金額を入力してください');
            return false;
        }
        
        this.clearValidationError();
        return true;
    }
    
    /**
     * 例示ボタン初期化
     * 視覚的フィードバック付きワンクリック入力
     */
    initializeExampleButtons() {
        document.querySelectorAll('.example-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const amount = btn.getAttribute('data-example');
                this.amountInput.value = this.formatNumber(amount);
                this.updateCalculateButton();
                
                // 視覚的フィードバック
                this.animateButtonPress(btn);
            });
        });
    }
    
    /**
     * ボタン押下アニメーション
     */
    animateButtonPress(button) {
        const originalColor = button.style.background;
        button.style.background = '#e67e22';
        button.style.transform = 'scale(0.95)';
        
        setTimeout(() => {
            button.style.background = originalColor;
            button.style.transform = 'scale(1)';
        }, 200);
    }
    
    /**
     * 数値フォーマット(カンマ区切り)
     */
    formatNumber(num) {
        return parseInt(num).toLocaleString();
    }
    
    /**
     * 計算ボタン状態更新
     */
    updateCalculateButton() {
        const amountStr = this.amountInput.value.replace(/[^\d]/g, '');
        const amount = parseInt(amountStr);
        
        if (amountStr && amount > 0 && this.validateAmount(amount)) {
            this.calculateBtn.disabled = false;
            this.calculateBtn.innerHTML = '<i class="fas fa-calculator"></i> 減税効果を計算する';
            this.calculateBtn.classList.remove('disabled');
        } else {
            this.calculateBtn.disabled = true;
            this.calculateBtn.innerHTML = '<i class="fas fa-calculator"></i> 金額を入力してください';
            this.calculateBtn.classList.add('disabled');
        }
    }
    
    /**
     * バリデーションエラー表示
     */
    showValidationError(message) {
        // エラーメッセージの表示実装
        console.warn(message);
    }
    
    clearValidationError() {
        // エラーメッセージのクリア実装
    }
}
// UI システム初期化
document.addEventListener('DOMContentLoaded', () => {
    new TaxSimulatorUI();
});
5. レスポンシブCSS設計
/* モバイルファーストレスポンシブ設計 */
.tax-simulator {
    max-width: 900px;
    margin: 0 auto;
    font-family: 'Helvetica Neue', Arial, sans-serif;
    padding: 20px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 5px 15px rgba(0,0,0,0.05);
}
/* CSS Grid による結果表示レイアウト */
.result-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-bottom: 30px;
}
@media (max-width: 768px) {
    .result-grid {
        grid-template-columns: 1fr;
    }
    
    .tax-simulator {
        padding: 15px;
    }
    
    .example-btn-container {
        flex-direction: column;
    }
    
    .example-btn {
        width: 100%;
        margin-bottom: 10px;
    }
}
/* カスタムラジオボタン */
.radio-custom {
    width: 20px;
    height: 20px;
    border: 2px solid #1e4080;
    border-radius: 50%;
    margin-right: 8px;
    position: relative;
    transition: all 0.3s ease;
}
.radio-option input[type="radio"]:checked + .radio-custom {
    background: #1e4080;
}
.radio-option input[type="radio"]:checked + .radio-custom::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 8px;
    height: 8px;
    background: white;
    border-radius: 50%;
}
/* 減税効果ハイライト表示 */
.reduction-effect {
    background: linear-gradient(135deg, #28a745, #20c997);
    color: white;
    padding: 25px;
    border-radius: 12px;
    text-align: center;
    box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);
    position: relative;
    overflow: hidden;
}
.reduction-effect::before {
    content: '';
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
    animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
    0%, 100% { transform: rotate(0deg); }
    50% { transform: rotate(180deg); }
}
工夫したポイント・苦労した点
1. 現実的な消費税計算の実装
課題: 一般的な百分率計算では実際の商取引と結果が一致しない
解決策: Math.floor()による端数切り捨て処理の徹底実装
// 問題のあるアプローチ(小数点が残る)
const wrongCalculation = taxIncludedAmount * (1 - taxReductionRate / 100);
// 正しいアプローチ(現実の消費税法準拠)
const currentPretaxAmount = Math.floor(taxIncludedAmount / (1 + currentTaxRate / 100));
const afterTaxAmount = Math.floor(currentPretaxAmount * newTaxRate / 100);
const correctResult = currentPretaxAmount + afterTaxAmount;
効果: 50,000円(10%→5%)で2,274円の節約という現実的な結果を表示
2. 日本語入力環境でのリアルタイム処理
課題: 日本語IME入力中に不正な文字処理が発生
解決策: CompositionEvent による入力状態管理
amountInput.addEventListener('compositionstart', () => {
    this.isComposing = true;
});
amountInput.addEventListener('compositionend', () => {
    this.isComposing = false;
    setTimeout(() => this.formatAndValidateInput(), 0);
});
amountInput.addEventListener('input', () => {
    if (!this.isComposing) { // 日本語入力中は処理をスキップ
        this.formatAndValidateInput();
    }
});
3. WordPress連携でのセキュリティ対策
課題: 公開APIでのカウンター乱用防止
解決策: IPベースの重複チェックとTransient API活用
// 5秒以内の連続アクセス制限
$user_ip = $_SERVER['REMOTE_ADDR'];
$last_access_key = 'tax_reduction_last_' . md5($user_ip);
$current_time = current_time('timestamp');
$last_access = get_transient($last_access_key);
if ($last_access && ($current_time - $last_access) < 5) {
    echo get_option('tax_reduction_counter', 0);
    wp_die();
}
set_transient($last_access_key, $current_time, 300); // 5分間保持
4. モバイルUXの最適化
課題: スマートフォンでの入力・表示の最適化
解決策: CSS Grid によるレスポンシブレイアウト
.result-grid {
    display: grid;
    grid-template-columns: 1fr 1fr; /* デスクトップ */
    gap: 20px;
}
@media (max-width: 768px) {
    .result-grid {
        grid-template-columns: 1fr; /* モバイル:縦並び */
    }
}
5. パフォーマンス最適化
実装のポイント:
- 単一HTMLファイル構成による高速ローディング
 - 外部ライブラリ依存なしの軽量実装
 - WordPress Options API による効率的なデータ管理
 - Transient API によるキャッシュ最適化
 
アーキテクチャ設計の考察
フロントエンド設計
- Single File Architecture: 配布性と保守性のバランス
 - Progressive Enhancement: 基本機能から段階的な機能拡張
 - Mobile First: スマートフォン利用を前提とした設計
 
バックエンド設計
- WordPress子テーマ: 既存サイトへの非侵襲的な統合
 - AJAX API: フロントエンドとの疎結合な連携
 - 軽量データベース設計: WordPress Options テーブルの活用
 
まとめ
消費税減税シミュレーターの開発を通じて得られた技術的知見:
1. 現実に即した計算ロジックの重要性
Math.floor()による端数処理により、理論値ではなく実用的な結果を提供
2. 日本語環境でのWeb開発の特殊性
CompositionEvent による適切な入力処理で、日本語ユーザーのUXを向上
3. WordPress エコシステムの活用
既存CMSとの連携により、開発コストを抑制しつつ実用的な機能を実現
4. 政策議論におけるデータの価値
抽象的な議論を具体的数値で支援することで、社会的な価値を創出
技術的にはシンプルな構成でありながら、精密な実装により実用性の高いツールを開発できました。特に消費税計算という身近でありながら複雑な計算処理を正確に実装することで、政策議論に具体性をもたらすという社会的意義も実現できたと考えています。
Discussion