Resource Scoping
Understand how resources are scoped in ARSAKA PUGUH.
Scoping Model
PUGUH uses a two-level scoping model:
plaintext
Organization
└── Application
├── Webhooks
├── Storage (Files)
├── API Keys
└── Members Scope Types
Organization-Scoped
Resources shared across all applications in the organization:
- Users & Roles: Members belong to the organization
- Billing & Subscriptions: One plan per organization
- Audit Logs: Organization-wide event history
- Settings: Organization preferences and policies
typescript
// List all members in the organization
const members = await client.organizations.listMembers(orgId);
// View organization-wide audit trail
const audit = await client.control.listAudit({ page: 1, limit: 50 }); Application-Scoped
Resources isolated within a specific application:
- Webhooks: Each application has its own webhook endpoints
- Storage: Files are isolated per application
- API Keys: Generated per application for integration
- Members: Users can be assigned to specific applications
typescript
// Create a webhook scoped to an application
const webhook = await client.webhooks.create({
url: 'https://your-app.com/webhook',
eventTypes: ['user.registered'],
applicationId: 'app-uuid',
});
// List webhooks for a specific application
const webhooks = await client.webhooks.list({ applicationId: 'app-uuid' }); Resource Scoping Rules
| Resource | Scope | Notes |
|---|---|---|
| Users | Organization | Members belong to org, can be assigned to apps |
| Roles | Organization | Owner, Admin, Member, Viewer |
| Applications | Organization | Created within an organization |
| Webhooks | Application | Isolated per application |
| Storage | Application | Files isolated per application |
| API Keys | Application | One key per application |
| Audit Logs | Both | Filterable by application |
| Billing | Organization | One subscription per organization |
Application Isolation
Applications provide resource isolation within an organization. This is useful for separating environments or teams:
plaintext
Organization: Acme Corp
├── Application: production
│ ├── Webhooks → HTTPS only, strict validation
│ ├── Storage → encrypted, access controls
│ └── API Key → used in production servers
├── Application: staging
│ ├── Webhooks → test endpoints
│ ├── Storage → relaxed limits
│ └── API Key → used in CI/CD
└── Application: development
├── Webhooks → localhost allowed
├── Storage → public access
└── API Key → used locally Scope Inheritance
Users & Permissions
- User permissions are inherited from their organization role
- An Admin in the organization can manage all applications
- Application-level member assignments restrict access further
- Organization Owners have full access to everything
Webhooks
- Webhooks are always application-scoped
- Events from one application do not trigger webhooks in another
- Each webhook has its own secret for signature verification
Audit Trail
- All actions are logged at the organization level
- Audit entries include
application_idwhen applicable - Filter by application to see application-specific events
Configuration Patterns
Pattern 1: Environment Separation
Use applications to separate deployment environments:
typescript
// Create environment-specific applications
const prod = await client.applications.create({
name: 'Production',
slug: 'production',
});
const staging = await client.applications.create({
name: 'Staging',
slug: 'staging',
});
// Each gets its own webhooks, storage, and API keys
await client.webhooks.create({
url: 'https://prod.example.com/webhook',
applicationId: prod.id,
eventTypes: ['user.registered', 'billing.payment_succeeded'],
}); Pattern 2: Team Isolation
Use applications to isolate resources between teams:
typescript
// Marketing team application
const marketing = await client.applications.create({
name: 'Marketing Portal',
slug: 'marketing',
});
// Engineering team application
const engineering = await client.applications.create({
name: 'Engineering Tools',
slug: 'engineering',
});
// Add team members to their respective applications
await client.applications.addMember(marketing.id, { userId: marketerId });
await client.applications.addMember(engineering.id, { userId: engineerId }); Pattern 3: Multi-Product
Use applications for different products under one organization:
typescript
// One organization, multiple products
const mobileApp = await client.applications.create({
name: 'Mobile App',
slug: 'mobile',
});
const webApp = await client.applications.create({
name: 'Web Dashboard',
slug: 'web',
});
// Each product has its own webhook integrations
await client.webhooks.create({
url: 'https://mobile-api.example.com/events',
applicationId: mobileApp.id,
eventTypes: ['user.registered'],
}); Best Practices
1. Define Clear Scope Boundaries
Document what belongs at organization vs application level:
| Resource Type | Scope | Reason |
|---|---|---|
| Team members | Organization | Company-wide identity |
| Webhooks | Application | Environment-specific endpoints |
| File storage | Application | Isolated per environment/product |
| Billing | Organization | Single subscription covers all apps |
2. Use Descriptive Application Names
Name applications clearly so their purpose is obvious:
plaintext
Good: "Production API", "Staging", "Mobile App"
Bad: "App 1", "Test", "New" 3. Audit Across Scopes
Regularly review activity at both levels:
typescript
// Organization-wide audit
const orgAudit = await client.control.listAudit({
actions: ['user.role_changed', 'organization.settings_updated'],
});
// Application-specific audit
const appAudit = await client.control.listAudit({
applicationId: 'app-uuid',
actions: ['webhook.created', 'webhook.deleted'],
}); 4. Manage Access Per Application
Restrict who can access each application:
- Only add relevant team members to each application
- Production applications should have fewer members
- Development applications can be more permissive