Next.jsReact企业官网

nextjs-job-board — Next.js 企业官网模板

作者 startupkit-app

基于 Kit 公共招聘 API 的 Next.js 招聘页面模板,包含职位列表、详情页、动态申请表单与人才库注册,可一键部署到 Vercel。

看看你的网站会是什么样

浏览真实页面截图,比较内容排版与手机效果。点击下方缩略图切换,放大查看整页细节。

2 个预览视图
桌面端首页1 / 2
桌面端截图首屏预览

由服务器浏览器实际访问页面后截取。

全部页面与视图 2

截图用于了解视觉与布局,交互效果请以实际项目为准。

采集于 2026-10-06查看来源

值得关注的模板亮点

从已有项目资料中,快速了解它的特点。

01

职位列表支持按部门、地点、雇佣类型、远程等 URL 参数筛选并分页

02

职位详情页包含薪资范围、招聘流程时间线、一次性阶段付款标注与 schema.org JobPosting JSON-LD

03

申请表单由 API schema 动态渲染,覆盖 8 种字段类型与 3 种问题类型,带内联校验与无障碍支持

04

简历直传存储:浏览器计算 MD5,Server Action 预签名后文件直接 PUT 到存储,不经过 Next.js 服务器

05

可选 Cloudflare Turnstile 防垃圾提交与 Webhook 缓存失效,未配置密钥时不生效

06

可选 Kit 职位分析,通过浏览器端 tracker 上报页面浏览、申请漏斗等事件

模板详细介绍

该模板是一个面向企业招聘场景的 Next.js 应用,数据来自 Kit(startupkit.app)的公开招聘 API。仓库采用 MIT 许可,README 说明可通过 Vercel 一键部署,或本地克隆后配置环境变量运行。

功能上,模板提供带 URL 筛选(部门、地点、雇佣类型、远程)和分页的职位列表、职位详情页(含薪资范围、招聘流程时间线、schema.org JobPosting JSON-LD),以及由 API schema 动态渲染的申请表单,覆盖文本、文本域、文件、URL、下拉、复选框、邮箱、电话等字段类型和文本、情景、单选三类问题,并带内联校验与无障碍支持。简历上传采用浏览器直传存储的方式,由 Server Action 预签名,避免大文件经过 Next.js 服务器。另有 /talent-pool 人才库注册表单,采用先同意后提交的流程并支持双重确认。

可选能力包括:通过发布密钥开启 Kit 职位分析(页面浏览、独立访客、来源、UTM、国家、设备、落地页及浏览到申请的漏斗),通过站点密钥启用 Cloudflare Turnstile 防垃圾提交,以及通过 Webhook 触发按标签的缓存失效,使新发布职位即时可见。未配置相应密钥时,这些功能不生效。

数据新鲜度依赖 Next.js 数据缓存:职位列表 revalidate 60 秒,职位详情与申请表单 revalidate 300 秒,人才库表单 revalidate 300 秒,均按标签缓存;Webhook 可进一步即时刷新。README 也指出 Webhook 不覆盖职位编辑与草稿回退两种情况。

使用限制:需要自行获取 Kit 的密钥(sk_…)并配置环境变量;分析功能必须使用可发布密钥(pk_…),且若密钥设置了来源白名单,站点域名需在白名单内;模板依赖 @startupkit-app/jobs 包,README 说明其版本固定为 ^0.5.0。

Next.js企业官网

适合你的项目吗?

适用场景

  • 为企业搭建独立域名的招聘页面,职位数据托管在 Kit 并对外展示
  • 需要动态申请表单(含简历上传、自定义问题、垃圾提交防护)的招聘站点
  • 希望将职位页与 Kit 招聘门户打通,保留活动归因并统一申请入口
  • 需要人才库注册表单,收集对当前职位不感兴趣但有意向的候选人
  • 希望用 Webhook 让新发布或关闭的职位在站点上即时生效

