메인 콘텐츠로 건너뛰기

Documentation Index

Fetch the complete documentation index at: https://docs.fim.ai/llms.txt

Use this file to discover all available pages before exploring further.

FIM One은 관리자가 제어하는 기능 플래그 뒤에 완전한 Stripe 결제 파이프라인을 제공합니다. 결제가 필요 없는 프라이빗 배포는 이를 비활성화하고 UI를 볼 수 없습니다. SaaS 운영자는 한 번의 토글로 호스팅된 Checkout, Customer Portal, 웹훅 기반 구독 생명주기 및 할당량 적용을 즉시 사용할 수 있습니다.
결제는 기본적으로 비활성화되어 있습니다. 새로운 설치 및 기존 셀프호스트 모두 system_settings.billing_enabled = FALSE로 시작합니다. 관리자가 명시적으로 활성화할 때까지 결제 UI는 표시되지 않습니다.

무엇을 얻을 수 있는가

  • Free + Pro 티어 — 월간 토큰 할당량 포함 (기본값: Free 1M / Pro 5M; 활성화 후 조정 가능)
  • Stripe 호스팅 Checkout — 사용자가 업그레이드할 때 카드 데이터가 코드를 거치지 않음
  • Customer Portal — 사용자가 결제 방법 업데이트, 청구서 다운로드, 구독 취소 — 모두 Stripe UI에서 처리
  • Webhook 기반 라이프사이클 — 구독 자동 프로비저닝 및 갱신; 취소된 구독은 기간 종료 시 Free로 강등
  • 할당량 적용 — 기간당 토큰 사용량 추적; 스트림 중 차단 및 구조화된 업그레이드 프롬프트
  • 관리자 페이지 — 요금제 CRUD 및 구독 모니터링

전제 조건

  1. Stripe 계정 (라이브 모드 활성화됨). 싱가포르 법인은 KYC 완료 필요(사업 UEN, 이사 신분증, 은행 계좌). 승인은 일반적으로 1-3일 소요됩니다.
  2. Stripe 라이브 API 키 (제한된 유형 권장 — 표준 sk_live_***보다 해지하기 쉽고 권한 범위 지정 가능).
  3. 웹훅 엔드포인트 (<your-domain>/api/webhooks/stripe에서 공개적으로 접근 가능).
  4. 은행 계좌 (지급용). 다중 통화 결제(예: USD 계좌로 USD 지급)는 USD 기본값이 아닌 Stripe 계정의 경우 거래당 1.5-2% FX 손실을 피하기 위해 권장됩니다.

설정

1. Stripe 대시보드

Pro 상품 만들기

  1. Catalog → Products → + Add product
  2. Name: Pro, description: 5M tokens / month, priority support
  3. Pricing: Recurring, monthly, $20.00 USD (adjust to your pricing strategy)
  4. Save → copy the resulting price_*** ID (you will UPDATE the local billing_plans table with this value after activation)

제한된 API 키 생성

  1. Developers → API keys → + Create restricted key
  2. Name: fim-one production
  3. Permissions (minimum):
    • Customers: Write
    • Subscriptions: Write
    • Checkout Sessions: Write
    • Customer portal: Write
    • Prices: Read
    • Products: Read
  4. Save → copy rk_live_***

웹훅 엔드포인트 등록

  1. Developers → Webhooks → + Add endpoint
  2. URL: https://<your-domain>/api/webhooks/stripe
  3. 수신할 이벤트:
    • checkout.session.completed
    • customer.subscription.created
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_succeeded
    • invoice.payment_failed
  4. 저장 후 “Reveal signing secret” 클릭 → whsec_*** 복사

다중 통화 결제 구성(권장)

Stripe 계정의 기본 통화가 청구하는 가격 통화와 다른 경우(일반적인 경우: SGD 계정에서 USD 청구):
  1. Settings → Bank accounts and currencies → Add a settlement currency
  2. 가격 통화 선택(예: USD)
  3. 일치하는 은행 계좌 연결(예: Aspire USD 가상 계좌)
  4. 저장 — Stripe가 USD 청구를 USD 지급으로 직접 라우팅하므로 환율 변환 없음

