SuperAPI AI Directory

kuroco-frontend-integration

Frontend & websites

View repository

Updated 10-16 05:06

About this skill

Kuroco frontend integration patterns

Integration patterns between Kuroco HeadlessCMS and frontend frameworks such as Vite/Nuxt.js/Next.js, as well as deciding the deployment target and deployment.

Documentation reference: /kuroco-docs You can search and reference the official Kuroco documentation using the skill.

Tutorial: For frontend deployment procedures and how to build a sample site, refer to Kuroco Sample Site Tutorial .

Table of contents

Screen design and design implementation

When newly implementing or changing a screen, read and apply the default design rules before implementation. When modifying an existing screen, review only the decisions relevant to the target.

Division of management between Kuroco and the frontend

Body text and images updated by editors are managed in Kuroco, while colors, spacing, and layout are managed on the frontend. When editors choose how something is displayed, give Kuroco meaningful selection values and map them to frontend display rules.

Checking the actual screen

Display and operate on the target devices, and check the main information and operations, long text, large numbers of items, missing images, and loading, empty, and failure states. Fix layout, shared components, and data mapping according to the cause of the breakage, and recheck screens that use the same components. Leave any range of the screen that could not be checked as unverified.

Deciding the deployment target

The default is KurocoFront. Unless specified by the user, proceed with KurocoFront without asking.

Situation Behavior
SSR / ISR is required KurocoFront is static content hosting (CDN) andcannot run a server, so it will not work. Suggest Vercel or similar. However, before suggesting, narrow it down using "Is SSR/ISR really necessary?" below
New build (no specification) Proceed with KurocoFront. Do not ask a question to make the user choose a deployment target
The user specifies Vercel / Netlify / Codex Sites / v0 / Lovable, etc. Proceed with that deployment target. Before implementation, fill in references/other-hosting.md the confirmation axes. In the case of Codex Sites, explain the execution environment constraints below first
New build running on Codex With KurocoFront as the default, you may present Codex Sites as an option only once. If no specification is returned, proceed with KurocoFront
Running in a normal ChatGPT chat Do not present Codex Sites (due to the execution environment constraints below). Proceed with KurocoFront
Modifying an existing site Maintain the current deployment destination. Only choose again when there is an explicit migration request

Execution environment constraints (Codex Sites)

Codex Sites(chatgpt.site) cannot be operated from a normal ChatGPT chat. Site creation and updates are premised on execution in Work mode (ChatGPT workspace) or Codex .

If you are proceeding with Kuroco construction in a normal chat and want to use Codex Sites, after explaining this constraint, working in Work mode or Codex is recommended. If you do not switch, proceed with KurocoFront.

Determining whether SSR/ISR is really necessary

The motivation behind requests for "SSR/ISR" is usually SEO or OGP, and in most cases SSG is sufficient. Carelessly deploying to Vercel disperses the operational destinations, sojudge by motivation。

Motivation Conclusion
Search traffic / OGP for each page SSG(KurocoFront) is sufficient. Since an SPA cannot have individual OGP for each page, use SSG
There are many pages and SSG builds are not realistically feasible / update frequency is high and waiting for builds is unacceptable SSR / ISR → Vercel, etc.. This cannot be achieved with KurocoFront
Membership-based / authentication-required screens SPA(KurocoFront). Even with SSR/ISR, no advantage arises (see below)
Public pages (OGP required) and member pages are mixed A mixed configuration of SSG for the public side + SPA for the member side. The deployment destination can remain KurocoFront

Why membership sites should not use SSR/ISR: Because the browser's session cookie is not included in server-side fetch, authenticated content will be fetched via client-side fetch anyway. Even with SSR, the advantages of server rendering (content included in the initial HTML display, OGP) cannot be obtained in the authenticated area, and only the configuration becomes more complex. For membership sites,leaning toward an SPA and keeping authentication closed on the client sideachieves better separation.

Implementation patterns for frameworks, authentication, CORS, and XSS countermeasures are common regardless of the deployment destination (sections below). Only the settings and deployment procedures differ by deployment destination, so read only the reference for the side you chose.

Support Framework

Framework Version Recommended use cases Delivery with KurocoFront
Vite + Vue 3 Vue 3 series Simple SPA (apps and tools that do not require SEO). Minimal configuration and straightforward authentication vite build → dist/ as is
Nuxt.js 3.x Vue 3 series Content sites that require SEO (static HTML generation with SSG, recommended) nuxt generate(SSG)。nuxt build SSR is not possible
Nuxt.js 2.x Vue 2 series Existing projects nuxt generate(SSG)
Next.js 13+ React (App Router) New React project output: 'export' only for static export (constraints below)
Next.js (Pages) React (Pages Router) Existing React project output: 'export' only for static export