适合人群

  • 使用 Kit 作为招聘数据源并希望自建前端展示的团队
  • 熟悉 Next.js App Router 与 Vercel 部署的开发者
  • 需要 SEO 友好职位页与结构化数据(Google for Jobs)的招聘站点
  • 接受按环境变量配置外部密钥、并自行核对第三方素材许可的项目

上手与定制指南

结合仓库当前版本的说明,按下面的资料检查内容、配置与运行要求。

  1. 1

    在 Kit 的 Hiring → Career Portal → Public API Keys 创建密钥,部署时需提供 STARTUPKIT_SECRET_KEY(sk_…)

  2. 2

    可选环境变量包括 STARTUPKIT_BASE_URL、NEXT_PUBLIC_STARTUPKIT_PUBLISHABLE_KEY、NEXT_PUBLIC_TURNSTILE_SITE_KEY、KIT_WEBHOOK_SIGNING_SECRET、NEXT_PUBLIC_COMPANY_NAME

  3. 3

    本地运行:克隆仓库后执行 npm install,复制 .env.example 为 .env.local 并填入密钥,再运行 npm run dev

  4. 4

    启用分析需使用可发布密钥(pk_…);若密钥有来源白名单,站点域名需在白名单内

  5. 5

    Webhook 端点指向 POST /api/revalidate,需配置签名密钥;README 说明职位编辑与草稿回退不会触发事件

查看仓库使用说明

授权与来源资料

使用条件与限制

免费使用 · 保留许可声明

本次收录的是公开仓库中采用 MIT 许可的免费版本;免费范围为该版本代码,不代表外部服务或第三方素材免费。

使用时需要遵守

  • 允许免费使用、修改、商用和分发该版本代码。
  • 分发代码副本或实质性部分时,保留原作者版权声明和完整 MIT 许可声明。
  • 代码按现状提供;担保与责任限制以原许可证及适用法律为准。

额外费用与待核对事项

  • 演示图片、字体、图标及其他第三方素材需按各自许可核对,不能仅凭代码的 MIT 许可判断。
  • 域名、托管、数据库、支付或 AI 等外部服务可能另外收费。
  • 使用前必须在 Kit 平台创建并获取密钥(sk_…),模板本身不提供招聘数据,需依赖 Kit 外部服务。
  • STARTUPKIT_SECRET_KEY 为必填环境变量,缺少该密钥无法运行。
  • 启用分析功能需额外配置可发布密钥(pk_…),且仅可发布密钥有效。
  • 若密钥设置了来源白名单,站点域名必须加入白名单,否则分析事件上报会返回 403。
  • 依赖 @startupkit-app/jobs 版本固定为 ^0.5.0,升级需手动修改。
  • 一次性阶段付款字段需依赖 @startupkit-app/jobs 0.4 或更新版本才能解析。
  • Webhook 不覆盖职位编辑与草稿回退,这两类变更不会即时刷新,仍受 ISR 缓存窗口限制。
查看原文依据

Permission is hereby granted, free of charge

许可证原文

In Kit, go to **Hiring → Career Portal → Public API Keys** and create a key. You need the **secret key** (`sk_…`).

README 原文

`STARTUPKIT_SECRET_KEY` | **Yes** | Secret API key (`sk_…`) from Kit → Hiring → Career Portal → Public API Keys

README 原文

To turn it on, set `NEXT_PUBLIC_STARTUPKIT_PUBLISHABLE_KEY` to a **publishable** key (`pk_…`) from Kit → Hiring → Career Portal → Public API Keys. Only a publishable key works

README 原文

If the key has an origin allowlist, your site's origin (e.g. `https://careers.example.com`) must be on it, or every batch is a 403 `origin_not_allowed`.

README 原文

The dependency is pinned as `^0.5.0`.

README 原文

This template consumes that field through `@startupkit-app/jobs` 0.4 or newer.

README 原文

Kit emits no `job_posting.updated` event, so edits to a job's title or description are not pushed; and reverting a job to draft fires no event at all even though it removes the job from the API.

