@cavuno/board 2.0.5 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +12 -3
- package/dist/{_spec-BKtVFcV9.d.mts → _spec-nkWAraS0.d.mts} +4 -18
- package/dist/{_spec-BKtVFcV9.d.ts → _spec-nkWAraS0.d.ts} +4 -18
- package/dist/bin.mjs +40 -57
- package/dist/{board-3Xj_Y-Tx.d.ts → board-NE98PlwN.d.ts} +2 -3
- package/dist/{board-pNN710Zc.d.mts → board-muu8BI8P.d.mts} +2 -3
- package/dist/doctor.js +21 -47
- package/dist/doctor.mjs +24 -50
- package/dist/filters.d.mts +2 -2
- package/dist/filters.d.ts +2 -2
- package/dist/format.d.mts +3 -3
- package/dist/format.d.ts +3 -3
- package/dist/index.d.mts +11 -27
- package/dist/index.d.ts +11 -27
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/dist/{jobs-C4qRfCdP.d.ts → jobs-BiEvL9d7.d.ts} +1 -1
- package/dist/{jobs-k84C0v_8.d.mts → jobs-lVvKCBCU.d.mts} +1 -1
- package/dist/{salaries--J5mTylN.d.ts → salaries-BahBpxWT.d.ts} +2 -2
- package/dist/{salaries-C9YLO5NG.d.mts → salaries-ChSqDBAM.d.mts} +2 -2
- package/dist/{search-CE_qQiM7.d.mts → search-CCyFWPi3.d.mts} +1 -1
- package/dist/{search-CLRQ_El9.d.ts → search-CyRvVMUp.d.ts} +1 -1
- package/dist/seo.d.mts +4 -4
- package/dist/seo.d.ts +4 -4
- package/dist/server.d.mts +5 -5
- package/dist/server.d.ts +5 -5
- package/dist/sitemap.d.mts +5 -5
- package/dist/sitemap.d.ts +5 -5
- package/dist/skills.d.mts +15 -4
- package/dist/skills.d.ts +15 -4
- package/dist/skills.js +30 -7
- package/dist/skills.mjs +30 -8
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/package.json +1 -11
- package/skills/cavuno-board-account/SKILL.md +58 -66
- package/skills/cavuno-board-api-client/SKILL.md +78 -0
- package/skills/cavuno-board-applications/SKILL.md +42 -52
- package/skills/cavuno-board-auth/SKILL.md +39 -60
- package/skills/cavuno-board-blog/SKILL.md +64 -49
- package/skills/cavuno-board-companies/SKILL.md +75 -53
- package/skills/cavuno-board-errors/SKILL.md +32 -45
- package/skills/cavuno-board-filters/SKILL.md +68 -75
- package/skills/cavuno-board-format/SKILL.md +65 -66
- package/skills/cavuno-board-i18n/SKILL.md +43 -68
- package/skills/cavuno-board-job-alerts/SKILL.md +72 -57
- package/skills/cavuno-board-jobs/SKILL.md +67 -55
- package/skills/cavuno-board-messaging/SKILL.md +57 -59
- package/skills/cavuno-board-paywall/SKILL.md +52 -54
- package/skills/cavuno-board-post-a-job/SKILL.md +122 -0
- package/skills/cavuno-board-salaries/SKILL.md +77 -50
- package/skills/cavuno-board-search-suggestions/SKILL.md +86 -0
- package/skills/cavuno-board-seo/BLOG.md +40 -0
- package/skills/cavuno-board-seo/JOB_AND_BREADCRUMBS.md +49 -0
- package/skills/cavuno-board-seo/LISTING.md +36 -0
- package/skills/cavuno-board-seo/SALARY.md +61 -0
- package/skills/cavuno-board-seo/SKILL.md +34 -161
- package/skills/cavuno-board-server-sessions/SKILL.md +147 -0
- package/skills/cavuno-board-setup/SKILL.md +46 -79
- package/skills/cavuno-board-sitemap/SKILL.md +78 -91
- package/skills/cavuno-board-smoke-test/SKILL.md +38 -69
- package/skills/manifest.json +43 -57
- package/dist/theme.d.mts +0 -115
- package/dist/theme.d.ts +0 -115
- package/dist/theme.js +0 -195
- package/dist/theme.mjs +0 -174
- package/skills/cavuno-board-client/SKILL.md +0 -89
- package/skills/cavuno-board-job-posting/SKILL.md +0 -116
- package/skills/cavuno-board-server/SKILL.md +0 -229
- package/skills/cavuno-board-suggest/SKILL.md +0 -119
- package/skills/cavuno-board-theme/SKILL.md +0 -57
- package/skills/flavors/tanstack-start/SKILL.md +0 -102
|
@@ -1,42 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cavuno-board-sitemap
|
|
3
|
-
description:
|
|
3
|
+
description: Board sitemap generation with @cavuno/board/sitemap. Use for sitemap indexes, bucket routes, XML rendering, catalog walking, chunking, or robots.txt discovery.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Sitemap
|
|
6
|
+
# Sitemap generation
|
|
7
7
|
|
|
8
|
-
`@cavuno/board/sitemap`
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
sitemap corpus lines up bucket-for-bucket with what cavuno.com would emit.
|
|
8
|
+
`@cavuno/board/sitemap` implements the hosted eight-bucket sitemap: an index at
|
|
9
|
+
`/sitemap.xml` points to ordinary `<urlset>` files for `marketing`,
|
|
10
|
+
`jobs-categories`, `jobs-skills`, `jobs-locations`, `jobs-details`,
|
|
11
|
+
`companies`, `salaries`, and optionally `blog`.
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
Structured data and head tags use `cavuno-board-seo`. The host app owns feeds.
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
`SITEMAP_CHUNK_SIZE` (45,000), `chunk`, `bucketFilename` /
|
|
18
|
-
`parseBucketFilename`, `renderUrlset`, `renderSitemapIndex`.
|
|
19
|
-
- **The walker** (opinionated, injected I/O): `listedBuckets(board)` and
|
|
20
|
-
`buildBucketUrls(board, origin, bucket)` take your `BoardSdk` instance
|
|
21
|
-
and return plain URL strings with the hosted rules applied — you never
|
|
22
|
-
re-derive the SEO policy.
|
|
15
|
+
## Use both tiers
|
|
23
16
|
|
|
24
|
-
|
|
17
|
+
The pure XML tier exports `SITEMAP_BUCKETS`, `SITEMAP_CHUNK_SIZE` (45,000),
|
|
18
|
+
`chunk`, `bucketFilename`, `parseBucketFilename`, `renderUrlset`, and
|
|
19
|
+
`renderSitemapIndex`. The catalog tier exports `listedBuckets(board)` and
|
|
20
|
+
`buildBucketUrls(board, origin, bucket)`; it walks the SDK and applies the
|
|
21
|
+
hosted indexing policy.
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
- Deciding which listing pages deserve indexing (the walker already does).
|
|
23
|
+
## Serve the index
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- Feeds (RSS/Atom) — app-owned.
|
|
33
|
-
|
|
34
|
-
## The two routes
|
|
35
|
-
|
|
36
|
-
The index lists one entry per bucket; each bucket route parses its filename
|
|
37
|
-
back to a bucket + chunk and renders a urlset. Empty buckets render a valid
|
|
38
|
-
empty urlset — only `blog` is dropped from the index when the feature is
|
|
39
|
-
off (`listedBuckets` handles that).
|
|
25
|
+
List every non-empty chunk filename for every listed bucket. Keep one filename
|
|
26
|
+
for an empty bucket so its route returns a valid empty urlset. `listedBuckets`
|
|
27
|
+
removes blog when the feature is off.
|
|
40
28
|
|
|
41
29
|
```ts snippet
|
|
42
30
|
import {
|
|
@@ -45,15 +33,13 @@ import {
|
|
|
45
33
|
bucketFilename,
|
|
46
34
|
chunk,
|
|
47
35
|
listedBuckets,
|
|
48
|
-
parseBucketFilename,
|
|
49
36
|
renderSitemapIndex,
|
|
50
|
-
renderUrlset,
|
|
51
37
|
} from '@cavuno/board/sitemap';
|
|
52
38
|
|
|
53
|
-
// GET /sitemap.xml — one <sitemap> per listed bucket (plus -2, -3… chunks).
|
|
54
39
|
const origin = 'https://jobs.example.com';
|
|
55
40
|
const buckets = await listedBuckets(board);
|
|
56
41
|
const locs: string[] = [];
|
|
42
|
+
|
|
57
43
|
for (const bucket of buckets) {
|
|
58
44
|
const urls = await buildBucketUrls(board, origin, bucket);
|
|
59
45
|
const chunks = chunk(urls, SITEMAP_CHUNK_SIZE);
|
|
@@ -61,87 +47,88 @@ for (const bucket of buckets) {
|
|
|
61
47
|
locs.push(`${origin}/sitemap/${bucketFilename(bucket, i)}`);
|
|
62
48
|
}
|
|
63
49
|
}
|
|
50
|
+
|
|
64
51
|
return xmlResponse(renderSitemapIndex(locs));
|
|
65
52
|
```
|
|
66
53
|
|
|
54
|
+
## Serve a bucket file
|
|
55
|
+
|
|
56
|
+
Parse the filename, rebuild that bucket, select its zero-based chunk, and
|
|
57
|
+
render it. A filename outside the bucket grammar resolves to 404.
|
|
58
|
+
|
|
67
59
|
```ts snippet
|
|
68
|
-
|
|
60
|
+
import {
|
|
61
|
+
SITEMAP_CHUNK_SIZE,
|
|
62
|
+
buildBucketUrls,
|
|
63
|
+
chunk,
|
|
64
|
+
parseBucketFilename,
|
|
65
|
+
renderUrlset,
|
|
66
|
+
} from '@cavuno/board/sitemap';
|
|
67
|
+
|
|
69
68
|
const parsed = parseBucketFilename(params.file);
|
|
70
69
|
if (!parsed) return notFound();
|
|
70
|
+
|
|
71
71
|
const urls = await buildBucketUrls(board, origin, parsed.bucket);
|
|
72
72
|
const page = chunk(urls, SITEMAP_CHUNK_SIZE)[parsed.chunkIndex] ?? [];
|
|
73
73
|
return xmlResponse(renderUrlset(page));
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
`renderUrlset` also accepts `{ url, lastModified?, images? }`
|
|
77
|
-
|
|
78
|
-
`
|
|
76
|
+
`renderUrlset` also accepts `{ url, lastModified?, images? }`; `Date` values
|
|
77
|
+
serialize to ISO 8601. `renderSitemapIndex` accepts strings or
|
|
78
|
+
`{ url, lastModified? }`. The hosted format omits `changefreq` and `priority`.
|
|
79
79
|
|
|
80
|
-
##
|
|
80
|
+
## Keep the walker policy intact
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
`buildBucketUrls` is the policy boundary:
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
- Taxonomy and location pages enter the sitemap at five distinct jobs,
|
|
85
|
+
`MIN_JOBS_PER_INDEXED_PAGE`.
|
|
86
|
+
- Marketing URLs follow context feature flags for impressum, talent directory,
|
|
87
|
+
and employers. Blog is listed only when `features.blog` is enabled.
|
|
88
|
+
- Salary index reads use `context().language`, producing board-language
|
|
89
|
+
canonical salary slugs. Job, company, market, and blog slugs arrive
|
|
90
|
+
canonical on the wire.
|
|
91
|
+
- Collections with `count` enumerate offsets in parallel up to the API's
|
|
92
|
+
10,000-offset window. Cursor walks stop after 200 pages. Both paths warn when
|
|
93
|
+
their backstop truncates output.
|
|
94
|
+
- XML escaping and hosted byte layout come from `renderUrlset` and
|
|
95
|
+
`renderSitemapIndex`.
|
|
87
96
|
|
|
88
|
-
|
|
97
|
+
Cursor and offset order may move while a large board changes. That is safe for
|
|
98
|
+
this deduplicated sitemap heuristic. Use an explicit sort or search with
|
|
99
|
+
`board.jobs.list` for a stable ordered export.
|
|
89
100
|
|
|
90
|
-
|
|
91
|
-
only with ≥5 distinct jobs (`MIN_JOBS_PER_INDEXED_PAGE`) — below that,
|
|
92
|
-
the page is thin content that wastes crawl budget.
|
|
93
|
-
- **Feature gating**: `/impressum`, `/talent`, `/employers` appear in the
|
|
94
|
-
marketing bucket only when `context().features` enables them; the blog
|
|
95
|
-
bucket exists only when `features.blog` is on.
|
|
96
|
-
- **Board language**: salary-index reads pass `context().language`, so a
|
|
97
|
-
non-English board emits board-language canonical salary slugs (jobs,
|
|
98
|
-
companies, and blog slugs arrive canonical on the wire already). No
|
|
99
|
-
locale parameter to thread.
|
|
100
|
-
- **Pagination backstops**: offset enumeration runs in parallel when the
|
|
101
|
-
envelope carries `count` (capped at the API's 10,000-offset window);
|
|
102
|
-
cursor walks cap at 200 pages. Both warn on truncation instead of
|
|
103
|
-
hanging a build.
|
|
101
|
+
## Preserve the named v1 exclusions
|
|
104
102
|
|
|
105
|
-
|
|
103
|
+
The walker omits families that v1 can discover only through per-slug N+1
|
|
104
|
+
reads: cross-axis salary pages (title×location, skill×location,
|
|
105
|
+
company×category, and per-entity salary indexes) and job
|
|
106
|
+
place×category/place×skill combinations. Internal links keep them reachable
|
|
107
|
+
until a bulk-pairs endpoint lets the walker add them.
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
churning board — two chunk requests may see slightly different orderings.
|
|
109
|
-
That is harmless for a sitemap (URLs dedupe and the ≥5 counts are a
|
|
110
|
-
heuristic), but do NOT reuse the walker as a general "export all jobs in
|
|
111
|
-
order" tool; for stable ordering, pass an explicit sort/query to
|
|
112
|
-
`board.jobs.list` yourself.
|
|
109
|
+
## Publish discovery
|
|
113
110
|
|
|
114
|
-
|
|
111
|
+
At the site root, point robots.txt at the index:
|
|
115
112
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- Cross-axis salary pages (title×location, skill×location,
|
|
121
|
-
company×category, and the per-entity `/locations` · `/titles` ·
|
|
122
|
-
`/skills` salary index pages).
|
|
123
|
-
- Jobs place×category / place×skill combination listings.
|
|
113
|
+
```txt
|
|
114
|
+
Sitemap: https://jobs.example.com/sitemap.xml
|
|
115
|
+
```
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
the walker picks them up additively — don't hand-enumerate them.
|
|
117
|
+
## Completion gate
|
|
127
118
|
|
|
128
|
-
|
|
119
|
+
Finish only after every applicable check passes:
|
|
129
120
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
- `/sitemap.xml` lists all enabled buckets, omits blog when disabled, and every
|
|
122
|
+
listed file returns valid XML, including empty buckets.
|
|
123
|
+
- A taxonomy page with four distinct jobs is absent and one with five is
|
|
124
|
+
present.
|
|
125
|
+
- `jobs-details-2.xml` round-trips through `parseBucketFilename`; an unknown
|
|
126
|
+
filename returns 404.
|
|
127
|
+
- More than 45,000 URLs produce numbered `-2`, `-3`, and later files without
|
|
128
|
+
dropping or duplicating a URL.
|
|
129
|
+
- robots.txt points to the absolute `/sitemap.xml` URL.
|
|
130
|
+
- No excluded N+1 URL family is enumerated outside the walker.
|
|
138
131
|
|
|
139
|
-
##
|
|
132
|
+
## Cavuno SDK reference
|
|
140
133
|
|
|
141
|
-
|
|
142
|
-
feature is off) and every listed file returns valid XML.
|
|
143
|
-
- [ ] A category with 4 jobs is absent from `jobs-categories.xml`; one with
|
|
144
|
-
5 is present.
|
|
145
|
-
- [ ] `jobs-details-2.xml` style chunk names round-trip through
|
|
146
|
-
`parseBucketFilename` and unknown filenames 404.
|
|
147
|
-
- [ ] robots.txt points at `/sitemap.xml`.
|
|
134
|
+
For setup and API details beyond this workflow, use the [Cavuno Board SDK documentation](https://cavuno.com/docs/sdk).
|
|
@@ -1,104 +1,73 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cavuno-board-smoke-test
|
|
3
|
-
description:
|
|
3
|
+
description: Prove a Cavuno board integration at runtime. Use after initial setup, an @cavuno/board upgrade, a board-key rotation, or when rendered board data is unexpectedly missing.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Smoke-
|
|
6
|
+
# Smoke-test a Cavuno board
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
app reaches the right board with the right credentials, or that gating,
|
|
10
|
-
auth, and SEO surfaces behave. Verify at runtime, in this order.
|
|
8
|
+
Follow the layers in order. Each passing layer narrows the next failure to app wiring rather than credentials or the public API.
|
|
11
9
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
- Right after `cavuno-board-setup` completes.
|
|
15
|
-
- After upgrading `@cavuno/board` or rotating the `pk_…` key.
|
|
16
|
-
- When any surface renders empty and you don't know which layer is wrong.
|
|
17
|
-
|
|
18
|
-
## 0 — Run `doctor` first (deterministic pass)
|
|
10
|
+
## 1. Run doctor
|
|
19
11
|
|
|
20
12
|
```bash
|
|
21
13
|
PUBLIC_CAVUNO_BOARD=pk_... \
|
|
22
14
|
npx @cavuno/board doctor --frontend http://localhost:3000
|
|
23
15
|
```
|
|
24
16
|
|
|
25
|
-
Doctor
|
|
26
|
-
read probes (home/jobs render, JobPosting JSON-LD, sitemap, robots) as
|
|
27
|
-
pass/fail/skip with a non-zero exit on failure — anything it SKIPS is
|
|
28
|
-
named in its summary and still needs the manual checks below. Use the
|
|
29
|
-
rest of this skill for the behavioral checks doctor does not automate
|
|
30
|
-
(auth flows, gating semantics, production build).
|
|
17
|
+
Doctor checks environment shape, API reachability, installed skills, and—when `--frontend` is present—rendered pages, sitemap, robots rules, and JobPosting structured data. It is read-only and reports every skipped check.
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
installed skills, and—when `--frontend` is provided—rendered pages, sitemaps,
|
|
34
|
-
robots rules, and JobPosting structured data. It never creates users,
|
|
35
|
-
applications, or alerts and needs no Cavuno operator credentials.
|
|
19
|
+
**Complete when:** doctor exits zero and every skip that applies to an implemented surface is recorded for manual verification below.
|
|
36
20
|
|
|
37
|
-
##
|
|
21
|
+
## 2. Probe the public API
|
|
38
22
|
|
|
39
|
-
Use the
|
|
23
|
+
Use the exact board value and API origin read by the app:
|
|
40
24
|
|
|
41
25
|
```bash
|
|
42
26
|
CAVUNO_API_URL="${PUBLIC_CAVUNO_API_URL:-https://api.cavuno.com}"
|
|
43
27
|
|
|
44
|
-
# Board context: MUST return JSON with "object": "public_board" and your
|
|
45
|
-
# board's name — not an HTML error page, not {"error":{"code":"boards_not_found"}}.
|
|
46
28
|
curl -s "$CAVUNO_API_URL/v1/boards/$PUBLIC_CAVUNO_BOARD" | head -c 300
|
|
47
|
-
|
|
48
|
-
# Jobs list: MUST return {"object":"list", ... "data":[...]}. An empty data
|
|
49
|
-
# array on a board you know has jobs means the wrong board identifier.
|
|
50
29
|
curl -s "$CAVUNO_API_URL/v1/boards/$PUBLIC_CAVUNO_BOARD/jobs?limit=2" | head -c 300
|
|
51
|
-
|
|
52
|
-
# Error envelope: a bogus job slug MUST return the v1 error shape with
|
|
53
|
-
# "code":"jobs_not_found" — anything else means a proxy is rewriting responses.
|
|
54
30
|
curl -s "$CAVUNO_API_URL/v1/boards/$PUBLIC_CAVUNO_BOARD/jobs/definitely-not-a-job"
|
|
55
31
|
```
|
|
56
32
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
The context response has `"object":"public_board"` and the expected name. The jobs response has `"object":"list"` and a `data` array. The fabricated slug has the v1 error code `jobs_not_found`. A protected board instead returns `board_password_required` for content reads; that is the expected pre-grant state.
|
|
34
|
+
|
|
35
|
+
Pause here when the API is unreachable, resolves a different board, or returns a non-v1 envelope. Report this layer as the blocker and preserve app code.
|
|
36
|
+
|
|
37
|
+
**Complete when:** identity, list shape, and error-envelope probes match the expected board, or the protected-board challenge is confirmed.
|
|
38
|
+
|
|
39
|
+
## 3. Probe the development app
|
|
40
|
+
|
|
41
|
+
Start the app and verify:
|
|
42
|
+
|
|
43
|
+
- The shell renders the name and logo from `board.context()`.
|
|
44
|
+
- A listing renders real jobs and links to `/companies/:companySlug/jobs/:jobSlug`.
|
|
45
|
+
- A fabricated job route renders the app's not-found state.
|
|
46
|
+
|
|
47
|
+
**Complete when:** all three behaviors are visible through the app rather than inferred from types or source code.
|
|
60
48
|
|
|
61
|
-
##
|
|
49
|
+
## 4. Exercise each implemented stateful surface
|
|
62
50
|
|
|
63
|
-
|
|
51
|
+
Run only the branches the app exposes:
|
|
64
52
|
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
|
|
53
|
+
- **Auth:** register, observe verification state, log in, prove `me.retrieve`, log out, then prove the app handles the next authenticated read as signed out.
|
|
54
|
+
- **Password gate:** confirm the anonymous challenge, verify the password, retry successfully, then confirm a wrong password renders `board_password_invalid`.
|
|
55
|
+
- **Saved jobs and applications:** save and reload to prove server persistence; submit the same application twice and confirm one application identity.
|
|
56
|
+
- **Paywall:** compare the anonymous `gatedCount` state with the entitled view at the same URL.
|
|
57
|
+
- **Alerts:** submit twice and confirm both responses preserve the uniform `submitted` state.
|
|
70
58
|
|
|
71
|
-
|
|
59
|
+
Pause a branch when its board password or test account is unavailable and report the exact credential needed.
|
|
72
60
|
|
|
73
|
-
|
|
74
|
-
read (`me.retrieve`) succeeds; after `auth.logout()` the same read fails
|
|
75
|
-
with a 401 that the app handles by signing out, not looping.
|
|
76
|
-
- **Password gate**: with protection enabled, an anonymous content read
|
|
77
|
-
redirects to the password page; `password.verify()` + retry renders
|
|
78
|
-
content; a wrong password shows `board_password_invalid` messaging.
|
|
79
|
-
- **Saved jobs / apply**: save → reload → still saved (server state, not
|
|
80
|
-
local); a second apply to the same job returns the same application
|
|
81
|
-
(idempotent), not a duplicate.
|
|
82
|
-
- **Paywall** (gated boards): anonymous list shows the `gatedCount` upsell;
|
|
83
|
-
an entitled login makes the same URL return the ungated view.
|
|
84
|
-
- **Alerts**: subscribe → `status: "submitted"`; repeat → same uniform `"submitted"` (never reveals already-subscribed).
|
|
61
|
+
**Complete when:** every implemented branch passes or has an explicit credential blocker; logout and refresh paths terminate without loops.
|
|
85
62
|
|
|
86
|
-
##
|
|
63
|
+
## 5. Prove the production artifact
|
|
87
64
|
|
|
88
|
-
|
|
89
|
-
tree-shake). Run the app's real build, boot the production output, and
|
|
90
|
-
repeat step 2 against it. `import 'server-only'`-style boundaries and env
|
|
91
|
-
prefixes (`VITE_`, `NEXT_PUBLIC_`) frequently pass dev and fail prod.
|
|
65
|
+
Run the app's production build, boot that output, and repeat the three app probes from step 3 against it. Use the app's real production command and environment-loading path.
|
|
92
66
|
|
|
93
|
-
|
|
67
|
+
**Complete when:** the build succeeds and the running production artifact passes the shell, listing/detail-link, and not-found probes.
|
|
94
68
|
|
|
95
|
-
|
|
96
|
-
are app-owned. This skill verifies board wiring only.
|
|
69
|
+
The smoke test covers Cavuno board wiring. Performance, visual regression, and broader SEO scoring belong to their dedicated project checks.
|
|
97
70
|
|
|
98
|
-
##
|
|
71
|
+
## Cavuno SDK reference
|
|
99
72
|
|
|
100
|
-
|
|
101
|
-
credentials/network, not code — do not "fix" app code to compensate); the
|
|
102
|
-
API returns codes the app has no branch for; or a check needs a credential
|
|
103
|
-
you don't have (board password, test account). Never commit real
|
|
104
|
-
credentials while fixing findings.
|
|
73
|
+
For setup and API details beyond this workflow, use the [Cavuno Board SDK documentation](https://cavuno.com/docs/sdk).
|
package/skills/manifest.json
CHANGED
|
@@ -1,173 +1,159 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "
|
|
2
|
+
"version": "3.1.0",
|
|
3
3
|
"skills": [
|
|
4
4
|
{
|
|
5
5
|
"name": "cavuno-board-account",
|
|
6
|
-
"description": "Candidate
|
|
6
|
+
"description": "Candidate self-service boundary with @cavuno/board. Use for account, profile, resume onboarding, avatar, experience, education, skills, languages, or notification preferences.",
|
|
7
7
|
"path": "skills/cavuno-board-account/SKILL.md",
|
|
8
8
|
"framework": null,
|
|
9
9
|
"category": "core"
|
|
10
10
|
},
|
|
11
|
+
{
|
|
12
|
+
"name": "cavuno-board-api-client",
|
|
13
|
+
"description": "Configure the @cavuno/board API client. Use when creating the shared client, adding global hooks or headers, passing framework fetch options, or calling an endpoint through the typed escape hatch.",
|
|
14
|
+
"path": "skills/cavuno-board-api-client/SKILL.md",
|
|
15
|
+
"framework": null,
|
|
16
|
+
"category": "core"
|
|
17
|
+
},
|
|
11
18
|
{
|
|
12
19
|
"name": "cavuno-board-applications",
|
|
13
|
-
"description": "
|
|
20
|
+
"description": "Candidate application handoff with @cavuno/board. Use for native or guest apply, application tracking, resume attachment, withdrawal, and saved jobs.",
|
|
14
21
|
"path": "skills/cavuno-board-applications/SKILL.md",
|
|
15
22
|
"framework": null,
|
|
16
23
|
"category": "core"
|
|
17
24
|
},
|
|
18
25
|
{
|
|
19
26
|
"name": "cavuno-board-auth",
|
|
20
|
-
"description": "Authenticate board users
|
|
27
|
+
"description": "Authenticate Cavuno board users. Use for registration, login, logout, token refresh, email verification, password recovery, magic links, OAuth, or authenticated board-user calls.",
|
|
21
28
|
"path": "skills/cavuno-board-auth/SKILL.md",
|
|
22
29
|
"framework": null,
|
|
23
30
|
"category": "core"
|
|
24
31
|
},
|
|
25
32
|
{
|
|
26
33
|
"name": "cavuno-board-blog",
|
|
27
|
-
"description": "
|
|
34
|
+
"description": "Public blog reads with @cavuno/board. Use for post archives, post detail, adjacent or similar posts, tag and author pages, or blog search.",
|
|
28
35
|
"path": "skills/cavuno-board-blog/SKILL.md",
|
|
29
36
|
"framework": null,
|
|
30
37
|
"category": "core"
|
|
31
38
|
},
|
|
32
|
-
{
|
|
33
|
-
"name": "cavuno-board-client",
|
|
34
|
-
"description": "Create and configure the @cavuno/board client — the pk_ board identifier, optional API-origin override, global headers, hooks, per-call FetchOptions, and the rule that keeps one shared instance safe under SSR.",
|
|
35
|
-
"path": "skills/cavuno-board-client/SKILL.md",
|
|
36
|
-
"framework": null,
|
|
37
|
-
"category": "core"
|
|
38
|
-
},
|
|
39
39
|
{
|
|
40
40
|
"name": "cavuno-board-companies",
|
|
41
|
-
"description": "
|
|
41
|
+
"description": "Company catalog reads with @cavuno/board. Use for company indexes, market archives, profiles, company job rails, similar companies, or company salary pages.",
|
|
42
42
|
"path": "skills/cavuno-board-companies/SKILL.md",
|
|
43
43
|
"framework": null,
|
|
44
44
|
"category": "core"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"name": "cavuno-board-errors",
|
|
48
|
-
"description": "
|
|
48
|
+
"description": "Classify Board API failures and board-password challenges. Use when mapping SDK errors to UI states, retries, support diagnostics, or password-gated access.",
|
|
49
49
|
"path": "skills/cavuno-board-errors/SKILL.md",
|
|
50
50
|
"framework": null,
|
|
51
51
|
"category": "core"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"name": "cavuno-board-filters",
|
|
55
|
-
"description": "
|
|
55
|
+
"description": "Listing-filter contracts with @cavuno/board. Use for job filter controls, sort controls, listing URL validation, or taxonomy-backed filter options.",
|
|
56
56
|
"path": "skills/cavuno-board-filters/SKILL.md",
|
|
57
57
|
"framework": null,
|
|
58
58
|
"category": "core"
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
"name": "cavuno-board-format",
|
|
62
|
-
"description": "
|
|
62
|
+
"description": "Board-language display formatting with @cavuno/board/format. Use for salary ranges, dates, job labels, location labels, card conversion, or salary metadata copy.",
|
|
63
63
|
"path": "skills/cavuno-board-format/SKILL.md",
|
|
64
64
|
"framework": null,
|
|
65
65
|
"category": "core"
|
|
66
66
|
},
|
|
67
67
|
{
|
|
68
68
|
"name": "cavuno-board-i18n",
|
|
69
|
-
"description": "
|
|
69
|
+
"description": "One-seam board localization with @cavuno/board. Use when localizing UI chrome, adding locale routing, merging operator labels, or preserving board-language content.",
|
|
70
70
|
"path": "skills/cavuno-board-i18n/SKILL.md",
|
|
71
71
|
"framework": null,
|
|
72
72
|
"category": "core"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"name": "cavuno-board-job-alerts",
|
|
76
|
-
"description": "
|
|
76
|
+
"description": "Job-alert two-lane model with @cavuno/board. Use for anonymous double opt-in, token-managed preferences, or signed-in alert CRUD.",
|
|
77
77
|
"path": "skills/cavuno-board-job-alerts/SKILL.md",
|
|
78
78
|
"framework": null,
|
|
79
79
|
"category": "core"
|
|
80
80
|
},
|
|
81
|
-
{
|
|
82
|
-
"name": "cavuno-board-job-posting",
|
|
83
|
-
"description": "Build the anonymous \"Post a job\" funnel with the @cavuno/board SDK — jobPosting.plans, create and its status-discriminated JobPostingResult (checkout / published / pending_approval / invoice_sent), logo upload + fetchLogoByDomain, and the email-verified billing helpers (sendBillingVerification, getBillingOptions).",
|
|
84
|
-
"path": "skills/cavuno-board-job-posting/SKILL.md",
|
|
85
|
-
"framework": null,
|
|
86
|
-
"category": "core"
|
|
87
|
-
},
|
|
88
81
|
{
|
|
89
82
|
"name": "cavuno-board-jobs",
|
|
90
|
-
"description": "
|
|
83
|
+
"description": "Job catalog reads with @cavuno/board. Use for job browse or search, job detail, similar jobs, candidate gating, or full-catalog iteration.",
|
|
91
84
|
"path": "skills/cavuno-board-jobs/SKILL.md",
|
|
92
85
|
"framework": null,
|
|
93
86
|
"category": "core"
|
|
94
87
|
},
|
|
95
88
|
{
|
|
96
89
|
"name": "cavuno-board-messaging",
|
|
97
|
-
"description": "
|
|
90
|
+
"description": "Polled messaging contract with @cavuno/board. Use for inboxes, unread badges, threads, read receipts, message moderation, or user blocks.",
|
|
98
91
|
"path": "skills/cavuno-board-messaging/SKILL.md",
|
|
99
92
|
"framework": null,
|
|
100
93
|
"category": "core"
|
|
101
94
|
},
|
|
102
95
|
{
|
|
103
96
|
"name": "cavuno-board-paywall",
|
|
104
|
-
"description": "
|
|
97
|
+
"description": "Grant-is-truth candidate paywall with @cavuno/board. Use for offers, gated job counts, embedded checkout handoff, access confirmation, or subscription portal links.",
|
|
105
98
|
"path": "skills/cavuno-board-paywall/SKILL.md",
|
|
106
99
|
"framework": null,
|
|
107
100
|
"category": "core"
|
|
108
101
|
},
|
|
102
|
+
{
|
|
103
|
+
"name": "cavuno-board-post-a-job",
|
|
104
|
+
"description": "Post a job publicly with @cavuno/board. Use for plan selection, logos, checkout handoff, or verified existing credit.",
|
|
105
|
+
"path": "skills/cavuno-board-post-a-job/SKILL.md",
|
|
106
|
+
"framework": null,
|
|
107
|
+
"category": "core"
|
|
108
|
+
},
|
|
109
109
|
{
|
|
110
110
|
"name": "cavuno-board-salaries",
|
|
111
|
-
"description": "
|
|
111
|
+
"description": "Salary read models with @cavuno/board. Use for title, skill, or location salary indexes and detail, cross-axis pages, or the salary companies hub.",
|
|
112
112
|
"path": "skills/cavuno-board-salaries/SKILL.md",
|
|
113
113
|
"framework": null,
|
|
114
114
|
"category": "core"
|
|
115
115
|
},
|
|
116
|
+
{
|
|
117
|
+
"name": "cavuno-board-search-suggestions",
|
|
118
|
+
"description": "Build server-ranked search suggestions with @cavuno/board. Use for company-and-term typeahead, autocomplete dropdowns, or suggestion-controller wiring.",
|
|
119
|
+
"path": "skills/cavuno-board-search-suggestions/SKILL.md",
|
|
120
|
+
"framework": null,
|
|
121
|
+
"category": "core"
|
|
122
|
+
},
|
|
116
123
|
{
|
|
117
124
|
"name": "cavuno-board-seo",
|
|
118
|
-
"description": "
|
|
125
|
+
"description": "SEO builders with @cavuno/board/seo. Use for JobPosting or breadcrumb JSON-LD, blog schema, salary rich results, or job-listing head metadata.",
|
|
119
126
|
"path": "skills/cavuno-board-seo/SKILL.md",
|
|
120
127
|
"framework": null,
|
|
121
128
|
"category": "core"
|
|
122
129
|
},
|
|
123
130
|
{
|
|
124
|
-
"name": "cavuno-board-server",
|
|
125
|
-
"description": "
|
|
126
|
-
"path": "skills/cavuno-board-server/SKILL.md",
|
|
131
|
+
"name": "cavuno-board-server-sessions",
|
|
132
|
+
"description": "Wire Cavuno server sessions and board-password access. Use when a server-rendered app needs httpOnly cookies, per-request bearer headers, single-flight refresh, grant cookies, or safe redirect-back handling.",
|
|
133
|
+
"path": "skills/cavuno-board-server-sessions/SKILL.md",
|
|
127
134
|
"framework": null,
|
|
128
135
|
"category": "core"
|
|
129
136
|
},
|
|
130
137
|
{
|
|
131
138
|
"name": "cavuno-board-setup",
|
|
132
|
-
"description": "
|
|
139
|
+
"description": "Orchestrate a headless Cavuno board integration. Use when starting a frontend with @cavuno/board or adding Cavuno board surfaces to an existing app.",
|
|
133
140
|
"path": "skills/cavuno-board-setup/SKILL.md",
|
|
134
141
|
"framework": null,
|
|
135
142
|
"category": "core"
|
|
136
143
|
},
|
|
137
144
|
{
|
|
138
145
|
"name": "cavuno-board-sitemap",
|
|
139
|
-
"description": "
|
|
146
|
+
"description": "Board sitemap generation with @cavuno/board/sitemap. Use for sitemap indexes, bucket routes, XML rendering, catalog walking, chunking, or robots.txt discovery.",
|
|
140
147
|
"path": "skills/cavuno-board-sitemap/SKILL.md",
|
|
141
148
|
"framework": null,
|
|
142
149
|
"category": "core"
|
|
143
150
|
},
|
|
144
151
|
{
|
|
145
152
|
"name": "cavuno-board-smoke-test",
|
|
146
|
-
"description": "
|
|
153
|
+
"description": "Prove a Cavuno board integration at runtime. Use after initial setup, an @cavuno/board upgrade, a board-key rotation, or when rendered board data is unexpectedly missing.",
|
|
147
154
|
"path": "skills/cavuno-board-smoke-test/SKILL.md",
|
|
148
155
|
"framework": null,
|
|
149
156
|
"category": "core"
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"name": "cavuno-board-suggest",
|
|
153
|
-
"description": "Federated keyword search suggestions with the @cavuno/board SDK — board.search.suggest for companies + taxonomy terms in one server-ranked list, and the headless createSuggestController under @cavuno/board/suggest (debounce, abort, stale-drop). Use when building a search dropdown, typeahead, or autocomplete that mirrors the hosted board.",
|
|
154
|
-
"path": "skills/cavuno-board-suggest/SKILL.md",
|
|
155
|
-
"framework": null,
|
|
156
|
-
"category": "core"
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
"name": "cavuno-board-tanstack-start",
|
|
160
|
-
"description": "TanStack-Start-on-Cloudflare-Workers reference wiring for a headless Cavuno board — SSR loaders calling @cavuno/board server-side, the session held in an __Host- httpOnly cookie owned by the app, a single-flight refresh helper, and FetchOptions cache passthrough on Workers.",
|
|
161
|
-
"path": "skills/flavors/tanstack-start/SKILL.md",
|
|
162
|
-
"framework": "tanstack-start",
|
|
163
|
-
"category": "flavor"
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"name": "cavuno-board-theme",
|
|
167
|
-
"description": "Optional hosted-board theme compatibility with @cavuno/board/theme. Use only when a custom frontend deliberately mirrors or migrates an existing Cavuno hosted theme; the consuming application normally owns tokens, fonts, and color mode.",
|
|
168
|
-
"path": "skills/cavuno-board-theme/SKILL.md",
|
|
169
|
-
"framework": null,
|
|
170
|
-
"category": "core"
|
|
171
157
|
}
|
|
172
158
|
]
|
|
173
159
|
}
|