2. Backend .env

프로덕션 .env에서 다음 세 개의 키를 설정하세요:
STRIPE_SECRET_KEY=rk_live_***
STRIPE_WEBHOOK_SECRET=whsec_***
STRIPE_BILLING_RETURN_URL=https://<your-domain>/settings?tab=billing
전체 참조는 Environment Variables를 참조하세요. .env를 편집한 후 백엔드를 다시 시작하여 키가 적용되도록 하세요:
./deploy.sh   # or: docker compose restart fim-one

3. Admin에서 활성화

  1. 관리자로 로그인
  2. Admin → System Settings → Billing
  3. Enable Stripe Billing 토글을 ON으로 설정
  4. 백엔드가 STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRET이 모두 존재하는지 검증합니다 — 둘 중 하나라도 누락되면 400을 반환하고 토글은 OFF 상태로 유지됩니다
  5. 처음 활성화할 때만 백엔드가 멱등성 설정을 실행합니다:
    • Free + Pro 플랜을 시드합니다 (이미 존재하면 건너뜀)
    • system_settings.default_plan_id를 Free 플랜 id로 설정합니다
    • 플랜이 없는 모든 사용자에 대해 users.plan_id = free.id를 역채우기합니다
    • default_token_quota → Free 플랜 monthly_token_quota를 동기화하여 기존 관리자 제어 전역 할당량이 유지되도록 합니다
  6. 이후 토글 끄기/켜기는 순수 플래그 전환이며 데이터 부작용이 없습니다

4. Pro 플랜을 라이브 가격으로 업데이트

활성화 후, 시드된 Pro 플랜을 라이브 Stripe 가격으로 업데이트하세요:
  • Admin → Billing → Plans → Pro → Edit
  • 1단계에서 얻은 price_1***Stripe Price ID에 붙여넣기
  • 저장
또는 SQL을 통해 (직접 DB 접근을 선호하는 경우):
UPDATE billing_plans
SET stripe_price_id = 'price_1***'
WHERE slug = 'pro';

5. Smoke test

  1. /settings?tab=billing을 일반 사용자로 열기
  2. Switch to Pro 클릭
  3. Stripe Checkout이 열림; 소액 실제 카드로 완료 (이후 환불)
  4. Webhook이 실행되어야 함 — Stripe Dashboard → Webhooks → 최근 이벤트에서 2xx 응답 확인
  5. subscriptions 테이블에 구독 행이 나타남; users.plan_idpro로 변경됨
  6. UI에 Pro 플랜 + “Manage subscription” 버튼 표시

청구 비활성화

