0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Quản lý Truy cập Tính năng Linh hoạt trong Ứng dụng SaaS Rails

Đăng vào 7 tháng trước

• 5 phút đọc

Giới thiệu

Khi xây dựng một ứng dụng SaaS, việc quản lý các gói đăng ký với các tính năng và giới hạn khác nhau là điều không thể tránh khỏi. Một cách tiếp cận phổ biến là mã hóa cứng các tính năng của gói đăng ký trực tiếp trong mô hình của bạn. Tuy nhiên, điều này có thể dẫn đến một hệ thống cứng nhắc và khó duy trì.

Bài viết này sẽ hướng dẫn bạn cách quản lý truy cập tính năng một cách linh hoạt, cho phép bạn dễ dàng điều chỉnh các tính năng cho từng người dùng mà không cần thay đổi mã nguồn. Chúng ta sẽ cùng khám phá cách thực hiện điều này trong ứng dụng Rails của bạn.

Mô hình Truy cập

Đầu tiên, chúng ta cần tạo một mô hình để lưu trữ cấu hình truy cập của từng người dùng. Sử dụng RailsVault, ta có thể định nghĩa các thuộc tính truy cập như sau:

ruby Copy
# app/models/user/access.rb
class User::Access < RailsVault::Base
  vault_attribute :member_count, :integer, default: Config::Plans.fallback.dig(:features, :member_count)
  vault_attribute :enabled_workflow_count, :integer, default: Config::Plans.fallback.dig(:features, :enabled_workflow_count)
  vault_attribute :enabled_endpoint_count, :integer, default: Config::Plans.fallback.dig(:features, :enabled_endpoint_count)
  vault_attribute :total_steps_per_workflow_count, :integer, default: Config::Plans.fallback.dig(:features, :total_steps_per_workflow_count)
  vault_attribute :total_monthly_run_count, :integer, default: Config::Plans.fallback.dig(:features, :total_monthly_run_count)
  vault_attribute :ai_enabled, :boolean, default: Config::Plans.fallback.dig(:features, :ai_enabled)
end

Mỗi thuộc tính đại diện cho một tính năng hoặc giới hạn cụ thể trong ứng dụng của bạn. Tôi thường sử dụng hậu tố _count cho các giới hạn số và _enabled cho các tính năng kiểu boolean.

Thêm Truy cập Tính năng cho Người dùng

Tiếp theo, chúng ta sẽ tạo một concern để xử lý logic truy cập tính năng:

ruby Copy
# app/models/user/feature_access.rb
module User::FeatureAccess
  extend ActiveSupport::Concern

  included do
    vault :access
  end

  def add_access(product_id)
    access.update Config::Plans[product_id.to_sym][:features]
  end
end

Phương thức add_access nhận một ID sản phẩm từ Stripe và áp dụng các tính năng tương ứng cho người dùng. Bạn thường gọi phương thức này từ handler webhook của Stripe khi một đăng ký được tạo hoặc cập nhật. Tuy nhiên, điều này không chỉ giới hạn cho Stripe.

Đừng quên thêm concern này vào mô hình Người dùng:

ruby Copy
# app/models/user.rb
class User < ApplicationRecord
  include FeatureAccess

  # …
end

Cấu hình Gói Đăng ký

Sử dụng hệ thống cấu hình từ bài viết trước của tôi, tôi định nghĩa tất cả các gói trong một tệp YAML:

yaml Copy
# config/configurations/plans.yml
shared:
  fallback:
    name: Free
    features:
      member_count: 1
      enabled_workflow_count: 1
      enabled_endpoint_count: 2
      total_steps_per_workflow_count: 3
      total_monthly_run_count: 100
      ai_enabled: false

development:
  starter_plan_id:
    name: Starter
    price_id: price_dev_starter
    amount: 19
    features:
      member_count: 1
      enabled_workflow_count: 5
      enabled_endpoint_count: 10
      total_steps_per_workflow_count: 5
      total_monthly_run_count: 5_000
      ai_enabled: false

  pro_plan_id:
    name: Pro
    price_id: price_dev_pro
    amount: 49
    features:
      member_count: 5
      enabled_workflow_count: 25
      enabled_endpoint_count: 50
      total_steps_per_workflow_count: 15
      total_monthly_run_count: 25_000
      ai_enabled: true

