Create the setup for the documentation page (#171)

* don't run for generated docusaurus

* format

* workflow to autoupdate docs version

* fix versioning

* add link back to app

* remove old docs

* html link???

* don't track .docusaurus

* documantation build
This commit is contained in:
Shaheer Sarfaraz 2026-02-15 22:50:52 +00:00 committed by GitHub
parent 3c41df9ba8
commit 1f929dfc7f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
76 changed files with 105 additions and 2786 deletions

View File

@ -76,7 +76,22 @@ jobs:
run: npm --workspace orchestrator run build:client
working-directory: .
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci --workspaces --include-workspace-root
working-directory: .
- name: Build documentation site
if: matrix.project == 'orchestrator'
run: npm run check:docs
working-directory: .

62
.github/workflows/docs-version.yml vendored Normal file
View File

@ -0,0 +1,62 @@
name: docs-version
on:
push:
tags: ["v*"]
permissions:
contents: write
concurrency:
group: docs-version-${{ github.ref }}
cancel-in-progress: true
jobs:
version-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci --workspaces --include-workspace-root
working-directory: .
- name: Derive docs version from tag
id: vars
run: |
VERSION="${GITHUB_REF_NAME#v}"
if [ -z "$VERSION" ]; then
echo "Unable to derive version from tag '$GITHUB_REF_NAME'" >&2
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
- name: Generate docs version
run: npm run docs:version -- "${{ steps.vars.outputs.version }}"
working-directory: .
- name: Commit and push generated docs version files
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add docs-site/versions.json docs-site/versioned_docs docs-site/versioned_sidebars
if git diff --cached --quiet; then
echo "No docs version changes detected; skipping commit."
exit 0
fi
git commit -m "docs: cut version ${{ steps.vars.outputs.version }}"
git push origin HEAD:main

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ node_modules/
**/node_modules/
**/.package-lock.json
**/.docusaurus/
docs-site/.docusaurus/
docs-site/build/
# Data directory (bind mount in Docker)

View File

@ -5,7 +5,12 @@
"indentWidth": 2
},
"files": {
"includes": ["**", "!!**/dist"]
"includes": [
"**",
"!!**/dist",
"!!docs-site/.docusaurus",
"!!docs-site/build"
]
},
"css": {
"parser": {

View File

@ -1,5 +0,0 @@
This folder stores temp files that Docusaurus' client bundler accesses.
DO NOT hand-modify files in this folder because they will be overwritten in the
next build. You can clear all build artifacts (including this folder) with the
`docusaurus clear` command.

View File

@ -1,7 +0,0 @@
export default [
require("/Users/ssarfaraz/coding/personal/job-ops/docs-site/.docusaurus/docusaurus-plugin-css-cascade-layers/default/layers.css"),
require("/Users/ssarfaraz/coding/personal/job-ops/node_modules/infima/dist/css/default/default.css"),
require("/Users/ssarfaraz/coding/personal/job-ops/node_modules/@docusaurus/theme-classic/lib/prism-include-languages"),
require("/Users/ssarfaraz/coding/personal/job-ops/node_modules/@docusaurus/theme-classic/lib/nprogress"),
require("/Users/ssarfaraz/coding/personal/job-ops/docs-site/src/css/custom.css"),
];

View File

@ -1 +0,0 @@
{}

View File

@ -1 +0,0 @@
{"options":{"routeBasePath":"/","sidebarPath":"/Users/ssarfaraz/coding/personal/job-ops/docs-site/sidebars.ts","editUrl":"https://github.com/DaKheera47/job-ops/tree/main/docs-site/","showLastUpdateAuthor":false,"showLastUpdateTime":true,"path":"docs","editCurrentVersion":false,"editLocalizedFiles":false,"tagsBasePath":"tags","include":["**/*.{md,mdx}"],"exclude":["**/_*.{js,jsx,ts,tsx,md,mdx}","**/_*/**","**/*.test.{js,jsx,ts,tsx}","**/__tests__/**"],"sidebarCollapsible":true,"sidebarCollapsed":true,"docsRootComponent":"@theme/DocsRoot","docVersionRootComponent":"@theme/DocVersionRoot","docRootComponent":"@theme/DocRoot","docItemComponent":"@theme/DocItem","docTagsListComponent":"@theme/DocTagsListPage","docTagDocListComponent":"@theme/DocTagDocListPage","docCategoryGeneratedIndexComponent":"@theme/DocCategoryGeneratedIndexPage","remarkPlugins":[],"rehypePlugins":[],"recmaPlugins":[],"beforeDefaultRemarkPlugins":[],"beforeDefaultRehypePlugins":[],"admonitions":true,"includeCurrentVersion":true,"disableVersioning":false,"versions":{},"breadcrumbs":true,"onInlineTags":"warn","id":"default"},"versionsMetadata":[{"versionName":"current","label":"Next","banner":"unreleased","badge":true,"noIndex":false,"className":"docs-version-current","path":"/docs/next","tagsPath":"/docs/next/tags","editUrl":"https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs","isLast":false,"sidebarFilePath":"/Users/ssarfaraz/coding/personal/job-ops/docs-site/sidebars.ts","contentPath":"/Users/ssarfaraz/coding/personal/job-ops/docs-site/docs"},{"versionName":"1.0.0","label":"1.0.0","banner":null,"badge":true,"noIndex":false,"className":"docs-version-1.0.0","path":"/docs/","tagsPath":"/docs/tags","editUrl":"https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0","isLast":true,"routePriority":-1,"sidebarFilePath":"/Users/ssarfaraz/coding/personal/job-ops/docs-site/versioned_sidebars/version-1.0.0-sidebars.json","contentPath":"/Users/ssarfaraz/coding/personal/job-ops/docs-site/versioned_docs/version-1.0.0"}]}

View File

@ -1,4 +0,0 @@
{
"name": "docusaurus-plugin-content-docs",
"id": "default"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,31 +0,0 @@
{
"id": "extractors/gradcracker",
"title": "Gradcracker Extractor",
"description": "How the Gradcracker crawler builds search URLs and extracts jobs.",
"source": "@site/docs/extractors/gradcracker.md",
"sourceDirName": "extractors",
"slug": "/extractors/gradcracker",
"permalink": "/docs/next/extractors/gradcracker",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/extractors/gradcracker.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "gradcracker",
"title": "Gradcracker Extractor",
"description": "How the Gradcracker crawler builds search URLs and extracts jobs.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "Extractors Overview",
"permalink": "/docs/next/extractors/overview"
},
"next": {
"title": "JobSpy Extractor",
"permalink": "/docs/next/extractors/jobspy"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/jobspy",
"title": "JobSpy Extractor",
"description": "How the JobSpy Python wrapper is orchestrated and normalized.",
"source": "@site/docs/extractors/jobspy.md",
"sourceDirName": "extractors",
"slug": "/extractors/jobspy",
"permalink": "/docs/next/extractors/jobspy",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/extractors/jobspy.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 3,
"frontMatter": {
"id": "jobspy",
"title": "JobSpy Extractor",
"description": "How the JobSpy Python wrapper is orchestrated and normalized.",
"sidebar_position": 3
},
"sidebar": "docsSidebar",
"previous": {
"title": "Gradcracker Extractor",
"permalink": "/docs/next/extractors/gradcracker"
},
"next": {
"title": "Manual Import Extractor",
"permalink": "/docs/next/extractors/manual"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/manual",
"title": "Manual Import Extractor",
"description": "Import jobs from pasted descriptions and run AI-assisted inference.",
"source": "@site/docs/extractors/manual.md",
"sourceDirName": "extractors",
"slug": "/extractors/manual",
"permalink": "/docs/next/extractors/manual",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/extractors/manual.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 4,
"frontMatter": {
"id": "manual",
"title": "Manual Import Extractor",
"description": "Import jobs from pasted descriptions and run AI-assisted inference.",
"sidebar_position": 4
},
"sidebar": "docsSidebar",
"previous": {
"title": "JobSpy Extractor",
"permalink": "/docs/next/extractors/jobspy"
},
"next": {
"title": "UKVisaJobs Extractor",
"permalink": "/docs/next/extractors/ukvisajobs"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/overview",
"title": "Extractors Overview",
"description": "Technical index of supported extractors and how they work.",
"source": "@site/docs/extractors/overview.md",
"sourceDirName": "extractors",
"slug": "/extractors/overview",
"permalink": "/docs/next/extractors/overview",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/extractors/overview.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "overview",
"title": "Extractors Overview",
"description": "Technical index of supported extractors and how they work.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Post-Application Tracking",
"permalink": "/docs/next/features/post-application-tracking"
},
"next": {
"title": "Gradcracker Extractor",
"permalink": "/docs/next/extractors/gradcracker"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/ukvisajobs",
"title": "UKVisaJobs Extractor",
"description": "Authenticated session flow, API pagination, and orchestrator ingestion.",
"source": "@site/docs/extractors/ukvisajobs.md",
"sourceDirName": "extractors",
"slug": "/extractors/ukvisajobs",
"permalink": "/docs/next/extractors/ukvisajobs",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/extractors/ukvisajobs.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 5,
"frontMatter": {
"id": "ukvisajobs",
"title": "UKVisaJobs Extractor",
"description": "Authenticated session flow, API pagination, and orchestrator ingestion.",
"sidebar_position": 5
},
"sidebar": "docsSidebar",
"previous": {
"title": "Manual Import Extractor",
"permalink": "/docs/next/extractors/manual"
},
"next": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/next/getting-started/self-hosting"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/ghostwriter",
"title": "Ghostwriter",
"description": "Context-aware per-job AI chat assistant behavior and API surface.",
"source": "@site/docs/features/ghostwriter.md",
"sourceDirName": "features",
"slug": "/features/ghostwriter",
"permalink": "/docs/next/features/ghostwriter",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/features/ghostwriter.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "ghostwriter",
"title": "Ghostwriter",
"description": "Context-aware per-job AI chat assistant behavior and API surface.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "Orchestrator",
"permalink": "/docs/next/features/orchestrator"
},
"next": {
"title": "Post-Application Tracking",
"permalink": "/docs/next/features/post-application-tracking"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/orchestrator",
"title": "Orchestrator",
"description": "Job states, ready flow, and PDF generation/regeneration behavior.",
"source": "@site/docs/features/orchestrator.md",
"sourceDirName": "features",
"slug": "/features/orchestrator",
"permalink": "/docs/next/features/orchestrator",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/features/orchestrator.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "orchestrator",
"title": "Orchestrator",
"description": "Job states, ready flow, and PDF generation/regeneration behavior.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/next/getting-started/self-hosting"
},
"next": {
"title": "Ghostwriter",
"permalink": "/docs/next/features/ghostwriter"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/post-application-tracking",
"title": "Post-Application Tracking",
"description": "Gmail-based tracking inbox, smart routing, and review workflow.",
"source": "@site/docs/features/post-application-tracking.md",
"sourceDirName": "features",
"slug": "/features/post-application-tracking",
"permalink": "/docs/next/features/post-application-tracking",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/features/post-application-tracking.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 3,
"frontMatter": {
"id": "post-application-tracking",
"title": "Post-Application Tracking",
"description": "Gmail-based tracking inbox, smart routing, and review workflow.",
"sidebar_position": 3
},
"sidebar": "docsSidebar",
"previous": {
"title": "Ghostwriter",
"permalink": "/docs/next/features/ghostwriter"
},
"next": {
"title": "Extractors Overview",
"permalink": "/docs/next/extractors/overview"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "getting-started/self-hosting",
"title": "Self-Hosting (Docker Compose)",
"description": "Deploy JobOps with Docker Compose and configure onboarding integrations.",
"source": "@site/docs/getting-started/self-hosting.md",
"sourceDirName": "getting-started",
"slug": "/getting-started/self-hosting",
"permalink": "/docs/next/getting-started/self-hosting",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/getting-started/self-hosting.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "self-hosting",
"title": "Self-Hosting (Docker Compose)",
"description": "Deploy JobOps with Docker Compose and configure onboarding integrations.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "JobOps Documentation",
"permalink": "/docs/next/"
},
"next": {
"title": "Orchestrator",
"permalink": "/docs/next/features/orchestrator"
}
}

View File

@ -1,28 +0,0 @@
{
"id": "intro",
"title": "JobOps Documentation",
"description": "Documentation index for setup, features, extractors, and common problems.",
"source": "@site/docs/intro.md",
"sourceDirName": ".",
"slug": "/",
"permalink": "/docs/next/",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/intro.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "intro",
"title": "JobOps Documentation",
"description": "Documentation index for setup, features, extractors, and common problems.",
"sidebar_position": 1,
"slug": "/"
},
"sidebar": "docsSidebar",
"next": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/next/getting-started/self-hosting"
}
}

View File

@ -1,27 +0,0 @@
{
"id": "reference/documentation-style-guide",
"title": "Documentation Style Guide",
"description": "Standards for writing user-facing docs in this repository.",
"source": "@site/docs/reference/documentation-style-guide.md",
"sourceDirName": "reference",
"slug": "/reference/documentation-style-guide",
"permalink": "/docs/next/reference/documentation-style-guide",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/reference/documentation-style-guide.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "documentation-style-guide",
"title": "Documentation Style Guide",
"description": "Standards for writing user-facing docs in this repository.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "FAQ",
"permalink": "/docs/next/reference/faq"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "reference/faq",
"title": "FAQ",
"description": "Frequently asked questions about deployment, docs, and operations.",
"source": "@site/docs/reference/faq.md",
"sourceDirName": "reference",
"slug": "/reference/faq",
"permalink": "/docs/next/reference/faq",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/reference/faq.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "faq",
"title": "FAQ",
"description": "Frequently asked questions about deployment, docs, and operations.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Common Problems",
"permalink": "/docs/next/troubleshooting/common-problems"
},
"next": {
"title": "Documentation Style Guide",
"permalink": "/docs/next/reference/documentation-style-guide"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "troubleshooting/common-problems",
"title": "Common Problems",
"description": "Quick fixes for the most frequent setup and runtime issues.",
"source": "@site/docs/troubleshooting/common-problems.md",
"sourceDirName": "troubleshooting",
"slug": "/troubleshooting/common-problems",
"permalink": "/docs/next/troubleshooting/common-problems",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/docs/troubleshooting/common-problems.md",
"tags": [],
"version": "current",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "common-problems",
"title": "Common Problems",
"description": "Quick fixes for the most frequent setup and runtime issues.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/next/getting-started/self-hosting"
},
"next": {
"title": "Common Problems",
"permalink": "/docs/next/troubleshooting/common-problems"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/gradcracker",
"title": "Gradcracker Extractor",
"description": "How the Gradcracker crawler builds search URLs and extracts jobs.",
"source": "@site/versioned_docs/version-1.0.0/extractors/gradcracker.md",
"sourceDirName": "extractors",
"slug": "/extractors/gradcracker",
"permalink": "/docs/extractors/gradcracker",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/extractors/gradcracker.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "gradcracker",
"title": "Gradcracker Extractor",
"description": "How the Gradcracker crawler builds search URLs and extracts jobs.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "Extractors Overview",
"permalink": "/docs/extractors/overview"
},
"next": {
"title": "JobSpy Extractor",
"permalink": "/docs/extractors/jobspy"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/jobspy",
"title": "JobSpy Extractor",
"description": "How the JobSpy Python wrapper is orchestrated and normalized.",
"source": "@site/versioned_docs/version-1.0.0/extractors/jobspy.md",
"sourceDirName": "extractors",
"slug": "/extractors/jobspy",
"permalink": "/docs/extractors/jobspy",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/extractors/jobspy.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 3,
"frontMatter": {
"id": "jobspy",
"title": "JobSpy Extractor",
"description": "How the JobSpy Python wrapper is orchestrated and normalized.",
"sidebar_position": 3
},
"sidebar": "docsSidebar",
"previous": {
"title": "Gradcracker Extractor",
"permalink": "/docs/extractors/gradcracker"
},
"next": {
"title": "Manual Import Extractor",
"permalink": "/docs/extractors/manual"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/manual",
"title": "Manual Import Extractor",
"description": "Import jobs from pasted descriptions and run AI-assisted inference.",
"source": "@site/versioned_docs/version-1.0.0/extractors/manual.md",
"sourceDirName": "extractors",
"slug": "/extractors/manual",
"permalink": "/docs/extractors/manual",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/extractors/manual.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 4,
"frontMatter": {
"id": "manual",
"title": "Manual Import Extractor",
"description": "Import jobs from pasted descriptions and run AI-assisted inference.",
"sidebar_position": 4
},
"sidebar": "docsSidebar",
"previous": {
"title": "JobSpy Extractor",
"permalink": "/docs/extractors/jobspy"
},
"next": {
"title": "UKVisaJobs Extractor",
"permalink": "/docs/extractors/ukvisajobs"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/overview",
"title": "Extractors Overview",
"description": "Technical index of supported extractors and how they work.",
"source": "@site/versioned_docs/version-1.0.0/extractors/overview.md",
"sourceDirName": "extractors",
"slug": "/extractors/overview",
"permalink": "/docs/extractors/overview",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/extractors/overview.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "overview",
"title": "Extractors Overview",
"description": "Technical index of supported extractors and how they work.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Post-Application Tracking",
"permalink": "/docs/features/post-application-tracking"
},
"next": {
"title": "Gradcracker Extractor",
"permalink": "/docs/extractors/gradcracker"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "extractors/ukvisajobs",
"title": "UKVisaJobs Extractor",
"description": "Authenticated session flow, API pagination, and orchestrator ingestion.",
"source": "@site/versioned_docs/version-1.0.0/extractors/ukvisajobs.md",
"sourceDirName": "extractors",
"slug": "/extractors/ukvisajobs",
"permalink": "/docs/extractors/ukvisajobs",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/extractors/ukvisajobs.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 5,
"frontMatter": {
"id": "ukvisajobs",
"title": "UKVisaJobs Extractor",
"description": "Authenticated session flow, API pagination, and orchestrator ingestion.",
"sidebar_position": 5
},
"sidebar": "docsSidebar",
"previous": {
"title": "Manual Import Extractor",
"permalink": "/docs/extractors/manual"
},
"next": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/getting-started/self-hosting"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/ghostwriter",
"title": "Ghostwriter",
"description": "Context-aware per-job AI chat assistant behavior and API surface.",
"source": "@site/versioned_docs/version-1.0.0/features/ghostwriter.md",
"sourceDirName": "features",
"slug": "/features/ghostwriter",
"permalink": "/docs/features/ghostwriter",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/features/ghostwriter.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "ghostwriter",
"title": "Ghostwriter",
"description": "Context-aware per-job AI chat assistant behavior and API surface.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "Orchestrator",
"permalink": "/docs/features/orchestrator"
},
"next": {
"title": "Post-Application Tracking",
"permalink": "/docs/features/post-application-tracking"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/orchestrator",
"title": "Orchestrator",
"description": "Job states, ready flow, and PDF generation/regeneration behavior.",
"source": "@site/versioned_docs/version-1.0.0/features/orchestrator.md",
"sourceDirName": "features",
"slug": "/features/orchestrator",
"permalink": "/docs/features/orchestrator",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/features/orchestrator.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "orchestrator",
"title": "Orchestrator",
"description": "Job states, ready flow, and PDF generation/regeneration behavior.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/getting-started/self-hosting"
},
"next": {
"title": "Ghostwriter",
"permalink": "/docs/features/ghostwriter"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "features/post-application-tracking",
"title": "Post-Application Tracking",
"description": "Gmail-based tracking inbox, smart routing, and review workflow.",
"source": "@site/versioned_docs/version-1.0.0/features/post-application-tracking.md",
"sourceDirName": "features",
"slug": "/features/post-application-tracking",
"permalink": "/docs/features/post-application-tracking",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/features/post-application-tracking.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 3,
"frontMatter": {
"id": "post-application-tracking",
"title": "Post-Application Tracking",
"description": "Gmail-based tracking inbox, smart routing, and review workflow.",
"sidebar_position": 3
},
"sidebar": "docsSidebar",
"previous": {
"title": "Ghostwriter",
"permalink": "/docs/features/ghostwriter"
},
"next": {
"title": "Extractors Overview",
"permalink": "/docs/extractors/overview"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "getting-started/self-hosting",
"title": "Self-Hosting (Docker Compose)",
"description": "Deploy JobOps with Docker Compose and configure onboarding integrations.",
"source": "@site/versioned_docs/version-1.0.0/getting-started/self-hosting.md",
"sourceDirName": "getting-started",
"slug": "/getting-started/self-hosting",
"permalink": "/docs/getting-started/self-hosting",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/getting-started/self-hosting.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "self-hosting",
"title": "Self-Hosting (Docker Compose)",
"description": "Deploy JobOps with Docker Compose and configure onboarding integrations.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "JobOps Documentation",
"permalink": "/docs/"
},
"next": {
"title": "Orchestrator",
"permalink": "/docs/features/orchestrator"
}
}

View File

@ -1,28 +0,0 @@
{
"id": "intro",
"title": "JobOps Documentation",
"description": "Documentation index for setup, features, extractors, and common problems.",
"source": "@site/versioned_docs/version-1.0.0/intro.md",
"sourceDirName": ".",
"slug": "/",
"permalink": "/docs/",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/intro.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "intro",
"title": "JobOps Documentation",
"description": "Documentation index for setup, features, extractors, and common problems.",
"sidebar_position": 1,
"slug": "/"
},
"sidebar": "docsSidebar",
"next": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/getting-started/self-hosting"
}
}

View File

@ -1,27 +0,0 @@
{
"id": "reference/documentation-style-guide",
"title": "Documentation Style Guide",
"description": "Standards for writing user-facing docs in this repository.",
"source": "@site/versioned_docs/version-1.0.0/reference/documentation-style-guide.md",
"sourceDirName": "reference",
"slug": "/reference/documentation-style-guide",
"permalink": "/docs/reference/documentation-style-guide",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/reference/documentation-style-guide.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 2,
"frontMatter": {
"id": "documentation-style-guide",
"title": "Documentation Style Guide",
"description": "Standards for writing user-facing docs in this repository.",
"sidebar_position": 2
},
"sidebar": "docsSidebar",
"previous": {
"title": "FAQ",
"permalink": "/docs/reference/faq"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "reference/faq",
"title": "FAQ",
"description": "Frequently asked questions about deployment, docs, and operations.",
"source": "@site/versioned_docs/version-1.0.0/reference/faq.md",
"sourceDirName": "reference",
"slug": "/reference/faq",
"permalink": "/docs/reference/faq",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/reference/faq.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "faq",
"title": "FAQ",
"description": "Frequently asked questions about deployment, docs, and operations.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Common Problems",
"permalink": "/docs/troubleshooting/common-problems"
},
"next": {
"title": "Documentation Style Guide",
"permalink": "/docs/reference/documentation-style-guide"
}
}

View File

@ -1,31 +0,0 @@
{
"id": "troubleshooting/common-problems",
"title": "Common Problems",
"description": "Quick fixes for the most frequent setup and runtime issues.",
"source": "@site/versioned_docs/version-1.0.0/troubleshooting/common-problems.md",
"sourceDirName": "troubleshooting",
"slug": "/troubleshooting/common-problems",
"permalink": "/docs/troubleshooting/common-problems",
"draft": false,
"unlisted": false,
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/versioned_docs/version-1.0.0/troubleshooting/common-problems.md",
"tags": [],
"version": "1.0.0",
"lastUpdatedAt": 1539502055000,
"sidebarPosition": 1,
"frontMatter": {
"id": "common-problems",
"title": "Common Problems",
"description": "Quick fixes for the most frequent setup and runtime issues.",
"sidebar_position": 1
},
"sidebar": "docsSidebar",
"previous": {
"title": "Self-Hosting (Docker Compose)",
"permalink": "/docs/getting-started/self-hosting"
},
"next": {
"title": "Common Problems",
"permalink": "/docs/troubleshooting/common-problems"
}
}

View File

@ -1,4 +0,0 @@
{
"name": "docusaurus-plugin-css-cascade-layers",
"id": "default"
}

View File

@ -1 +0,0 @@
@layer docusaurus.infima, docusaurus.theme-common, docusaurus.theme-classic, docusaurus.core, docusaurus.plugin-debug, docusaurus.theme-mermaid, docusaurus.theme-live-codeblock, docusaurus.theme-search-algolia.docsearch, docusaurus.theme-search-algolia;

View File

@ -1,4 +0,0 @@
{
"name": "docusaurus-plugin-debug",
"id": "default"
}

View File

@ -1,386 +0,0 @@
/*
* AUTOGENERATED - DON'T EDIT
* Your edits in this file will be overwritten in the next build!
* Modify the docusaurus.config.js file at your site's root instead.
*/
export default {
"title": "JobOps Documentation",
"tagline": "Self-hosted job search automation docs",
"favicon": "img/favicon.ico",
"future": {
"v4": {
"removeLegacyPostBuildHeadAttribute": true,
"useCssCascadeLayers": true
},
"experimental_faster": {
"swcJsLoader": false,
"swcJsMinimizer": false,
"swcHtmlMinimizer": false,
"lightningCssMinimizer": false,
"mdxCrossCompilerCache": false,
"rspackBundler": false,
"rspackPersistentCache": false,
"ssgWorkerThreads": false
},
"experimental_storage": {
"type": "localStorage",
"namespace": false
},
"experimental_router": "browser"
},
"url": "http://localhost:3005",
"baseUrl": "/docs/",
"onBrokenLinks": "throw",
"markdown": {
"hooks": {
"onBrokenMarkdownLinks": "throw",
"onBrokenMarkdownImages": "throw"
},
"format": "mdx",
"mermaid": false,
"emoji": true,
"mdx1Compat": {
"comments": true,
"admonitions": true,
"headingIds": true
},
"anchors": {
"maintainCase": false
}
},
"i18n": {
"defaultLocale": "en",
"locales": [
"en"
],
"path": "i18n",
"localeConfigs": {}
},
"presets": [
[
"classic",
{
"docs": {
"routeBasePath": "/",
"sidebarPath": "./sidebars.ts",
"editUrl": "https://github.com/DaKheera47/job-ops/tree/main/docs-site/",
"showLastUpdateAuthor": false,
"showLastUpdateTime": true
},
"blog": false,
"pages": false,
"theme": {
"customCss": "./src/css/custom.css"
}
}
]
],
"themeConfig": {
"navbar": {
"title": "JobOps Docs",
"logo": {
"alt": "JobOps",
"src": "img/logo.svg"
},
"items": [
{
"type": "docSidebar",
"sidebarId": "docsSidebar",
"position": "left",
"label": "Documentation"
},
{
"to": "/",
"label": "Latest",
"position": "left"
},
{
"type": "docsVersionDropdown",
"position": "right",
"dropdownActiveClassDisabled": true,
"dropdownItemsBefore": [],
"dropdownItemsAfter": []
},
{
"href": "https://github.com/DaKheera47/job-ops",
"label": "GitHub",
"position": "right"
}
],
"hideOnScroll": false
},
"footer": {
"style": "dark",
"links": [
{
"title": "Docs",
"items": [
{
"label": "Introduction",
"to": "/"
},
{
"label": "Self-Hosting",
"to": "/getting-started/self-hosting"
}
]
},
{
"title": "Project",
"items": [
{
"label": "Repository",
"href": "https://github.com/DaKheera47/job-ops"
},
{
"label": "Issues",
"href": "https://github.com/DaKheera47/job-ops/issues"
}
]
}
],
"copyright": "Copyright © 2026 JobOps"
},
"prism": {
"theme": {
"plain": {
"color": "#393A34",
"backgroundColor": "#f6f8fa"
},
"styles": [
{
"types": [
"comment",
"prolog",
"doctype",
"cdata"
],
"style": {
"color": "#999988",
"fontStyle": "italic"
}
},
{
"types": [
"namespace"
],
"style": {
"opacity": 0.7
}
},
{
"types": [
"string",
"attr-value"
],
"style": {
"color": "#e3116c"
}
},
{
"types": [
"punctuation",
"operator"
],
"style": {
"color": "#393A34"
}
},
{
"types": [
"entity",
"url",
"symbol",
"number",
"boolean",
"variable",
"constant",
"property",
"regex",
"inserted"
],
"style": {
"color": "#36acaa"
}
},
{
"types": [
"atrule",
"keyword",
"attr-name",
"selector"
],
"style": {
"color": "#00a4db"
}
},
{
"types": [
"function",
"deleted",
"tag"
],
"style": {
"color": "#d73a49"
}
},
{
"types": [
"function-variable"
],
"style": {
"color": "#6f42c1"
}
},
{
"types": [
"tag",
"selector",
"keyword"
],
"style": {
"color": "#00009f"
}
}
]
},
"darkTheme": {
"plain": {
"color": "#F8F8F2",
"backgroundColor": "#282A36"
},
"styles": [
{
"types": [
"prolog",
"constant",
"builtin"
],
"style": {
"color": "rgb(189, 147, 249)"
}
},
{
"types": [
"inserted",
"function"
],
"style": {
"color": "rgb(80, 250, 123)"
}
},
{
"types": [
"deleted"
],
"style": {
"color": "rgb(255, 85, 85)"
}
},
{
"types": [
"changed"
],
"style": {
"color": "rgb(255, 184, 108)"
}
},
{
"types": [
"punctuation",
"symbol"
],
"style": {
"color": "rgb(248, 248, 242)"
}
},
{
"types": [
"string",
"char",
"tag",
"selector"
],
"style": {
"color": "rgb(255, 121, 198)"
}
},
{
"types": [
"keyword",
"variable"
],
"style": {
"color": "rgb(189, 147, 249)",
"fontStyle": "italic"
}
},
{
"types": [
"comment"
],
"style": {
"color": "rgb(98, 114, 164)"
}
},
{
"types": [
"attr-name"
],
"style": {
"color": "rgb(241, 250, 140)"
}
}
]
},
"additionalLanguages": [],
"magicComments": [
{
"className": "theme-code-block-highlighted-line",
"line": "highlight-next-line",
"block": {
"start": "highlight-start",
"end": "highlight-end"
}
}
]
},
"colorMode": {
"defaultMode": "light",
"disableSwitch": false,
"respectPrefersColorScheme": false
},
"docs": {
"versionPersistence": "localStorage",
"sidebar": {
"hideable": false,
"autoCollapseCategories": false
}
},
"blog": {
"sidebar": {
"groupByYear": true
}
},
"metadata": [],
"tableOfContents": {
"minHeadingLevel": 2,
"maxHeadingLevel": 3
}
},
"baseUrlIssueBanner": true,
"onBrokenAnchors": "warn",
"onDuplicateRoutes": "warn",
"staticDirectories": [
"static"
],
"customFields": {},
"plugins": [],
"themes": [],
"scripts": [],
"headTags": [],
"stylesheets": [],
"clientModules": [],
"titleDelimiter": "|",
"noIndex": false
};

View File

@ -1,176 +0,0 @@
{
"docusaurus-plugin-content-docs": {
"default": {
"path": "/docs/",
"versions": [
{
"name": "current",
"label": "Next",
"isLast": false,
"path": "/docs/next",
"mainDocId": "intro",
"docs": [
{
"id": "extractors/gradcracker",
"path": "/docs/next/extractors/gradcracker",
"sidebar": "docsSidebar"
},
{
"id": "extractors/jobspy",
"path": "/docs/next/extractors/jobspy",
"sidebar": "docsSidebar"
},
{
"id": "extractors/manual",
"path": "/docs/next/extractors/manual",
"sidebar": "docsSidebar"
},
{
"id": "extractors/overview",
"path": "/docs/next/extractors/overview",
"sidebar": "docsSidebar"
},
{
"id": "extractors/ukvisajobs",
"path": "/docs/next/extractors/ukvisajobs",
"sidebar": "docsSidebar"
},
{
"id": "features/ghostwriter",
"path": "/docs/next/features/ghostwriter",
"sidebar": "docsSidebar"
},
{
"id": "features/orchestrator",
"path": "/docs/next/features/orchestrator",
"sidebar": "docsSidebar"
},
{
"id": "features/post-application-tracking",
"path": "/docs/next/features/post-application-tracking",
"sidebar": "docsSidebar"
},
{
"id": "getting-started/self-hosting",
"path": "/docs/next/getting-started/self-hosting",
"sidebar": "docsSidebar"
},
{
"id": "intro",
"path": "/docs/next/",
"sidebar": "docsSidebar"
},
{
"id": "reference/documentation-style-guide",
"path": "/docs/next/reference/documentation-style-guide",
"sidebar": "docsSidebar"
},
{
"id": "reference/faq",
"path": "/docs/next/reference/faq",
"sidebar": "docsSidebar"
},
{
"id": "troubleshooting/common-problems",
"path": "/docs/next/troubleshooting/common-problems",
"sidebar": "docsSidebar"
}
],
"draftIds": [],
"sidebars": {
"docsSidebar": {
"link": {
"path": "/docs/next/",
"label": "intro"
}
}
}
},
{
"name": "1.0.0",
"label": "1.0.0",
"isLast": true,
"path": "/docs/",
"mainDocId": "intro",
"docs": [
{
"id": "extractors/gradcracker",
"path": "/docs/extractors/gradcracker",
"sidebar": "docsSidebar"
},
{
"id": "extractors/jobspy",
"path": "/docs/extractors/jobspy",
"sidebar": "docsSidebar"
},
{
"id": "extractors/manual",
"path": "/docs/extractors/manual",
"sidebar": "docsSidebar"
},
{
"id": "extractors/overview",
"path": "/docs/extractors/overview",
"sidebar": "docsSidebar"
},
{
"id": "extractors/ukvisajobs",
"path": "/docs/extractors/ukvisajobs",
"sidebar": "docsSidebar"
},
{
"id": "features/ghostwriter",
"path": "/docs/features/ghostwriter",
"sidebar": "docsSidebar"
},
{
"id": "features/orchestrator",
"path": "/docs/features/orchestrator",
"sidebar": "docsSidebar"
},
{
"id": "features/post-application-tracking",
"path": "/docs/features/post-application-tracking",
"sidebar": "docsSidebar"
},
{
"id": "getting-started/self-hosting",
"path": "/docs/getting-started/self-hosting",
"sidebar": "docsSidebar"
},
{
"id": "intro",
"path": "/docs/",
"sidebar": "docsSidebar"
},
{
"id": "reference/documentation-style-guide",
"path": "/docs/reference/documentation-style-guide",
"sidebar": "docsSidebar"
},
{
"id": "reference/faq",
"path": "/docs/reference/faq",
"sidebar": "docsSidebar"
},
{
"id": "troubleshooting/common-problems",
"path": "/docs/troubleshooting/common-problems",
"sidebar": "docsSidebar"
}
],
"draftIds": [],
"sidebars": {
"docsSidebar": {
"link": {
"path": "/docs/",
"label": "intro"
}
}
}
}
],
"breadcrumbs": true
}
}
}

View File

@ -1,20 +0,0 @@
{
"defaultLocale": "en",
"locales": [
"en"
],
"path": "i18n",
"currentLocale": "en",
"localeConfigs": {
"en": {
"label": "English",
"direction": "ltr",
"htmlLang": "en",
"calendar": "gregory",
"path": "en",
"translate": false,
"url": "http://localhost:3005",
"baseUrl": "/docs/"
}
}
}

View File

@ -1,42 +0,0 @@
export default {
"__comp---theme-debug-config-23-a-2ff": [() => import(/* webpackChunkName: "__comp---theme-debug-config-23-a-2ff" */ "@theme/DebugConfig"), "@theme/DebugConfig", require.resolveWeak("@theme/DebugConfig")],
"__comp---theme-debug-contentba-8-ce7": [() => import(/* webpackChunkName: "__comp---theme-debug-contentba-8-ce7" */ "@theme/DebugContent"), "@theme/DebugContent", require.resolveWeak("@theme/DebugContent")],
"__comp---theme-debug-global-dataede-0fa": [() => import(/* webpackChunkName: "__comp---theme-debug-global-dataede-0fa" */ "@theme/DebugGlobalData"), "@theme/DebugGlobalData", require.resolveWeak("@theme/DebugGlobalData")],
"__comp---theme-debug-registry-679-501": [() => import(/* webpackChunkName: "__comp---theme-debug-registry-679-501" */ "@theme/DebugRegistry"), "@theme/DebugRegistry", require.resolveWeak("@theme/DebugRegistry")],
"__comp---theme-debug-routes-946-699": [() => import(/* webpackChunkName: "__comp---theme-debug-routes-946-699" */ "@theme/DebugRoutes"), "@theme/DebugRoutes", require.resolveWeak("@theme/DebugRoutes")],
"__comp---theme-debug-site-metadata-68-e-3d4": [() => import(/* webpackChunkName: "__comp---theme-debug-site-metadata-68-e-3d4" */ "@theme/DebugSiteMetadata"), "@theme/DebugSiteMetadata", require.resolveWeak("@theme/DebugSiteMetadata")],
"__comp---theme-doc-item-178-a40": [() => import(/* webpackChunkName: "__comp---theme-doc-item-178-a40" */ "@theme/DocItem"), "@theme/DocItem", require.resolveWeak("@theme/DocItem")],
"__comp---theme-doc-roota-94-67a": [() => import(/* webpackChunkName: "__comp---theme-doc-roota-94-67a" */ "@theme/DocRoot"), "@theme/DocRoot", require.resolveWeak("@theme/DocRoot")],
"__comp---theme-doc-version-roota-7-b-5de": [() => import(/* webpackChunkName: "__comp---theme-doc-version-roota-7-b-5de" */ "@theme/DocVersionRoot"), "@theme/DocVersionRoot", require.resolveWeak("@theme/DocVersionRoot")],
"__comp---theme-docs-root-5-e-9-0b6": [() => import(/* webpackChunkName: "__comp---theme-docs-root-5-e-9-0b6" */ "@theme/DocsRoot"), "@theme/DocsRoot", require.resolveWeak("@theme/DocsRoot")],
"__props---docs-11-b-f70": [() => import(/* webpackChunkName: "__props---docs-11-b-f70" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-7fc.json")],
"__props---docs-docusaurus-debug-content-344-8d5": [() => import(/* webpackChunkName: "__props---docs-docusaurus-debug-content-344-8d5" */ "@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json"), "@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json", require.resolveWeak("@generated/docusaurus-plugin-debug/default/p/docs-docusaurus-debug-content-a52.json")],
"__props---docs-nextbf-1-ba7": [() => import(/* webpackChunkName: "__props---docs-nextbf-1-ba7" */ "@generated/docusaurus-plugin-content-docs/default/p/docs-next-d71.json"), "@generated/docusaurus-plugin-content-docs/default/p/docs-next-d71.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/p/docs-next-d71.json")],
"content---docs-5-d-9-a16": [() => import(/* webpackChunkName: "content---docs-5-d-9-a16" */ "@site/versioned_docs/version-1.0.0/intro.md"), "@site/versioned_docs/version-1.0.0/intro.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/intro.md")],
"content---docs-extractors-gradcracker-529-af3": [() => import(/* webpackChunkName: "content---docs-extractors-gradcracker-529-af3" */ "@site/versioned_docs/version-1.0.0/extractors/gradcracker.md"), "@site/versioned_docs/version-1.0.0/extractors/gradcracker.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/extractors/gradcracker.md")],
"content---docs-extractors-jobspy-80-d-e15": [() => import(/* webpackChunkName: "content---docs-extractors-jobspy-80-d-e15" */ "@site/versioned_docs/version-1.0.0/extractors/jobspy.md"), "@site/versioned_docs/version-1.0.0/extractors/jobspy.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/extractors/jobspy.md")],
"content---docs-extractors-manual-479-cf9": [() => import(/* webpackChunkName: "content---docs-extractors-manual-479-cf9" */ "@site/versioned_docs/version-1.0.0/extractors/manual.md"), "@site/versioned_docs/version-1.0.0/extractors/manual.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/extractors/manual.md")],
"content---docs-extractors-overview-6-d-9-5d6": [() => import(/* webpackChunkName: "content---docs-extractors-overview-6-d-9-5d6" */ "@site/versioned_docs/version-1.0.0/extractors/overview.md"), "@site/versioned_docs/version-1.0.0/extractors/overview.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/extractors/overview.md")],
"content---docs-extractors-ukvisajobs-31-a-da8": [() => import(/* webpackChunkName: "content---docs-extractors-ukvisajobs-31-a-da8" */ "@site/versioned_docs/version-1.0.0/extractors/ukvisajobs.md"), "@site/versioned_docs/version-1.0.0/extractors/ukvisajobs.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/extractors/ukvisajobs.md")],
"content---docs-features-ghostwriter-185-10f": [() => import(/* webpackChunkName: "content---docs-features-ghostwriter-185-10f" */ "@site/versioned_docs/version-1.0.0/features/ghostwriter.md"), "@site/versioned_docs/version-1.0.0/features/ghostwriter.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/features/ghostwriter.md")],
"content---docs-features-orchestrator-24-b-7c5": [() => import(/* webpackChunkName: "content---docs-features-orchestrator-24-b-7c5" */ "@site/versioned_docs/version-1.0.0/features/orchestrator.md"), "@site/versioned_docs/version-1.0.0/features/orchestrator.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/features/orchestrator.md")],
"content---docs-features-post-application-tracking-3-a-9-fd1": [() => import(/* webpackChunkName: "content---docs-features-post-application-tracking-3-a-9-fd1" */ "@site/versioned_docs/version-1.0.0/features/post-application-tracking.md"), "@site/versioned_docs/version-1.0.0/features/post-application-tracking.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/features/post-application-tracking.md")],
"content---docs-getting-started-self-hostingd-3-f-b47": [() => import(/* webpackChunkName: "content---docs-getting-started-self-hostingd-3-f-b47" */ "@site/versioned_docs/version-1.0.0/getting-started/self-hosting.md"), "@site/versioned_docs/version-1.0.0/getting-started/self-hosting.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/getting-started/self-hosting.md")],
"content---docs-next-0-e-3-072": [() => import(/* webpackChunkName: "content---docs-next-0-e-3-072" */ "@site/docs/intro.md"), "@site/docs/intro.md", require.resolveWeak("@site/docs/intro.md")],
"content---docs-next-extractors-gradcrackeraa-2-35e": [() => import(/* webpackChunkName: "content---docs-next-extractors-gradcrackeraa-2-35e" */ "@site/docs/extractors/gradcracker.md"), "@site/docs/extractors/gradcracker.md", require.resolveWeak("@site/docs/extractors/gradcracker.md")],
"content---docs-next-extractors-jobspye-48-bba": [() => import(/* webpackChunkName: "content---docs-next-extractors-jobspye-48-bba" */ "@site/docs/extractors/jobspy.md"), "@site/docs/extractors/jobspy.md", require.resolveWeak("@site/docs/extractors/jobspy.md")],
"content---docs-next-extractors-manuald-05-f39": [() => import(/* webpackChunkName: "content---docs-next-extractors-manuald-05-f39" */ "@site/docs/extractors/manual.md"), "@site/docs/extractors/manual.md", require.resolveWeak("@site/docs/extractors/manual.md")],
"content---docs-next-extractors-overview-749-c9f": [() => import(/* webpackChunkName: "content---docs-next-extractors-overview-749-c9f" */ "@site/docs/extractors/overview.md"), "@site/docs/extractors/overview.md", require.resolveWeak("@site/docs/extractors/overview.md")],
"content---docs-next-extractors-ukvisajobs-389-6c0": [() => import(/* webpackChunkName: "content---docs-next-extractors-ukvisajobs-389-6c0" */ "@site/docs/extractors/ukvisajobs.md"), "@site/docs/extractors/ukvisajobs.md", require.resolveWeak("@site/docs/extractors/ukvisajobs.md")],
"content---docs-next-features-ghostwriterb-88-c5c": [() => import(/* webpackChunkName: "content---docs-next-features-ghostwriterb-88-c5c" */ "@site/docs/features/ghostwriter.md"), "@site/docs/features/ghostwriter.md", require.resolveWeak("@site/docs/features/ghostwriter.md")],
"content---docs-next-features-orchestratorfd-3-3fa": [() => import(/* webpackChunkName: "content---docs-next-features-orchestratorfd-3-3fa" */ "@site/docs/features/orchestrator.md"), "@site/docs/features/orchestrator.md", require.resolveWeak("@site/docs/features/orchestrator.md")],
"content---docs-next-features-post-application-tracking-5-cf-e2f": [() => import(/* webpackChunkName: "content---docs-next-features-post-application-tracking-5-cf-e2f" */ "@site/docs/features/post-application-tracking.md"), "@site/docs/features/post-application-tracking.md", require.resolveWeak("@site/docs/features/post-application-tracking.md")],
"content---docs-next-getting-started-self-hosting-47-e-517": [() => import(/* webpackChunkName: "content---docs-next-getting-started-self-hosting-47-e-517" */ "@site/docs/getting-started/self-hosting.md"), "@site/docs/getting-started/self-hosting.md", require.resolveWeak("@site/docs/getting-started/self-hosting.md")],
"content---docs-next-reference-documentation-style-guideb-28-9f0": [() => import(/* webpackChunkName: "content---docs-next-reference-documentation-style-guideb-28-9f0" */ "@site/docs/reference/documentation-style-guide.md"), "@site/docs/reference/documentation-style-guide.md", require.resolveWeak("@site/docs/reference/documentation-style-guide.md")],
"content---docs-next-reference-faq-656-100": [() => import(/* webpackChunkName: "content---docs-next-reference-faq-656-100" */ "@site/docs/reference/faq.md"), "@site/docs/reference/faq.md", require.resolveWeak("@site/docs/reference/faq.md")],
"content---docs-next-troubleshooting-common-problemsced-1cd": [() => import(/* webpackChunkName: "content---docs-next-troubleshooting-common-problemsced-1cd" */ "@site/docs/troubleshooting/common-problems.md"), "@site/docs/troubleshooting/common-problems.md", require.resolveWeak("@site/docs/troubleshooting/common-problems.md")],
"content---docs-reference-documentation-style-guideefe-1c9": [() => import(/* webpackChunkName: "content---docs-reference-documentation-style-guideefe-1c9" */ "@site/versioned_docs/version-1.0.0/reference/documentation-style-guide.md"), "@site/versioned_docs/version-1.0.0/reference/documentation-style-guide.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/reference/documentation-style-guide.md")],
"content---docs-reference-faqf-1-a-03a": [() => import(/* webpackChunkName: "content---docs-reference-faqf-1-a-03a" */ "@site/versioned_docs/version-1.0.0/reference/faq.md"), "@site/versioned_docs/version-1.0.0/reference/faq.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/reference/faq.md")],
"content---docs-troubleshooting-common-problemsd-94-383": [() => import(/* webpackChunkName: "content---docs-troubleshooting-common-problemsd-94-383" */ "@site/versioned_docs/version-1.0.0/troubleshooting/common-problems.md"), "@site/versioned_docs/version-1.0.0/troubleshooting/common-problems.md", require.resolveWeak("@site/versioned_docs/version-1.0.0/troubleshooting/common-problems.md")],
"plugin---docs-aba-4f5": [() => import(/* webpackChunkName: "plugin---docs-aba-4f5" */ "@generated/docusaurus-plugin-content-docs/default/__plugin.json"), "@generated/docusaurus-plugin-content-docs/default/__plugin.json", require.resolveWeak("@generated/docusaurus-plugin-content-docs/default/__plugin.json")],
"plugin---docs-docusaurus-debugb-38-c84": [() => import(/* webpackChunkName: "plugin---docs-docusaurus-debugb-38-c84" */ "@generated/docusaurus-plugin-debug/default/__plugin.json"), "@generated/docusaurus-plugin-debug/default/__plugin.json", require.resolveWeak("@generated/docusaurus-plugin-debug/default/__plugin.json")],};