Admin → System Settings → Billing에서 Enable Stripe Billing 스위치를 OFF로 전환합니다. 비활성화되면:
  • 모든 /api/billing/* 엔드포인트가 503을 반환합니다
  • 웹훅 엔드포인트가 503을 반환합니다 (Stripe가 재시도한 후 Dashboard에 실패로 표시됩니다 — 청구가 영구적으로 비활성화된 경우 Stripe Dashboard에서 웹훅을 비활성화할 수 있습니다)
  • Plan & Billing 사용자 대면 탭이 사라집니다
  • Admin → Billing 네비게이션 그룹이 숨겨집니다
  • 할당량 체인이 요금제 계층을 건너뛰고 default_token_quota로 직접 폴백합니다
데이터는 보존됩니다: 기존 subscriptions, billing_plans, users.plan_id 행은 변경되지 않습니다. 다시 활성화하면 마이그레이션 없이 동일한 상태에서 재개됩니다.

계산 참고 — 할당량 및 토큰 수학

이것은 사용자가 소비할 수 있는 것, 카운터가 언제 재설정되는지, 그리고 해결 체인이 어떻게 구성되는지를 결정하는 모든 숫자 규칙의 권위 있는 참고 자료입니다. 가격 책정을 변경하거나, 할당량을 조정하거나, 사용량 대시보드를 구축하거나, v2/v3 작업을 계획하기 전에 이것을 읽으세요. 아직 배포되지 않은 향후 규칙은 예약된 슬롯에 문서화되어 있으므로 기여자들이 새로운 로직이 어디에 연결되는지 알 수 있습니다.

용어집

변수저장소의미범위
users.token_quotaper-user (override)3가지 상태 오버라이드; 아래 의미 참조NULL, 0, 또는 양의 정수
users.tokens_used_this_periodper-user (counter)마지막 리셋 이후 누적 토큰음이 아닌 정수
users.quota_reset_atper-user (anchor)유료 사용자의 Subscription.current_period_end 반영timestamp
users.plan_idper-user (FK)활성 플랜FK billing_plans.id
billing_plans.monthly_token_quotaper-plan이 플랜의 사용자에 대한 하드 캡음이 아닌 정수
system_settings.default_token_quotasingleton적용되는 플랜이 없을 때의 방어적 폴백음이 아닌 정수
system_settings.default_plan_idsingleton신규/미할당 사용자를 위한 무료 플랜 포인터FK 또는 NULL
system_settings.billing_enabledsingleton마스터 스위치 — 체인의 2단계를 제어boolean

토큰으로 계산되는 항목

토큰 소비는 LLM 호출 레이어에서 계산되며, 모든 완료 시 LiteLLM의 usage 객체에서 소싱됩니다.
  • 계산됨: 모든 모델 호출에서 프롬프트 토큰 + 완료 토큰
  • 계산됨: 다단계 / 도구 사용 에이전트 흐름의 모든 왕복 (각 모델 호출은 자체 차감)
  • 계산됨: 임베딩 요청 (KB 수집, 검색 점수 매김)
  • 계산 안 됨: 모델로 전송되지 않은 입력 (예: 사용자가 버린 업로드된 파일)
  • 계산 안 됨: 제공자에 도달하기 전에 실패한 요청 (인증 오류, 속도 제한 사전 확인)
  • 캐시된 입력: v1에서는 정가로 계산됨 (제공자 캐시 할인이 표시되지 않음). v2는 캐시된 프롬프트 토큰을 별도로 크레딧할 수 있습니다.

3단계 오버라이드 의미론

users.token_quota는 사용자별 관리 오버라이드입니다. 하나의 열에 세 가지 의미를 담고 있습니다:
의미사용 사례
NULL설정되지 않음 — 플랜 / 기본값으로 위임모든 일반 사용자의 기본 상태
0무제한관리자 / 내부 계정; “VIP 선물”
N > 0N에서 하드 캡유료 구독을 취소하지 않고 악용자 차단; 선결제 엔터프라이즈 할당량
오버라이드는 항상 플랜과 기본값을 우선합니다. 관리자가 Stripe를 건드리지 않고도 개별 사용자를 플랜 계층 위 또는 아래에 고정할 수 있도록 존재합니다.

할당량 해결 체인 — v1 (현재)

인증된 모든 요청에 대해 상한은 하향식으로 계산됩니다 — 첫 번째 일치가 우선입니다:
1. users.token_quota        ── NULL? skip. 0? unlimited. N>0? cap at N.
2. users.plan.monthly_token_quota   ── only when billing_enabled = TRUE
3. system_settings.default_token_quota  ── defensive fallback
4. unlimited                ── last resort if everything above is NULL
청구가 활성화되면 3단계에 거의 도달하지 않습니다. 활성화가 모든 사용자에 대해 users.plan_id를 역채우기하기 때문입니다. 잘못 구성된 플랜이 사용자를 자동으로 무제한으로 설정하지 않도록 하는 심층 방어 메커니즘으로 존재합니다.

기간 재설정

  • 유료 사용자의 경우, quota_reset_atSubscription.current_period_end를 반영합니다. invoice.payment_succeeded 웹훅 핸들러는 각 갱신 성공 시 tokens_used_this_period = 0으로 설정하고 quota_reset_at을 새로운 기간 종료로 진행합니다.
  • Free 사용자(Stripe 구독 없음)의 경우, 시간별 크론이 계획 할당 날짜를 기준으로 한 달력 월 경계에서 tokens_used_this_period를 0으로 롤링합니다.
  • 기간 중 계획 변경은 카운터를 재설정하지 않습니다 — 갱신만 재설정합니다. 이는 할당량 순환 악용(“구독 → Pro 할당량 사용 → 취소 → 다시 구독”)을 방지합니다.

스트림 중 적용

  • 채팅 호출 진입 시 사전 점검: 가장 저렴한 경로로, 사용자가 감당할 수 없는 요청을 차단합니다.
  • 스트리밍 중에는 모든 청크에서 실행 중인 토큰 수를 다시 평가합니다. 한도를 초과하면 네트워크 오류가 아닌 구조화된 종료 프레임으로 스트림을 닫습니다.
  • 프론트엔드는 종료자를 해석하고 /settings?tab=billing으로의 딥 링크와 함께 <QuotaExceededDialog>를 표시합니다.
  • 비스트리밍 응답은 HTTP 402를 반환하며, 본문은 { code: "QUOTA_EXCEEDED", reset_at, upgrade_url }입니다.

청구 비활성화 폴백

system_settings.billing_enabled = FALSE일 때:
  • 체인의 2단계가 건너뛰어집니다 — 체인이 override → default → unlimited로 축소됩니다.
  • /api/billing/*/api/webhooks/stripe503을 반환합니다.
  • Plan & Billing 사용자 탭 및 Admin → Billing 네비게이션 그룹이 숨겨집니다.
  • 모든 청구 데이터(구독, 플랜, users.plan_id)는 보존됩니다 — 다시 활성화하면 마이그레이션 없이 동일한 상태에서 재개됩니다.