production:
  starter_plan_id:
    name: Starter
    price_id: price_prod_starter
    amount: 19
    features:
      member_count: 1
      enabled_workflow_count: 5
      enabled_endpoint_count: 10
      total_steps_per_workflow_count: 5
      total_monthly_run_count: 5_000
      ai_enabled: false

  pro_plan_id:
    name: Pro
    price_id: price_prod_pro
    amount: 49
    features:
      member_count: 5
      enabled_workflow_count: 25
      enabled_endpoint_count: 50
      total_steps_per_workflow_count: 15
      total_monthly_run_count: 25_000
      ai_enabled: true

Phần fallback định nghĩa gói miễn phí mặc định mà người dùng mới nhận được. Mỗi hash features của gói tương ứng chính xác với các thuộc tính vault được định nghĩa trong mô hình Truy cập.

Sử dụng

Giờ đây, bạn có thể dễ dàng kiểm tra quyền truy cập của người dùng trong toàn bộ ứng dụng:

ruby Copy
# Kiểm tra giới hạn
Current.user.access.member_count # => 5
Current.user.access.enabled_workflow_count # => 25

# Kiểm tra boolean với hậu tố ?
Current.user.ai_enabled? # => true

Khi xử lý webhook từ Stripe, việc áp dụng truy cập trở nên dễ dàng:

ruby Copy
# Trong handler webhook của Stripe
def checkout_session_completed(event)
  session = event.data.object
  user = User.find_by(stripe_customer_id: session.customer)

  # Trích xuất ID sản phẩm từ các mục dòng
  product_id = session.line_items.data.first.price.product

  user.add_access(product_id)
end

Mẹo và Thực tiễn Tốt nhất

  • Thực hiện kiểm tra truy cập: Đảm bảo kiểm tra quyền truy cập của người dùng trước khi cho phép họ thực hiện các hành động liên quan đến tính năng.
  • Ghi chú rõ ràng: Sử dụng ghi chú trong mã để giải thích các quyết định thiết kế. Điều này giúp cho việc bảo trì mã trở nên dễ dàng hơn.
  • Kiểm tra A/B: Sử dụng khả năng tùy chỉnh để thực hiện các thử nghiệm A/B với các tính năng khác nhau cho người dùng khác nhau.

Những Cạm bẫy Thường Gặp

  • Quên cập nhật cấu hình: Đảm bảo rằng bạn luôn cập nhật cấu hình gói khi có thay đổi. Sự không nhất quán có thể dẫn đến trải nghiệm người dùng không tốt.
  • Thiếu kiểm tra quyền truy cập: Hãy chắc chắn rằng mọi tính năng yêu cầu kiểm tra quyền truy cập đều được thực hiện đúng cách để tránh các lỗ hổng bảo mật.

Kết luận

Với cách tiếp cận này, bạn có thể tạo ra một hệ thống linh hoạt cho phép bạn điều chỉnh tính năng cho từng người dùng mà không cần phải thay đổi mã nguồn. Điều này không chỉ giảm bớt gánh nặng cho đội ngũ phát triển mà còn cải thiện trải nghiệm khách hàng. Nếu bạn có thắc mắc hoặc cần thêm thông tin, hãy liên hệ với tôi! Hãy bắt đầu nâng cao trải nghiệm người dùng của bạn ngay hôm nay!

Câu hỏi thường gặp (FAQ)

  1. Tôi có thể sử dụng cách tiếp cận này cho các ứng dụng không phải SaaS không?
    Có, bạn có thể áp dụng cách tiếp cận này cho bất kỳ ứng dụng nào cần quản lý quyền truy cập tính năng.

  2. Cách nào để thực hiện kiểm tra A/B trong Rails?
    Bạn có thể sử dụng các gem như split hoặc ab để thực hiện thử nghiệm A/B trong Rails.

  3. Tôi có thể áp dụng cách tiếp cận này mà không cần Stripe không?
    Hoàn toàn có thể! Cách tiếp cận này có thể được áp dụng cho bất kỳ hệ thống thanh toán nào hoặc ngay cả khi không có hệ thống thanh toán.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào