Files
MySMSAPio/CLAUDE.md
2025-10-22 17:22:17 +08:00

12 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

MySMSAPio is an SMS Gateway Backend API - a Rails 8.0 REST API and WebSocket server for managing SMS messaging through Android gateway devices. It provides programmatic SMS capabilities with OTP management, webhooks, and real-time WebSocket communication.

The project includes a web-based admin interface for managing API keys, monitoring SMS logs, and viewing gateway status. See ADMIN_INTERFACE.md for detailed documentation.

Tech Stack

  • Framework: Rails 8.0.3 (API-only mode)
  • Ruby: 3.4.7
  • Database: PostgreSQL 14+
  • Cache/Queue: Redis 7+
  • Background Jobs: Sidekiq 7 with sidekiq-cron
  • WebSocket: Action Cable (Redis adapter)
  • Authentication: API Keys with SHA256 hashing
  • Server: Puma with Thruster for production
  • Deployment: Kamal (Docker-based deployment)
  • Code Quality: RuboCop with rails-omakase configuration, Brakeman for security

SMS Gateway Dependencies

  • redis: WebSocket, caching, background jobs
  • sidekiq: Background job processing
  • sidekiq-cron: Scheduled jobs (health checks, cleanup)
  • jwt: API authentication tokens
  • rack-cors: Cross-origin resource sharing
  • phonelib: Phone number validation
  • rotp: OTP generation
  • httparty: Webhook HTTP requests
  • pagy: Pagination

Development Commands

Initial Setup

bin/setup

This will:

  • Install dependencies
  • Prepare the database
  • Clear logs and temp files
  • Start the development server

To skip auto-starting the server:

bin/setup --skip-server

Running the Application

bin/dev
# or
bin/rails server

Database

Create and migrate databases:

bin/rails db:create
bin/rails db:migrate

Prepare database (create + migrate + seed):

bin/rails db:prepare

Reset database:

bin/rails db:reset

Database console:

bin/rails dbconsole
# or via Kamal:
bin/kamal dbc

Testing

Run all tests:

bin/rails test

Run specific test file:

bin/rails test test/models/your_model_test.rb

Run specific test by line number:

bin/rails test test/models/your_model_test.rb:42

System tests:

bin/rails test:system

Tests run in parallel using all processor cores by default.

Code Quality

Run RuboCop:

bin/rubocop

Auto-correct RuboCop violations:

bin/rubocop -a

Run Brakeman security scanner:

bin/brakeman

Rails Console

bin/rails console
# or via Kamal:
bin/kamal console

Background Jobs (Sidekiq)

Start Sidekiq:

bundle exec sidekiq

View scheduled jobs:

bundle exec sidekiq-cron

Scheduled jobs run automatically:

  • CheckGatewayHealthJob: Every minute
  • CleanupExpiredOtpsJob: Every 15 minutes
  • ResetDailyCountersJob: Daily at midnight

Asset Management

Precompile assets:

bin/rails assets:precompile

Clear compiled assets:

bin/rails assets:clobber

Deployment (Kamal)

Deploy application:

bin/kamal deploy

View logs:

bin/kamal logs

Access remote shell:

bin/kamal shell

View configuration:

bin/kamal config

The deployment configuration is in config/deploy.yml. Production uses Docker containers with SSL enabled via Let's Encrypt.

Database Architecture

Development/Test

Single PostgreSQL database per environment:

  • Development: my_smsa_pio_development
  • Test: my_smsa_pio_test

Production

Multi-database setup for performance isolation:

  • Primary: Main application data
  • Cache: Database-backed cache via Solid Cache (migrations in db/cache_migrate/)
  • Queue: Job queue via Solid Queue (migrations in db/queue_migrate/)
  • Cable: WebSocket connections via Solid Cable (migrations in db/cable_migrate/)

Each database shares connection pooling configuration but maintains separate migration paths.

Application Structure