Reserved: quota chain v2 — Team seats

아직 출시되지 않았습니다. v2 작업이 알려진 착륙 지점을 가지도록 여기에 문서화되어 있습니다.
Team 플랜이 출시될 때:
  • Subscription.quantity는 좌석 수를 전달합니다(Stripe 기본).
  • 사용자의 유효한 플랜은 Team 멤버십을 통해 해결되며, 그 후 개인 플랜으로 폴백됩니다:
    effective_plan = team.plan if team_member(user) else user.plan
    
  • 할당량은 좌석당(각 Team 멤버는 전체 monthly_token_quota를 받음)이며, 풀링된 버킷이 아닙니다. 풀링된 버킷은 선착순 소진을 만들고 고객 친화적이지 않습니다.
  • 재정의 의미는 변경되지 않습니다 — Team 관리자는 여전히 users.token_quota = N을 통해 개별 멤버를 하드 캡할 수 있으며, 이는 team 플랜 체인 위에 있습니다.

Reserved: quota chain v3 — native Org allocation (no Stripe)

아직 출시되지 않음. Stripe를 통해 사용자당 비용을 지불하지 않고 내부적으로 할당량을 배분하는 온프레미스/엔터프라이즈 배포용으로 예약됨.
  • 새로운 테이블 org_quota_allocations(user_id, monthly_token_quota, org_id)는 상위 예산을 멤버 전체에 배분합니다.
  • 할당량은 공유 풀이 아닌 사용자별 — 모든 멤버가 명확한 개별 SLA를 가집니다.
  • 업데이트된 체인:
    override → max(plan_quota, org_allocation) → default → unlimited
    
  • max(), sum() 아님. 유료 Pro 사용자는 조직 관리자가 낮은 할당량을 설정하더라도 결코 지불한 것보다 적게 받지 않습니다. Stripe 지불 할당량은 절대 불변입니다.

예약됨: 종량제 크레딧 잔액 (v3 별도 차원)

