INTEGRITY Документация

Создание справочника сотрудников

В этом руководстве вы узнаете, как с помощью D1 создать справочник сотрудников. Это приложение позволит пользователям просматривать данные о сотрудниках организации, а администраторам добавлять новых сотрудников прямо в приложении. Для этого вам сначала нужно будет настроить База данных D1 для удобного управления данными, а затем разработаете и развернёте приложение с помощью Фреймворк HonoX и Cloudflare Pages.

Предварительные требования

Прежде чем приступить к этому руководству, убедитесь, что у вас есть следующее:

Если вы не хотите проходить настройку сейчас, просмотреть готовый код на GitHub.

1. Установите HonoX

В этом руководстве вы будете использовать HonoX, метафреймворк для создания full-stack сайтов и веб-API при сборке вашего приложения. Чтобы использовать HonoX в своём проекте, выполните hono-create команда.

Чтобы начать, выполните следующую команду:

npm create hono@latest

В процессе настройки вам нужно будет указать имя каталога проекта и выбрать шаблон. При выборе укажите x-basic шаблон.

2. Инициализируйте приложение HonoX

После настройки проекта вы увидите список сгенерированных файлов, как показано ниже. Это типичная структура проекта для приложения HonoX:

.
├── app
│   ├── global.d.ts // global type definitions
│   ├── routes
│   │   ├── _404.tsx // not found page
│   │   ├── _error.tsx // error page
│   │   ├── _renderer.tsx // renderer definition
│   │   ├── about
│   │   │   └── [name].tsx // matches `/about/:name`
│   │   └── index.tsx // matches `/`
│   └── server.ts // server entry file
├── package.json
├── tsconfig.json
└── vite.config.ts

Проект содержит каталоги с кодом приложения, маршрутами и настройками сервера, а также конфигурационные файлы для управления пакетами, TypeScript и Vite.

3. Создайте базу данных

Чтобы создать базу данных для своего проекта, используйте инструмент командной строки Cloudflare Wrangler, которое поддерживает wrangler d1 команду для операций с базой данных D1. Создайте новую базу данных с именем staff-directory с помощью следующей команды:

npx wrangler d1 create staff-directory

После создания базы данных вам нужно будет настроить привязка в конфигурационный файл Wrangler чтобы интегрировать базу данных с приложением.

Эта привязка позволяет приложению взаимодействовать с ресурсами Cloudflare, такими как базы данных D1, пространства имён KV и бакеты R2. Чтобы настроить её, создайте файл Wrangler в корневом каталоге проекта и укажите основные параметры:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "staff-directory",
	// Set this to today's date
	"compatibility_date": "2026-08-28"
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "staff-directory"
# Set this to today's date
compatibility_date = "2026-08-28"

Далее добавьте данные привязки базы данных в файл Wrangler. Для этого нужно указать имя привязки (в данном случае, DB), которая будет использоваться для обращения к базе данных в вашем приложении, вместе с database_name и database_id указанный при создании базы данных:

{
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "staff-directory",
			"database_id": "f495af5f-dd71-4554-9974-97bdda7137b3"
		}
	]
}
[[d1_databases]]
binding = "DB"
database_name = "staff-directory"
database_id = "f495af5f-dd71-4554-9974-97bdda7137b3"

Теперь ваше приложение настроено для доступа и взаимодействия с базой данных D1, будь то через командную строку или напрямую в коде.

Также потребуется внести изменения в конфигурационный файл Vite в vite.config.js. Добавьте следующие параметры конфигурации, чтобы Vite был правильно настроен для работы с привязками Cloudflare в локальной среде:

import adapter from "@hono/vite-dev-server/cloudflare";

export default defineConfig(({ mode }) => {
	if (mode === "client") {
		return {
			plugins: [client()],
		};
	} else {
		return {
			plugins: [
				honox({
					devServer: {
						adapter,
					},
				}),
				pages(),
			],
		};
	}
});

4. Взаимодействуйте с D1