View File

@ -1,230 +0,0 @@
import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator';
export default [
{
path: '/docs/__docusaurus/debug',
component: ComponentCreator('/docs/__docusaurus/debug', 'e58'),
exact: true
},
{
path: '/docs/__docusaurus/debug/config',
component: ComponentCreator('/docs/__docusaurus/debug/config', '2ce'),
exact: true
},
{
path: '/docs/__docusaurus/debug/content',
component: ComponentCreator('/docs/__docusaurus/debug/content', '11b'),
exact: true
},
{
path: '/docs/__docusaurus/debug/globalData',
component: ComponentCreator('/docs/__docusaurus/debug/globalData', 'f13'),
exact: true
},
{
path: '/docs/__docusaurus/debug/metadata',
component: ComponentCreator('/docs/__docusaurus/debug/metadata', 'bff'),
exact: true
},
{
path: '/docs/__docusaurus/debug/registry',
component: ComponentCreator('/docs/__docusaurus/debug/registry', '830'),
exact: true
},
{
path: '/docs/__docusaurus/debug/routes',
component: ComponentCreator('/docs/__docusaurus/debug/routes', '13e'),
exact: true
},
{
path: '/docs/',
component: ComponentCreator('/docs/', 'd18'),
routes: [
{
path: '/docs/next',
component: ComponentCreator('/docs/next', '86e'),
routes: [
{
path: '/docs/next',
component: ComponentCreator('/docs/next', '732'),
routes: [
{
path: '/docs/next/',
component: ComponentCreator('/docs/next/', 'cd6'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/extractors/gradcracker',
component: ComponentCreator('/docs/next/extractors/gradcracker', '65d'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/extractors/jobspy',
component: ComponentCreator('/docs/next/extractors/jobspy', 'db9'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/extractors/manual',
component: ComponentCreator('/docs/next/extractors/manual', '5fd'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/extractors/overview',
component: ComponentCreator('/docs/next/extractors/overview', '0d7'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/extractors/ukvisajobs',
component: ComponentCreator('/docs/next/extractors/ukvisajobs', '8b3'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/features/ghostwriter',
component: ComponentCreator('/docs/next/features/ghostwriter', '0cf'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/features/orchestrator',
component: ComponentCreator('/docs/next/features/orchestrator', '299'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/features/post-application-tracking',
component: ComponentCreator('/docs/next/features/post-application-tracking', 'f32'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/getting-started/self-hosting',
component: ComponentCreator('/docs/next/getting-started/self-hosting', '6cb'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/reference/documentation-style-guide',
component: ComponentCreator('/docs/next/reference/documentation-style-guide', '32c'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/reference/faq',
component: ComponentCreator('/docs/next/reference/faq', '3d6'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/next/troubleshooting/common-problems',
component: ComponentCreator('/docs/next/troubleshooting/common-problems', 'e34'),
exact: true,
sidebar: "docsSidebar"
}
]
}
]
},
{
path: '/docs/',
component: ComponentCreator('/docs/', '2b9'),
routes: [
{
path: '/docs/',
component: ComponentCreator('/docs/', '25b'),
routes: [
{
path: '/docs/extractors/gradcracker',
component: ComponentCreator('/docs/extractors/gradcracker', 'de4'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/extractors/jobspy',
component: ComponentCreator('/docs/extractors/jobspy', '3b4'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/extractors/manual',
component: ComponentCreator('/docs/extractors/manual', '77c'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/extractors/overview',
component: ComponentCreator('/docs/extractors/overview', 'b46'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/extractors/ukvisajobs',
component: ComponentCreator('/docs/extractors/ukvisajobs', '3ff'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/features/ghostwriter',
component: ComponentCreator('/docs/features/ghostwriter', '6a0'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/features/orchestrator',
component: ComponentCreator('/docs/features/orchestrator', '19c'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/features/post-application-tracking',
component: ComponentCreator('/docs/features/post-application-tracking', '385'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/getting-started/self-hosting',
component: ComponentCreator('/docs/getting-started/self-hosting', 'e3c'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/reference/documentation-style-guide',
component: ComponentCreator('/docs/reference/documentation-style-guide', '68e'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/reference/faq',
component: ComponentCreator('/docs/reference/faq', 'd50'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/troubleshooting/common-problems',
component: ComponentCreator('/docs/troubleshooting/common-problems', 'b1f'),
exact: true,
sidebar: "docsSidebar"
},
{
path: '/docs/',
component: ComponentCreator('/docs/', 'cb8'),
exact: true,
sidebar: "docsSidebar"
}
]
}
]
}
]
},
{
path: '*',
component: ComponentCreator('*'),
},
];

View File

@ -1,169 +0,0 @@
{
"/docs/__docusaurus/debug-e58": {
"__comp": "__comp---theme-debug-config-23-a-2ff",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/__docusaurus/debug/config-2ce": {
"__comp": "__comp---theme-debug-config-23-a-2ff",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/__docusaurus/debug/content-11b": {
"__comp": "__comp---theme-debug-contentba-8-ce7",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
},
"__props": "__props---docs-docusaurus-debug-content-344-8d5"
},
"/docs/__docusaurus/debug/globalData-f13": {
"__comp": "__comp---theme-debug-global-dataede-0fa",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/__docusaurus/debug/metadata-bff": {
"__comp": "__comp---theme-debug-site-metadata-68-e-3d4",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/__docusaurus/debug/registry-830": {
"__comp": "__comp---theme-debug-registry-679-501",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/__docusaurus/debug/routes-13e": {
"__comp": "__comp---theme-debug-routes-946-699",
"__context": {
"plugin": "plugin---docs-docusaurus-debugb-38-c84"
}
},
"/docs/-d18": {
"__comp": "__comp---theme-docs-root-5-e-9-0b6",
"__context": {
"plugin": "plugin---docs-aba-4f5"
}
},
"/docs/next-86e": {
"__comp": "__comp---theme-doc-version-roota-7-b-5de",
"__props": "__props---docs-nextbf-1-ba7"
},
"/docs/next-732": {
"__comp": "__comp---theme-doc-roota-94-67a"
},
"/docs/next/-cd6": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-0-e-3-072"
},
"/docs/next/extractors/gradcracker-65d": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-extractors-gradcrackeraa-2-35e"
},
"/docs/next/extractors/jobspy-db9": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-extractors-jobspye-48-bba"
},
"/docs/next/extractors/manual-5fd": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-extractors-manuald-05-f39"
},
"/docs/next/extractors/overview-0d7": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-extractors-overview-749-c9f"
},
"/docs/next/extractors/ukvisajobs-8b3": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-extractors-ukvisajobs-389-6c0"
},
"/docs/next/features/ghostwriter-0cf": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-features-ghostwriterb-88-c5c"
},
"/docs/next/features/orchestrator-299": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-features-orchestratorfd-3-3fa"
},
"/docs/next/features/post-application-tracking-f32": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-features-post-application-tracking-5-cf-e2f"
},
"/docs/next/getting-started/self-hosting-6cb": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-getting-started-self-hosting-47-e-517"
},
"/docs/next/reference/documentation-style-guide-32c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-reference-documentation-style-guideb-28-9f0"
},
"/docs/next/reference/faq-3d6": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-reference-faq-656-100"
},
"/docs/next/troubleshooting/common-problems-e34": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-next-troubleshooting-common-problemsced-1cd"
},
"/docs/-2b9": {
"__comp": "__comp---theme-doc-version-roota-7-b-5de",
"__props": "__props---docs-11-b-f70"
},
"/docs/-25b": {
"__comp": "__comp---theme-doc-roota-94-67a"
},
"/docs/extractors/gradcracker-de4": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-extractors-gradcracker-529-af3"
},
"/docs/extractors/jobspy-3b4": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-extractors-jobspy-80-d-e15"
},
"/docs/extractors/manual-77c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-extractors-manual-479-cf9"
},
"/docs/extractors/overview-b46": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-extractors-overview-6-d-9-5d6"
},
"/docs/extractors/ukvisajobs-3ff": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-extractors-ukvisajobs-31-a-da8"
},
"/docs/features/ghostwriter-6a0": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-features-ghostwriter-185-10f"
},
"/docs/features/orchestrator-19c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-features-orchestrator-24-b-7c5"
},
"/docs/features/post-application-tracking-385": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-features-post-application-tracking-3-a-9-fd1"
},
"/docs/getting-started/self-hosting-e3c": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-getting-started-self-hostingd-3-f-b47"
},
"/docs/reference/documentation-style-guide-68e": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-reference-documentation-style-guideefe-1c9"
},
"/docs/reference/faq-d50": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-reference-faqf-1-a-03a"
},
"/docs/troubleshooting/common-problems-b1f": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-troubleshooting-common-problemsd-94-383"
},
"/docs/-cb8": {
"__comp": "__comp---theme-doc-item-178-a40",
"content": "content---docs-5-d-9-a16"
}
}

