Conversation
…Public Job Board, Application Forms, Dashboard, and Architecture Overview - Introduced Document Storage feature documentation detailing upload, validation, and security measures. - Added Public Job Board documentation covering job listings, SEO optimization, and application flow. - Created Application Forms documentation explaining custom question types and management. - Documented the Dashboard feature with widgets, navigation, and API integration. - Provided an overview of the system architecture, directory structure, data model, and security measures. - Included contributing guidelines for development setup and coding conventions.
📝 WalkthroughWalkthroughAdds a full documentation section (content/docs + new docs pages and index), integrates Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🚅 Deployed to the reqcore-pr-69 environment in applirank
|
…mproved readability
There was a problem hiding this comment.
Actionable comments posted: 16
🧹 Nitpick comments (2)
content/docs/4.architecture/1.overview.md (1)
84-95: Data model diagram shows linear workflow, but transitions are bidirectional.For consistency with the correction needed in
content/docs/3.features/1.job-management.md, note that the job status flow shown here (draft → open → closed → archived) is simplified. The actual implementation allows reopening closed jobs and reverting archived jobs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@content/docs/4.architecture/1.overview.md` around lines 84 - 95, The data model diagram currently shows a linear job lifecycle "draft → open → closed → archived" but the system allows bidirectional transitions (e.g., reopening closed jobs and reverting archived jobs); update the diagram or accompanying text to reflect reversible transitions by replacing the one-way arrows with bidirectional arrows (e.g., draft ↔ open ↔ closed ↔ archived or explicitly annotate that closed and archived can be reverted) and add a short clarifying note that job statuses (draft, open, closed, archived) are not strictly terminal and can transition backward.app/pages/docs/[...slug].vue (1)
137-170: Extract shared docs nav/footer to reduce duplication.This markup is duplicated across docs pages and will drift. Consider moving it to shared components/layout.
♻️ Refactor direction
- <nav ...>...</nav> + <DocsTopNav :session="session" active="docs" /> @@ - <footer ...>...</footer> + <DocsFooter />Also applies to: 267-283
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/pages/docs/`[...slug].vue around lines 137 - 170, The docs navigation/footer markup is duplicated; extract the <nav> block (including the NuxtLink entries, Github component usage, and session?.user conditional Dashboard/Sign In links) into a reusable component (e.g., DocsNav.vue or SharedNav.vue) and similarly extract the footer into a DocsFooter.vue or include both in a shared DocsLayout; then import and use that component/layout in pages like the current docs/[...slug].vue and other docs pages to remove the duplicated markup and centralize future updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/pages/docs/`[...slug].vue:
- Around line 147-153: Update the icon-only external anchor that wraps the
Github component (the <a ... class="transition hover:text-white"> containing
<Github class="size-4" />) to include rel="noopener noreferrer" alongside
target="_blank" and add an accessible name (e.g., aria-label="Open ReqCore on
GitHub") so screen readers can describe the link; apply the same two changes to
the other identical GitHub anchor instance in the file (the second <a> wrapping
<Github />).
In `@app/pages/docs/index.vue`:
- Around line 128-134: The external GitHub anchor that wraps the Github
component uses target="_blank" but lacks rel protection and an accessible name;
update the anchor (the <a> that contains the Github component) to include
rel="noopener noreferrer" and add an accessible label (e.g., aria-label="Open
Reqcore on GitHub" or include a visually hidden text node) so screen readers can
identify the link; apply the same changes to the other identical anchor (the one
around lines 229-232).
- Around line 90-96: The index page currently only renders items from the
hard-coded sections array (sections: DocSection[]) so any docs with computed
doc.section || 'Other' will be omitted; update the rendering logic to derive the
displayed sections dynamically by merging the existing static sections with any
additional section keys discovered from the docs collection (use the same
key/title/description/icon shape as in sections), or replace the static sections
with a computedSections getter that returns [...sections, ...extraSections]
where extraSections is built from docs.map(d => d.section || 'Other')
deduplicated, and ensure the component that uses sections (the list renderer)
references this computedSections instead of the static sections variable (look
for usages of sections and doc.section || 'Other' in the file).
In `@content/docs/1.getting-started/3.configuration.md`:
- Around line 27-40: Add a short clarifying note under "Optional Variables" that
the four client-exposed vars LIVE_DEMO_EMAIL, LIVE_DEMO_SECRET,
NUXT_PUBLIC_GISCUS_REPO_ID and NUXT_PUBLIC_GISCUS_CATEGORY_ID are read directly
from process.env in nuxt.config.ts and exposed via runtimeConfig.public, and
therefore are not validated by the Zod schema in server/utils/env.ts (they will
not cause startup failures if missing/malformed); reference those variable names
and the two files (nuxt.config.ts and server/utils/env.ts) so readers can locate
where validation does and does not occur.
- Around line 14-26: The README incorrectly marks S3_REGION as required; update
the docs to reflect that S3_REGION is optional with default 'us-east-1' per
server/utils/env.ts where S3_REGION is defined as
.optional().default('us-east-1'). Move the `S3_REGION` row from the "Required
Variables" table into the "Optional Variables" table and adjust its
description/example to indicate it's optional and defaults to us-east-1.
In `@content/docs/2.deployment/1.docker-compose.md`:
- Line 94: Replace the misspelled reverse proxy name "Traefin" with the correct
"Traefik" in the list item that begins "1. **Put a reverse proxy in front**
(Nginx, Caddy, or Traefin) with TLS termination" so the sentence reads "(Nginx,
Caddy, or Traefik)"; update the string literal occurrence "Traefin" wherever it
appears in that document to "Traefik".
- Around line 24-26: Clarify the Quick Start flow to avoid port conflicts:
either document that docker compose is the full-stack solution (remove the
host-side steps `npm install`/`npm run dev` and state that the app is served by
the container started via `docker compose up -d`, which uses the Dockerfile
Stage 2 CMD ["node", ".output/server/index.mjs"] on port 3000), or present
Docker Compose as a backend-only option (remove the `app` service from the
compose example and state that compose only runs `db` and `minio` while
developers run the Nuxt dev server on the host with `npm run dev`); update the
Quick Start text and the architecture notes so they explicitly state which mode
is intended and avoid running both containerized CMD and host `npm run dev`
binding to port 3000 simultaneously.
In `@content/docs/2.deployment/3.environment-variables.md`:
- Around line 12-26: Update the docs to reflect that S3_REGION is optional with
a default of "us-east-1" (see server/utils/env.ts where S3_REGION default is
applied) and that BETTER_AUTH_URL is conditionally required (it is validated in
the env schema's superRefine logic — only required outside Railway PR/preview
environments where RAILWAY_PUBLIC_DOMAIN is used to derive the value); change
the table entries accordingly to mark S3_REGION as optional with default and
BETTER_AUTH_URL as conditionally required with a note about Railway preview
derivation.
In `@content/docs/3.features/1.job-management.md`:
- Around line 14-27: The docs incorrectly claim transitions are forward-only;
update the job lifecycle text in content/docs/3.features/1.job-management.md to
reflect the actual allowed transitions implemented in
shared/status-transitions.ts (e.g., allow closed → open and archived →
draft/open), replace the linear "Draft → Open → Closed → Archived" wording and
the final sentence with a diagram or sentence stating that transitions are
validated server-side and that closed jobs can be reopened and archived jobs can
be reverted to draft or open (mentioning the file shared/status-transitions.ts
as the source of truth).
In `@content/docs/3.features/2.candidate-pipeline.md`:
- Around line 14-19: Update the pipeline transitions block to reflect the real
allowed transitions instead of implying a strictly linear flow: replace the
current arrow diagram with the explicit map using the status identifiers (new,
screening, interview, offer, hired, rejected) — e.g. "new -> screening |
interview | rejected", "screening -> interview | offer | rejected", "interview
-> offer | rejected", "offer -> hired | rejected", "hired -> (terminal)",
"rejected -> new" — and update the "Status transitions" sentence to read "Move
the candidate to any allowed next status" so the docs and UI/API behavior align
with the actual transition rules.
In `@content/docs/3.features/5.application-forms.md`:
- Around line 53-55: The fenced code block containing the line
"/jobs/{slug}/apply" is missing a fence language and triggers markdownlint
MD040; update that block (the triple-backtick fence surrounding
"/jobs/{slug}/apply") to include a language identifier such as text or bash
(e.g., change ``` to ```text) so the block has an explicit language.
In `@content/docs/3.features/6.dashboard.md`:
- Around line 76-78: The fenced code block containing the endpoint "GET
/api/dashboard/stats" is missing a language tag; update that code fence (the
block that currently contains just GET /api/dashboard/stats) to include a
language tag such as "http" (e.g., ```http) to satisfy markdownlint MD040 and
remove the warning.
In `@content/docs/4.architecture/2.directory-structure.md`:
- Around line 14-82: The fenced directory-tree block uses plain triple backticks
without a language tag; update the opening fence in the block that lists the
repo tree (the ``````` reqcore/ … ``` block) to include a language identifier
such as "text" (i.e., change ``` to ```text) so the MD040 lint warning is
resolved and the tree renders as plain text.
In `@content/docs/4.architecture/3.data-model.md`:
- Around line 31-77: Update the documented table definitions to match the actual
schema: in the `job` table replace `employmentType` with `type` and add the
`requireResume` and `requireCoverLetter` columns; in the `candidate` table
either add the `notes` column if present in schema or remove it from the docs to
match `candidate`'s actual columns; in the `application` table add
`coverLetterText` to the column list. Use the exact column identifiers (`type`,
`requireResume`, `requireCoverLetter`, `notes`, `coverLetterText`) and update
the descriptions/column types to mirror `server/database/schema/app.ts` so docs
and schema are consistent.
In `@content/docs/5.contributing/2.coding-conventions.md`:
- Around line 65-71: The fenced route-mapping block showing the API paths (the
three backtick block containing lines like "server/api/jobs/index.get.ts → GET
/api/jobs" and the other route mappings) lacks a language tag and triggers
markdownlint MD040; fix it by adding a language identifier (use "text") to the
opening fence so the block becomes ```text and the rest of the content remains
unchanged.
In `@nuxt.config.ts`:
- Around line 191-196: The current top-level content.highlight setting must be
moved under the build->markdown tree: remove the existing content.highlight
entry and add it as content.build.markdown.highlight with the same theme value
(i.e., move the 'highlight' object from the top-level 'content' config into
'content.build.markdown.highlight'); update the 'content' object in nuxt config
so the 'highlight' key lives at content.build.markdown.highlight (preserving
theme: 'one-dark-pro').
---
Nitpick comments:
In `@app/pages/docs/`[...slug].vue:
- Around line 137-170: The docs navigation/footer markup is duplicated; extract
the <nav> block (including the NuxtLink entries, Github component usage, and
session?.user conditional Dashboard/Sign In links) into a reusable component
(e.g., DocsNav.vue or SharedNav.vue) and similarly extract the footer into a
DocsFooter.vue or include both in a shared DocsLayout; then import and use that
component/layout in pages like the current docs/[...slug].vue and other docs
pages to remove the duplicated markup and centralize future updates.
In `@content/docs/4.architecture/1.overview.md`:
- Around line 84-95: The data model diagram currently shows a linear job
lifecycle "draft → open → closed → archived" but the system allows bidirectional
transitions (e.g., reopening closed jobs and reverting archived jobs); update
the diagram or accompanying text to reflect reversible transitions by replacing
the one-way arrows with bidirectional arrows (e.g., draft ↔ open ↔ closed ↔
archived or explicitly annotate that closed and archived can be reverted) and
add a short clarifying note that job statuses (draft, open, closed, archived)
are not strictly terminal and can transition backward.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5d27249a-e3a9-4fc4-b6d7-5ec5bc06ff93
📒 Files selected for processing (26)
app/pages/blog/[...slug].vueapp/pages/blog/index.vueapp/pages/docs/[...slug].vueapp/pages/docs/index.vueapp/pages/index.vuecontent.config.tscontent/docs/1.getting-started/1.introduction.mdcontent/docs/1.getting-started/2.installation.mdcontent/docs/1.getting-started/3.configuration.mdcontent/docs/1.getting-started/4.quick-start.mdcontent/docs/2.deployment/1.docker-compose.mdcontent/docs/2.deployment/2.railway.mdcontent/docs/2.deployment/3.environment-variables.mdcontent/docs/3.features/1.job-management.mdcontent/docs/3.features/2.candidate-pipeline.mdcontent/docs/3.features/3.document-storage.mdcontent/docs/3.features/4.public-job-board.mdcontent/docs/3.features/5.application-forms.mdcontent/docs/3.features/6.dashboard.mdcontent/docs/4.architecture/1.overview.mdcontent/docs/4.architecture/2.directory-structure.mdcontent/docs/4.architecture/3.data-model.mdcontent/docs/4.architecture/4.security.mdcontent/docs/5.contributing/1.development-setup.mdcontent/docs/5.contributing/2.coding-conventions.mdnuxt.config.ts
| <a | ||
| href="https://github.com/reqcore-inc/reqcore" | ||
| target="_blank" | ||
| class="transition hover:text-white" | ||
| > | ||
| <Github class="size-4" /> | ||
| </a> |
There was a problem hiding this comment.
Harden external links and label the icon-only GitHub link.
Please add rel="noopener noreferrer" on target="_blank" links, and add an accessible name on the icon-only nav link.
🔧 Suggested patch
<a
href="https://github.com/reqcore-inc/reqcore"
target="_blank"
+ rel="noopener noreferrer"
+ aria-label="Reqcore GitHub repository"
class="transition hover:text-white"
>
<Github class="size-4" />
</a>
@@
<a
href="https://github.com/reqcore-inc/reqcore"
target="_blank"
+ rel="noopener noreferrer"
class="transition hover:text-white/60"
>
GitHub
</a>Also applies to: 274-277
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/pages/docs/`[...slug].vue around lines 147 - 153, Update the icon-only
external anchor that wraps the Github component (the <a ... class="transition
hover:text-white"> containing <Github class="size-4" />) to include
rel="noopener noreferrer" alongside target="_blank" and add an accessible name
(e.g., aria-label="Open ReqCore on GitHub") so screen readers can describe the
link; apply the same two changes to the other identical GitHub anchor instance
in the file (the second <a> wrapping <Github />).
| const sections: DocSection[] = [ | ||
| { key: 'Getting Started', title: 'Getting Started', description: 'Install, configure, and start using Reqcore', icon: Rocket }, | ||
| { key: 'Deployment', title: 'Deployment', description: 'Self-host with Docker or deploy to Railway', icon: Container }, | ||
| { key: 'Features', title: 'Features', description: 'Jobs, pipeline, documents, and job board', icon: Briefcase }, | ||
| { key: 'Architecture', title: 'Architecture', description: 'System design, data model, and security', icon: Layers }, | ||
| { key: 'Contributing', title: 'Contributing', description: 'Development setup and coding conventions', icon: Code }, | ||
| ] |
There was a problem hiding this comment.
Docs in non-predefined sections are grouped but never displayed.
doc.section || 'Other' is computed, but the UI only renders the fixed sections array. Any unexpected section becomes hidden from the index.
🔧 Suggested patch
const docsBySection = computed(() => {
if (!allDocs.value) return {}
const grouped: Record<string, typeof allDocs.value> = {}
for (const doc of allDocs.value) {
const section = doc.section || 'Other'
if (!grouped[section]) grouped[section] = []
grouped[section].push(doc)
}
return grouped
})
+
+const visibleSections = computed<DocSection[]>(() => {
+ const known = new Set(sections.map(section => section.key))
+ const extra: DocSection[] = Object.keys(docsBySection.value)
+ .filter(sectionKey => !known.has(sectionKey))
+ .map(sectionKey => ({
+ key: sectionKey,
+ title: sectionKey,
+ description: 'Additional documentation',
+ icon: BookOpen,
+ }))
+ return [...sections, ...extra]
+})- <div v-for="section in sections" :key="section.key" class="mb-12">
+ <div v-for="section in visibleSections" :key="section.key" class="mb-12">Also applies to: 99-108, 178-178
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/pages/docs/index.vue` around lines 90 - 96, The index page currently only
renders items from the hard-coded sections array (sections: DocSection[]) so any
docs with computed doc.section || 'Other' will be omitted; update the rendering
logic to derive the displayed sections dynamically by merging the existing
static sections with any additional section keys discovered from the docs
collection (use the same key/title/description/icon shape as in sections), or
replace the static sections with a computedSections getter that returns
[...sections, ...extraSections] where extraSections is built from docs.map(d =>
d.section || 'Other') deduplicated, and ensure the component that uses sections
(the list renderer) references this computedSections instead of the static
sections variable (look for usages of sections and doc.section || 'Other' in the
file).
| <a | ||
| href="https://github.com/reqcore-inc/reqcore" | ||
| target="_blank" | ||
| class="transition hover:text-white" | ||
| > | ||
| <Github class="size-4" /> | ||
| </a> |
There was a problem hiding this comment.
Add rel protection and an accessible name for the icon-only external link.
Please harden target="_blank" links and ensure the icon-only GitHub link has an accessible label.
🔧 Suggested patch
<a
href="https://github.com/reqcore-inc/reqcore"
target="_blank"
+ rel="noopener noreferrer"
+ aria-label="Reqcore GitHub repository"
class="transition hover:text-white"
>
<Github class="size-4" />
</a>
@@
<a
href="https://github.com/reqcore-inc/reqcore"
target="_blank"
+ rel="noopener noreferrer"
class="transition hover:text-white/60"
>
GitHub
</a>Also applies to: 229-232
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/pages/docs/index.vue` around lines 128 - 134, The external GitHub anchor
that wraps the Github component uses target="_blank" but lacks rel protection
and an accessible name; update the anchor (the <a> that contains the Github
component) to include rel="noopener noreferrer" and add an accessible label
(e.g., aria-label="Open Reqcore on GitHub" or include a visually hidden text
node) so screen readers can identify the link; apply the same changes to the
other identical anchor (the one around lines 229-232).
| ### Required Variables | ||
|
|
||
| | Variable | Description | Example | | ||
| |----------|-------------|---------| | ||
| | `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@localhost:5432/reqcore` | | ||
| | `BETTER_AUTH_SECRET` | Session signing secret (min 32 chars) | Generated by `setup.sh` | | ||
| | `BETTER_AUTH_URL` | Public URL of the application | `http://localhost:3000` | | ||
| | `S3_ENDPOINT` | S3-compatible storage endpoint | `http://localhost:9000` | | ||
| | `S3_ACCESS_KEY` | Storage access key | `minioadmin` | | ||
| | `S3_SECRET_KEY` | Storage secret key | `minioadmin` | | ||
| | `S3_BUCKET` | Storage bucket name | `reqcore` | | ||
| | `S3_REGION` | Storage region | `us-east-1` | | ||
|
|
There was a problem hiding this comment.
S3_REGION is optional with a default, not required.
Per server/utils/env.ts (lines 58-59), S3_REGION is defined as .optional().default('us-east-1'). It should be moved to the optional variables section.
📝 Suggested fix
Move S3_REGION from the Required Variables table to the Optional Variables section:
| `S3_BUCKET` | Storage bucket name | `reqcore` |
-| `S3_REGION` | Storage region | `us-east-1` |
### Optional Variables
| Variable | Description | Default |
|----------|-------------|---------|
+| `S3_REGION` | Storage region | `us-east-1` |
| `S3_FORCE_PATH_STYLE` | Use path-style S3 URLs (required for MinIO) | `true` |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/1.getting-started/3.configuration.md` around lines 14 - 26, The
README incorrectly marks S3_REGION as required; update the docs to reflect that
S3_REGION is optional with default 'us-east-1' per server/utils/env.ts where
S3_REGION is defined as .optional().default('us-east-1'). Move the `S3_REGION`
row from the "Required Variables" table into the "Optional Variables" table and
adjust its description/example to indicate it's optional and defaults to
us-east-1.
| ### Optional Variables | ||
|
|
||
| | Variable | Description | Default | | ||
| |----------|-------------|---------| | ||
| | `S3_FORCE_PATH_STYLE` | Use path-style S3 URLs (required for MinIO) | `true` | | ||
| | `NUXT_PUBLIC_SITE_URL` | Public site URL for SEO | `https://reqcore.com` | | ||
| | `DEMO_ORG_SLUG` | Show read-only demo banner for this org | *(empty)* | | ||
| | `LIVE_DEMO_EMAIL` | Prefill sign-in with demo email | `demo@reqcore.com` | | ||
| | `LIVE_DEMO_SECRET` | Prefill sign-in with demo password | `demo1234` | | ||
| | `GITHUB_FEEDBACK_TOKEN` | GitHub PAT for in-app feedback | *(empty)* | | ||
| | `GITHUB_FEEDBACK_REPO` | GitHub repo for feedback issues | *(empty)* | | ||
| | `NUXT_PUBLIC_GISCUS_REPO_ID` | Giscus repo node ID for comments | *(empty)* | | ||
| | `NUXT_PUBLIC_GISCUS_CATEGORY_ID` | Giscus category node ID for comments | *(empty)* | | ||
|
|
There was a problem hiding this comment.
Clarify that some optional variables are not Zod-validated.
LIVE_DEMO_EMAIL, LIVE_DEMO_SECRET, NUXT_PUBLIC_GISCUS_REPO_ID, and NUXT_PUBLIC_GISCUS_CATEGORY_ID are read directly from process.env in nuxt.config.ts (lines 100-122) and exposed via runtimeConfig.public. They are not validated by the Zod schema in server/utils/env.ts and won't cause startup failures if missing/malformed.
Consider adding a note to distinguish these client-side config vars from the Zod-validated server vars.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/1.getting-started/3.configuration.md` around lines 27 - 40, Add
a short clarifying note under "Optional Variables" that the four client-exposed
vars LIVE_DEMO_EMAIL, LIVE_DEMO_SECRET, NUXT_PUBLIC_GISCUS_REPO_ID and
NUXT_PUBLIC_GISCUS_CATEGORY_ID are read directly from process.env in
nuxt.config.ts and exposed via runtimeConfig.public, and therefore are not
validated by the Zod schema in server/utils/env.ts (they will not cause startup
failures if missing/malformed); reference those variable names and the two files
(nuxt.config.ts and server/utils/env.ts) so readers can locate where validation
does and does not occur.
| ``` | ||
| GET /api/dashboard/stats | ||
| ``` |
There was a problem hiding this comment.
Add a language tag to the fenced block.
The endpoint code fence is unlabeled; markdownlint MD040 will keep warning here.
Suggested fix
-```
+```http
GET /api/dashboard/stats</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @content/docs/3.features/6.dashboard.md around lines 76 - 78, The fenced code
block containing the endpoint "GET /api/dashboard/stats" is missing a language
tag; update that code fence (the block that currently contains just GET
/api/dashboard/stats) to include a language tag such as "http" (e.g., ```http)
to satisfy markdownlint MD040 and remove the warning.
</details>
<!-- fingerprinting:phantom:poseidon:hawk -->
<!-- This is an auto-generated comment by CodeRabbit -->
| ``` | ||
| reqcore/ | ||
| ├── app/ # Client source (Nuxt 4 srcDir) | ||
| │ ├── app.vue # Root component | ||
| │ ├── assets/ | ||
| │ │ └── css/main.css # Tailwind CSS entry + @theme tokens | ||
| │ ├── components/ # Auto-imported Vue components | ||
| │ ├── composables/ # Auto-imported composables (useXxx) | ||
| │ ├── layouts/ # Layout components | ||
| │ │ ├── dashboard.vue # Sidebar + main content | ||
| │ │ ├── auth.vue # Centered card for auth pages | ||
| │ │ └── public.vue # Simple header/footer for public pages | ||
| │ ├── middleware/ # Client-side route middleware | ||
| │ ├── pages/ # File-based routing | ||
| │ │ ├── index.vue # Landing page (dark theme) | ||
| │ │ ├── roadmap.vue # Public roadmap | ||
| │ │ ├── blog/ # Blog listing + detail | ||
| │ │ ├── docs/ # Documentation listing + detail | ||
| │ │ ├── catalog/ # Feature catalog | ||
| │ │ ├── jobs/ # Public job board | ||
| │ │ ├── auth/ # Sign-in / sign-up | ||
| │ │ ├── dashboard/ # Authenticated dashboard | ||
| │ │ └── onboarding/ # Org creation flow | ||
| │ ├── plugins/ # Client-side Nuxt plugins | ||
| │ └── utils/ # Auto-imported utilities | ||
| │ └── auth-client.ts # Better Auth Vue client | ||
| ├── server/ # Nitro server (at project root) | ||
| │ ├── api/ # API route handlers | ||
| │ │ ├── auth/[...all].ts # Better Auth catch-all | ||
| │ │ ├── jobs/ # Job CRUD + questions | ||
| │ │ ├── candidates/ # Candidate CRUD + documents | ||
| │ │ ├── applications/ # Application CRUD | ||
| │ │ ├── documents/ # Document access endpoints | ||
| │ │ ├── dashboard/ # Dashboard stats | ||
| │ │ └── public/jobs/ # Unauthenticated job board API | ||
| │ ├── database/ | ||
| │ │ ├── schema/ # Drizzle ORM table definitions | ||
| │ │ │ ├── app.ts # Domain tables (job, candidate, etc.) | ||
| │ │ │ ├── auth.ts # Better Auth tables (DO NOT MODIFY) | ||
| │ │ │ └── index.ts # Re-exports | ||
| │ │ └── migrations/ # Generated SQL migrations | ||
| │ ├── middleware/ # Global server middleware | ||
| │ ├── plugins/ | ||
| │ │ ├── migrations.ts # Auto-apply migrations on startup | ||
| │ │ └── s3-bucket.ts # Ensure S3 bucket exists + enforce private policy | ||
| │ └── utils/ # Auto-imported server utilities | ||
| │ ├── auth.ts # Better Auth instance | ||
| │ ├── db.ts # Drizzle client + connection pool | ||
| │ ├── env.ts # Zod-validated environment variables | ||
| │ ├── requireAuth.ts # Auth guard (throws 401/403) | ||
| │ ├── s3.ts # S3/MinIO client, upload, delete | ||
| │ ├── slugify.ts # URL slug generation | ||
| │ ├── rateLimit.ts # IP-based sliding window rate limiter | ||
| │ └── schemas/ # Zod validation schemas | ||
| ├── content/ # @nuxt/content v3 collections | ||
| │ ├── blog/ # Blog articles (Markdown) | ||
| │ ├── catalog/ # Feature catalog items | ||
| │ └── docs/ # Documentation pages | ||
| ├── shared/ # Shared between app and server | ||
| ├── public/ # Static assets (favicon, images) | ||
| ├── i18n/ # Internationalization | ||
| │ └── locales/ # Translation JSON files | ||
| ├── e2e/ # Playwright end-to-end tests | ||
| ├── nuxt.config.ts # Nuxt configuration | ||
| ├── content.config.ts # Content collection definitions | ||
| ├── drizzle.config.ts # Drizzle Kit configuration | ||
| ├── docker-compose.yml # PostgreSQL + MinIO + Adminer | ||
| └── package.json | ||
| ``` |
There was a problem hiding this comment.
Label the directory-tree code fence.
The large fenced block is missing a language identifier (MD040).
Suggested fix
-```
+```text
reqcore/
...</details>
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```suggestion
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)
[warning] 14-14: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/4.architecture/2.directory-structure.md` around lines 14 - 82,
The fenced directory-tree block uses plain triple backticks without a language
tag; update the opening fence in the block that lists the repo tree (the ```````
reqcore/ … ``` block) to include a language identifier such as "text" (i.e.,
change ``` to ```text) so the MD040 lint warning is resolved and the tree
renders as plain text.
| | Column | Type | Description | | ||
| |--------|------|-------------| | ||
| | `id` | `uuid` | Primary key | | ||
| | `organizationId` | `string` | FK → organization | | ||
| | `title` | `string` | Job title | | ||
| | `description` | `text` | Full description (Markdown) | | ||
| | `status` | `enum` | `draft`, `open`, `closed`, `archived` | | ||
| | `location` | `string` | Office location | | ||
| | `employmentType` | `string` | Full-time, Part-time, etc. | | ||
| | `slug` | `string` | URL slug for public page | | ||
| | `salaryMin` / `salaryMax` | `integer` | Salary range | | ||
| | `salaryCurrency` | `string` | Currency code (USD, EUR, etc.) | | ||
| | `salaryUnit` | `string` | HOUR, DAY, WEEK, MONTH, YEAR | | ||
| | `remoteStatus` | `string` | On-site, Remote, Hybrid | | ||
| | `validThrough` | `timestamp` | Application deadline | | ||
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | ||
|
|
||
| ### `candidate` | ||
|
|
||
| A person who has applied or been added to the talent pool. | ||
|
|
||
| | Column | Type | Description | | ||
| |--------|------|-------------| | ||
| | `id` | `uuid` | Primary key | | ||
| | `organizationId` | `string` | FK → organization | | ||
| | `firstName` / `lastName` | `string` | Full name | | ||
| | `email` | `string` | Email (unique per org) | | ||
| | `phone` | `string` | Phone number | | ||
| | `notes` | `text` | Recruiter notes | | ||
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | ||
|
|
||
| **Unique constraint**: `(organizationId, email)` — prevents duplicate candidates within an org. | ||
|
|
||
| ### `application` | ||
|
|
||
| Links a candidate to a job with a pipeline status. | ||
|
|
||
| | Column | Type | Description | | ||
| |--------|------|-------------| | ||
| | `id` | `uuid` | Primary key | | ||
| | `organizationId` | `string` | FK → organization | | ||
| | `jobId` | `uuid` | FK → job | | ||
| | `candidateId` | `uuid` | FK → candidate | | ||
| | `status` | `enum` | `new`, `screening`, `interview`, `offer`, `hired`, `rejected` | | ||
| | `notes` | `text` | Application-specific notes | | ||
| | `score` | `integer` | Recruiter-assigned score | | ||
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | |
There was a problem hiding this comment.
Data model tables are out of sync with the actual schema.
Several documented columns don’t match server/database/schema/app.ts:
job:employmentTypeshould betype, andrequireResume/requireCoverLetterare missing.candidate:notesis documented but not present.application:coverLetterTextexists in schema but is missing here.
This should be aligned before merge to avoid incorrect query/code assumptions.
Suggested doc corrections (example)
-| `employmentType` | `string` | Full-time, Part-time, etc. |
+| `type` | `enum` | `full_time`, `part_time`, `contract`, `internship` |
+| `requireResume` | `boolean` | Whether resume is required on application form |
+| `requireCoverLetter` | `boolean` | Whether cover letter is required on application form |
...
-| `notes` | `text` | Recruiter notes |
...
| `notes` | `text` | Application-specific notes |
| `score` | `integer` | Recruiter-assigned score |
+| `coverLetterText` | `text` | Parsed/submitted cover letter text |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `title` | `string` | Job title | | |
| | `description` | `text` | Full description (Markdown) | | |
| | `status` | `enum` | `draft`, `open`, `closed`, `archived` | | |
| | `location` | `string` | Office location | | |
| | `employmentType` | `string` | Full-time, Part-time, etc. | | |
| | `slug` | `string` | URL slug for public page | | |
| | `salaryMin` / `salaryMax` | `integer` | Salary range | | |
| | `salaryCurrency` | `string` | Currency code (USD, EUR, etc.) | | |
| | `salaryUnit` | `string` | HOUR, DAY, WEEK, MONTH, YEAR | | |
| | `remoteStatus` | `string` | On-site, Remote, Hybrid | | |
| | `validThrough` | `timestamp` | Application deadline | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | |
| ### `candidate` | |
| A person who has applied or been added to the talent pool. | |
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `firstName` / `lastName` | `string` | Full name | | |
| | `email` | `string` | Email (unique per org) | | |
| | `phone` | `string` | Phone number | | |
| | `notes` | `text` | Recruiter notes | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | |
| **Unique constraint**: `(organizationId, email)` — prevents duplicate candidates within an org. | |
| ### `application` | |
| Links a candidate to a job with a pipeline status. | |
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `jobId` | `uuid` | FK → job | | |
| | `candidateId` | `uuid` | FK → candidate | | |
| | `status` | `enum` | `new`, `screening`, `interview`, `offer`, `hired`, `rejected` | | |
| | `notes` | `text` | Application-specific notes | | |
| | `score` | `integer` | Recruiter-assigned score | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | |
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `title` | `string` | Job title | | |
| | `description` | `text` | Full description (Markdown) | | |
| | `status` | `enum` | `draft`, `open`, `closed`, `archived` | | |
| | `location` | `string` | Office location | | |
| | `type` | `enum` | `full_time`, `part_time`, `contract`, `internship` | | |
| | `requireResume` | `boolean` | Whether resume is required on application form | | |
| | `requireCoverLetter` | `boolean` | Whether cover letter is required on application form | | |
| | `slug` | `string` | URL slug for public page | | |
| | `salaryMin` / `salaryMax` | `integer` | Salary range | | |
| | `salaryCurrency` | `string` | Currency code (USD, EUR, etc.) | | |
| | `salaryUnit` | `string` | HOUR, DAY, WEEK, MONTH, YEAR | | |
| | `remoteStatus` | `string` | On-site, Remote, Hybrid | | |
| | `validThrough` | `timestamp` | Application deadline | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | |
| ### `candidate` | |
| A person who has applied or been added to the talent pool. | |
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `firstName` / `lastName` | `string` | Full name | | |
| | `email` | `string` | Email (unique per org) | | |
| | `phone` | `string` | Phone number | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | | |
| **Unique constraint**: `(organizationId, email)` — prevents duplicate candidates within an org. | |
| ### `application` | |
| Links a candidate to a job with a pipeline status. | |
| | Column | Type | Description | | |
| |--------|------|-------------| | |
| | `id` | `uuid` | Primary key | | |
| | `organizationId` | `string` | FK → organization | | |
| | `jobId` | `uuid` | FK → job | | |
| | `candidateId` | `uuid` | FK → candidate | | |
| | `status` | `enum` | `new`, `screening`, `interview`, `offer`, `hired`, `rejected` | | |
| | `notes` | `text` | Application-specific notes | | |
| | `score` | `integer` | Recruiter-assigned score | | |
| | `coverLetterText` | `text` | Parsed/submitted cover letter text | | |
| | `createdAt` / `updatedAt` | `timestamp` | Timestamps | |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@content/docs/4.architecture/3.data-model.md` around lines 31 - 77, Update the
documented table definitions to match the actual schema: in the `job` table
replace `employmentType` with `type` and add the `requireResume` and
`requireCoverLetter` columns; in the `candidate` table either add the `notes`
column if present in schema or remove it from the docs to match `candidate`'s
actual columns; in the `application` table add `coverLetterText` to the column
list. Use the exact column identifiers (`type`, `requireResume`,
`requireCoverLetter`, `notes`, `coverLetterText`) and update the
descriptions/column types to mirror `server/database/schema/app.ts` so docs and
schema are consistent.
| ``` | ||
| server/api/jobs/index.get.ts → GET /api/jobs | ||
| server/api/jobs/index.post.ts → POST /api/jobs | ||
| server/api/jobs/[id].get.ts → GET /api/jobs/:id | ||
| server/api/jobs/[id].patch.ts → PATCH /api/jobs/:id | ||
| server/api/jobs/[id].delete.ts → DELETE /api/jobs/:id | ||
| ``` |
There was a problem hiding this comment.
Specify a language for the route-mapping block.
This fenced block has no language tag, which triggers markdownlint MD040.
Suggested fix
-```
+```text
server/api/jobs/index.get.ts → GET /api/jobs
...</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @content/docs/5.contributing/2.coding-conventions.md around lines 65 - 71,
The fenced route-mapping block showing the API paths (the three backtick block
containing lines like "server/api/jobs/index.get.ts → GET /api/jobs" and the
other route mappings) lacks a language tag and triggers markdownlint MD040; fix
it by adding a language identifier (use "text") to the opening fence so the
block becomes ```text and the rest of the content remains unchanged.
</details>
<!-- fingerprinting:phantom:poseidon:hawk -->
<!-- This is an auto-generated comment by CodeRabbit -->
| content: { | ||
| // content.config.ts handles collection definitions | ||
| highlight: { | ||
| theme: 'one-dark-pro', | ||
| }, | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
@nuxt/content v3 module options configuration highlight
💡 Result:
In Nuxt Content v3, syntax highlighting is configured under:
content.build.markdown.highlight
highlight can be false (default) or an object with:
theme: a Shiki theme string, or an object of themes (supports Nuxt Color Mode; recommended to includedefault)langs: an array of Shiki languages to preload (defaults includejson,js,ts,html,css,vue,shell,mdc,md,yaml) [1]
Example (nuxt.config.ts):
export default defineNuxtConfig({
content: {
build: {
markdown: {
highlight: {
theme: {
default: 'github-light',
dark: 'github-dark'
},
langs: ['json', 'ts', 'vue', 'bash', 'python']
}
}
}
}
})Nuxt Content uses Shiki for highlighting (used by ProsePre / ProseCode) [1]. Shiki is provided via the MDC layer that Nuxt Content builds on [2].
Sources: [1] [2]
🌐 Web query:
@nuxt/content v3 syntax highlighting theme configuration
💡 Result:
In @nuxt/content v3, syntax highlighting is configured via content.highlight in nuxt.config.ts, and the theme is set with content.highlight.theme. It can be:
- a single Shiki theme id (applies to all color schemes), or
- an object of themes keyed by color-mode names (recommended to include
default). [1]
// nuxt.config.ts
export default defineNuxtConfig({
content: {
highlight: {
// single theme
theme: 'github-light',
// or per color-mode theme
// theme: {
// default: 'github-light',
// dark: 'github-dark',
// sepia: 'monokai'
// }
}
}
})Pick any theme id bundled by Shiki (see the “Themes” list), or use none to bypass highlighting. [2]
🌐 Web query:
@nuxt/content ModuleOptions v3 API reference
💡 Result:
@nuxt/content v3 ModuleOptions (API reference)
Where the canonical options live
- Docs (human-readable): Nuxt Content v3 configuration reference (this is what you set under
content:innuxt.config). [1] - Types (TypeScript source of truth):
ModuleOptionsis declared in the package’s generated types (e.g.dist/module.d.mts). [2]
The package export also points the root types to./dist/module.d.mts. [3]
How to use in Nuxt config
export default defineNuxtConfig({
content: {
// ModuleOptions here
}
})[1]
ModuleOptions (top-level shape, v3)
From the published type definition, ModuleOptions includes (at least) these top-level keys: [2]
database(prod database adapter/config)preview(preview mode config)watch(dev HMR / watcher config)renderer(render-time options likealias,anchorLinks)build(build-time parsing/markdown options liketransformers, markdowntoc,remarkPlugins, etc.)pathMeta-related options (slug/path metadata behavior)
Full details for build/database/renderer/watch (including defaults and option types) are documented here: [1]
Sources: [1] [2] [3]
Move syntax highlighting configuration to content.build.markdown.highlight.
In @nuxt/content v3, the highlight option is no longer a top-level content module property. It must be nested under content.build.markdown.highlight. Update the configuration to:
content: {
build: {
markdown: {
highlight: {
theme: 'one-dark-pro',
},
},
},
},🧰 Tools
🪛 GitHub Actions: PR Validation
[error] 193-193: TypeScript error: Object literal may only specify known properties, and 'highlight' does not exist in type 'Partial'.
🪛 GitHub Check: Build, typecheck, and test
[failure] 193-193:
Object literal may only specify known properties, and 'highlight' does not exist in type 'Partial'.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@nuxt.config.ts` around lines 191 - 196, The current top-level
content.highlight setting must be moved under the build->markdown tree: remove
the existing content.highlight entry and add it as
content.build.markdown.highlight with the same theme value (i.e., move the
'highlight' object from the top-level 'content' config into
'content.build.markdown.highlight'); update the 'content' object in nuxt config
so the 'highlight' key lives at content.build.markdown.highlight (preserving
theme: 'one-dark-pro').
Signed-off-by: Joachim <joachim.l.kolle.pers@gmail.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
app/pages/docs/[...slug].vue (2)
84-90: Consider centralizing section-to-icon mappings.The
sectionIconsmapping here (5 entries) differs from theiconMapinapp/pages/docs/index.vue(19 entries with different keys). Both files independently define icon mappings, which could lead to maintenance drift.Consider extracting a shared
docs-config.tsutility:// app/utils/docs-config.ts import { Rocket, Container, Briefcase, Layers, Code, BookOpen } from 'lucide-vue-next' import type { LucideIcon } from 'lucide-vue-next' export const sectionIcons: Record<string, LucideIcon> = { 'Getting Started': Rocket, 'Deployment': Container, 'Features': Briefcase, 'Architecture': Layers, 'Contributing': Code, } export const defaultIcon = BookOpen🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/pages/docs/`[...slug].vue around lines 84 - 90, The section-to-icon mapping is duplicated between sectionIcons and iconMap; extract a shared mapping and default icon into a new module (e.g., docs-config) and import it where needed: move the current sectionIcons object into the new module, add a defaultIcon (e.g., BookOpen), and update both the sectionIcons reference in the component that defines sectionIcons and the iconMap user in the other component to import the shared sectionIcons and defaultIcon; ensure all references to sectionIcons and iconMap keys align (rename or merge keys as needed) so components use the single canonical mapping.
104-108: Consider adding fallbacks for defensive robustness, though current docs are well-formed.Verification confirms all 19 docs in
content/docs/havetitlefields defined, anddoc.pathis auto-generated by Nuxt Content. The non-null assertions are currently safe. However, adding fallback values would improve resilience against edge cases and makes the code more defensive:grouped[section].push({ - path: doc.path!, - title: doc.title!, + path: doc.path ?? '', + title: doc.title ?? 'Untitled', active: doc.path === slugPath.value, })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/pages/docs/`[...slug].vue around lines 104 - 108, The code uses non-null assertions for doc.path and doc.title when pushing into grouped[section]; replace these with safe fallbacks to avoid runtime errors: use a fallback path like doc.path ?? '' (or String(doc.path ?? '')) and a fallback title like doc.title ?? 'Untitled' (or similar), and compute active by comparing (doc.path ?? '') to slugPath.value to ensure the comparison won't fail if path is undefined; update the push in the grouped[section] block and any related logic that reads doc.path/doc.title to use these fallbacks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@app/pages/docs/`[...slug].vue:
- Around line 84-90: The section-to-icon mapping is duplicated between
sectionIcons and iconMap; extract a shared mapping and default icon into a new
module (e.g., docs-config) and import it where needed: move the current
sectionIcons object into the new module, add a defaultIcon (e.g., BookOpen), and
update both the sectionIcons reference in the component that defines
sectionIcons and the iconMap user in the other component to import the shared
sectionIcons and defaultIcon; ensure all references to sectionIcons and iconMap
keys align (rename or merge keys as needed) so components use the single
canonical mapping.
- Around line 104-108: The code uses non-null assertions for doc.path and
doc.title when pushing into grouped[section]; replace these with safe fallbacks
to avoid runtime errors: use a fallback path like doc.path ?? '' (or
String(doc.path ?? '')) and a fallback title like doc.title ?? 'Untitled' (or
similar), and compute active by comparing (doc.path ?? '') to slugPath.value to
ensure the comparison won't fail if path is undefined; update the push in the
grouped[section] block and any related logic that reads doc.path/doc.title to
use these fallbacks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 07fbdfee-7cfe-4627-8a60-09f6bf0be368
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (9)
.github/workflows/allure-pages.yml.github/workflows/e2e-tests.yml.gitignore.npmrcallurerc.mjsapp/pages/docs/[...slug].vuenuxt.config.tspackage.jsonplaywright.config.ts
💤 Files with no reviewable changes (4)
- playwright.config.ts
- .github/workflows/allure-pages.yml
- .github/workflows/e2e-tests.yml
- allurerc.mjs
Summary
Type of change
Validation
DCO
Signed-off-by) viagit commit -sSummary by CodeRabbit
New Features
Documentation
Configuration
Chores