Чтобы взаимодействовать с базой данных D1, вы можете напрямую выполнять SQL-команды с помощью wrangler d1 execute команда:

wrangler d1 execute staff-directory --command "SELECT name FROM sqlite_schema WHERE type ='table'"

Приведённая выше команда позволяет выполнять запросы или операции прямо из командной строки.

Для таких операций, как первоначальное заполнение данными или пакетная обработка, можно передать SQL-файл с командами. Для этого создайте schema.sql файл в корневом каталоге вашего проекта и вставьте свои SQL-запросы в этот файл:

CREATE TABLE locations (
    location_id INTEGER PRIMARY KEY AUTOINCREMENT,
    location_name VARCHAR(255) NOT NULL
);

CREATE TABLE departments (
    department_id INTEGER PRIMARY KEY AUTOINCREMENT,
    department_name VARCHAR(255) NOT NULL
);

CREATE TABLE employees (
    employee_id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(255) NOT NULL,
    position VARCHAR(255) NOT NULL,
    image_url VARCHAR(255) NOT NULL,
    join_date DATE NOT NULL,
    location_id INTEGER REFERENCES locations(location_id),
    department_id INTEGER REFERENCES departments(department_id)
);

INSERT INTO locations (location_name) VALUES ('London, UK'), ('Paris, France'), ('Berlin, Germany'), ('Lagos, Nigeria'), ('Nairobi, Kenya'), ('Cairo, Egypt'), ('New York, NY'), ('San Francisco, CA'), ('Chicago, IL');

INSERT INTO departments (department_name) VALUES ('Software Engineering'), ('Product Management'), ('Information Technology (IT)'), ('Quality Assurance (QA)'), ('User Experience (UX)/User Interface (UI) Design'), ('Sales and Marketing'), ('Human Resources (HR)'), ('Customer Support'), ('Research and Development (R&D)'), ('Finance and Accounting');

Приведённые выше запросы создадут три таблицы: Locations, Departments, а также Employees. Чтобы заполнить эти таблицы начальными данными, используйте INSERT INTO команду. После подготовки файла схемы с помощью этих команд его можно применить к базе данных D1. Для этого используйте --file флаг, чтобы указать файл схемы для выполнения:

wrangler d1 execute staff-directory --file=./schema.sql

Чтобы выполнить схему локально и заполнить локальный каталог тестовыми данными, передайте --local флаг к приведённой выше команде.

5. Создайте SQL-операторы

После того как вы настроите базу данных D1 и сконфигурируете файл Wrangler, как описано в предыдущих шагах, ваша база данных станет доступна в коде через DB привязку. Это позволяет напрямую работать с базой данных, подготавливая и выполняя инструкции SQL. На следующем шаге вы узнаете, как с помощью этой привязки выполнять типичные операции с базой данных, такие как получение данных и вставка новых записей.

Получение данных из базы данных

export const findAllEmployees = async (db: D1Database) => {
	const query = `
      SELECT employees.*, locations.location_name, departments.department_name
      FROM employees
      JOIN locations ON employees.location_id = locations.location_id
      JOIN departments ON employees.department_id = departments.department_id
      `;
	const { results } = await db.prepare(query).run();
	const employees = results;
	return employees;
};

Вставка данных в базу данных

export const createEmployee = async (db: D1Database, employee: Employee) => {
	const query = `
      INSERT INTO employees (name, position, join_date, image_url, department_id, location_id)
      VALUES (?, ?, ?, ?, ?, ?)`;

	const results = await db
		.prepare(query)
		.bind(
			employee.name,
			employee.position,
			employee.join_date,
			employee.image_url,
			employee.department_id,
			employee.location_id,
		)
		.run();
	const employees = results;
	return employees;
};

Полный список всех запросов, используемых в приложении, см. в db.ts файл в кодовой базе.

6. Разработайте интерфейс

Приложение использует hono/jsx для рендеринга. Настроить Renderer можно в app/routes/_renderer.tsx с использованием миддлвара, отрисовывающего JSX и служащего точкой входа для вашего приложения:

