feat: Phase 1 - Implementation of Data Security Infrastructure

Implemented comprehensive data security infrastructure for SFERA platform:

## Security Classes Created:
- `SupplyDataFilter`: Role-based data filtering for supply orders
- `ParticipantIsolation`: Data isolation between competing organizations
- `RecipeAccessControl`: Protection of production recipes and trade secrets
- `CommercialDataAudit`: Audit logging and suspicious activity detection
- `SecurityLogger`: Centralized security event logging system

## Infrastructure Components:
- Feature flags system for gradual security rollout
- Database migrations for audit logging (AuditLog, SecurityAlert models)
- Secure resolver wrapper for automatic GraphQL security
- TypeScript interfaces and type safety throughout

## Security Features:
- Role-based access control (SELLER, WHOLESALE, FULFILLMENT, LOGIST)
- Commercial data protection between competitors
- Production recipe confidentiality
- Audit trail for all data access
- Real-time security monitoring and alerts
- Rate limiting and suspicious activity detection

## Implementation Notes:
- All console logging replaced with centralized security logger
- Comprehensive TypeScript typing with no explicit 'any' types
- Modular architecture following SFERA coding standards
- Feature flag controlled rollout for safe deployment

This completes Phase 1 of the security implementation plan.
Next phases will integrate these classes into existing GraphQL resolvers.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-22 17:51:02 +03:00
parent e7e4889102
commit 6e3201f491
20 changed files with 5671 additions and 66 deletions

View File

@ -548,6 +548,242 @@ type Organization {
referralCode: String
referralPoints: Int!
# Marketplace данные
market: String # Физический рынок (для WHOLESALE)
# Временные метки
createdAt: DateTime!
updatedAt: DateTime!
}
```
## 🏪 СПЕЦИФИЧНЫЕ ПРАВИЛА ДЛЯ ПОСТАВЩИКОВ (WHOLESALE)
### ЗАПРОСЫ ПОСТАВЩИКОВ:
```graphql
# Получение товаров поставщика
query GetMyProducts {
myProducts {
id
name
article
price
quantity
organization {
id
name
market # Физический рынок поставщика
}
}
}
# Получение входящих заказов поставщика
query GetSupplierOrders($status: SupplyOrderStatus) {
supplyOrders(where: { partnerId: $myOrgId, status: $status }) {
id
status
totalAmount
deliveryDate
organization {
name
inn
} # Заказчик
fulfillmentCenter {
name
address
} # Получатель
items {
id
quantity
price
totalPrice
product {
id
name
article
}
}
}
}
# Получение партнеров поставщика
query GetMyCounterparties($type: OrganizationType) {
myCounterparties(type: $type) {
id
name
type
market
fullName
inn
isCounterparty
hasOutgoingRequest
hasIncomingRequest
}
}
```
### МУТАЦИИ ПОСТАВЩИКОВ:
```graphql
# Одобрение заказа поставщиком с опциональными полями упаковки
mutation SupplierApproveOrder(
$orderId: ID!
$packagesCount: Int
$volume: Float
$readyDate: DateTime
$notes: String
) {
supplierApproveOrder(
id: $orderId
packagesCount: $packagesCount # Опционально: для логистических расчетов
volume: $volume # Опционально: для планирования логистики
readyDate: $readyDate # Опционально: дата готовности к отгрузке
notes: $notes # Опционально: комментарии
) {
success
message
order {
id
status # PENDING → SUPPLIER_APPROVED
organization {
id
name
}
totalAmount
packagesCount # null если не указано
volume # null если не указано
readyDate # null если не указано
notes # null если не указано
}
}
}
# Отклонение заказа поставщиком
mutation SupplierRejectOrder($orderId: ID!, $reason: String) {
supplierRejectOrder(id: $orderId, reason: $reason) {
success
message
order {
id
status # PENDING → CANCELLED
}
}
}
# Отгрузка товара поставщиком
mutation SupplierShipOrder($orderId: ID!) {
supplierShipOrder(id: $orderId) {
success
message
order {
id
status # LOGISTICS_CONFIRMED → SHIPPED
organization {
id
name
}
logisticsPartner {
id
name
}
}
}
}
# Создание товара поставщиком
mutation CreateProduct($input: ProductInput!) {
createProduct(input: $input) {
success
message
product {
id
article
name
price
organization {
id
name
}
}
}
}
```
### ПРАВИЛА АВТОРИЗАЦИИ ПОСТАВЩИКОВ:
```typescript
// Resolver-level security для поставщиков
const wholesaleResolvers = {
// Проверка что пользователь - поставщик
validateWholesaleAccess: (context) => {
if (context.user.organization.type !== 'WHOLESALE') {
throw new GraphQLError('Access denied: Wholesale access required')
}
},
// Фильтрация заказов для поставщика
getSupplierOrders: async (parent, args, context) => {
// Поставщик видит только заказы где он является поставщиком
return await prisma.supplyOrder.findMany({
where: {
partnerId: context.user.organization.id, // Мы - поставщик
...args.where,
},
})
},
// Проверка доступа к товарам
validateProductAccess: async (productId, context) => {
const product = await prisma.product.findFirst({
where: {
id: productId,
organizationId: context.user.organizationId, // Только свои товары
},
})
if (!product) {
throw new GraphQLError('Product not found or access denied')
}
return product
},
}
```
### КРИТИЧЕСКИЕ ПРАВИЛА ПАРТНЕРСТВА:
```typescript
// ✅ ПРАВИЛЬНО: Поставщики берутся ТОЛЬКО из партнеров
const getWholesalePartners = `
query GetMyCounterparties {
myCounterparties(type: WHOLESALE) {
id, name, fullName, inn, market
isCounterparty # Должно быть true
}
}
`;
// ❌ НЕПРАВИЛЬНО: Прямой запрос всех поставщиков
const wrongSupplierQuery = `
query GetAllSuppliers {
organizations(type: WHOLESALE) { # Неправильно - нет проверки партнерства
id, name
}
}
`;
// Правильная фильтрация в резолвере:
const correctPartnershipFilter = `
// Показываем только организации-партнеры
const counterparties = await prisma.counterparty.findMany({
where: {
initiatorId: currentUser.organization.id,
status: 'ACCEPTED',
partner: { type: 'WHOLESALE' }
},
include: { partner: true }
})
`;
# Временные метки (обязательно)
createdAt: DateTime!
updatedAt: DateTime!