View File

@ -1,31 +0,0 @@
{
"docusaurusVersion": "3.9.2",
"siteVersion": "0.0.0",
"pluginVersions": {
"docusaurus-plugin-css-cascade-layers": {
"type": "package",
"name": "@docusaurus/plugin-css-cascade-layers",
"version": "3.9.2"
},
"docusaurus-plugin-content-docs": {
"type": "package",
"name": "@docusaurus/plugin-content-docs",
"version": "3.9.2"
},
"docusaurus-plugin-debug": {
"type": "package",
"name": "@docusaurus/plugin-debug",
"version": "3.9.2"
},
"docusaurus-plugin-svgr": {
"type": "package",
"name": "@docusaurus/plugin-svgr",
"version": "3.9.2"
},
"docusaurus-theme-classic": {
"type": "package",
"name": "@docusaurus/theme-classic",
"version": "3.9.2"
}
}
}

View File

@ -1,4 +0,0 @@
{
"type": "localStorage",
"namespace": ""
}

View File

@ -64,6 +64,12 @@ const config: Config = {
position: "right",
dropdownActiveClassDisabled: true,
},
{
type: "html",
value:
'<a class="navbar__item navbar__link" href="/overview">Back to App</a>',
position: "right",
},
{
href: "https://github.com/DaKheera47/job-ops",
label: "GitHub",

View File

@ -1 +1 @@
["1.0.0"]
["0.1.20"]

View File

@ -1,96 +0,0 @@
# JobOps Documentation
> [!IMPORTANT]
> The source of truth is now `docs-site/docs/` (served at `/docs`).
> This `documentation/` directory is retained temporarily for migration compatibility.
Welcome to the JobOps documentation. This folder contains comprehensive guides for setting up, configuring, and using JobOps.
## Getting Started
- **[Self-Hosting Guide](./self-hosting.md)** - Deploy JobOps with Docker Compose
- Docker setup instructions
- Gmail OAuth configuration for email tracking
- Environment variables reference
- Demo mode deployment
## Feature Documentation
- **[Orchestrator](./orchestrator.md)** - Core job workflow and PDF generation
- Job states explained (discovered, ready, applied, etc.)
- The "Ready" flow (manual vs auto)
- PDF generation and regeneration
- Post-application tracking overview
- **[Ghostwriter](./ghostwriter.md)** - Context-aware per-job chat assistant
- One persistent conversation per job
- Streaming responses, stop, and regenerate
- Markdown rendering and drawer UX behavior
- Writing style settings impact
- **[Post-Application Tracking](./post-application-tracking.md)** - Email-to-job matching
- How the Smart Router AI works
- Gmail integration setup
- Using the Tracking Inbox
- Privacy and security details
- API reference
## Extractors
JobOps uses specialized extractors to gather jobs from different sources:
- **[Extractors Overview](./extractors/README.md)** - Architecture and how extractors work
- **[Gradcracker](./extractors/gradcracker.md)** - UK graduate jobs and internships
- **[UKVisaJobs](./extractors/ukvisajobs.md)** - UK visa sponsorship jobs
- **[JobSpy](./extractors/jobspy.md)** - Multi-platform job aggregator (Indeed, LinkedIn, etc.)
- **[Manual Import](./extractors/manual.md)** - Import jobs from URLs or text
## Quick Reference
### Main Components
- **Orchestrator** - Main application (UI, API, database)
- **Extractors** - Specialized job crawlers
- **Shared** - Common types and utilities
### Key Features
1. **Job Discovery** - Automatically find jobs from multiple sources
2. **AI Scoring** - Rank jobs by suitability for your profile
3. **Resume Tailoring** - Generate custom resumes for each job
4. **PDF Export** - Create tailored PDFs via RxResume integration
5. **Application Tracking** - Monitor your applied jobs
6. **Email Tracking** - Auto-track post-application responses (interviews, offers, rejections)
### Documentation Structure
```
documentation/
├── self-hosting.md # Deployment guide
├── orchestrator.md # Core workflow documentation
├── ghostwriter.md # Ghostwriter feature documentation
├── post-application-tracking.md # Email tracking feature
└── extractors/ # Job source extractors
├── README.md
├── gradcracker.md
├── jobspy.md
├── manual.md
├── ukvisajobs.md
└── gradcracker.md
```
## Contributing to Documentation
When adding new features:
1. Update the relevant feature documentation
2. Add API endpoint documentation to orchestrator README
3. Update this index if adding new docs
4. Include mermaid diagrams for complex workflows
5. Provide practical examples
## Support
- Open an [issue](https://github.com/DaKheera47/job-ops/issues) for documentation errors
- Check existing docs before asking questions
- See main README for general project info

View File

@ -1,8 +0,0 @@
# Extractors
Technical breakdowns of how each extractor works.
- Gradcracker: `gradcracker.md`
- JobSpy: `jobspy.md`
- UKVisaJobs: `ukvisajobs.md`
- Manual Import: `manual.md`

View File

@ -1,47 +0,0 @@
# Gradcracker Scraper (How It Works)
This is a plain-English walkthrough of the Gradcracker extractor in `extractors/gradcracker`.
## Big picture
The scraper builds a list of Gradcracker search URLs, visits each list page, extracts job cards, then opens each job?s detail page to grab the full description and the external application link.
## 1) Build search URLs
- It starts with a fixed set of UK regions (e.g. London & South East, West Midlands, South West).
- It uses default role terms like `web-development` and `software-systems`.
- If you set `GRADCRACKER_SEARCH_TERMS`, those replace the defaults (JSON array of strings).
- Every role is combined with every location to form a Gradcracker search URL, sorted by newest first.
## 2) Crawl list pages
On each list page it:
- Waits for the job cards to load (`article[wire:key]`).
- Scrapes basic fields from each card: title, employer, employer URL, discipline, deadline, salary, location, degree required, and start date.
- Queues each job?s detail page for deeper scraping.
Optional controls:
- `GRADCRACKER_MAX_JOBS_PER_TERM` caps how many jobs are queued per role term.
- `JOBOPS_SKIP_APPLY_FOR_EXISTING=1` and `JOBOPS_EXISTING_JOB_URLS` (or `JOBOPS_EXISTING_JOB_URLS_FILE`) let it skip jobs you already know about.
## 3) Crawl job detail pages
On each job page it:
- Waits for the main content block (`.body-content`).
- Saves the full description text.
- Looks for the Apply button and clicks it to capture the final application URL.
- Handles both popup windows and same-tab redirects.
- Waits for the URL to stabilize before recording it.
- Skips the Apply click if the job is already known (same env rules as above).
## 4) Progress reporting (optional)
If `JOBOPS_EMIT_PROGRESS=1` is set, the extractor prints structured progress lines that the orchestrator can stream into the UI.
## Notes
- The crawler runs with Playwright + Crawlee, launched through Camoufox to look more like a real browser.
- Concurrency is kept low (1 or 2) and timeouts are generous to reduce flakiness.

View File

@ -1,43 +0,0 @@
# JobSpy Extractor (How It Works)
This is a simple walkthrough of the JobSpy extractor used for Indeed, LinkedIn, and Glassdoor.
## Big picture
JobSpy is a Python library. We wrap it in a tiny Python script, run it once per search term, then ingest the JSON it writes into our database format.
## 1) Inputs and defaults
The Python wrapper (`extractors/jobspy/scrape_jobs.py`) reads environment variables and falls back to sensible defaults:
- `JOBSPY_SITES` (default: `indeed,linkedin`)
- `JOBSPY_SEARCH_TERM` (default: `web developer`)
- `JOBSPY_LOCATION` (default: `UK`)
- `JOBSPY_RESULTS_WANTED` (default: `200`)
- `JOBSPY_HOURS_OLD` (default: `72`)
- `JOBSPY_COUNTRY_INDEED` (default: `UK`)
- `JOBSPY_LINKEDIN_FETCH_DESCRIPTION` (default: `true`)
It writes output to both CSV and JSON files. The JSON is what we ingest.
## 2) Orchestrator flow
The Node service (`orchestrator/src/server/services/jobspy.ts`) controls the run:
- Builds a list of search terms (from the UI, or `JOBSPY_SEARCH_TERMS` env).
- Runs the Python script once per search term with a unique output filename.
- Reads the JSON file, maps each row to our internal `CreateJobInput` shape.
- De-dupes by `jobUrl` so the same listing only appears once.
- Deletes the CSV/JSON files after ingesting (best effort).
## 3) Mapping and cleanup
The mapper normalizes fields like salary ranges, converts empty values to null, and keeps extra metadata (skills, company rating, remote flag, etc.) when available.
If a row is missing a valid site (`indeed`, `linkedin`, or `glassdoor`) or a job URL, it gets skipped.
## Notes
- If `JOBSPY_SEARCH_TERMS` is a JSON array, it will be parsed as-is. Otherwise it can be a `|`, comma, or newline-separated list.
- LinkedIn descriptions are optional and can slow the crawl; set `JOBSPY_LINKEDIN_FETCH_DESCRIPTION=0` to disable.
- Output files are stored under `data/imports/` before being cleaned up.

View File

@ -1,40 +0,0 @@
# Manual Import Extractor (How It Works)
This is a walkthrough of the manual job import flow, which allows users to add jobs that aren't captured by automated scrapers.
## Big Picture
Instead of scraping a website, the manual extractor takes a raw job description (pasted text), parses the details (using AI), and allows the user to review and edit the data before importing it into the pipeline.
## 1) Input
The user provides input via the **Manual Import** sheet in the UI. They paste a full job description, copied from any source (job board, company site, email, etc.).
## 2) AI Inference
When the user clicks "Analyze JD", the orchestrator calls an internal endpoint (`/api/manual-jobs/infer`).
The server-side service (`orchestrator/src/server/services/manualJob.ts`) then:
- Sends the raw text to an LLM (via the configured provider; OpenRouter by default).
- Uses a specific prompt to extract structured data (title, employer, location, salary, etc.).
- Returns a JSON object containing the inferred fields.
If the LLM API key is not configured (e.g. `LLM_API_KEY` for OpenRouter/OpenAI/Gemini), the inference step skips and warns the user to fill details manually.
(`OPENROUTER_API_KEY` is deprecated and is automatically copied to `LLM_API_KEY` for compatibility.)
## 3) Review and Edit
The inferred data is populated into a form in the UI. The user can:
- Correct any mistakes made by the AI.
- Add missing information.
## 4) Storage and Scoring
Once the user clicks "Import Job", the data is sent to `/api/manual-jobs/import`.
The orchestrator:
- Generates a unique ID for the job if no URL is provided.
- Saves the job to the database with the source set to `manual`.
- **Asynchronously triggers scoring**: The job is immediately run through the suitability scorer (`orchestrator/src/server/services/scorer.ts`) against the user's current resume profile.
- Updates the job record with the suitability score and reason once complete.

View File

@ -1,87 +0,0 @@
# UKVisaJobs Extractor (How It Works)
This is a plain-English walkthrough of the UK Visa Jobs extractor. It's the most complex one because the site requires an authenticated session before the API will return jobs.
## Big picture
There are two layers:
1) `extractors/ukvisajobs/src/main.ts` handles logging in, talking to the UKVisaJobs API, and writing a Crawlee-style dataset.
2) `orchestrator/src/server/services/ukvisajobs.ts` runs that extractor, reads the dataset, de-dupes results, and optionally enriches descriptions.
## 1) Authentication and session cache
The API requires a token + cookies. The extractor keeps these in a cache file:
- `extractors/ukvisajobs/storage/ukvisajobs-auth.json`
Flow:
- If there's a cached session, it uses it.
- If not, it launches a real browser (Playwright + Camoufox), logs in with `UKVISAJOBS_EMAIL` and `UKVISAJOBS_PASSWORD`, then captures the auth cookies + token.
- It stores those values in the cache file for reuse.
You can force a refresh with:
- `UKVISAJOBS_REFRESH_ONLY=1`
If the API responds with an "expired" token error, it will automatically re-login and retry.
## 2) API requests
Once authenticated, it posts to:
- `https://my.ukvisajobs.com/ukvisa-api/api/fetch-jobs-data`
Each request:
- Includes the auth token in a form field.
- Includes cookies in the header (`csrf_token`, `ci_session`, `authToken`).
- Filters by search keyword if provided.
- Uses pagination (15 jobs per page).
## 3) Job mapping
The extractor normalizes the raw API data into the project's job shape:
- Salary is built from min/max values and interval.
- Visa-related flags are turned into a short fallback description if the job has no real description.
- The `job_link` becomes both `jobUrl` and `applicationLink`.
## 4) Output dataset
The extractor writes the results to:
- `extractors/ukvisajobs/storage/datasets/default/`
It mirrors Crawlee's dataset format:
- One JSON file per job.
- A combined `jobs.json` containing all jobs.
## 5) Orchestrator flow (how the app uses it)
When the pipeline runs:
- The server spawns the extractor as a child process (`npx tsx src/main.ts`).
- It can run multiple search terms sequentially (with a short delay between them).
- It reads the dataset and de-dupes by `sourceJobId` (or `jobUrl` fallback).
- If a job's description is missing or too short, it makes a direct HTTP request to the job URL and extracts plain text.
- This is effectively a curl-style fetch of the job page to fill in the JD for scoring and summarization.
## Controls and limits
Key environment variables:
- `UKVISAJOBS_EMAIL`, `UKVISAJOBS_PASSWORD` (required for auth refresh)
- `UKVISAJOBS_HEADLESS` (set `false` to show the browser)
- `UKVISAJOBS_MAX_JOBS` (default 50, max 200)
- `UKVISAJOBS_SEARCH_KEYWORD` (single keyword filter)
The UI also lets you set max jobs and search terms via the pipeline settings.
## Practical notes
- If you remove the auth cache file, the next run will re-login.
- The extractor is intentionally polite: it runs low concurrency and adds short delays.
- If the API or session changes on the UKVisaJobs side, the refresh logic is the first thing to check.