import { jsxRenderer } from 'hono/jsx-renderer'
import { Script } from 'honox/server'

export default jsxRenderer(({ children, title }) => {
  return (
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>{title}</title>
        <Script src="/app/client.ts" async />
      </head>
      <body>{children}</body>
    </html>
  )
})

Добавьте привязки, определённые ранее в global.d.ts файл, где определены глобальные типы для TypeScript, что обеспечивает согласованность типов во всём приложении:

declare module "hono" {
	interface Env {
		Variables: {};
		Bindings: {
			DB: D1Database;
		};
	}
}

Это приложение использует Tailwind CSS для стилизации. Чтобы использовать Tailwind CSS, см. Документация TailwindCSS, либо выполните шаги доступен на GitHub.

Чтобы вывести список сотрудников, вызовите findAllEmployees функцию из своего db.ts файл и вызовите его внутри routes/index.tsx файл. createRoute() функция, присутствующая в файле, служит вспомогательной функцией для определения маршрутов, обрабатывающих разные HTTP методы, такие как GET, POST, PUT, или DELETE.

import { css } from 'hono/css'
import { createRoute } from 'honox/factory'
import Counter from '../islands/counter'

const className = css`
  font-family: sans-serif;
`

export default createRoute((c) => {
  const name = c.req.query('name') ?? 'Hono'
  return c.render(
    <div class={className}>
      <h1>Hello, {name}!</h1>
      <Counter />
    </div>,
    { title: name }
  )
})

Существующий код в файле содержит заглушку, использующую компонент Counter. Замените этот раздел следующим блоком кода:

import { createRoute } from 'honox/factory'
import type { FC } from 'hono/jsx'
import type { Employee } from '../db'
import { findAllEmployees, findAllDepartments, findAllLocations } from '../db'

const EmployeeCard: FC<{ employee: Employee }> = ({ employee }) => {
  const { employee_id, name, image_url, department_name, location_name } = employee;
  return (
    <div className="max-w-sm bg-white border border-gray-200 rounded-lg shadow-md">
      <a href={`/employee/${employee_id}`}>
        <img className="bg-indigo-600 p-4 rounded-t-lg" src={image_url} alt={name} />
        //...
      </a>
    </div>
  );
};

export const GET = createRoute(async (c) => {
  const employees = await findAllEmployees(c.env.DB)
  const locations = await findAllLocations(c.env.DB)
  const departments = await findAllDepartments(c.env.DB)
  return c.render(
    <section className="flex-grow">
      <h1 className="mb-4 text-3xl font-extrabold text-gray-900 dark:text-white md:text-5xl lg:text-6xl mt-12">
        <span className="text-transparent bg-clip-text bg-gradient-to-r to-blue-600 from-sky-400">{`Directory `}</span>
      </h1>
      //...
      </section>
      <section className="flex flex-wrap -mx-4">
        {employees.map((employee) => (
          <div className="w-full sm:w-1/2 md:w-1/3 lg:w-1/4 px-2 mb-4">
            <EmployeeCard employee={employee} />
          </div>
        ))}
      </section>
    </section>
  )
})

Этот фрагмент кода показывает, как импортировать findAllEmployees, findAllLocations, а также findAllDepartments функции из db.ts файл и как использовать привязку c.env.DB чтобы вызвать эти функции. С их помощью вы можете получать и отображать полученные данные на странице.

Добавление сотрудника

Используйте export POST маршрут для создания нового сотрудника через /admin страница:

import { createRoute } from "honox/factory";
import type { Employee } from "../../db";
import { getFormDataValue, getFormDataNumber } from "../../utils/formData";
import { createEmployee } from "../../db";