KurocoFront is static content hosting (CDN), so configurations that involve server execution will not work. If SSR / ISR is required,Deciding the deployment destinationGo back to.

Constraints when delivering Next.js on KurocoFront

next.config.js に output: 'export' Set, andout/ Deliver. As of Next.js 16, the following are not available with static exportCannot be used(Official documentation)。

Unavailable features Workaround in Kuroco configuration
cookies() Perform authentication on the client side. For both Cookie authentication and dynamic access tokens, call the Kuroco API directly from the browser
Server Actions Send form submissions by POSTing directly to the Kuroco API from the client
next.config の Rewrites / Redirects / Headers kuroco_front.json の rewrites / redirects Configure with (references/kuroco-front.md)
ISR、Draft Mode、Intercepting Routes、Proxy No alternative. If necessary, change the deployment destination to Vercel, etc.
Route Handlers that depend on Request If making it static, export const dynamic = 'force-static'(GET only). If dynamic reads are needed, handle them on the Kuroco API side
dynamicParams: true / generateStaticParams() Dynamic routes without At build time, generateStaticParams() Enumerate all paths with. If the number is too large to enumerate, shift toward SPA
next/image default loader Specify a custom loader, or use the Kuroco Files image URL directly

Environment setup

Environment variables

# .env.local
NUXT_PUBLIC_API_BASE=https://example.g.kuroco.app
NEXT_PUBLIC_API_BASE=https://example.g.kuroco.app
API_ID=1

Project structure

Nuxt.js:

pages/
├── news/
│   ├── index.vue      # 一覧
│   └── [slug].vue     # 詳細 (Nuxt3)
├── login.vue
└── profile.vue
composables/
├── useAuth.ts
└── useApi.ts

Next.js (App Router):

app/
├── news/
│   ├── page.tsx       # 一覧
│   └── [slug]/page.tsx
├── login/page.tsx
└── profile/page.tsx
lib/
├── auth.ts
└── api.ts

API settings prerequisites

1. Security settings (Cookie authentication)

  1. Admin panel → API → Security → CookieSelect
  2. Set the frontend and API domains to differ only by subdomain
    • Example: www.example.com と api.example.com

2. CORS settings

Admin panel: [API] → [Security] → [CORS settings]

CORS_ALLOW_ORIGINS:
  - http://localhost:3000
  - https://your-frontend-domain.com

CORS_ALLOW_CREDENTIALS: true

CORS_ALLOW_METHODS:
  - GET
  - POST

Authentication implementation

Login

interface LoginResponse {
  grant_token: string
  status: number
  member_id: number
}

async function login(email: string, password: string): Promise<LoginResponse> {
  const response = await fetch(
    'https://example.g.kuroco.app/rcms-api/1/login',
    {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email, password })
    }
  )

  if (!response.ok) {
    const error = await response.json()
    throw new Error(error.errors?.[0]?.message || 'ログインに失敗しました')
  }

  return response.json()
}

Logout

async function logout(): Promise<void> {
  await fetch('https://example.g.kuroco.app/rcms-api/1/logout', {
    method: 'POST',
    credentials: 'include'
  })
}

Checking login status

async function checkAuth(): Promise<ProfileResponse | null> {
  try {
    const response = await fetch(
      'https://example.g.kuroco.app/rcms-api/1/profile',
      { credentials: 'include' }
    )
    if (!response.ok) return null
    return response.json()
  } catch {
    return null
  }
}

Member registration

async function signup(memberData: SignupData): Promise<void> {
  const response = await fetch(
    'https://example.g.kuroco.app/rcms-api/1/member/insert',
    {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(memberData)
    }
  )

  if (!response.ok) {
    const error = await response.json()
    throw new Error(error.errors?.[0]?.message || '登録に失敗しました')
  }
}

Nuxt.js integration

Detailed implementation example: references/nuxt.md See

Quick Start (Nuxt 3):

// composables/useKurocoApi.ts
export function useKurocoApi() {
  const config = useRuntimeConfig()

  async function get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
    const query = params ? `?${new URLSearchParams(params)}` : ''
    return await $fetch<T>(
      `${config.public.apiBase}/rcms-api/${config.public.apiId}/${endpoint}${query}`,
      { credentials: 'include' }
    )
  }

  return { get }
}

Next.js integration

Detailed implementation example: references/nextjs.md See

Quick Start (App Router):

