# First Steps

### <mark style="color:red;">Prerequisites</mark>

Before you begin, ensure you have the following installed:

* **Node.js 24.5.0 or higher** ([Download](https://nodejs.org/))
* **A package manager**: pnpm (recommended), npm (comes with Node.js), or yarn
* **A code editor**: VS Code/Cursor, Zed, WebStorm, or your preferred editor
* **Basic knowledge of**: React, TypeScript, and modern JavaScript

#### Verify Your Setup

```bash
# Check Node.js version
node --version
# Should output v24.5.0 or higher

# Check npm version
pnpm --version
```

### <mark style="color:red;">Quick Start: Create Your First Extension</mark>

The fastest way to get started is using `create-akinon-app`:

```bash
pnpm create akinon-app@latest my-first-extension
```

This command will:

1. Prompt you to choose an extension type
2. Scaffold the project structure
3. Install dependencies automatically
4. Set up development tooling

#### Interactive Setup

You'll see a series of prompts:

```
? What type of extension do you want to create? (Use arrow keys)
  ❯ plugin - Small widget embedded in specific areas
    fullpage - Full-page application with routing
    multi-plugin - Multiple plugin apps in one project
    multi-fullpage - Multiple fullpage apps in one project

? Which package manager would you like to use?
  ❯ pnpm (recommended)
    npm
    yarn

? Do you want to include the development shell? (Y/n)
  ❯ Yes - Includes local shell for testing
    No - Standalone development only
```

#### Understanding Extension Types

**Plugin**: Best for widgets, inline tools, or contextual features

* Embeds within specific page areas
* Receives parameters from the host
* Lightweight and focused
* Example: Order status widget, quick action toolbar

**Fullpage**: Best for dashboards, management interfaces, or complex workflows

* Takes over the entire content area
* Full routing capabilities
* Can define menu items
* Example: Campaign manager, analytics dashboard

**Multi-plugin/Multi-fullpage**: Advanced setup for multiple related extensions

* Share code between extensions
* Single deployment URL
* Consistent state management

### <mark style="color:red;">Development Workflow</mark>

#### 1. Start Your Extension

Navigate to your project and start the development server:

```bash
cd my-first-extension

# Install dependencies (if not already done)
pnpm install

# Start development server
pnpm dev
```

Your extension is now running at:

* **Plugin**: `http://localhost:4002`
* **Fullpage**: `http://localhost:4001`

#### 2. Test in Development Shell

Extensions are designed to run inside shell applications. To test yours locally:

```bash
# In a separate terminal, start the development shell
pnpm dev:shell
```

The development shell runs at `http://localhost:4000` and embeds your extension, simulating the production environment.

**Why use the development shell?**

* Tests communication with the host application
* Verifies data sharing and actions
* Simulates realistic integration
* Enables debugging shell-specific issues

#### 3. Make Your First Changes

Let's customize your extension to understand the structure.

**For Plugin Extensions**

Open `src/components/Content.tsx`:

```tsx
// Before
export const Content = () => {
  return (
    <div className="content">
      <h2>Welcome to Your Plugin</h2>
    </div>
  );
};

// After - Add some interactivity
import { useAppClient } from '@akinon/app-client';
import { Button } from '@akinon/ui-react';

export const Content = () => {
  const { data, showToast } = useAppClient();

  const handleClick = () => {
    showToast?.('Button clicked!', 'success');
  };

  return (
    <div className="content">
      <h2>Welcome to Your Plugin</h2>
      <p>Shell data: {JSON.stringify(data)}</p>
      <Button type="primary" onClick={handleClick}>
        Test Action
      </Button>
    </div>
  );
};
```

Save the file and watch your browser hot-reload with the changes.

**For Fullpage Extensions**

Open `src/pages/Home/index.tsx`:

```tsx
// Before
export const PageHome = () => {
  return (
    <div>
      <h1>Home Page</h1>
    </div>
  );
};

// After - Add navigation
import { useAppClient } from '@akinon/app-client';
import { Button, Space } from '@akinon/ui-react';

export const PageHome = () => {
  const { navigate } = useAppClient();

  return (
    <div>
      <Space>
      <h1>Home Page</h1>
        <Button onClick={() => navigate({ path: '/about' })}>
          Go to About
        </Button>
      </Space>
    </div>
  );
};
```

#### 4. Add a New Component

Let's create a reusable component using Akinon UI Kit:

```bash
# Create a new component file
mkdir -p src/components/UserCard
touch src/components/UserCard/index.tsx
```

Edit `src/components/UserCard/index.tsx`:

```tsx
import { Card, Avatar, Typography } from '@akinon/ui-react';

const { Text, Title } = Typography;

interface UserCardProps {
  name: string;
  email: string;
  avatar?: string;
}

export const UserCard = ({ name, email, avatar }: UserCardProps) => {
  return (
    <Card style={{ width: 300 }}>
      <Card.Meta
        avatar={<Avatar src={avatar}>{name[0]}</Avatar>}
        title={<Title level={4}>{name}</Title>}
        description={<Text type="secondary">{email}</Text>}
      />
    </Card>
  );
};
```

Export it from `src/components/index.tsx`:

```tsx
export { UserCard } from './UserCard';
```

Use it in your pages:

```tsx
import { UserCard } from '@/components';

export const PageHome = () => {
  return (
    <div>
      <h1>Team Members</h1>
      <UserCard
        name="John Doe"
        email="john@example.com"
      />
    </div>
  );
};
```

### <mark style="color:red;">Project Structure Explained</mark>

#### Plugin Project Structure

```
my-plugin-extension/
├── src/
│   ├── components/       # Reusable UI components
│   │   ├── Content.tsx   # Main plugin content
│   │   └── Loading.tsx   # Loading state component
│   ├── hooks/            # Custom React hooks
│   │   └── useConfig.tsx # Access plugin configuration
│   ├── App.tsx           # Plugin entry component
│   ├── AppWrapper.tsx    # Wraps app with providers
│   ├── config.ts         # Plugin configuration
│   ├── main.tsx          # Application entry point
│   ├── main.scss         # Global styles
│   └── providers.tsx     # Context providers
├── public/
│   └── locales/          # i18n translation files
│       ├── en/
│       └── tr/
├── __tests__/            # Unit and integration tests
├── shell.config.js       # Development shell configuration
├── vite.config.ts        # Vite build configuration
├── package.json          # Dependencies and scripts
└── tsconfig.json         # TypeScript configuration
```

#### Key Files

**`src/config.ts`** Defines your plugin configuration:

```typescript
import type { PluginApplicationConfig } from '@akinon/app-client';

export const config: PluginApplicationConfig = {
  isDev: true,                    // Development mode
  forceRedirect: true,            // Force iframe mode
  placeholderId: 'placeholder-1', // Where to render
};
```

**`src/providers.tsx`** Sets up React context providers:

```tsx
import { AppClientProvider } from '@akinon/app-client';
import { AkinonUIProvider } from '@akinon/ui-react';
import config from './config';

export const Providers = ({ children }) => (
  <AppClientProvider config={config}>
    <AkinonUIProvider>
      {children}
    </AkinonUIProvider>
  </AppClientProvider>
);
```

**`shell.config.js`** Configures the development shell:

```javascript
export default {
  plugin: {
    url: 'http://localhost:4002',  // Your plugin URL
    path: './src',                 // Source path
    name: 'My Plugin',             // Display name
    type: 'plugin',                // Extension type
  },
  shell: {
    port: 4000,                    // Shell server port
    theme: 'omnitron',             // Shell theme
    title: 'Plugin Development',   // Page title
  },
};
```

### <mark style="color:red;">Using Akinon UI Kit Components</mark>

Your extension has access to Akinon's comprehensive component library. Here are common patterns:

#### Layout Components

```tsx
import { Layout, Menu } from '@akinon/ui-react';

const { Header, Content, Sider } = Layout;

export const AppLayout = ({ children }) => (
  <Layout>
    <Header>My Extension</Header>
    <Layout>
      <Sider width={200}>
        <Menu
          mode="inline"
          items={[
            { key: '1', label: 'Dashboard' },
            { key: '2', label: 'Settings' },
          ]}
        />
      </Sider>
      <Content>{children}</Content>
    </Layout>
  </Layout>
);
```

#### Form Components

```tsx
import { Form, Input, Button } from '@akinon/ui-react';
import { useAppClient } from '@akinon/app-client';

export const UserForm = () => {
  const { showToast } = useAppClient();
  const [form] = Form.useForm();

  const onFinish = (values) => {
    console.log('Form values:', values);
    showToast?.('User saved!', 'success');
  };

  return (
    <Form form={form} onFinish={onFinish} layout="vertical">
      <Form.Item name="name" label="Name" rules={[{ required: true }]}>
        <Input placeholder="Enter name" />
      </Form.Item>
      <Form.Item name="email" label="Email" rules={[{ required: true, type: 'email' }]}>
        <Input placeholder="Enter email" />
      </Form.Item>
      <Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form.Item>
    </Form>
  );
};
```

#### Data Display Components

```tsx
import { Table, Tag, Space, Button } from '@akinon/ui-react';

export const OrdersTable = () => {
  const columns = [
    {
      title: 'Order ID',
      dataIndex: 'id',
      key: 'id',
    },
    {
      title: 'Status',
      dataIndex: 'status',
      key: 'status',
      render: (status) => (
        <Tag color={status === 'completed' ? 'green' : 'orange'}>
          {status}
        </Tag>
      ),
    },
    {
      title: 'Actions',
      key: 'actions',
      render: (_, record) => (
        <Space>
          <Button size="small">View</Button>
          <Button size="small" danger>Delete</Button>
        </Space>
      ),
    },
  ];

  const data = [
    { id: '1001', status: 'completed' },
    { id: '1002', status: 'pending' },
  ];

  return <Table columns={columns} dataSource={data} />;
};
```

### <mark style="color:red;">Communicating with the Shell</mark>

#### Accessing Shared Data

The shell provides data to your extension:

```tsx
import { useAppClient } from '@akinon/app-client';

export const MyComponent = () => {
  const { data, isLoading } = useAppClient();

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>
      <p>Omnitron Token: {data?.omnitronToken}</p>
    </div>
  );
};
```

#### Invoking Shell Actions

Request the shell to perform actions:

```tsx
import { useAppClient } from '@akinon/app-client';
import { Button } from '@akinon/ui-react';

export const ActionButtons = () => {
  const {
    showModalDialog,
    showConfirmationDialog,
    showToast,
    invokeAction
  } = useAppClient();

  const handleSave = () => {
    showConfirmationDialog?.({
      title: 'Confirm Save',
      content: 'Are you sure you want to save?',
      onConfirm: (data) => {
        showToast?.('Saved successfully!', 'success');
      },
      onCancel: () => {
        showToast?.('Save canceled', 'info');
      },
    });
  };

  const handleCustomAction = async () => {
    try {
      await invokeAction('refreshData');
      showToast?.('Data refreshed!', 'success');
    } catch (error) {
      showToast?.('Failed to refresh', 'error');
    }
  };

  return (
    <div>
      <Button onClick={handleSave}>Save</Button>
      <Button onClick={handleCustomAction}>Refresh</Button>
    </div>
  );
};
```

#### Navigation

Navigate within the shell application:

```tsx
import { useAppClient } from '@akinon/app-client';
import { Button } from '@akinon/ui-react';

export const NavigationExample = () => {
  const { navigate } = useAppClient();

  return (
    <Button
      onClick={() => navigate({ path: '/orders/123' })}
    >
      View Order
    </Button>
  );
};
```

### <mark style="color:red;">Internationalization (i18n)</mark>

Your extension supports multiple languages out of the box.

#### Adding Translations

Edit `public/locales/en/translation.json`:

```json
{
  "welcome": "Welcome to My Extension",
  "actions": {
    "save": "Save",
    "cancel": "Cancel",
    "delete": "Delete"
  },
  "messages": {
    "success": "Operation completed successfully",
    "error": "An error occurred"
  }
}
```

Edit `public/locales/tr/translation.json`:

```json
{
  "welcome": "Eklentime Hoş Geldiniz",
  "actions": {
    "save": "Kaydet",
    "cancel": "İptal",
    "delete": "Sil"
  },
  "messages": {
    "success": "İşlem başarıyla tamamlandı",
    "error": "Bir hata oluştu"
  }
}
```

#### Using Translations

```tsx
import { useTranslation } from '@akinon/akilocale/react';
import { Button } from '@akinon/ui-react';

export const TranslatedComponent = () => {
  const { t } = useTranslation();

  return (
    <div>
      <h1>{t('welcome')}</h1>
      <Button>{t('actions.save')}</Button>
      <Button>{t('actions.cancel')}</Button>
    </div>
  );
};
```

The shell automatically synchronizes locale changes with your extension.

### <mark style="color:red;">Testing Your Extension</mark>

#### Running Tests

```bash
# Run tests in watch mode
pnpm test

# Run tests once
pnpm test:run

# Generate coverage report
pnpm test:coverage

# Run tests with UI
pnpm test:ui
```

#### Writing Tests

Example component test:

```tsx
// __tests__/components/UserCard.test.tsx
import { render, screen } from '@testing-library/react';
import { UserCard } from '@/components/UserCard';

describe('UserCard', () => {
  it('renders user information', () => {
    render(
      <UserCard
        name="John Doe"
        email="john@example.com"
      />
    );

    expect(screen.getByText('John Doe')).toBeInTheDocument();
    expect(screen.getByText('john@example.com')).toBeInTheDocument();
  });
});
```

### <mark style="color:red;">Building for Production</mark>

When you're ready to deploy:

```bash
# Build production bundle
pnpm build
```

This creates an optimized build in the `dist/` directory:

```
dist/
├── assets/
│   ├── index-[hash].js    # JavaScript bundle
│   └── index-[hash].css   # CSS bundle
└── index.html             # Entry HTML file
```

#### Deployment

1. **Configure:** Configure your application for [ACC integration](/akinon-ui/ui-protocol/acc-integration.md)
2. **Host your build**: Build and deploy your application with [ACC](/tutorials/acc/how-to-move-apps-into-acc.md)
3. **Related Product**: (Optional) Communicate with Akinon team if your extension is not for Omnitron

### <mark style="color:red;">Next Steps</mark>

Congratulations! You've created your first Akinon UI extension. Here's what to explore next:

#### Dive Deeper

* [**UI Kit Components**](/akinon-ui/ui-kit/usage.md): Explore the complete component library
* [**UI Protocol Guide**](/akinon-ui/ui-protocol/usage.md): Learn about shell integration and client APIs
* [**Advanced Patterns**](/akinon-ui/ui-protocol/examples.md): Study examples for complex use cases
* [**Hooks & Utilities**](/akinon-ui/ui-kit/hooks.md): Discover custom hooks and utility functions

#### Common Tasks

* Create a multi-page fullpage application
* Implement data fetching patterns
* Work with forms
* Build tables with filtering

#### Get Help

* Check the [FAQ](/akinon-ui/resources/faqs.md) for common questions
* Review [API Reference](/akinon-ui/ui-protocol/client-application/api-reference.md) for detailed documentation
* Explore the [Glossary](/akinon-ui/resources/glossary.md) for terminology

### <mark style="color:red;">Troubleshooting</mark>

#### Extension not loading in shell

1. Ensure your dev server is running (`pnpm dev`)
2. Check `shell.config.js` has the correct URL
3. Verify ports are not in use by other applications
4. Check browser console for errors

#### Components not styling correctly

1. Import Akinon fonts: `import '@akinon/fonts-jost-variable'`
2. Import UI utilities: `import '@akinon/ui-utils'`
3. Ensure `AkinonUIProvider` wraps your app in `providers.tsx`&#x20;
4. Ensure all components has the same Ant Design version (see [Changelogs](/akinon-ui/resources/changelogs.md))

#### Cannot communicate with shell

1. Verify `AppClientProvider` is configured with correct settings
2. Check `config.ts` has `forceRedirect: true` in development
3. Ensure you're using the development shell (`pnpm dev:shell`)

### <mark style="color:red;">Summary</mark>

You've learned how to:

* ✅ Create a new extension with `create-akinon-app`
* ✅ Understand project structure and key files
* ✅ Use Akinon UI Kit components
* ✅ Communicate with the shell application
* ✅ Add internationalization
* ✅ Write and run tests
* ✅ Build for production

You're now ready to build production-quality extensions for Akinon's platform!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akinon.com/akinon-ui/getting-started/first-steps.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