README 原文
https://github.com/startupkit-app/nextjs-job-board/blob/main/LICENSEhttps://github.com/startupkit-app/nextjs-job-board/blob/main/README.md

DeepSeek 根据仓库许可证和 README 整理 ·2026-10-06。结果仅覆盖已读取资料,依赖、图片、字体及后续条款变更以各自原文为准。

项目核对记录与介绍依据

模板资料

来源平台
GitHub
资料与维护参考分
资料较完整 · 80 / 100
技术栈
Next.js · React
网站类型
企业官网
这个分数如何计算

本站按许可资料(最高30分)、演示链接(12分)、预览图(10分)、Star数(15分)、记录的维护时间(15分)、描述完整度(8分)、功能记录(5分)和分类资料(5分)计算。它不是代码、安全或性能测试,也不是 Google 评分;有链接不代表已实测可用。

这个项目需要核对什么

记录的仓库更新时间
2026-10-06
截图检查日期
2026-10-06

已收录演示链接。请用你的内容与屏幕尺寸检查;有演示不代表表单、认证或支付已经可用。

目录记录的主要技术栈是 Next.js。请通过依赖清单和锁文件核对实际版本与托管要求。这些说明基于收录资料,不代表代码审计或部署实测。

查看具体选型方法 →

介绍的制作与核对状态

介绍由 AI 辅助整理目录与仓库资料。仓库作者不等于这篇介绍的审核者。

审核声明: [email protected] · 2026-10-06

查看当时使用的来源资料

SHA-256: 47a73ed9f7d0008f4665a1c30f2d29d7034c8247fda473d44f8d2b31d7fb54fa

2026-10-06T10:23:37.541Z

来源文件 / 仓库
# Kit Job Board — Next.js Template