View File

@ -1,60 +0,0 @@
# Ghostwriter
Ghostwriter is the per-job AI chat assistant in JobOps. It is optional to use and is designed for drafting application content with job-specific context already loaded.
## What Ghostwriter is for
Ghostwriter is not a generic chat box. For each job, it uses:
- The current job description and job metadata
- A reduced snapshot of your resume/profile
- Your global Ghostwriter writing style settings
This makes it useful for:
- Drafting role-specific answers
- Cover letter and outreach drafts
- Interview prep talking points tied to the current JD
- Rephrasing content to match your preferred style
## Where it appears
- Available from job details in `discovered` and `ready` flows
- Opens as a right-side drawer
- One persistent conversation per job
## Writing style settings impact
Ghostwriter settings are global and affect new generations:
- `Tone`: adds a tone instruction in the Ghostwriter system prompt
- `Formality`: adds a formality instruction
- `Constraints`: appended as explicit writing constraints
- `Do-not-use terms`: appended as language to avoid
Defaults:
- Tone: `professional`
- Formality: `medium`
- Constraints: empty
- Do-not-use terms: empty
## Context + safety model
Ghostwriter context is assembled server-side with size limits and sanitization:
- Job snapshot is truncated to fit prompt budget
- Profile snapshot includes only relevant slices (summary, skills, projects, experience)
- System prompt enforces read-only assistant behavior
- Logging stores metadata only (not raw full prompt/response dumps)
## API surface (current)
Primary per-job endpoints:
- `GET /api/jobs/:id/chat/messages`
- `POST /api/jobs/:id/chat/messages` (supports streaming)
- `POST /api/jobs/:id/chat/runs/:runId/cancel`
- `POST /api/jobs/:id/chat/messages/:assistantMessageId/regenerate` (supports streaming)
Compatibility endpoints for thread resources remain present, but UI behavior is one conversation per job.

