architect/_archive/2025-11-13-before-restructure/platform-projects/projects/cifra/archive/2025-11-10-restructure-v2/PLUGIN_API.md

CIFRA Plugin API

Версия: 1.0.0
Дата: 2025-11-10


Структура плагина

my-plugin/
├── plugin.yaml          # Манифест
├── __init__.py          # Entry point
├── hooks.py             # Event hooks
├── fields.py            # Кастомные поля (опционально)
└── ui/                  # UI компоненты (опционально)
    └── widgets.py

plugin.yaml

plugin:
  id: social-media
  name: "Social Media Fields"
  version: "1.0.0"
  author: "John Doe"
  description: "Adds social media fields to Contact entity"

  requires:
    cifra: ">=1.0.0"
    plugins:
      - contacts: "^1.0.0"

  permissions:
    - entity:Contact:extend
    - api:read

  entities:
    Contact:
      fields:
        facebook: {type: string}
        twitter: {type: string}
        linkedin: {type: string}

  hooks:
    - event: "entity.Contact.before_save"
      handler: "hooks.validate_social_urls"

Hooks (Lifecycle Events)

from cifra.plugins import hook

@hook('entity.*.before_save')
async def validate_data(entity, data):
    """Before save любой Entity"""
    ...

@hook('entity.Contact.after_create')
async def on_contact_created(contact):
    """After Contact создан"""
    await send_welcome_email(contact.email)

@hook('entity.Deal.stage_changed')
async def on_deal_stage_changed(deal, old_stage, new_stage):
    """When Deal stage изменён"""
    if new_stage == 'won':
        await create_invoice(deal)

# Все доступные hooks:
# - entity.*.before_save
# - entity.*.after_save
# - entity.*.before_delete
# - entity.*.after_delete
# - entity.*.before_update
# - entity.*.after_update
# - api.*.before_request
# - api.*.after_response
# - auth.user.login
# - auth.user.logout

Extending Entity

from cifra.plugins import extend_entity
from cifra.fields import StringField

@extend_entity('Contact')
def add_social_fields(entity_class):
    """Add social media fields to Contact"""
    entity_class.add_field('facebook', StringField(
        label="Facebook",
        validators=[URLValidator()]
    ))
    entity_class.add_field('twitter', StringField(
        label="Twitter"
    ))

Custom API Endpoints

from cifra.plugins import register_endpoint
from fastapi import APIRouter

router = APIRouter()

@router.get('/api/contacts/{id}/social')
async def get_social_profiles(contact_id: UUID):
    """Get social media profiles for contact"""
    contact = await Contact.get(contact_id)
    return {
        'facebook': contact.facebook,
        'twitter': contact.twitter,
        'linkedin': contact.linkedin
    }

# Register in plugin
def register(app):
    app.include_router(router)

UI Widgets

from cifra.plugins import register_widget
from cifra.ui import Widget

@register_widget('SocialMediaCard')
class SocialMediaWidget(Widget):
    """Display social media links"""

    def render(self, contact):
        return f"""
        <div class="social-links">
            <a href="https://facebook.com/{contact.facebook}">Facebook</a>
            <a href="https://twitter.com/{contact.twitter}">Twitter</a>
        </div>
        """

Plugin Registry

from cifra.plugins import Plugin

class SocialMediaPlugin(Plugin):
    def __init__(self):
        super().__init__('social-media', version='1.0.0')

    def install(self):
        """Called when plugin installed"""
        print("Installing social-media plugin...")

    def enable(self):
        """Called when plugin enabled"""
        pass

    def disable(self):
        """Called when plugin disabled"""
        pass

    def uninstall(self):
        """Called when plugin uninstalled"""
        pass

Полная документация: https://docs.cifra.io/plugins