The application follows standard Rails 8 conventions with the modern "Omakase" stack:

  • app/: Standard Rails application code (models, controllers, views, jobs, mailers, helpers)
  • config/: Configuration files including multi-database setup
  • db/: Database schemas with separate migration directories for each database role
  • lib/: Custom library code (autoloaded via config.autoload_lib)
  • test/: Minitest-based test suite with system tests using Capybara + Selenium

Key Configuration Details

Module Name

The Rails application module is MySmsaPio (defined in config/application.rb).

Environment Variables

Required:

  • DATABASE_URL: PostgreSQL connection string
  • REDIS_URL: Redis connection string (used for Action Cable, Sidekiq, caching)
  • SECRET_KEY_BASE: Rails secret key
  • RAILS_ENV: Environment (development, test, production)

Optional:

  • ALLOWED_ORIGINS: CORS allowed origins (default: *)
  • DEFAULT_COUNTRY_CODE: Default country for phone validation (default: US)
  • RAILS_LOG_LEVEL: Logging level

Docker & Production

The application is containerized using a multi-stage Dockerfile optimized for production:

  • Base Ruby 3.4.7 slim image
  • Uses Thruster as the web server (listens on port 80)
  • Non-root user (rails:rails, uid/gid 1000)
  • Entrypoint handles database preparation via bin/docker-entrypoint
  • Assets precompiled during build

Code Style

Follow RuboCop Rails Omakase conventions. Configuration is minimal, inheriting from rubocop-rails-omakase gem.

Health Checks

The application includes a health check endpoint:

GET /up

Returns 200 if app boots successfully, 500 otherwise. Used by load balancers and monitoring.


SMS Gateway Specific Information

Database Models

Gateway (app/models/gateway.rb):

  • Represents Android SMS gateway devices
  • Tracks connection status, heartbeat, message counts
  • Generates and stores API keys (hashed with SHA256)

SmsMessage (app/models/sms_message.rb):

  • Stores all SMS messages (inbound and outbound)
  • Auto-generates unique message IDs
  • Validates phone numbers using Phonelib
  • Triggers SendSmsJob on creation for outbound messages

OtpCode (app/models/otp_code.rb):

  • Generates 6-digit OTP codes
  • Enforces rate limiting (3 per phone per hour)
  • Auto-expires after 5 minutes
  • Tracks verification attempts (max 3)

WebhookConfig (app/models/webhook_config.rb):

  • Configures webhooks for SMS events
  • Signs payloads with HMAC-SHA256
  • Supports retry logic

ApiKey (app/models/api_key.rb):

  • Client API keys for application access
  • Permissions-based access control
  • Tracks usage and expiration

API Controllers

Gateway APIs (app/controllers/api/v1/gateway/):

  • RegistrationsController: Register new gateway devices
  • HeartbeatsController: Keep-alive from gateways
  • SmsController: Report received SMS and delivery status

Client APIs (app/controllers/api/v1/):

  • SmsController: Send/receive SMS, check status
  • OtpController: Generate and verify OTP codes
  • Admin::GatewaysController: Manage gateway devices
  • Admin::StatsController: System statistics

WebSocket Communication

GatewayChannel (app/channels/gateway_channel.rb):

  • Real-time bidirectional communication with gateway devices
  • Authenticated via API key digest
  • Handles:
    • Gateway connection/disconnection
    • Heartbeat messages
    • Delivery reports
    • Inbound SMS notifications
    • Outbound SMS commands

Connection (app/channels/application_cable/connection.rb):

  • Authenticates WebSocket connections
  • Verifies gateway API keys

Background Jobs

Processing Jobs:

  • SendSmsJob: Routes outbound SMS to available gateways via WebSocket
  • ProcessInboundSmsJob: Triggers webhooks for received SMS
  • RetryFailedSmsJob: Retries failed messages with exponential backoff
  • TriggerWebhookJob: Executes webhook HTTP requests