View File

@ -1,144 +0,0 @@
# Orchestrator: Job States and PDF Flow
This doc explains how the orchestrator thinks about job states, how the "Ready" flow is supposed to work, and how to generate or regenerate PDFs after edits.
## Job states (what each one means)
- `discovered`: The job was found by a crawler/import. It has not been processed into a tailored resume yet.
- `processing`: The system is currently generating tailoring data and/or the PDF.
- `ready`: A tailored PDF has been generated and the job is ready for you to apply.
- `applied`: You marked it as applied.
- `skipped`: You explicitly skipped it (so it stays out of your active queue).
- `expired`: Deadline has passed. This is a terminal state used for cleanup/triage.
## The intended "Ready" flow
There are two main ways a job becomes Ready:
1. **Manual flow (most common)**
- A job starts in `discovered`.
- You open it in the Discovered panel, decide to Tailor.
- In Tailor mode you can edit job description (optional), tailored summary, tailored headline, tailored skills, and project picks.
- You click **Finalize & Move to Ready**.
- This runs summarization (if needed), generates the PDF, and sets status to `ready`.
2. **Auto flow (pipeline top picks)**
- The pipeline scores all discovered jobs.
- It auto-processes the top N above the score threshold.
- Those jobs go directly to `ready` with PDFs generated.
Once a job is `ready`, the Ready panel is the "shipping lane":
- View/download the PDF.
- Open Ghostwriter for context-aware drafting tied to the current job.
- Open the job listing.
- Mark Applied (moves to `applied`).
- Optional: edit tailoring, edit the JD, or regenerate the PDF.
## Ghostwriter (per-job context chat)
Ghostwriter is always on and is available in both `discovered` and `ready` job views.
- It uses the current job context, profile context, and your global writing style settings.
- Conversation state is persistent per job.
- Responses stream in real time and can be cancelled.
- Regenerate is available for the last assistant response.
- Messages render as Markdown.
For full details and API surface, see [Ghostwriter](./ghostwriter.md).
## Generating PDFs (first time)
The PDF is generated from:
- The base resume selected from your v4.rxresu.me account (via Onboarding or Settings).
- The job description (used for AI tailoring and project selection).
- Your tailored summary, tailored headline, tailored skills, and selected projects.
Paths:
- **Discovered ? Tailor ? Finalize**
- Calls `/api/jobs/:id/process`.
- Runs AI summary + project selection, then generates the PDF.
- Sets status to `ready` and saves `pdfPath`.
- **Ready panel ? Regenerate PDF**
- Calls `/api/jobs/:id/generate-pdf` using the current saved tailoring fields.
## Regenerating PDFs after edits
If the job description or tailoring changes, regenerate the PDF so it stays in sync.
### Typical UI flow
1. Edit job description or tailoring in the Discovered/Tailor view, or use ?Edit job description? in Ready.
2. If you want AI to re-tailor based on the updated JD, click **Generate draft** (Discovered) or **AI Summarize** (editor).
3. Click **Finalize & Move to Ready** (if still in Discovered) or **Regenerate PDF** (if already Ready).
### API flow (for automation)
1. Update the data:
```bash
PATCH /api/jobs/:id
{
"jobDescription": "<new JD>",
"tailoredSummary": "<optional>",
"tailoredHeadline": "<optional>",
"tailoredSkills": "[{\"name\":\"Backend\",\"keywords\":[\"TypeScript\",\"Node.js\"]}]",
"selectedProjectIds": "p1,p2"
}
```
2. (Optional) re-run AI tailoring based on the new JD:
```bash
POST /api/jobs/:id/summarize?force=true
```
3. Generate the PDF using current stored fields:
```bash
POST /api/jobs/:id/generate-pdf
```
## Post-Application Tracking (Tracking Inbox)
After you've applied to jobs, the Tracking Inbox feature automatically monitors your Gmail for responses:
### How it works
1. **Gmail Sync**: Periodically checks your Gmail for recruitment-related emails
2. **Smart Router AI**: Analyzes each email for:
- Relevance (is it about job applications?)
- Job matching (which applied job is this about?)
- Message type (interview, offer, rejection, update)
- Confidence score (0-100%)
3. **Automatic Processing**:
- **95-100% confidence**: Auto-linked to the matched job, timeline updated
- **50-94% confidence**: Goes to Inbox for review with suggested match
- **<50% confidence**: Goes to Inbox as "orphan" if relevant; ignored if not
4. **User Review**: Items in the Inbox wait for your approve/ignore decision
### Gmail Setup
1. Configure Gmail OAuth credentials (see `self-hosting.md`)
2. In the UI: Tracking Inbox → Connect Gmail
3. Authorize read-only Gmail access
## Notes and gotchas
- `processing` is transient. If PDF generation fails, the job is reverted back to `discovered`.
- The PDF is served at `/pdfs/resume_<jobId>.pdf` and cache-busted with the job?s `updatedAt` timestamp.
- If a job is `skipped` or `applied` and you want to re-open it, you can PATCH its `status` back to `discovered`.
- Job text search is handled through the command bar (`Cmd/Ctrl+K`) and is not persisted as a URL filter.
## External payload and sanitization defaults
- **LLM providers** receive only prompt inputs required for scoring/tailoring/project selection/manual extraction tasks.
- By default, prompt construction uses minimized profile/job fields and avoids sending unnecessary sensitive data.
- **Webhook payloads** are sanitized and whitelisted by default; large/sensitive blobs are not sent.
- Server logs and error details are redacted/truncated by default (secrets, tokens, cookies, passwords, API keys, and oversized payload fields).
- Correlation data is included in logs (`requestId`, and when available `pipelineRunId` / `jobId`) to improve traceability without exposing raw payloads.

