Ver3.5 ๐ Shopify API์ ์ปค์คํฐ๋ง์ด์ง์ผ๋ก ๋ง๋๋ ๋๋ง์ ๋ง์ถคํ ์ผํ๋ชฐ ๊ฐ๋ฐ ๊ฐ์ด๋

๐ Shopify API์ ์ปค์คํฐ๋ง์ด์ง์ผ๋ก ๋ง๋๋ ๋๋ง์ ๋ง์ถคํ ์ผํ๋ชฐ ๊ฐ๋ฐ ๊ฐ์ด๋
Liquid ํ ํ๋ฆฟ๋ถํฐ REST/GraphQL API, ์ฑ ๊ฐ๋ฐ๊น์ง โ ์ค์ ์ค์ฌ์ผ๋ก ํํค์ณ๋ด โจ
Shopify๋ ์ ์ธ๊ณ 175๊ฐ๊ตญ ์ด์์์ ์ฌ์ฉ๋๊ณ ์๋ ๊ธ๋ก๋ฒ ์ด์ปค๋จธ์ค ํ๋ซํผ์ด์ผ. ๋จ์ํ "ํ
๋ง ๊ณจ๋ผ์ ์ํ ์ฌ๋ฆฌ๋ฉด ๋"์ด๋ผ๊ณ ์๊ฐํ๋ฉด ์์ ์ค์ฐ์ ใ
ใ
ใ
์ค์ ๋ก Shopify๊ฐ ๊ฐ๋ ฅํ ์ด์ ๋ API ์ํ๊ณ์ ์ปค์คํฐ๋ง์ด์ง ์์ ๋ ๋๋ฌธ์ด๊ฑฐ๋ . ๊ธฐ์
ํ ์ผํ๋ชฐ๋ถํฐ ๊ฐ์ธ ๋ธ๋๋ ์คํ ์ด๊น์ง, ์ํ๋ ๊ธฐ๋ฅ์ API๋ก ์ฐ๊ฒฐํ๊ณ Liquid ํ
ํ๋ฆฟ์ผ๋ก UI๋ฅผ ์กฐ๊ฐํ๋ฉด ์ง์ง ์ธ์์ ํ๋๋ฟ์ธ ์ผํ๋ชฐ์ด ํ์ํจ.
์ด ๊ธ์์๋ Shopify ๊ฐ๋ฐ์ ํต์ฌ์ธ API ๊ตฌ์กฐ, Liquid ์ปค์คํฐ๋ง์ด์ง, ์ฑ ๊ฐ๋ฐ, ์นํ
ํ์ฉ๊น์ง ์ค์ ์์ฃผ๋ก ์น ๋ค ์ ๋ฆฌํด๋ณผ๊ฒ ๐ช
๐ Shopify API, ๋ญ๊ฐ ์๋์ง ์ ๋๋ก ์์๋ณด์
Shopify API๋ ํฌ๊ฒ 3๊ฐ์ง ํต์ฌ API๋ก ๋๋์ด. ๊ฐ๊ฐ ์ฐ์์๊ฐ ๋ค๋ฅด๋๊น ์ํฉ์ ๋ง๊ฒ ๊ณจ๋ผ ์จ์ผ ํจ ใ ใ
์ํยท์ฃผ๋ฌธยท๊ณ ๊ฐ CRUD
๋ณต์กํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
ํค๋๋ฆฌ์ค ์ปค๋จธ์ค
โ Admin REST API โ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋ ๋ ์
Admin REST API๋ Shopify ์คํ ์ด์ ๋ฐฑ์๋ ๋ฐ์ดํฐ๋ฅผ CRUDํ ์ ์๋ API์ผ. ์ํ ๋ฑ๋ก, ์ฃผ๋ฌธ ์กฐํ, ๊ณ ๊ฐ ์ ๋ณด ์์ ๋ฑ ๊ฑฐ์ ๋ชจ๋ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ API๋ก ์ฒ๋ฆฌํ ์ ์์.
์๋ํฌ์ธํธ ํ์์ ์ด๋ ๊ฒ ์๊ฒผ์ด:
https://{store-name}.myshopify.com/admin/api/{version}/{resource}.json
์๋ฅผ ๋ค์ด ์ํ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ:
GET https://my-store.myshopify.com/admin/api/2024-01/products.json
์ธ์ฆ์ Access Token ๋ฐฉ์์ ์ฌ์ฉํจ. ํค๋์ X-Shopify-Access-Token์ ๋ฃ์ด์ฃผ๋ฉด ๋จ.
API ๋ฒ์ ๊ด๋ฆฌ๋ ์ค์ํ๋ฐ, Shopify๋ ๋ถ๊ธฐ๋ง๋ค ์ ๋ฒ์ ์ ๋ฆด๋ฆฌ์ฆํ๊ณ ์ต์ 12๊ฐ์์ ์ง์ํด์ค. 2024-01, 2024-04 ์ด๋ฐ ์์ผ๋ก ๋ฒ์ ์ด ๋ถ์ด์์ด.
โก Admin GraphQL API โ ์์ฆ ๋์ธ๋ ์ด๊ฑฐ์
Shopify๋ REST API๋ณด๋ค GraphQL API๋ฅผ ์ ์ ๋ ๋ฐ๊ณ ์์ ใ
ใ
์ค์ ๋ก ์๋ก์ด ๊ธฐ๋ฅ๋ค์ GraphQL์์๋ง ์ง์๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์.
GraphQL์ ์ฅ์ ์ ํ์ํ ๋ฐ์ดํฐ๋ง ์ ํํ๊ฒ ์์ฒญํ ์ ์๋ค๋ ๊ฑฐ์ผ. REST๋ ์๋ํฌ์ธํธ ํ๋ ์น๋ฉด ์ธ๋ฐ์๋ ๋ฐ์ดํฐ๊น์ง ์์ฐฝ ์ค๋๋ฐ, GraphQL์ ๋ด๊ฐ ์ํ๋ ํ๋๋ง ๋ฑ ์ง์ ํด์ ๋ฐ์ ์ ์์.
POST https://my-store.myshopify.com/admin/api/2024-01/graphql.json
query {
products(first: 10) {
edges {
node {
id
title
priceRangeV2 {
minVariantPrice {
amount
currencyCode
}
}
}
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ์ํ 10๊ฐ์ ID, ์ ๋ชฉ, ์ต์ ๊ฐ๋ง ๋ฑ ๋ฐ์์ฌ ์ ์์. REST๋ก ํ๋ฉด ๋ถํ์ํ ํ๋๊ฐ ์์ญ ๊ฐ ๋ธ๋ ค์ค๋๋ฐ ใ
ใ
โข Storefront API โ ํค๋๋ฆฌ์ค ์ปค๋จธ์ค์ ํต์ฌ
Storefront API๋ ๊ณ ๊ฐ facing ํ๋ก ํธ์๋๋ฅผ ์ํ API์ผ. ์ฆ, ์ผํ๋ชฐ ๋ฐฉ๋ฌธ์๋ค์ด ์ํ ๋ณด๊ณ , ์ฅ๋ฐ๊ตฌ๋ ๋ด๊ณ , ๊ฒฐ์ ํ๋ ๋ชจ๋ ๊ณผ์ ์ ์ปค์คํ
ํ๋ก ํธ์๋๋ก ๊ตฌํํ ๋ ์.
ํค๋๋ฆฌ์ค ์ปค๋จธ์ค(Headless Commerce)๊ฐ ๋ญ๋๋ฉด, Shopify์ ๋ฐฑ์๋(์ํ๊ด๋ฆฌ, ๊ฒฐ์ , ์ฌ๊ณ )๋ ๊ทธ๋๋ก ์ฐ๋ฉด์ ํ๋ก ํธ์๋๋ React, Next.js, Vue ๊ฐ์ ๊ฑธ๋ก ์์ ํ ์๋ก ๋ง๋๋ ๋ฐฉ์์ด์ผ.
์ธ์ฆ ๋ฐฉ์๋ ๋ฌ๋ผ. Storefront API๋ Storefront Access Token์ ์ฐ๋๋ฐ, ์ด๊ฑด ํผ๋ธ๋ฆญ ํ ํฐ์ด๋ผ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์ ์จ๋ ๋จ (Admin API ํ ํฐ์ ์ ๋ ํ๋ก ํธ์ ๋
ธ์ถํ๋ฉด ์ ๋จ!).
const client = createStorefrontApiClient({
storeDomain: 'my-store.myshopify.com',
apiVersion: '2024-01',
publicAccessToken: 'your-storefront-access-token',
});
- ์ปค์คํ ํ๋ก ํธ์๋ ๊ฐ๋ฐ โ Storefront API
- ๋ ๊ฑฐ์ ํตํฉ์ด๋ ๋จ์ CRUD โ Admin REST API
๐ง Liquid ํ ํ๋ฆฟ ์ธ์ด โ Shopify ํ ๋ง์ ์ฌ์ฅ
Liquid๋ Shopify๊ฐ ๋ง๋ ์คํ์์ค ํ ํ๋ฆฟ ์ธ์ด์ผ. Ruby ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ก๊ณ , Shopify ํ ๋ง์ ๋ชจ๋ HTML ํ์ผ์์ ์ฌ์ฉ๋จ. ์ฒ์ ๋ณด๋ฉด ์ข ๋ฏ์ค ์ ์๋๋ฐ, ์ต์ํด์ง๋ฉด ์ง์ง ๊ฐ๋ ฅํจ ใ ใ
Liquid ๊ธฐ๋ณธ ๋ฌธ๋ฒ 3๊ฐ์ง
1. ์ถ๋ ฅ ํ๊ทธ (Output Tags) โ ์ด์ค ์ค๊ดํธ ์ฌ์ฉ
{{ product.title }}
{{ product.price | money }}
{{ shop.name }}
2. ๋ก์ง ํ๊ทธ (Logic Tags) โ ์ค๊ดํธ + ํผ์ผํธ ์ฌ์ฉ
{% if product.available %}
<button>์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ</button>
{% else %}
<button disabled>ํ์ </button>
{% endif %}
{% for product in collection.products %}
<div>{{ product.title }}</div>
{% endfor %}
3. ํํฐ (Filters) โ ํ์ดํ(|)๋ก ๋ฐ์ดํฐ ๋ณํ
{{ product.price | money }} โ โฉ15,000
{{ product.title | upcase }} โ PRODUCT NAME
{{ 'style.css' | asset_url | stylesheet_tag }}
{{ product.description | truncate: 100 }}
Shopify ํ ๋ง ํ์ผ ๊ตฌ์กฐ
Shopify ํ ๋ง๋ ์ ํด์ง ํด๋ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ผ์ผ ํจ:
theme/
โโโ assets/ # CSS, JS, ์ด๋ฏธ์ง ํ์ผ
โโโ config/ # ํ
๋ง ์ค์ (settings_schema.json)
โโโ layout/ # ๊ธฐ๋ณธ ๋ ์ด์์ (theme.liquid)
โโโ locales/ # ๋ค๊ตญ์ด ๋ฒ์ญ ํ์ผ
โโโ sections/ # ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์น์
์ปดํฌ๋ํธ
โโโ snippets/ # ์์ ์ฌ์ฌ์ฉ ์ฝ๋ ์กฐ๊ฐ
โโโ templates/ # ๊ฐ ํ์ด์ง ํ
ํ๋ฆฟ
ํนํ sections/ ํด๋๊ฐ ํต์ฌ์. Shopify 2.0๋ถํฐ๋ ์น์
๊ธฐ๋ฐ ์ํคํ
์ฒ๋ก ๋ฐ๋์ด์, ๋๋๊ทธ์ค๋๋กญ์ผ๋ก ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ ์ ์๊ฒ ๋์ด.
Online Store 2.0 โ ํ ๋ง ๊ฐ๋ฐ์ ํจ๋ฌ๋ค์ ๋ณํ
Shopify Online Store 2.0(2021๋ ์ถ์)์ ํ ๋ง ๊ฐ๋ฐ ๋ฐฉ์์ ์์ ํ ๋ฐ๊ฟ๋จ์. ํต์ฌ ๋ณํ๋:
์ค์ ์น์ ์ฝ๋ ์์
์ปค์คํ ์ํ ์นด๋ ์น์ ๋ง๋ค๊ธฐ ์์:
{% comment %} sections/custom-product-card.liquid {% endcomment %}
<div class="product-card">
{% if section.settings.show_image %}
<img src="{{ product.featured_image | img_url: '400x400' }}"
alt="{{ product.featured_image.alt }}">
{% endif %}
<h2>{{ product.title }}</h2>
<p class="price">{{ product.price | money }}</p>
{% if product.compare_at_price > product.price %}
<span class="sale-badge">SALE</span>
<s>{{ product.compare_at_price | money }}</s>
{% endif %}
<form action="/cart/add" method="post">
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
<button type="submit">์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ</button>
</form>
</div>
{% schema %}
{
"name": "์ปค์คํ
์ํ ์นด๋",
"settings": [
{
"type": "checkbox",
"id": "show_image",
"label": "์ด๋ฏธ์ง ํ์",
"default": true
}
]
}
{% endschema %}
๐ฑ Shopify ์ฑ ๊ฐ๋ฐ โ ๊ธฐ๋ฅ ํ์ฅ์ ๋ํ์
Shopify ์ฑ์ ์คํ ์ด์ ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๋ฐฉ์์ด์ผ. ํฌ๊ฒ ํผ๋ธ๋ฆญ ์ฑ๊ณผ ์ปค์คํ ์ฑ์ผ๋ก ๋๋จ.
๐ ํผ๋ธ๋ฆญ ์ฑ Shopify App Store์ ์ฌ๋ ค์ ๋ชจ๋ ์์ธ์ด ์ค์นํ ์ ์๋ ์ฑ. OAuth ์ธ์ฆ ํ์. ์์ต ์ฐฝ์ถ ๊ฐ๋ฅ.
OAuth 2.0 App Store ์์ตํ๐ ์ปค์คํ ์ฑ ํน์ ์คํ ์ด ํ๋๋ง์ ์ํ ์ฑ. ๋ณต์กํ OAuth ์์ด Admin API ํ ํฐ์ผ๋ก ๋ฐ๋ก ์ฐ๊ฒฐ. ๋ด๋ถ ๋๊ตฌ ๊ฐ๋ฐ์ ์ต์ .
๋จ์ผ ์คํ ์ด ๋น ๋ฅธ ๊ฐ๋ฐ ๋ด๋ถ ๋๊ตฌShopify CLI๋ก ์ฑ ๊ฐ๋ฐ ์์ํ๊ธฐ
Shopify๋ Shopify CLI๋ผ๋ ๊ณต์ ๊ฐ๋ฐ ๋๊ตฌ๋ฅผ ์ ๊ณตํจ. ์ด๊ฑธ๋ก ์ฑ ํ๋ก์ ํธ๋ฅผ ๋น ๋ฅด๊ฒ ์ธํ ํ ์ ์์ด:
# Shopify CLI ์ค์น
npm install -g @shopify/cli @shopify/theme
# ์ ์ฑ ํ๋ก์ ํธ ์์ฑ
shopify app init
# ๊ฐ๋ฐ ์๋ฒ ์คํ
shopify app dev
๊ธฐ๋ณธ ์ฑ ์คํ์ Node.js + Express + React ์กฐํฉ์ด ๋ง์ด ์ฐ์ด๊ณ , ์ต๊ทผ์ Remix ํ๋ ์์ํฌ๋ฅผ Shopify๊ฐ ๊ณต์ ์ง์ํ๋ฉด์ Remix ๊ธฐ๋ฐ ์ฑ ๊ฐ๋ฐ์ด ํธ๋ ๋์ ใ
ใ
OAuth ์ธ์ฆ ํ๋ก์ฐ โ ํผ๋ธ๋ฆญ ์ฑ ํ์ ์ง์
redirect_uri๋ก ๋ฆฌ๋ค์ด๋ ํธcode๋ฅผ ์ฑ์ ์ ๋ฌcode๋ฅผ access_token์ผ๋ก ๊ตํ (์๋ฒ์ฌ์ด๋์์!)access_token์ผ๋ก Admin API ํธ์ถ ๊ฐ๋ฅ ๐// access_token ๊ตํ ์์ (Node.js)
const response = await fetch(
`https://${shop}/admin/oauth/access_token`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.SHOPIFY_API_KEY,
client_secret: process.env.SHOPIFY_API_SECRET,
code: req.query.code,
}),
}
);
const { access_token } = await response.json();
Shopify App Bridge โ ์ฑ UI ํตํฉ
App Bridge๋ Shopify ๊ด๋ฆฌ์ ํ์ด์ง ์์ ์ฑ UI๋ฅผ ์์ฐ์ค๋ฝ๊ฒ ํตํฉ์์ผ์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. ์ด๊ฑธ ์ฐ๋ฉด Shopify ๊ด๋ฆฌ์์ ๋ค๋น๊ฒ์ด์
, ํ ์คํธ ๋ฉ์์ง, ๋ชจ๋ฌ ๋ฑ์ ์ฑ์์ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์์.
Polaris๋ Shopify์ ๊ณต์ ๋์์ธ ์์คํ
+ React ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ผ. ์ฑ UI๋ฅผ Shopify ์คํ์ผ์ ๋ง๊ฒ ๋น ๋ฅด๊ฒ ๋ง๋ค ์ ์์:
import { Page, Card, Button, TextField } from '@shopify/polaris';
function MyApp() {
return (
<Page title="๋ด ์ปค์คํ
์ฑ">
<Card>
<TextField label="์ํ๋ช
" value={value} onChange={setValue} />
<Button primary>์ ์ฅํ๊ธฐ</Button>
</Card>
</Page>
);
}
๐ Webhooks โ ์ค์๊ฐ ์ด๋ฒคํธ ์ฒ๋ฆฌ์ ํต์ฌ
Webhook์ Shopify์์ ํน์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ๋ด ์๋ฒ๋ก ์๋์ผ๋ก HTTP POST ์์ฒญ์ ๋ณด๋ด์ฃผ๋ ๊ธฐ๋ฅ์ด์ผ. ํด๋ง(์ฃผ๊ธฐ์ ์ผ๋ก API ํธ์ถํด์ ๋ณ๊ฒฝ ํ์ธ) ๋์ ์ด๋ฒคํธ ๊ธฐ๋ฐ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ด์ ํจ์ฌ ํจ์จ์ ์.
์ฃผ์ Webhook ์ด๋ฒคํธ ๋ชฉ๋ก:
orders/create orders/paid orders/fulfilled orders/cancelled products/create products/update customers/create customers/update inventory_levels/update checkouts/create refunds/create app/uninstalled
Webhook ๋ฑ๋ก ๋ฐฉ๋ฒ
GraphQL๋ก Webhook ๋ฑ๋กํ๊ธฐ:
mutation {
webhookSubscriptionCreate(
topic: ORDERS_CREATE
webhookSubscription: {
format: JSON
callbackUrl: "https://my-app.com/webhooks/orders"
}
) {
webhookSubscription {
id
topic
endpoint {
__typename
... on WebhookHttpEndpoint {
callbackUrl
}
}
}
userErrors {
field
message
}
}
}
Webhook ์์ ๋ฐ ๊ฒ์ฆ โ ๋ณด์์ด ํต์ฌ!
Webhook์ ๋ฐ์ ๋ ๋ฐ๋์ ์๋ช
๊ฒ์ฆ์ ํด์ผ ํจ! ์๋ฌด๋ ๋ด ์๋ํฌ์ธํธ์ ๊ฐ์ง ์์ฒญ ๋ณด๋ผ ์ ์๊ฑฐ๋ ใ
ใ
Shopify๋ ๊ฐ Webhook ์์ฒญ์ X-Shopify-Hmac-Sha256 ํค๋๋ฅผ ํฌํจ์์ผ. ์ด๊ฑธ ๋ด API Secret์ผ๋ก ๊ฒ์ฆํด์ผ ํจ:
const crypto = require('crypto');
function verifyWebhook(req) {
const hmac = req.headers['x-shopify-hmac-sha256'];
const body = req.rawBody; // raw body ํ์!
const hash = crypto
.createHmac('sha256', process.env.SHOPIFY_API_SECRET)
.update(body, 'utf8')
.digest('base64');
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(hmac)
);
}
// Express ๋ผ์ฐํฐ์์
app.post('/webhooks/orders', (req, res) => {
if (!verifyWebhook(req)) {
return res.status(401).send('Unauthorized');
}
const order = req.body;
console.log('์ ์ฃผ๋ฌธ ๋ฐ์!', order.id);
// ์ฃผ๋ฌธ ์ฒ๋ฆฌ ๋ก์ง...
res.status(200).send('OK');
});
์ค์: Webhook ์ฒ๋ฆฌ๋ 5์ด ์ด๋ด์ 200 ์๋ต์ ๋ณด๋ด์ผ ํจ. ์ค๋ ๊ฑธ๋ฆฌ๋ ์์
์ ํ(Queue)์ ๋ฃ๊ณ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํด์ผ ํด.
๐๏ธ ๋ฉํํ๋ โ ์ปค์คํ ๋ฐ์ดํฐ ์ ์ฅ์ ๋ชจ๋ ๊ฒ
Shopify์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ง์ผ๋ก๋ ๋ถ์กฑํ ๋๊ฐ ์์์? ์๋ฅผ ๋ค์ด ์ํ์ "์์ฐ์ง", "์ฑ๋ถ ๋ชฉ๋ก", "์ฌ์ฉ ๋ฐฉ๋ฒ" ๊ฐ์ ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ณ ์ถ์ ๋ ๋ฉํํ๋(Metafields)๋ฅผ ์ฌ์ฉํจ.
๋ฉํํ๋ ์ง์ ๋ฆฌ์์ค:
products variants collections customers orders pages blogs shop
์ง์ ๋ฐ์ดํฐ ํ์ :
single_line_text_field multi_line_text_field number_integer number_decimal date boolean json file_reference product_reference color url rating
๋ฉํํ๋ ์์ฑ ๋ฐ ์กฐํ
GraphQL๋ก ์ํ ๋ฉํํ๋ ์์ฑ:
mutation {
metafieldsSet(metafields: [
{
ownerId: "gid://shopify/Product/1234567890"
namespace: "custom"
key: "origin_country"
value: "๋ํ๋ฏผ๊ตญ"
type: "single_line_text_field"
}
]) {
metafields {
id
key
value
}
userErrors {
field
message
}
}
}
Liquid์์ ๋ฉํํ๋ ์ถ๋ ฅ:
{% comment %} ์ํ ํ์ด์ง์์ ๋ฉํํ๋ ์ถ๋ ฅ {% endcomment %}
{% if product.metafields.custom.origin_country %}
<p>์์ฐ์ง: {{ product.metafields.custom.origin_country.value }}</p>
{% endif %}
๋ฉํ์ค๋ธ์ ํธ โ ๋ ๋ณต์กํ ์ปค์คํ ๋ฐ์ดํฐ
๋ฉํ์ค๋ธ์ ํธ(Metaobjects)๋ 2022๋
์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ์ผ๋ก, ์์ ํ ์ปค์คํ
ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค ์ ์์ด. ์๋ฅผ ๋ค์ด "ํ์ ์๊ฐ", "FAQ ํญ๋ชฉ", "๋ธ๋๋ ์คํ ๋ฆฌ" ๊ฐ์ ๊ตฌ์กฐํ๋ ์ฝํ
์ธ ๋ฅผ ๋ง๋ค ๋ ์.
๋ฉํ์ค๋ธ์ ํธ๋ ํ์
์ ์ โ ์ธ์คํด์ค ์์ฑ โ ์ฐธ์กฐ ์์๋ก ์ฌ์ฉํด:
# 1. ๋ฉํ์ค๋ธ์ ํธ ํ์
์ ์ (GraphQL)
mutation {
metaobjectDefinitionCreate(definition: {
name: "ํ์"
type: "team_member"
fieldDefinitions: [
{ name: "์ด๋ฆ", key: "name", type: "single_line_text_field" }
{ name: "์ง์ฑ
", key: "role", type: "single_line_text_field" }
{ name: "์ฌ์ง", key: "photo", type: "file_reference" }
]
}) {
metaobjectDefinition { id }
}
}
๐ ํค๋๋ฆฌ์ค ์ปค๋จธ์ค โ Next.js + Shopify ์กฐํฉ
ํค๋๋ฆฌ์ค ์ปค๋จธ์ค๋ Shopify ๋ฐฑ์๋ + ์ปค์คํ
ํ๋ก ํธ์๋ ์กฐํฉ์ด์ผ. ์ฑ๋ฅ, ์ ์ฐ์ฑ, ๊ฐ๋ฐ์ ๊ฒฝํ ๋ชจ๋ ์ต๊ณ ์์ค์ผ๋ก ๋์ด์ฌ๋ฆด ์ ์์.
Shopify๋ ๊ณต์์ ์ผ๋ก Hydrogen์ด๋ผ๋ React ๊ธฐ๋ฐ ํค๋๋ฆฌ์ค ํ๋ ์์ํฌ๋ฅผ ์ ๊ณตํ๊ณ , ๋ฐฐํฌ๋ Oxygen(Shopify ์์ฒด ํธ์คํ
)์์ ํ ์ ์์ด.
๐ฅ Hydrogen (๊ณต์) Shopify ๊ณต์ ํค๋๋ฆฌ์ค ํ๋ ์์ํฌ. Remix ๊ธฐ๋ฐ. Shopify API์ ์ต์ ํ๋ ํตํฉ. Oxygen์ ๋ฐฐํฌ.
Remix ๊ณต์ ์ง์ Oxygen ๋ฐฐํฌโก Next.js + Storefront API Next.js๋ก ํ๋ก ํธ ๊ตฌ์ฑ + Storefront API๋ก Shopify ์ฐ๊ฒฐ. ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ์ปค๋ฎค๋ํฐ ์คํ.
Next.js Vercel ๋ฐฐํฌ ์ ์ฐ์ฑ ์ต๊ณNext.js + Storefront API ์ค์ ์์
// lib/shopify.js
const domain = process.env.SHOPIFY_STORE_DOMAIN;
const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;
async function shopifyFetch({ query, variables }) {
const res = await fetch(
`https://${domain}/api/2024-01/graphql.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
},
body: JSON.stringify({ query, variables }),
}
);
return res.json();
}
// ์ํ ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ
export async function getProducts() {
const { data } = await shopifyFetch({
query: `
query {
products(first: 20) {
edges {
node {
id
title
handle
priceRange {
minVariantPrice {
amount
currencyCode
}
}
images(first: 1) {
edges {
node {
url
altText
}
}
}
}
}
}
}
`,
});
return data.products.edges.map(({ node }) => node);
}
// pages/products/index.js
export async function getStaticProps() {
const products = await getProducts();
return { props: { products }, revalidate: 60 };
}
export default function ProductsPage({ products }) {
return (
<div>
{products.map(product => (
<div key={product.id}>
<h2>{product.title}</h2>
<p>{product.priceRange.minVariantPrice.amount}์</p>
</div>
))}
</div>
);
}
์ฅ๋ฐ๊ตฌ๋ ๊ตฌํ โ Storefront API Cart
ํค๋๋ฆฌ์ค์์ ์ฅ๋ฐ๊ตฌ๋๋ Storefront API์ Cart API๋ก ๊ตฌํํจ:
// ์ฅ๋ฐ๊ตฌ๋ ์์ฑ
mutation cartCreate($input: CartInput!) {
cartCreate(input: $input) {
cart {
id
checkoutUrl
lines(first: 10) {
edges {
node {
id
quantity
merchandise {
... on ProductVariant {
id
title
priceV2 { amount currencyCode }
}
}
}
}
}
}
}
}
// ์์ดํ
์ถ๊ฐ
mutation cartLinesAdd($cartId: ID!, $lines: [CartLineInput!]!) {
cartLinesAdd(cartId: $cartId, lines: $lines) {
cart {
id
totalQuantity
}
}
}
์ฅ๋ฐ๊ตฌ๋ ID๋ localStorage์ ์ ์ฅํด์ ์ธ์
๊ฐ ์ ์งํ๋ฉด ๋จ. ๊ฒฐ์ ๋ checkoutUrl๋ก ๋ฆฌ๋ค์ด๋ ํธํ๋ฉด Shopify ๊ธฐ๋ณธ ๊ฒฐ์ ํ์ด์ง๋ก ์ด๋ํด.
๐ณ ๊ฒฐ์ ์ปค์คํฐ๋ง์ด์ง โ Checkout Extensions
Shopify์ ๊ฒฐ์ ํ์ด์ง๋ฅผ ์ปค์คํฐ๋ง์ด์งํ๋ ๊ฑด ์์ ์ Plus ํ๋์์๋ง ๊ฐ๋ฅํ๋๋ฐ, ์ด์ ๋ Checkout Extensions๋ฅผ ํตํด ์ผ๋ฐ ํ๋์์๋ ์ด๋ ์ ๋ ์ปค์คํฐ๋ง์ด์ง์ด ๊ฐ๋ฅํด์ก์ด.
Checkout Extensions๋ก ํ ์ ์๋ ๊ฒ๋ค:
Checkout Extension ๊ธฐ๋ณธ ๊ตฌ์กฐ:
import {
extension,
Banner,
BlockStack,
Text,
} from '@shopify/ui-extensions/checkout';
export default extension(
'purchase.checkout.block.render',
(root, { lines, cost }) => {
const totalItems = lines.current.reduce(
(sum, line) => sum + line.quantity, 0
);
root.appendChild(
root.createComponent(Banner, { status: 'info' },
root.createComponent(BlockStack, {},
root.createComponent(Text, {},
`์ด ${totalItems}๊ฐ ์ํ ยท ${cost.totalAmount.current.amount}์`
)
)
)
);
}
);
checkout.liquid๋ 2024๋
8์ ์ดํ ์ง์ ์ข
๋ฃ๋จ. ์ด์ ๋ Checkout Extensions๋ก ๋ง์ด๊ทธ๋ ์ด์
ํด์ผ ํด.
โก Shopify ์ผํ๋ชฐ ์ฑ๋ฅ ์ต์ ํ ์ ๋ต
์๋ฌด๋ฆฌ ๋ฉ์ง ์ปค์คํฐ๋ง์ด์ง์ ํด๋ ๋๋ฆฌ๋ฉด ๋ค ์์ฉ์์ ใ ใ Core Web Vitals ์ ์๊ฐ SEO์๋ ์ง๊ฒฐ๋๋๊น ์ฑ๋ฅ ์ต์ ํ๋ ํ์์ผ.
์ด๋ฏธ์ง ์ต์ ํ
Shopify๋ ์์ฒด CDN์ ํตํด ์ด๋ฏธ์ง๋ฅผ ์ ๊ณตํ๋๋ฐ, Liquid์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ง์ ํด์ ๋ถํ์ํ๊ฒ ํฐ ์ด๋ฏธ์ง ๋ก๋ฉ์ ๋ง์ ์ ์์ด:
{% comment %} ๋์ ์ - ์๋ณธ ์ด๋ฏธ์ง ๊ทธ๋๋ก ๋ก๋ {% endcomment %}
<img src="{{ product.featured_image | img_url }}">
{% comment %} ์ข์ ์ - ํฌ๊ธฐ ์ง์ + WebP ํฌ๋งท {% endcomment %}
<img
src="{{ product.featured_image | image_url: width: 800 }}"
srcset="{{ product.featured_image | image_url: width: 400 }} 400w,
{{ product.featured_image | image_url: width: 800 }} 800w,
{{ product.featured_image | image_url: width: 1200 }} 1200w"
sizes="(max-width: 768px) 100vw, 50vw"
loading="lazy"
alt="{{ product.featured_image.alt }}"
>
Shopify CDN์ ์๋์ผ๋ก WebP ๋ณํ์ ์ง์ํ๊ณ , image_url ํํฐ๋ก ํฌ๊ธฐ๋ฅผ ์ง์ ํ๋ฉด ์๋ฒ์์ ๋ฆฌ์ฌ์ด์งํด์ ์ค.
JavaScript ์ต์ ํ
Shopify ํ ๋ง์์ JS ์ฑ๋ฅ์ ๋์ด๋ ํต์ฌ ์ ๋ต๋ค:
์น์ ๋ ๋๋ง API โ ๋ถ๋ถ ์ ๋ฐ์ดํธ์ ํ๋ช
Shopify์ Section Rendering API๋ ํ์ด์ง ์ ์ฒด๋ฅผ ์๋ก๊ณ ์นจํ์ง ์๊ณ ํน์ ์น์ ๋ง ์ ๋ฐ์ดํธํ ์ ์๊ฒ ํด์ค. ํํฐ, ์ ๋ ฌ, ์ฅ๋ฐ๊ตฌ๋ ์ ๋ฐ์ดํธ ๋ฑ์ ํ์ฉ:
// ์ปฌ๋ ์
ํํฐ ์ ์ฉ ์ ์น์
๋ง ์
๋ฐ์ดํธ
async function updateProductGrid(filterParams) {
const url = `${window.location.pathname}?${filterParams}§ions=product-grid`;
const response = await fetch(url);
const data = await response.json();
// ์น์
HTML๋ง ๊ต์ฒด
document.getElementById('product-grid').innerHTML =
data['product-grid'];
}
์ด๋ ๊ฒ ํ๋ฉด ์ ์ฒด ํ์ด์ง ๋ฆฌ๋ก๋ ์์ด ์ํ ๋ชฉ๋ก๋ง ์
๋ฐ์ดํธ๋จ. UX๊ฐ ํจ์ฌ ๋ถ๋๋ฌ์์ง๊ณ ์ฑ๋ฅ๋ ์ข์์ง ใ
ใ
๐ฏ ์ค์ ์ปค์คํฐ๋ง์ด์ง ์ฌ๋ก ๋ชจ์
์ด๋ก ์ ์ถฉ๋ถํ ๋ดค์ผ๋๊น ์ค์ ๋ก ๋ง์ด ์ฐ์ด๋ ์ปค์คํฐ๋ง์ด์ง ์ฌ๋ก๋ค์ ์ดํด๋ณด์ ใ ใ
โ ์ปค์คํ ํํฐ & ์ ๋ ฌ ๊ตฌํ
Shopify์ ๊ธฐ๋ณธ ํํฐ ๊ธฐ๋ฅ์ ์ปค์คํฐ๋ง์ด์งํ๊ฑฐ๋, Storefront API๋ก ์์ ํ ์๋ก์ด ํํฐ UI๋ฅผ ๋ง๋ค ์ ์์ด:
query getFilteredProducts(
$handle: String!
$filters: [ProductFilter!]
$sortKey: ProductCollectionSortKeys
$reverse: Boolean
) {
collection(handle: $handle) {
products(
first: 20
filters: $filters
sortKey: $sortKey
reverse: $reverse
) {
filters {
id
label
type
values {
id
label
count
input
}
}
edges {
node {
id
title
priceRange {
minVariantPrice { amount }
}
}
}
}
}
}
โก ๋ฒ๋ค ์ํ & ์ ์ ๊ธฐ๋ฅ
์ฌ๋ฌ ์ํ์ ๋ฌถ์ด์ ํ ์ธ ํ๋งคํ๋ ๋ฒ๋ค ๊ธฐ๋ฅ์ Shopify ๊ธฐ๋ณธ ๊ธฐ๋ฅ์ ์์ด์ ์ปค์คํ ์ผ๋ก ๊ตฌํํด์ผ ํจ. ๋ฐฉ๋ฒ์ ํฌ๊ฒ ๋ ๊ฐ์ง:
๋ฐฉ๋ฒ 1: ๋ฉํํ๋ ํ์ฉ โ ๋ฒ๋ค ์ํ์ ๊ด๋ จ ์ํ ID๋ฅผ ๋ฉํํ๋๋ก ์ ์ฅํ๊ณ , ์ฅ๋ฐ๊ตฌ๋์ ํ ๋ฒ์ ์ถ๊ฐ
// ๋ฒ๋ค ์ํ๋ค์ ์ฅ๋ฐ๊ตฌ๋์ ํ ๋ฒ์ ์ถ๊ฐ
async function addBundleToCart(bundleItems) {
const response = await fetch('/cart/add.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
items: bundleItems.map(item => ({
id: item.variantId,
quantity: item.quantity,
properties: { '_bundle_id': bundleItems[0].variantId }
}))
})
});
return response.json();
}
๋ฐฉ๋ฒ 2: Shopify Bundles ์ฑ โ Shopify ๊ณต์ ๋ฒ๋ค ์ฑ ์ฌ์ฉ (2023๋
์ถ์, ๋ฌด๋ฃ)
โข ์ค์๊ฐ ์ฌ๊ณ ์๋ฆผ ๊ธฐ๋ฅ
ํ์ ์ํ์ "์ฌ์ ๊ณ ์๋ฆผ" ๊ธฐ๋ฅ ๊ตฌํ:
// ์ฌ์
๊ณ ์๋ฆผ ์ ์ฒญ ํผ
<form id="back-in-stock-form">
<input type="email" name="email" placeholder="์ด๋ฉ์ผ ์
๋ ฅ" required>
<input type="hidden" name="variant_id" value="{{ product.selected_variant.id }}">
<button type="submit">์ฌ์
๊ณ ์๋ฆผ ์ ์ฒญ</button>
</form>
<script>
document.getElementById('back-in-stock-form').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
// ๋ด ์ฑ ์๋ฒ์ ์ ์ฒญ ์ ๋ณด ์ ์ฅ
await fetch('/apps/back-in-stock/subscribe', {
method: 'POST',
body: JSON.stringify({
email: formData.get('email'),
variantId: formData.get('variant_id')
})
});
alert('์ฌ์
๊ณ ์ ์๋ฆผ์ ๋ณด๋ด๋๋ฆด๊ฒ์! ๐ง');
});
</script>
Webhook inventory_levels/update๋ฅผ ๊ตฌ๋
ํด์ ์ฌ๊ณ ๊ฐ ์๊ธฐ๋ฉด ๋ฑ๋ก๋ ์ด๋ฉ์ผ๋ก ์๋ ๋ฐ์กํ๋ฉด ๋จ.
โฃ ๋ค๊ตญ์ด & ๋คํตํ ์ง์
Shopify Markets๋ฅผ ํ์ฉํ๋ฉด ๊ธ๋ก๋ฒ ํ๋งค๊ฐ ํจ์ฌ ์ฌ์์ง. Liquid์์ ๋ค๊ตญ์ด ์ฒ๋ฆฌ:
{% comment %} locales/ko.default.json {% endcomment %}
{
"products": {
"add_to_cart": "์ฅ๋ฐ๊ตฌ๋ ๋ด๊ธฐ",
"sold_out": "ํ์ ",
"sale": "์ธ์ผ"
}
}
{% comment %} locales/en.default.json {% endcomment %}
{
"products": {
"add_to_cart": "Add to Cart",
"sold_out": "Sold Out",
"sale": "Sale"
}
}
{% comment %} ํ
ํ๋ฆฟ์์ ์ฌ์ฉ {% endcomment %}
<button>{{ 'products.add_to_cart' | t }}</button>
ํตํ ๋ณํ์ Shopify๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌํด์ฃผ๋๋ฐ, {{ product.price | money_with_currency }}๋ก ํ์ฌ ํตํ์ ๋ง๊ฒ ํ์๋จ.
๐ ๏ธ Shopify ๊ฐ๋ฐ ํ๊ฒฝ ์ธํ & ํ์ ๋๊ตฌ
ํ์ ๊ฐ๋ฐ ํ๊ฒฝ ์ธํ ์์:
npm install -g @shopify/clishopify theme dev --store=my-store.myshopify.com์ถ์ฒ ๊ฐ๋ฐ ๋๊ตฌ & ์ต์คํ ์
๐ง VS Code ์ต์คํ ์
Shopify Liquid Liquid Languages Support Shopify Theme Check
Theme Check๋ Liquid ์ฝ๋์ ์ค๋ฅ์ ์ฑ๋ฅ ์ด์๋ฅผ ์๋์ผ๋ก ์ก์์ค. ํ์์ ใ ใ
๐งช ํ ์คํธ & ๋๋ฒ๊น
Shopify Theme Inspector Chrome DevTools Postman / Insomnia
Theme Inspector๋ Liquid ๋ ๋๋ง ์ฑ๋ฅ์ ์๊ฐํํด์ ๋ณด์ฌ์ค. ๋ณ๋ชฉ ์ฐพ๊ธฐ ์ต๊ณ
Shopify Theme Check โ ์ฝ๋ ํ์ง ๊ด๋ฆฌ
Theme Check๋ Liquid ์ฝ๋์ ๋ฌธ์ ๋ฅผ ์๋์ผ๋ก ๊ฐ์งํด์ฃผ๋ ๋ฆฐํฐ์ผ:
# Theme Check ์คํ
shopify theme check
# ํน์ ๊ท์น๋ง ์ฒดํฌ
shopify theme check --only LiquidHTMLSyntaxError
# ์๋ ์์ ๊ฐ๋ฅํ ์ด์ ์์
shopify theme check --auto-correct
์ฃผ์ ์ฒดํฌ ํญ๋ชฉ๋ค:
Liquid ๋ฌธ๋ฒ ์ค๋ฅ ๋ฏธ์ฌ์ฉ ๋ณ์ ์ฑ๋ฅ ์ด์ ์ ๊ทผ์ฑ ๋ฌธ์ ๋ฒ์ญ ํค ๋๋ฝ deprecated ํํฐ
shopify theme dev๋ฅผ ์คํํ๋ฉด ๋ก์ปฌ์์ ์์ ํ ๋ด์ฉ์ด ์ค์๊ฐ์ผ๋ก ๊ฐ๋ฐ ์คํ ์ด์ ๋ฐ์๋จ. Hot reload ์ง์์ด๋ผ ๊ฐ๋ฐ ์๋๊ฐ ์์ฒญ ๋นจ๋ผ์ง ใ
ใ
๐ ๋ณด์ & ๊ฐ๋ฐ ๋ชจ๋ฒ ์ฌ๋ก
Shopify ๊ฐ๋ฐ์์ ๋ณด์์ ์ ๋ ํํํ๋ฉด ์ ๋๋ ์์ญ์ด์ผ. ํนํ API ํค ๊ด๋ฆฌ์ ์ ๋ ฅ๊ฐ ๊ฒ์ฆ์ ๊ธฐ๋ณธ ์ค์ ๊ธฐ๋ณธ์.
๐จ ์ ๋ ํ๋ฉด ์ ๋๋ ๊ฒ๋ค:
โ ๋ฐ๋์ ํด์ผ ํ๋ ๊ฒ๋ค:
API Rate Limit ์ฒ๋ฆฌ ์์
// GraphQL API์ ๋น์ฉ ๊ธฐ๋ฐ Rate Limit ์ฒ๋ฆฌ
async function shopifyGraphQL(query, variables) {
const response = await fetch(endpoint, {
method: 'POST',
headers: headers,
body: JSON.stringify({ query, variables }),
});
const data = await response.json();
// Rate Limit ์ ๋ณด ํ์ธ
const cost = data.extensions?.cost;
if (cost) {
const { throttleStatus } = cost;
const { currentlyAvailable, restoreRate } = throttleStatus;
// ๋จ์ ํฌ์ธํธ๊ฐ ๋ถ์กฑํ๋ฉด ๋๊ธฐ
if (currentlyAvailable < 100) {
const waitTime = (100 - currentlyAvailable) / restoreRate * 1000;
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
return data;
}
๐ ํต์ฌ ๋ด์ฉ ์ด์ ๋ฆฌ
์ ์ด์ Shopify API์ ์ปค์คํฐ๋ง์ด์ง์ ๋ํด ๊ฝค ๊น์ด ํ๋ดค๋๋ฐ, ํต์ฌ๋ง ๋ค์ ์ ๋ฆฌํด๋ณผ๊ฒ ใ ใ
๐ API ์ ํ ๊ธฐ์ค
โข Admin GraphQL API โ ๋ฐฑ์๋ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ํ์ค. REST๋ณด๋ค GraphQL ์ฐ์ ์ฌ์ฉ
โข Storefront API โ ํค๋๋ฆฌ์ค ์ปค๋จธ์ค ํ๋ก ํธ์๋ ๊ตฌํ ์ ํ์
โข Admin REST API โ ๋ ๊ฑฐ์ ํตํฉ์ด๋ ๋จ์ CRUD์๋ง ์ฌ์ฉ
๐ง Liquid ๊ฐ๋ฐ ํต์ฌ
โข Online Store 2.0 ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ฐ (JSON ํ
ํ๋ฆฟ + ์น์
์ํคํ
์ฒ)
โข Theme Check๋ก ์ฝ๋ ํ์ง ๊ด๋ฆฌ
โข ๋์ ๊ธฐ๋ฅ์ Section Rendering API + JavaScript ์กฐํฉ์ผ๋ก ๊ตฌํ
โข Dawn ํ
๋ง ์์ค์ฝ๋๋ฅผ ๋ ํผ๋ฐ์ค๋ก ํ์ฉ
๐ฑ ์ฑ ๊ฐ๋ฐ ํต์ฌ
โข ํผ๋ธ๋ฆญ ์ฑ: OAuth 2.0 ์ธ์ฆ + Polaris UI + App Bridge
โข ์ปค์คํ
์ฑ: Admin API ํ ํฐ์ผ๋ก ๋น ๋ฅด๊ฒ ๊ฐ๋ฐ
โข Webhook์ผ๋ก ์ค์๊ฐ ์ด๋ฒคํธ ์ฒ๋ฆฌ (์๋ช
๊ฒ์ฆ ํ์!)
โข Shopify CLI + Remix ์คํ์ด ํ์ฌ ํธ๋ ๋
๐ ํค๋๋ฆฌ์ค ์ปค๋จธ์ค ํต์ฌ
โข Shopify Hydrogen (๊ณต์) ๋๋ Next.js + Storefront API
โข ์ฅ๋ฐ๊ตฌ๋๋ Cart API๋ก ๊ตฌํ, checkoutUrl๋ก ๊ฒฐ์ ์ฐ๊ฒฐ
โข ์ด๋ฏธ์ง ์ต์ ํ + ์ฝ๋ ์คํ๋ฆฌํ
์ผ๋ก ์ฑ๋ฅ ํ๋ณด
โข ISR(Incremental Static Regeneration)์ผ๋ก SEO + ์ฑ๋ฅ ๋์ ๋ฌ์ฑ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.