아직 출시되지 않음. 위의 체인과 별개의 축——크레딧은 구독 티어가 아닌 일회성 충전입니다.
  • 새로운 테이블 user_credits(user_id, balance_cents, currency) — Stripe Checkout mode='payment'를 통해 자금 조달됨.
  • 소비 순서: 구독 할당량 우선, 그 다음 크레딧 잔액 (구독이 소진된 후에만 크레딧 차감 시작).
  • 크레딧 잔액은 환불 불가능 (선불식 업계 표준).
  • UI는 두 개의 바를 노출: Subscription quota: 4.2M / 5M used + Credits: $7.40 remaining.

기본값

배포 시 기본값 — 명시된 경우를 제외하고 모두 설치 후 조정 가능합니다.
변수기본값조정 방법
billing_plans.monthly_token_quota (Free)1,000,000Admin → Billing → Plans → Free → Edit
billing_plans.monthly_token_quota (Pro)5,000,000Admin → Billing → Plans → Pro → Edit
system_settings.default_token_quota1,000,000 (활성화 시 Free와 동기화)Admin → System Settings → Quotas
system_settings.billing_enabledFALSEAdmin → System Settings → Billing
Pro 정가$20.00 USD / monthStripe Dashboard (price object)
구독한 Stripe 웹훅 이벤트6Stripe Dashboard → Webhooks
Stripe 가격 캐시 TTL5 minutesstripe_client.py에 하드코딩됨
구독 수명 주기 cron매시간web/main.py의 APScheduler
Free 티어 리셋 cron매시간 (달력 월 경계)web/main.py의 APScheduler

가격 책정 모델

V1은 정액 구독입니다. Free + Pro, 월간 청구, USD만 지원합니다. V1 범위 외 (의도적으로 로드맵으로 연기됨):
  • Team 플랜 (Stripe seats / subscription.quantity)
  • 연간 청구
  • 다중 통화 표시
  • 쿠폰 / 프로모션 코드
  • 세금 처리 (Stripe Tax 통합 — 별도 규정 검토 필요)
  • 사용량 기반 계량 / 초과 요금
  • 선불 크레딧 잔액 (일회성 충전)
다음 계획된 사항은 로드맵을 참조하세요.

문제 해결

활성화 엔드포인트에는 STRIPE_SECRET_KEYSTRIPE_WEBHOOK_SECRET이 모두 설정되어야 합니다. .env에 존재하는지 확인하고 편집 후 백엔드가 다시 시작되었는지 확인하세요.
청구가 비활성화되어 있거나(토글이 OFF) 요청 서명 검증에 실패했습니다(STRIPE_WEBHOOK_SECRET 불일치). Stripe 대시보드 → 웹훅 → 최근 이벤트에서 실제 오류 본문을 확인하세요.
checkout.session.completed 웹훅이 백엔드에 도달하지 않았습니다. Stripe 대시보드의 엔드포인트 URL이 <your-domain>/api/webhooks/stripe와 정확히 일치하는지(후행 경로 포함) 확인하세요. 웹훅 최근 전달 기록에서 실패를 확인하세요.
시드 마이그레이션이 테스트 모드 가격 ID를 작성합니다. 프로덕션 청구를 활성화한 후 관리자 → 청구 → 요금제 → Pro → 편집을 통해 Pro 요금제를 라이브 price_1***을 사용하도록 업데이트하거나 직접 SQL UPDATE를 실행하세요.
Stripe 대시보드 → 설정 → 브랜딩에서 비즈니스 브랜딩을 구성하세요. 로고, 비즈니스 이름(예: “FIM Labs Pte. Ltd.”), 주소를 추가하세요. Stripe는 이를 모든 자동 생성 영수증 및 청구서에 적용합니다.
Stripe 계정 기본 통화가 청구 통화와 다르면 Stripe는 매번 지급할 때 환전합니다(1.5-2% 스프레드). 설정 → 은행 계좌 및 통화에서 일치하는 결제 통화를 추가하고 동일 통화 은행 계좌를 연결하면 Stripe가 환전 없이 동일 통화 결제를 라우팅합니다.