export const POST = createRoute(async (c) => {
	try {
		const formData = await c.req.formData();
		const imageFile = formData.get("image_file");
		let imageUrl = "";

		// TODO: process image url with R2

		const employeeData: Employee = {
			employee_id: getFormDataValue(formData, "employee_id"),
			name: getFormDataValue(formData, "name"),
			position: getFormDataValue(formData, "position"),
			image_url: imageUrl,
			join_date: getFormDataValue(formData, "join_date"),
			department_id: getFormDataNumber(formData, "department_id"),
			location_id: getFormDataNumber(formData, "location_id"),
			location_name: "",
			department_name: "",
		};

		await createEmployee(c.env.DB, employeeData);
		return c.redirect("/", 303);
	} catch (error) {
		return new Response("Error processing your request", { status: 500 });
	}
});

Хранение изображений в R2

При создании нового сотрудника загруженное изображение можно сохранить в бакете R2 ещё до добавления в базу данных.

Чтобы сохранить изображение в бакете R2:

  1. Создайте bucket R2.
  2. Загрузите изображение в этот бакет.
  3. Получите публичный URL изображения из бакета. Этот URL затем сохраняется в базе данных и указывает на изображение, хранящееся в бакете R2.

Используйте wrangler r2 bucket create команду для создания бакета:

wrangler r2 bucket create employee-avatars

После создания бакета добавьте привязку бакета R2 в файл Wrangler:

{
	"r2_buckets": [
		{
			"binding": "MY_BUCKET",
			"bucket_name": "employee-avatars"
		}
	]
}
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "employee-avatars"

Передайте привязку R2 в global.d.ts файле:

declare module "hono" {
	interface Env {
		Variables: {};
		Bindings: {
			DB: D1Database;
			MY_BUCKET: R2Bucket;
		};
	}
}

Чтобы сохранить загруженное изображение в бакете R2, используйте put() метод, предоставляемый R2. Он позволяет загрузить файл изображения в ваш бакет:

if (imageFile instanceof File) {
	const key = `${new Date().getTime()}-${imageFile.name}`;
	const fileBuffer = await imageFile.arrayBuffer();

	await c.env.MY_BUCKET.put(key, fileBuffer, {
		httpMetadata: {
			contentType: imageFile.type || "application/octet-stream",
		},
	});
	console.log(`File uploaded successfully: ${key}`);
	imageUrl = `https://pub-8d936184779047cc96686a631f318fce.r2.dev/${key}`;
}

См. GitHub с полным кодом проекта.

7. Разверните своё приложение HonoX

Когда приложение готово к развертыванию, используйте Wrangler для сборки и развертывания проекта в Cloudflare Network. Убедитесь, что вы вошли в аккаунт Cloudflare, выполнив wrangler whoami команду. Если вы не выполнили вход, Wrangler предложит войти, создав API-ключ, с помощью которого можно автоматически отправлять аутентифицированные запросы с вашего компьютера.

После успешного входа убедитесь, что ваш файл Wrangler настроен так же, как показано в блоке кода ниже:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "staff-directory",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"r2_buckets": [
		{
			"binding": "MY_BUCKET",
			"bucket_name": "employee-avatars"
		}
	],
	"d1_databases": [
		{
			"binding": "DB",
			"database_name": "staff-directory",
			"database_id": "f495af5f-dd71-4554-9974-97bdda7137b3"
		}
	]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "staff-directory"
# Set this to today's date
compatibility_date = "2026-08-28"

[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "employee-avatars"

[[d1_databases]]
binding = "DB"
database_name = "staff-directory"
database_id = "f495af5f-dd71-4554-9974-97bdda7137b3"

Запустите wrangler deploy чтобы развернуть проект в Cloudflare. После развёртывания вы можете проверить работу приложения, перейдя по предоставленному URL-адресу развёртывания. В браузере должно отобразиться ваше приложение с базовым интерфейсом, который вы создали. Если в вашей базе данных нет данных, перейдите в /admin страницу, чтобы добавить нового сотрудника, и это должно вернуть нового сотрудника на вашей домашней странице.

Заключение

В этом руководстве вы создали приложение справочника сотрудников, в котором пользователи могут просматривать всех сотрудников организации. Обратитесь к Репозиторий Staff Directory с полным исходным кодом.

демонстрация Staff Directory