Files
myeasycms-v2/packages/features/AGENTS.md
Giancarlo Buomprisco 533dfba5b9 Optimized agents rules subfolders, dependencies updates (#355)
* Update AGENTS.md and CLAUDE.md for improved clarity and structure
* Added MCP Server
* Added missing triggers to tables that should have used them
* Updated all dependencies
* Fixed rare bug in React present in the Admin layout which prevents navigating to pages (sometimes...)
2025-09-17 11:36:02 +08:00

6.4 KiB

Feature Packages Instructions

This file contains instructions for working with feature packages including accounts, teams, billing, auth, and notifications.

Feature Package Structure

  • accounts/ - Personal account management
  • admin/ - Super admin functionality
  • auth/ - Authentication features
  • notifications/ - Notification system
  • team-accounts/ - Team account management

Account Services

Personal Accounts API

Located at: packages/features/accounts/src/server/api.ts

import { createAccountsApi } from '@kit/accounts/api';
import { getSupabaseServerClient } from '@kit/supabase/server-client';

const client = getSupabaseServerClient();
const api = createAccountsApi(client);

// Get account data
const account = await api.getAccount(accountId);

// Get account workspace
const workspace = await api.getAccountWorkspace();

// Load user accounts
const accounts = await api.loadUserAccounts();

// Get subscription
const subscription = await api.getSubscription(accountId);

// Get customer ID
const customerId = await api.getCustomerId(accountId);

Team Accounts API

Located at: packages/features/team-accounts/src/server/api.ts

import { createTeamAccountsApi } from '@kit/team-accounts/api';

const api = createTeamAccountsApi(client);

// Get team account by slug
const account = await api.getTeamAccount(slug);

// Get account workspace
const workspace = await api.getAccountWorkspace(slug);

// Check permissions
const hasPermission = await api.hasPermission({
  accountId,
  userId,
  permission: 'billing.manage'
});

// Get members count
const count = await api.getMembersCount(accountId);

// Get invitation
const invitation = await api.getInvitation(adminClient, token);

Workspace Contexts

Personal Account Context

Use in apps/web/app/home/(user) routes:

import { useUserWorkspace } from 'kit/accounts/hooks/use-user-workspace';

function PersonalComponent() {
  const { user, account } = useUserWorkspace();
  
  // user: authenticated user data
  // account: personal account data
  
  return <div>Welcome {user.name}</div>;
}

Context provider: packages/features/accounts/src/components/user-workspace-context-provider.tsx

Team Account Context

Use in apps/web/app/home/[account] routes:

import { useTeamAccountWorkspace } from '@kit/team-accounts/hooks/use-team-account-workspace';

function TeamComponent() {
  const { account, user, accounts } = useTeamAccountWorkspace();
  
  // account: current team account data
  // user: authenticated user data  
  // accounts: all accounts user has access to
  
  return <div>Team: {account.name}</div>;
}

Context provider: packages/features/team-accounts/src/components/team-account-workspace-context-provider.tsx

Billing Services

Personal Billing

Located at: apps/web/app/home/(user)/billing/_lib/server/user-billing.service.ts

// Personal billing operations
// - Manage individual user subscriptions
// - Handle personal account payments
// - Process individual billing changes

Team Billing

Located at: apps/web/app/home/[account]/billing/_lib/server/team-billing.service.ts

// Team billing operations
// - Manage team subscriptions
// - Handle team payments
// - Process team billing changes

Per-Seat Billing Service

Located at: packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts

import { createAccountPerSeatBillingService } from '@kit/team-accounts/billing';

const billingService = createAccountPerSeatBillingService(client);

// Increase seats when adding team members
await billingService.increaseSeats(accountId);

// Decrease seats when removing team members  
await billingService.decreaseSeats(accountId);

// Get per-seat subscription item
const subscription = await billingService.getPerSeatSubscriptionItem(accountId);

Authentication Features

OTP for Sensitive Operations

Use one-time tokens from packages/otp/src/api/index.ts:

import { VerifyOtpForm } from '@kit/otp/components';

<VerifyOtpForm
  purpose="account-deletion"
  email={user.email}
  onSuccess={(otp) => {
    // Proceed with verified operation
    handleSensitiveOperation(otp);
  }}
  CancelButton={<Button variant="outline">Cancel</Button>}
/>

Admin Features

Super Admin Protection

For admin routes, use AdminGuard:

import { AdminGuard } from '@kit/admin/components/admin-guard';

function AdminPage() {
  return (
    <div>
      <h1>Admin Dashboard</h1>
      {/* Admin content */}
    </div>
  );
}

// Wrap the page component
export default AdminGuard(AdminPage);

Admin Service

Located at: packages/features/admin/src/lib/server/services/admin.service.ts

// Admin service operations
// - Manage all accounts
// - Handle admin-level operations
// - Access system-wide data

Checking Admin Status

import { isSuperAdmin } from '@kit/admin';

function criticalAdminFeature() {
  const isAdmin = await isSuperAdmin(client);

  if (!isAdmin) {
    throw new Error('Access denied: Admin privileges required');
  }

  // ...
}

Error Handling & Logging

Structured Logging

Use logger from packages/shared/src/logger/logger.ts:

import { getLogger } from '@kit/shared/logger';

async function featureOperation() {
  const logger = await getLogger();

  const ctx = { 
    name: 'feature-operation', 
    userId: user.id,
    accountId: account.id 
  };

  try {
    logger.info(ctx, 'Starting feature operation');
    
    // Perform operation
    const result = await performOperation();
    
    logger.info({ ...ctx, result }, 'Feature operation completed');
    return result;
  } catch (error) {
    logger.error({ ...ctx, error }, 'Feature operation failed');
    throw error;
  }
}

Permission Patterns

Team Permissions

import { createTeamAccountsApi } from '@kit/team-accounts/api';

const api = createTeamAccountsApi(client);

// Check if user has specific permission on account
const canManageBilling = await api.hasPermission({
  accountId,
  userId,
  permission: 'billing.manage'
});

if (!canManageBilling) {
  throw new Error('Insufficient permissions');
}

Account Ownership

// Check if user is account owner (works for both personal and team accounts)
const isOwner = await client.rpc('is_account_owner', { 
  account_id: accountId 
});

if (!isOwner) {
  throw new Error('Only account owners can perform this action');
}