Developer guide

Build a frontend with AI

Copy a ready prompt into Lovable, v0, Cursor or ChatGPT.

Every website has a personalised prompt in the dashboard: Website → API → AI prompt. It includes your real domain, languages and only the modules you have enabled. Pick a framework and style, then copy it or download it as Markdown or llms.txt.

Generic version (example.com, all modules):

# Build the public website for "Example Co" (example.com)

You are building a fast, SEO-friendly, multilingual website using **Next.js (App Router)**. All content comes from the CMS.af headless API. Do not hard-code content that the API provides.

## Languages & URLs
- Languages: `en` English (ltr), `fa` Dari (rtl), `ps` Pashto (rtl). Default: `en`.
- Every page lives under a language prefix: `/en/...`, `/fa/...`, `/ps/...`. `/` redirects to `/en`.
- For `fa` and `ps` set `<html lang dir="rtl">`; use CSS logical properties (margin-inline-start, padding-inline-end) and mirror directional icons.
- Add `<link rel="alternate" hreflang="..">` for every language and `x-default`, a canonical URL, and per-page `<title>`/meta description from the API `seo` fields.
- Include a language switcher that keeps the current page.
- Generate `sitemap.xml` with every language version and `robots.txt`.
- Use a font that supports Persian script for rtl languages (e.g. Vazirmatn).

## API
Base URL: `https://cms.af/api/public/v1/example.com`
- Public, no key needed, CORS enabled, JSON. Every response is `{ "data": ... }`; errors are `{ "error": "message" }` with 4xx/5xx.
- Lists accept `?page=1&per_page=20` and return `{ data: { page, per_page, total, items: [...] } }`.
- Responses are edge-cached (ETag). Cache on your side too (e.g. revalidate every 60s).
- Never put a secret API key in frontend code.

### Endpoints available for this website
- `GET https://cms.af/api/public/v1/example.com/{lang}/settings` — Site name, logo, contact details, social links and SEO for one language.
- `GET https://cms.af/api/public/v1/example.com/{lang}/posts` — Published blog posts, newest first. Query: `page` (Page number, default 1), `per_page` (1–50, default 10), `category` (Category slug), `tag` (Tag slug), `q` (Search text (max 100 chars)).
- `GET https://cms.af/api/public/v1/example.com/{lang}/posts/{slug}` — One published post with full body, category, tags and SEO.
- `GET https://cms.af/api/public/v1/example.com/{lang}/taxonomies` — All blog categories and tags.
- `GET https://cms.af/api/public/v1/example.com/{lang}/about` — The About page content.
- `GET https://cms.af/api/public/v1/example.com/{lang}/contacts` — Public contact information (phones, emails, addresses).
- `GET https://cms.af/api/public/v1/example.com/{lang}/projects` — Published projects. Query: `page` (Page number, default 1), `per_page` (1–50, default 12), `status` (planned | ongoing | completed), `q` (Search text (max 200 chars)).
- `GET https://cms.af/api/public/v1/example.com/{lang}/projects/{slug}` — One published project.
- `GET https://cms.af/api/public/v1/example.com/{lang}/services` — Published services with price info. Query: `page` (Page number, default 1), `per_page` (1–100, default 20), `filter` (featured).
- `GET https://cms.af/api/public/v1/example.com/{lang}/services/{slug}` — One service with full description and related projects.
- `GET https://cms.af/api/public/v1/example.com/{lang}/team` — Published team members (name, role, department, photo, social links). Query: `page` (Page number, default 1), `per_page` (1–100, default 20), `filter` (featured).
- `GET https://cms.af/api/public/v1/example.com/{lang}/pages` — Published custom pages (FAQ, Privacy, Terms…).
- `GET https://cms.af/api/public/v1/example.com/{lang}/pages/{slug}` — One page with content, template and FAQ items.
- `GET https://cms.af/api/public/v1/example.com/{lang}/menus` — Header and footer menus with translated labels, plus footer settings.
- `GET https://cms.af/api/public/v1/example.com/{lang}/footer` — Footer columns, description, copyright, contact and social links.
- `POST https://cms.af/api/public/v1/example.com/contact` — Submit a contact-form message (JSON body).

### Response shapes
Settings (`/{lang}/settings`) — load once for layout (site name, logo, contact, social, SEO, modules, alternates):
json
{
  "data": {
    "domain": "example.com",
    "locale": "fa",
    "dir": "rtl",
    "locales": ["en", "fa", "ps"],
    "site_name": "شرکت نمونه",
    "tagline": "...",
    "logo_url": "https://.../media/...webp",
    "contact": { "email": "...", "phone": "..." },
    "social": { "facebook": "https://..." },
    "seo": { "title": "...", "description": "...", "keywords": "..." },
    "modules": ["blog", "services", "..."],
    "alternates": { "en": "https://example.com/en", "fa": "https://example.com/fa", "ps": "https://example.com/ps" }
  }
}

List example:

json
{
  "data": {
    "page": 1,
    "per_page": 20,
    "total": 42,
    "items": [
      { "slug": "my-slug", "title": "...", "excerpt": "...", "cover_url": "https://...", "featured": false }
    ]
  }
}

Detail example (/{slug}):

json
{
  "data": {
    "slug": "my-slug",
    "title": "...",
    "excerpt": "...",
    "content": "Markdown…",
    "cover_url": "https://...",
    "published_at": "2026-01-01T00:00:00Z",
    "seo": { "title": "...", "description": "..." },
    "alternates": { "en": "/en/...", "fa": "/fa/...", "ps": "/ps/..." }
  }
}

Rich text fields (content, body) are Markdown — render them with a Markdown renderer and sanitize.

Build header and footer navigation from /{lang}/menus (items have type page | module | url and target; one level of children).

Pages to build

  • Home (/{lang}) — hero from settings, highlights from featured items of each module.
  • blog: list page /{lang}/blog and detail page /{lang}/.../{slug}
  • about: list page /{lang}/about
  • contacts: list page /{lang}/contacts
  • projects: list page /{lang}/projects and detail page /{lang}/.../{slug}
  • services: list page /{lang}/services and detail page /{lang}/.../{slug}
  • team_members: list page /{lang}/team and detail page /{lang}/.../{slug}
  • pages: list page /{lang}/pages and detail page /{lang}/.../{slug}
  • menus: list page /{lang}/menus
  • 404 page per language.

Contact form

POST https://cms.af/api/public/v1/example.com/contact with JSON { name, email or phone, subject, message, locale }. Add a hidden honeypot field website left empty. Show success/error messages in the current language.

Design

Clean, modern, professional, mobile-first. Use the logo and brand from settings.

  • Fully responsive, accessible (semantic HTML, alt text from API), fast (lazy images, no layout shift).
  • Show friendly loading and empty states when a list has no items.