View File

@ -1,241 +0,0 @@
# Post-Application Email Tracking
The Post-Application Tracking feature (also called "Tracking Inbox") automatically monitors your Gmail for job application responses and updates your job timeline accordingly.
## Overview
After you've applied to jobs, keeping track of responses can be tedious. This feature automates that process by:
1. **Scanning your Gmail** for recruitment-related emails
2. **Matching emails** to your tracked job applications using AI
3. **Updating your timeline** with interview invites, offers, rejections, and updates
4. **Asking for your review** when the AI is uncertain
## How It Works
### The Smart Router Flow
```mermaid
flowchart TD
A[Recruitment email arrives in Gmail] --> B[Smart Router AI analyzes content]
B --> C{How confident is the match?}
C -->|95-100%| D[Auto-linked to job]
D --> E[Timeline updated automatically]
C -->|50-94%| F[Goes to Inbox for review<br/>with suggested job match]
C -->|<50%| G{Is it relevant?}
G -->|Yes| H[Goes to Inbox as orphan<br/>relevant but job unclear]
G -->|No| I[Ignored - not job-related]
F --> J{You review in Inbox}
H --> J
J -->|Approve| K[Linked to selected job<br/>Timeline updated]
J -->|Ignore| L[Marked as not relevant]
```
### What the AI Analyzes
For each email, the Smart Router evaluates:
- **Content Relevance**: Is this email about a job application lifecycle?
- **Job Matching**: Which of your "Applied" or "Processing" jobs does this relate to?
- **Message Type**:
- Interview invitation (phone screen, technical, onsite)
- Offer received
- Rejection/withdrawal
- General update/status change
- **Confidence Score**: 0-100% certainty of the match
### Processing Outcomes
| Confidence | Processing | Your Action Required |
| ----------------------- | ------------------------------ | ---------------------------------------- |
| **95-100%** | Auto-linked to job | None - appears in timeline automatically |
| **50-94%** | Pending review with suggestion | Quick approve/ignore in Inbox |
| **<50% (relevant)** | Pending review as orphan | Approve with manual job selection |
| **<50% (not relevant)** | Ignored | None - filtered out |
## Setup
### Prerequisites
1. **Gmail account** with job application emails
2. **Google OAuth credentials** (see below)
### Step 1: Create Google OAuth Credentials
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select existing
3. Enable the **Gmail API**
4. Configure **OAuth consent screen**:
- User Type: External
- Fill in app name, user support email, developer contact
- Add scope: `https://www.googleapis.com/auth/gmail.readonly`
- Add test users (your email)
5. Create **OAuth 2.0 Client ID**:
- Application type: Web application
- Authorized redirect URIs:
- `http://localhost:3005/oauth/gmail/callback` (local)
- `https://your-domain.com/oauth/gmail/callback` (production)
6. Copy the **Client ID** and **Client Secret**
### Step 2: Configure Environment Variables
Set these in your JobOps environment:
```bash
GMAIL_OAUTH_CLIENT_ID=your-client-id.apps.googleusercontent.com
GMAIL_OAUTH_CLIENT_SECRET=your-client-secret
# Optional - defaults to /oauth/gmail/callback on current host
GMAIL_OAUTH_REDIRECT_URI=https://your-domain.com/oauth/gmail/callback
```
### Step 3: Connect Gmail in the UI
1. Restart JobOps with the new environment variables
2. Navigate to **Tracking Inbox** in the dashboard
3. Click **Connect Gmail**
4. Authorize JobOps to access your Gmail (read-only scope)
5. You're connected! The system will now sync emails automatically
## Using the Tracking Inbox
### Reviewing Pending Items
When emails need your review, they appear in the **Inbox**:
1. Go to **Tracking Inbox****Inbox** tab
2. Each item shows:
- Sender and subject
- AI confidence score
- Suggested job match (if available)
- Message type (interview, offer, etc.)
3. Choose an action:
- **Approve**: Links to the suggested job (or select a different one)
- **Ignore**: Marks as not relevant
### Understanding Confidence Scores
- **Green (95-100%)**: High confidence, auto-processed
- **Yellow (50-94%)**: Moderate confidence, needs review
- **Red (<50%)**: Low confidence or unclear match
### Timeline Updates
When you approve an email (or it's auto-approved), the system:
1. Creates a timeline event for the job
2. Updates the job stage (e.g., "Interview Scheduled", "Offer Received")
3. Records the event date from the email
## Privacy & Security
### What Data is Sent to AI
Only minimal job metadata is sent for matching:
- Company name
- Job title
- Snippets of email content
### Gmail Permissions
- **Scope**: `gmail.readonly` only
- **Access**: Read-only, cannot send/delete emails
- **Data Storage**: Email metadata stored locally in your SQLite database
### Data Retention
- Sync history retained for debugging
- You can disconnect Gmail at any time
- All email data is local to your instance
## Troubleshooting
### Common Issues
**"No refresh token" error**
- Disconnect and reconnect Gmail
- This forces a fresh consent flow
**Emails not appearing**
- Check sync run history in Tracking Inbox → Runs
- Verify Gmail OAuth credentials are correct
- Ensure email subjects match recruitment keywords
**Wrong job matches**
- This is expected for low-confidence matches
- Use the Inbox to correct matches
### Viewing Sync History
Go to **Tracking Inbox****Runs** to see:
- When syncs ran
- How many messages were discovered
- How many were auto-linked vs. pending review
- Any errors that occurred
## Configuration
### Environment Variables
| Variable | Required | Description |
| --------------------------- | -------- | ------------------------------ |
| `GMAIL_OAUTH_CLIENT_ID` | Yes | Google OAuth client ID |
| `GMAIL_OAUTH_CLIENT_SECRET` | Yes | Google OAuth client secret |
| `GMAIL_OAUTH_REDIRECT_URI` | No | Custom redirect URI (optional) |
### Advanced Settings
Currently, the feature uses sensible defaults:
- Searches last 30 days of emails
- Looks for recruitment-related keywords in subjects
- Processes up to 100 messages per sync
- Runs automatically when you open the Tracking Inbox
## API Reference
### REST Endpoints
| Method | Endpoint | Description |
| ------ | ----------------------------------------- | --------------------- |
| GET | `/api/post-application/inbox` | List pending messages |
| POST | `/api/post-application/inbox/:id/approve` | Approve message |
| POST | `/api/post-application/inbox/:id/deny` | Ignore message |
| GET | `/api/post-application/runs` | List sync runs |
| POST | `/api/post-application/gmail/connect` | Start OAuth flow |
| GET | `/api/post-application/gmail/callback` | OAuth callback |
### Example: Approve an Inbox Item
```bash
curl -X POST http://localhost:3005/api/post-application/inbox/msg_123/approve \
-H "Content-Type: application/json" \
-d '{
"jobId": "job_456",
"note": "Phone screen scheduled"
}'
```
## Best Practices
1. **Review regularly**: Check your Inbox weekly to stay on top of pending matches
2. **Be decisive**: Approve or ignore items quickly to keep your Inbox clean
3. **Correct mismatches**: If the AI suggests the wrong job, select the correct one when approving
4. **Monitor sync runs**: Check the Runs tab occasionally to ensure syncing is working
5. **Privacy first**: Remember only minimal job data is sent to AI - your email content stays private
## Future Enhancements
Potential improvements planned:
- Multiple email provider support (Outlook, etc.)
- IMAP support for non-Gmail accounts
- Calendar integration for interview scheduling

View File

@ -1,136 +0,0 @@
# Self-Hosting (Docker Compose)
The easiest way to run JobOps is via Docker Compose. The app is self-configuring and will guide you through the setup on your first visit.
## Prereqs
- Docker Desktop or Docker Engine + Compose v2
## 1) Start the stack
No environment variables are strictly required to start. Simply run:
```bash
docker compose up -d
```
This pulls the pre-built image from **GitHub Container Registry (GHCR)** and starts the API, UI, and scrapers in a single container. The image is multi-arch (supports `amd64` and `arm64`), making it compatible with Apple Silicon and Raspberry Pi.
If you want to build it yourself, you can run `docker compose up -d --build`.
## 2) Access the app and Onboard
Open your browser to:
- **Dashboard**: http://localhost:3005
On first launch, you will be greeted by an **Onboarding Wizard**. The app will help you validate and save your configuration:
1. **LLM Provider**: OpenRouter is the default. Add an API key if required (OpenRouter/OpenAI/Gemini), or configure a local base URL (LM Studio/Ollama).
2. **PDF Export**: Add your RxResume credentials (used to export PDFs from v4.rxresu.me).
3. **Template Resume**: Select a base resume from your v4.rxresu.me account.
The app saves these to its persistent database, so you don't need to manage `.env` files for basic setup. All other settings (like search terms, job sources, and more) can also be configured directly in the UI.
Upgrade note: `OPENROUTER_API_KEY` is deprecated. Existing OpenRouter keys are automatically migrated/copied to `LLM_API_KEY` so you don't lose them.
## Gmail OAuth (Post-Application Inbox)
If you want to connect Gmail in the Tracking Inbox page, configure Google OAuth credentials for the API server.
### 1) Create Google OAuth credentials
In Google Cloud:
1. Open your project (or create one), then configure the OAuth consent screen.
2. Enable the Gmail API.
3. Create an OAuth client ID (`Web application` type).
4. Add an authorized redirect URI:
- `http://localhost:3005/oauth/gmail/callback` (default local setup)
- or your deployed app URL, for example `https://your-domain.com/oauth/gmail/callback`
### 2) Configure environment variables
Set these on the JobOps container:
- `GMAIL_OAUTH_CLIENT_ID` (required)
- `GMAIL_OAUTH_CLIENT_SECRET` (required)
- `GMAIL_OAUTH_REDIRECT_URI` (optional, recommended for production)
- If omitted, JobOps derives it from the incoming request host as `/oauth/gmail/callback`.
### 3) Restart and connect
After setting env vars, restart the container and use `Tracking Inbox -> Connect Gmail`.
Notes:
- JobOps requests `gmail.readonly` scope.
- If Google returns no refresh token, disconnect and re-connect to force a fresh consent flow.
## Email-to-Job Matching Overview
When Gmail sync runs, your emails are automatically analyzed and routed. Here's what happens:
```mermaid
flowchart TD
A[Recruitment email arrives in Gmail] --> B[Smart Router AI analyzes content]
B --> C{How confident is the match?}
C -->|95-100%| D[Auto-linked to job]
D --> E[Timeline updated automatically]
C -->|50-94%| F[Goes to Inbox for review<br/>with suggested job match]
C -->|<50%| G{Is it relevant?}
G -->|Yes| H[Goes to Inbox as orphan<br/>relevant but job unclear]
G -->|No| I[Ignored - not job-related]
F --> J{You review in Inbox}
H --> J
J -->|Approve| K[Linked to selected job<br/>Timeline updated]
J -->|Ignore| L[Marked as not relevant]
```
**What the AI looks for:**
- Content relevance - Is this about job applications?
- Job matching - Which of your tracked jobs is this about?
- Message type - Interview, offer, rejection, or update?
**Your control:**
- High-confidence matches (95%+) happen automatically
- Everything else appears in your Inbox for a quick yes/no decision
- You can always correct the job match when approving
**Privacy note:** Only job ID, company name, and title are sent to the AI for matching. Full email content stays local.
## Persistent data
`./data` is bind-mounted into the container. It stores:
- SQLite DB: `data/jobs.db` (contains your API keys and configuration)
- Generated PDFs: `data/pdfs/`
- Template resume selection: Stored internally after selection.
## Public demo deployment (`DEMO_MODE=true`)
For a public sandbox website, set `DEMO_MODE=true` on the container.
Behavior in demo mode:
- **Works (local demo DB):** browsing, filtering, job status updates, timeline edits.
- **Simulated (no external side effects):** pipeline run, job summarize/process/rescore/pdf/apply, onboarding validations.
- **Blocked:** settings writes, database clear, backup create/delete, status bulk deletes.
- **Auto-reset:** seeded demo data is reset every 6 hours.
## Updating
```bash
git pull
docker compose pull
docker compose up -d
```
## Self-hosted Reactive Resume
If you are also self-hosting Reactive Resume, you should configure the url
by setting `RXRESUME_URL` to your instance (e.g. `http://rxresume.local.net`).

View File

@ -8,6 +8,8 @@ import {
Shield,
} from "lucide-react";
declare const __APP_VERSION__: string;
export type NavLink = {
to: string;
label: string;
@ -16,6 +18,16 @@ export type NavLink = {
external?: boolean;
};
const releaseVersion = (() => {
if (typeof __APP_VERSION__ !== "string") return null;
const match = __APP_VERSION__.match(/^v\d+\.\d+\.\d+/);
return match ? match[0] : null;
})();
const docsLabel = releaseVersion
? `Documentation (${releaseVersion})`
: "Documentation";
export const NAV_LINKS: NavLink[] = [
{ to: "/overview", label: "Overview", icon: Home },
{
@ -36,7 +48,7 @@ export const NAV_LINKS: NavLink[] = [
activePaths: ["/applications/in-progress"],
},
{ to: "/tracking-inbox", label: "Tracking Inbox", icon: Inbox },
{ to: "/docs", label: "Documentation", icon: BookOpen, external: true },
{ to: "/docs", label: docsLabel, icon: BookOpen, external: true },
{ to: "/visa-sponsors", label: "Visa Sponsors", icon: Shield },
{ to: "/settings", label: "Settings", icon: Settings },
];