// lib/api.ts
export async function apiGet<T>(endpoint: string): Promise<T> {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_BASE}/rcms-api/1/${endpoint}`,
    { credentials: 'include', cache: 'no-store' }
  )
  if (!response.ok) throw new Error(`API Error: ${response.status}`)
  return response.json()
}

KurocoFront integration

KurocoFront is a frontend hosting service provided by Kuroco (static hosting + CDN).

If delivering an SPA (client-side routing with the History API),kuroco_front.json の rewrites に {"source": ".*", "destination": "/index.html"} is required(without it, reloads, direct URL entry, and shared links will result in 404). source は .* Fixed, and/assets/ Do not write rules yourself that exclude, etc.^/.*$ With other approaches such as or exclusion patterns without anchors, JS and CSS are also replaced with index.html , resulting in a white screen. Recommended settings including why it breaks and the relationship with error_page are described in references/kuroco-front.md "SPA delivery"are summarized in.

kuroco_front.json settings (rewrites / redirects / Basic authentication / IP address restrictions), Private by default (until the user explicitly makes it public, robots.txt Disallow: / + the default of deploying with Basic authentication/IP restrictions applied), GitHub-linked deployment, Direct deployment from Admin MCP (files-create_temp_upload_url → kuroco_front-deploy → kuroco_front-history) procedures and constraints, see references/kuroco-front.md .

4 points to check when deploying directly from Admin MCP

The full procedure is in references/kuroco-front.md "Deployment method". What is placed here is only the parts where, even if you make a mistake, accepted may be returned and the failure may not remain in either errors or history.

  • The zip is thecontentsas the root: cd dist && zip -r ../dist.zip .of the build output. Before uploading, verify with unzip -l that index.html と kuroco_front.json exists directly under the root
  • kuroco_front-deploy の accepted is receipt of queue submission, not success. It takes 30 seconds to several minutes to be reflected
  • For reflection confirmation, both the line in kuroco_front-history and that the public URL response header x-rcms-hash・x-rcms-deploy corresponds to the hash of that line
  • If it is not satisfied even after 10 minutes, it is a failure. For troubleshooting, see references/kuroco-front.md "How to tell when it is not reflected"

Notes

Third-party cookie issue (SPA cookie authentication)

If the frontend and API are on different domains (e.g., www.example.com と {site_key}.g.kuroco.app), cross-site cookies are blocked by Safari's ITP etc., and cookie authentication does not work. There are 2 workarounds:

Workaround 1: Align to the same parent domain (when continuing cookie authentication)

Set a custom domain for the API (e.g., api.example.com) and align the parent domain with the frontend (www.example.com), and cookies will be treated as first-party. Settings: Register the API domain in the admin panel [Custom domain/TLS certificate] → update the API base URL in [Account settings].

Note Safari's 7-day cookie limit: Even if you align the parent domain, Safari limits the cookie expiration for this configuration to 7 days due to CNAME cloaking countermeasures. For tools used daily this is not a practical problem, but for sites with low login frequency, Safari users will need to log in again after 7 days.

Workaround 2: Switch to dynamic access token authentication (a reliable method for SPAs)

The access token is not stored in a Cookie but in X-RCMS-API-ACCESS-TOKEN is sent in the request header, so it is not subject to ITP or third-party cookie restrictions. This is recommended for SPAs and cross-domain configurations that require long-term login retention.

  1. Set API security to "dynamic access token", andtoken endpoint (Login::token) create
  2. Login: login → grant_token obtain → token POST to and access_token(+ refresh_token) obtain
  3. For subsequent requests, attach the X-RCMS-API-ACCESS-TOKEN: {access_token} header
  4. When expired, send to the refresh_token を token endpoint to reissue (set the period withaccess_token_lifespan / refresh_token_lifespan )

When storing tokens in localStorage, thoroughly implement XSS countermeasures (such as the HTML sanitization described later).

During development (localhost): By making the API appear to be on the same origin using the development server's proxy (such as Vite's server.proxy , etc.), you can develop without being subject to browser cookie restrictions.

HTML sanitization

v-html や dangerouslySetInnerHTML When using , be careful of XSS:

import DOMPurify from 'dompurify'
const sanitizedHtml = DOMPurify.sanitize(htmlContent)

Related Skills

  • /kuroco-api-content - API design/authentication patterns, content CRUD operations
  • /kuroco-admin-mcp - Administrative operations via Admin MCP

Related Documents

  • ../kuroco-docs/docs/tutorials-frontend-1.md(integrate-kuroco-with-nuxt) - Nuxt.js integration
  • ../kuroco-docs/docs/tutorials-auth-member-2.md(integrate-login) - Login implementation
  • ../kuroco-docs/docs/tutorials-auth-member-4.md(signup) - User registration
  • ../kuroco-docs/docs/tutorials-misc.md(beginners-guide) - Beginner's Guide
  • ../kuroco-docs/docs/tutorials-frontend-1.md(corporate-sample-site-to-ssg) - SSG support
  • Kuroco Sample Site Tutorial - Sample site build and deployment procedure