A production-ready careers site built on the [Kit](https://startupkit.app) public hiring API.
Fork it, set one environment variable, and you have a fast, SEO-friendly job board with a
fully dynamic application form — resume uploads, custom questions, Turnstile spam protection,
and instant cache busting via webhooks.

**▶ Live demo: [nextjs-job-board-orcin.vercel.app](https://nextjs-job-board-orcin.vercel.app)** — this template deployed against real Kit job data.

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/startupkit-app/nextjs-job-board&env=STARTUPKIT_SECRET_KEY&envDescription=Secret%20API%20key%20from%20Kit%20Settings&envLink=https://startupkit.app/docs/public-jobs-api&demo-title=Kit%20Job%20Board&demo-description=A%20careers%20site%20on%20the%20Kit%20public%20hiring%20API&demo-url=https://nextjs-job-board-orcin.vercel.app)

## Features

- **Next.js App Router** (v16) — Server Components, Server Actions, ISR with tag-based revalidation
- **Job list** with URL-driven filters (department, location, employment type, remote) and pagination
- **Job detail pages** with salary ranges, hiring-process timeline, clearly labelled one-time
  stage payments, and schema.org `JobPosting` JSON-LD (Google for Jobs ready), statically
  generated via `generateStaticParams` + ISR
- **Application form rendered from the API schema** — all 8 field types (text, textarea, file,
  url, select, checkbox, email, phone) and all 3 question types (text, scenario, multiple choice),
  with inline validation errors, character counters, and full keyboard/screen-reader accessibility
- **Direct-to-storage resume uploads** — the browser computes an MD5 checksum, a Server Action
  presigns the upload with your secret key, and the file PUTs straight to storage. Large files
  never touch your Next.js server (no Vercel 4.5 MB body-limit issues), with a real progress bar
- **Talent-pool signup** at `/talent-pool` — a consent-first form for people who like the company
  but not today's openings. The consent checkbox starts unchecked and its disclosure is rendered
  from the API, the visitor's real IP is forwarded so the consent receipt records the person and
  not your server, and Kit confirms the address by double opt-in. Adapting this into your own
  codebase: hand your coding agent [TALENT_POOL.md](TALENT_POOL.md)
- **Optional Kit job analytics** — page views, unique visitors, traffic sources, UTM campaigns,
  countries, devices, landing pages and the view → apply funnel in Kit → Hiring → Analytics,
  reported from the visitor's browser by the SDK's tracker. Set a publishable key and it is on;
  leave it unset and it is a no-op. Adding it to a site forked from an older version of this
  template: hand your coding agent [ANALYTICS.md](ANALYTICS.md)
- **Optional Cloudflare Turnstile** spam protection (progressive enhancement — just set a site key)
- **Optional webhook revalidation** endpoint so newly published jobs appear instantly
- **Tailwind CSS v4**, dark mode, responsive, zero UI-kit dependencies — maximally forkable

## Quick start

### 1. Get an API key

In Kit, go to **Hiring → Career Portal → Public API Keys** and create a key. You need the
**secret key** (`sk_…`). It is only ever used server-side (Server Components and Server
Actions import it through a [`server-only`](https://www.npmjs.com/package/server-only) module),
so it never reaches the browser.

### 2. Deploy

Click the **Deploy** button above and paste your secret key when Vercel asks for
`STARTUPKIT_SECRET_KEY`. Done.

### Or run locally

```bash
git clone https://github.com/startupkit-app/nextjs-job-board
cd nextjs-job-board
npm install
cp .env.example .env.local   # then paste your sk_… key
npm run dev
```

## Environment variables

| Variable                         | Required | Description                                                                 |
| -------------------------------- | -------- | --------------------------------------------------------------------------- |
| `STARTUPKIT_SECRET_KEY`          | **Yes**  | Secret API key (`sk_…`) from Kit → Hiring → Career Portal → Public API Keys |
| `STARTUPKIT_BASE_URL`            | No       | API base URL. Defaults to `https://app.startupkit.app`                      |
| `NEXT_PUBLIC_STARTUPKIT_PUBLISHABLE_KEY` | No | Publishable key (`pk_…`) for browser-side job analytics. Unset = analytics off |
| `NEXT_PUBLIC_STARTUPKIT_BASE_URL` | No      | Browser-side counterpart of `STARTUPKIT_BASE_URL`, for a custom Kit domain only |
| `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | No       | Cloudflare Turnstile site key — renders the widget on the apply form        |
| `KIT_WEBHOOK_SIGNING_SECRET`     | No       | Signing secret of the Kit webhook endpoint targeting `POST /api/revalidate` |
| `NEXT_PUBLIC_COMPANY_NAME`       | No       | Company name for the header, titles, and JobPosting structured data         |

## Connect your external careers site to Kit

Keep job descriptions at `/jobs/:public_token`, using `job.id` from the public API.
In Kit's Career Portal settings, set this deployment as your external careers homepage and
enable external job pages after verifying a live job URL. Public Kit job links then
send visitors to the matching page on your site and retain campaign attribution.
Explicit `destination=kit` links and Kit's dedicated application URLs stay on Kit.
See [CAREERS_URLS.md](CAREERS_URLS.md) for the fixed route contract, nested deployments,
application behavior and verification steps.

## How freshness works (ISR + webhooks)

All API reads go through Next.js' data cache:

- Job list: `revalidate: 60`, tagged `jobs`
- Job detail / apply form: `revalidate: 300`, tagged `jobs` and `job-<token>`
- Talent-pool form: `revalidate: 300`, tagged `talent-pool`

So the site is never more than a minute or two stale, with zero configuration. For **instant**
updates, create a webhook endpoint in Kit (Integrations → Webhooks) pointing at:

```
POST https://your-site.example/api/revalidate
```

and set `KIT_WEBHOOK_SIGNING_SECRET` to that endpoint's signing secret.

Kit authenticates deliveries by **signature**, not by a shared bearer token — it sends
`X-Webhook-Signature` (HMAC-SHA256 of `<timestamp>.<body>`, hex) alongside `X-Webhook-Timestamp`
and `X-Webhook-Event`, and cannot attach a custom `Authorization` header. The route recomputes
the HMAC over the raw request body and rejects anything that does not match, or whose timestamp
is more than 5 minutes old.

Subscribe to the job lifecycle events:

- `job_posting.published` / `job_posting.reopened` — the role becomes visible on the public API
- `job_posting.paused` / `job_posting.closed` — the role starts returning 404

All four bust both the `jobs` list tag and that job's `job-<token>` tag. Pausing and closing
matter as much as publishing: without them a cached page keeps advertising a role that is no
longer open. `application.*` events refresh just the job they belong to, which is useful if
roles auto-close at an application cap.

Two things webhooks do **not** cover, so the ISR window still earns its keep: Kit emits no
`job_posting.updated` event, so edits to a job's title or description are not pushed; and
reverting a job to draft fires no event at all even though it removes the job from the API.

## Analytics

Kit's **Hiring → Analytics** dashboard is fed by page events. Kit's hosted career portal sends
them itself; a headless site has to, or the dashboard stays empty. Pages here are ISR-cached,
so the events are sent from the visitor's browser by the SDK's `createTracker`
([`lib/kit-tracker.ts`](lib/kit-tracker.ts)), and Kit records them as the same events the
hosted portal writes, so every chart fills in unchanged:

| Event                   | Sent from                                                           |
| ----------------------- | ------------------------------------------------------------------- |
| `job_board.viewed`      | `<TrackJobBoardView />` on the job list                             |
| `job.viewed`            | `<TrackJobView job={…} />` on the job detail page                   |
| `application.started`   | first keystroke, or focus other than autofocus, in the apply form   |
| `application.submitted` | the apply form's success state                                      |
| `talent_pool.joined`    | the talent-pool form's success state                                |

To turn it on, set `NEXT_PUBLIC_STARTUPKIT_PUBLISHABLE_KEY` to a **publishable** key (`pk_…`)
from Kit → Hiring → Career Portal → Public API Keys. Only a publishable key works: visitor
identity (masked IP + user agent) and geo are read from the browser's own request, so a
server-side relay would count every visitor as your server, and the tracker refuses an
`sk_…` key outright. If the key has an origin allowlist, your site's origin (e.g.
`https://careers.example.com`) must be on it, or every batch is a 403 `origin_not_allowed`.

Verify: open a job page, and DevTools → Network shows `POST /api/public/v1/events` → `202`
within a second; Kit → Hiring → Analytics shows the view shortly after. Without the key
nothing is sent and nothing logs. In development, tracker errors (bad key, missing origin,
a Kit server without the endpoint yet) are `console.warn`ed; in production they are silent,
and the page is never affected either way.

## About the SDK

This template talks to Kit through the published **[`@startupkit-app/jobs`](https://www.npmjs.com/package/@startupkit-app/jobs)**
package. [`lib/kit.ts`](lib/kit.ts) is the single place that imports it: it re-exports the types
and exposes a `kit` client authenticated with the secret key. That module is marked `server-only`,
so the key can never be bundled into a client component.

[`lib/kit-tracker.ts`](lib/kit-tracker.ts) is the one other import: the browser-side analytics
tracker, which only ever sees the publishable key.

The dependency is pinned as `^0.5.0`. A caret on a `0.x` version does not cross minor releases,
so picking up a new SDK minor is always a deliberate edit here rather than something `npm install`
does on its own — worth knowing when the API grows a field the template wants to read.

## API surface used

Base URL `https://app.startupkit.app`, auth via `Authorization: Bearer sk_…`:

| Endpoint                                       | Used for                                                  |
| ---------------------------------------------- | --------------------------------------------------------- |
| `GET /api/public/v1/jobs`                      | Job list, filters, pagination, `generateStaticParams`      |
| `GET /api/public/v1/jobs/:public_token`        | Job detail, application form schema, JSON-LD               |
| `POST /api/public/v1/direct_uploads`           | Presigning resume/file uploads (server action)             |
| `POST /api/public/v1/jobs/:token/applications` | Submitting applications (server action)                    |
| `GET /api/public/v1/talent_pool`               | Talent-pool form schema: fields, consent terms, resume     |
| `POST /api/public/v1/talent_pool/entries`      | Talent-pool signups (server action)                        |
| `POST /api/public/v1/events`                   | Job analytics events, from the browser with the `pk_…` key |

Error responses (`{ "error": { "code", "message", "fields" } }`) are surfaced as inline form
errors; `already_applied` (409), `already_in_talent_pool` (409), `consent_required` (422) and
`turnstile_failed` (422) get friendly dedicated messages.

On job details, hiring stages may include an optional
`compensation: { amount, currency }` object. The timeline labels the stage as **eligible for a
one-time payment** after completion, separately from the job's recurring salary. Older API
responses that omit `compensation` render exactly as before. This template consumes that field
through `@startupkit-app/jobs` 0.4 or newer.

## Project structure

```
app/
  page.tsx                     # Job list (ISR 60s, tag "jobs") + filters + pagination
  layout.tsx                   # Shell: header, footer, skip link
  loading.tsx / error.tsx / not-found.tsx
  opengraph-image.tsx          # Branded OG image
  jobs/[token]/
    page.tsx                   # Job detail (ISR 300s, JSON-LD, generateStaticParams)
    loading.tsx
    apply/
      page.tsx                 # Fetches the form schema server-side
      apply-form.tsx           # Client: dynamic field/question renderer, useActionState
      actions.ts               # Server Action: submitApplication
  talent-pool/
    page.tsx                   # Talent-pool schema + consent terms (ISR 300s)
    signup-form.tsx            # Client: consent-first signup form, useActionState
    actions.ts                 # Server Action: joinTalentPool (forwards the consent IP)
  api/revalidate/route.ts      # Optional webhook → revalidateTag
components/
  file-upload.tsx              # Client: MD5 → presign → direct PUT with progress
  kit-analytics.tsx            # Client: <TrackJobBoardView /> + <TrackJobView /> page-view events
  hiring-process.tsx           # Responsive stage timeline + optional one-time payments
  job-card.tsx  job-filters.tsx  salary.tsx  empty-state.tsx  turnstile.tsx
lib/
  kit.ts                       # server-only client instance + re-exported SDK types
  kit-tracker.ts               # browser analytics tracker (publishable key, no-op without one)
  kit-errors.ts                # shared submission-failure copy + API field-error shaping
  upload-actions.ts            # Server Action: createFileUpload (presign), shared by both forms
  md5.ts                       # vendored MD5 (base64) for upload checksums
  jsonld.ts                    # schema.org JobPosting builder
  sanitize.ts                  # HTML sanitizer for API-supplied markup
  format.ts  jobs.ts  talent-pool.ts  # display helpers, cached job + talent-pool fetchers
```

## Scripts

```bash
npm run dev         # start the dev server
npm run build       # production build
npm run start       # serve the production build
npm run lint        # eslint
npm run typecheck   # tsc --noEmit
npm test            # route/attribution helpers (Node 22.18+)
npm run test:browser # production browser regressions, mocked API only
```

For browser tests, install Chromium once with `npx playwright install chromium`.
The harness copies the app into an ignored temporary workspace, builds it against a local
fixture API, and checks the candidate flow both at `/` and with Next.js `basePath: "/careers"`.
It preserves your app and deployment configuration, excludes `.env*` files, and uses only
fixture applicants. GitHub Actions runs these checks on pull requests and `main` with Node 24.

## Changelog

Notable changes are recorded in [CHANGELOG.md](CHANGELOG.md).

## License

[MIT](LICENSE)
反馈内容错误

看看同类模板

对比同技术栈与用途的模板,找到更适合的视觉与内容结构。