Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/ffsshhttiikk/opencode-agents-skills --skill saas명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | saas |
| description | Software as a Service architecture |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"architect, developer","category":"devops"} |
| Model | Isolation | Complexity | Cost |
|---|---|---|---|
| Shared Everything | Database | Low | Low |
| Shared Database | Schema | Medium | Medium |
| Shared Application | Container | Medium | Medium |
| Isolated | VPC/Account | High | High |
-- PostgreSQL multi-tenant schema
CREATE TABLE tenants (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
subdomain VARCHAR(63) UNIQUE NOT NULL,
plan VARCHAR(50) DEFAULT 'free',
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
name VARCHAR(255),
role VARCHAR(50) DEFAULT 'member',
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(tenant_id, email)
);
-- Row-level security
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY "tenant_isolation" ON users
FOR ALL
USING (tenant_id = current_setting('app.tenant_id')::UUID);
# FastAPI multi-tenancy
from contextvars import ContextVar
from fastapi import Request, Depends
tenant_context: ContextVar[str] = ContextVar('tenant_id', default=None)
def get_tenant_id(request: Request) -> str:
# Extract from subdomain
host = request.headers.get('host', '')
subdomain = host.split('.')[0]
# Or from JWT
# token = request.headers.get('authorization')
# tenant_id = decode_jwt(token)['tenant_id']
return tenant_context.set(subdomain)
def get_current_tenant() -> Tenant:
tenant_id = tenant_context.get()
return Tenant.objects.get(subdomain=tenant_id)
@app.get("/api/users")
async def list_users(tenant: Tenant = Depends(get_current_tenant)):
return User.objects.filter(tenant=tenant).all()
// OAuth2 for SaaS
const oauth2Client = new OAuth2Client(
process.env.GOOGLE_CLIENT_ID,
process.env.GOOGLE_CLIENT_SECRET,
'https://yourapp.com/callback'
);
// Multi-tenant SSO
const samlConfig = {
entryPoint: 'https://idp.example.com/sso',
issuer: 'yourapp',
callbackHandler: async (profile) => {
const tenant = await findOrCreateTenant(profile.orgId);
const user = await findOrCreateUser(profile, tenant);
return { user, tenant };
}
};
// Role-based access for SaaS
const permissions = {
admin: ['*'],
manager: ['read', 'write', 'users:read'],
member: ['read', 'write:own'],
viewer: ['read']
};
class UsageTracker:
def track_event(self, tenant_id: str, event_type: str, metadata: dict):
# Record usage event
event = UsageEvent(
tenant_id=tenant_id,
event_type=event_type,
metadata=metadata,
timestamp=datetime.utcnow()
)
self.db.save(event)
# Update meter
meter = self.get_or_create_meter(tenant_id, event_type)
meter.increment(metadata.get('quantity', 1))
def get_usage(self, tenant_id: str, period: Period) -> UsageReport:
events = self.db.query(UsageEvent)
.filter(
tenant_id=tenant_id,
timestamp__gte=period.start,
timestamp__lte=period.end
)
return self.aggregate_events(events)
# Stripe SaaS billing
import stripe
stripe.api_key = os.environ['STRIPE_SECRET_KEY']
def create_customer(tenant: Tenant):
customer = stripe.Customer.create(
email=tenant.admin_email,
metadata={'tenant_id': str(tenant.id)}
)
tenant.stripe_customer_id = customer.id
tenant.save()
def create_subscription(tenant: Tenant, plan_id: str):
subscription = stripe.Subscription.create(
customer=tenant.stripe_customer_id,
items=[{'price': plan_id}],
metadata={'tenant_id': str(tenant.id)},
trial_period_days=14
)
def get_invoices(tenant: Tenant):
return stripe.Invoice.list(
customer=tenant.stripe_customer_id,
limit=12
)