Scheduled Jobs (config/sidekiq_cron.yml):

  • CheckGatewayHealthJob: Marks offline gateways (every minute)
  • CleanupExpiredOtpsJob: Deletes expired OTP codes (every 15 minutes)
  • ResetDailyCountersJob: Resets daily message counters (daily at midnight)

Admin Web Interface

Admin Authentication (app/models/admin.rb, app/controllers/admin/):

  • Session-based authentication with bcrypt password hashing
  • Access URL: /admin/login
  • Default credentials (development): admin@example.com / password123

Admin Features:

  1. Dashboard (/admin/dashboard): Real-time statistics and recent activity
  2. API Keys Management (/admin/api_keys): Create, view, and revoke API keys
  3. SMS Logs (/admin/logs): Monitor messages with advanced filtering
  4. Gateway Management (/admin/gateways): View and manage gateway devices

Admin Controllers:

  • Admin::BaseController: Base controller with authentication
  • Admin::SessionsController: Login/logout
  • Admin::DashboardController: Dashboard with stats
  • Admin::ApiKeysController: API key CRUD operations
  • Admin::LogsController: SMS logs with filtering
  • Admin::GatewaysController: Gateway management

See ADMIN_INTERFACE.md for complete documentation.

Authentication & Security

API Key Types:

  1. Gateway Keys (gw_live_...): For Android gateway devices
  2. Client Keys (api_live_...): For application APIs
  3. Admin Access: Session-based web authentication

Authentication Flow:

  • API keys passed in Authorization: Bearer <key> header
  • Keys are hashed with SHA256 before storage
  • Admin passwords hashed with bcrypt
  • Concerns: ApiAuthenticatable, RateLimitable

Rate Limiting:

  • Implemented via Redis caching
  • OTP: Max 3 per phone per hour
  • SMS Send: 100 per minute per API key
  • Customizable per endpoint

Key Files

Models: app/models/{gateway,sms_message,otp_code,webhook_config,api_key}.rb

Controllers: app/controllers/api/v1/**/*_controller.rb

Jobs: app/jobs/{send_sms_job,process_inbound_sms_job,retry_failed_sms_job,trigger_webhook_job,check_gateway_health_job,cleanup_expired_otps_job,reset_daily_counters_job}.rb

Channels: app/channels/{gateway_channel,application_cable/connection}.rb

Concerns: app/controllers/concerns/{api_authenticatable,rate_limitable}.rb, app/models/concerns/metrics.rb

Config:

  • config/routes.rb: API routes
  • config/cable.yml: Action Cable (Redis)
  • config/sidekiq_cron.yml: Scheduled jobs
  • config/initializers/{cors,sidekiq,phonelib,pagy}.rb

Common Development Tasks

Generate new API key:

# In Rails console
result = ApiKey.generate!(name: "My App", permissions: { send_sms: true, receive_sms: true })
puts result[:raw_key] # Save this immediately!

Register gateway manually:

# In Rails console
gateway = Gateway.new(device_id: "my-device-001", name: "My Gateway")
api_key = gateway.generate_api_key!
puts api_key # Save this immediately!

Check gateway status:

# In Rails console
Gateway.online.each { |g| puts "#{g.name}: #{g.status}" }

View pending messages:

# In Rails console
SmsMessage.pending.count
SmsMessage.failed.each { |msg| puts "#{msg.message_id}: #{msg.error_message}" }

Test WebSocket connection:

# Use wscat or similar WebSocket client
wscat -c "ws://localhost:3000/cable?api_key=gw_live_your_key_here"

Important Notes

  • Redis is required for Action Cable, Sidekiq, and caching to work
  • All phone numbers are validated and normalized using Phonelib
  • Gateway devices must send heartbeats every 2 minutes or they'll be marked offline
  • Outbound SMS messages are queued and sent asynchronously via Sidekiq
  • Failed messages retry automatically up to 3 times with exponential backoff
  • OTP codes expire after 5 minutes and allow max 3 verification attempts
  • All API keys are SHA256 hashed - raw keys are only shown once during creation