diff --git a/.gitea/workflows/ci-deploy.yml b/.gitea/workflows/ci-deploy.yml index 3254d03..d2110c7 100644 --- a/.gitea/workflows/ci-deploy.yml +++ b/.gitea/workflows/ci-deploy.yml @@ -37,7 +37,7 @@ jobs: - name: Test frontend working-directory: job-tracker-ui - run: npm test -- --watchAll=false --runInBand App.test.tsx confirm.test.tsx prompt.test.tsx dialog-flow.test.tsx confirm-flow.test.tsx attachments.test.tsx job-details-generated-drafts.test.tsx admin-system-page.test.tsx + run: npm test -- --watchAll=false --runInBand App.test.tsx confirm.test.tsx prompt.test.tsx dialog-flow.test.tsx confirm-flow.test.tsx attachments.test.tsx job-details-generated-drafts.test.tsx admin-system-page.test.tsx profile-page.test.tsx - name: Build frontend working-directory: job-tracker-ui @@ -55,6 +55,7 @@ jobs: username: ${{ secrets.PROD_USER }} key: ${{ secrets.PROD_SSH_KEY }} script: | + set -euo pipefail if [ ! -d /opt/job-tracker/app/.git ]; then echo "Expected git checkout at /opt/job-tracker/app but .git was not found." exit 1 diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 68bf9d6..2846236 100644 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -23,19 +23,46 @@ export APP_VERSION="${APP_VERSION:-0.0.0}" export APP_COMMIT_SHA="${APP_COMMIT_SHA:-unknown}" export APP_BUILD_STAMP="${APP_BUILD_STAMP:-unknown}" -docker compose pull || true -docker compose build +compose() { + docker compose "$@" +} + +build_with_recovery() { + if compose build; then + return 0 + fi + + echo "docker compose build failed. Attempting one cleanup + retry because layer extraction can fail on constrained hosts." + docker image rm -f app-ai-service:latest 2>/dev/null || true + docker builder prune -af >/dev/null 2>&1 || true + docker system prune -f >/dev/null 2>&1 || true + compose build --no-cache ai-service + compose build backend frontend +} + +compose pull || true +build_with_recovery # Force recreation so updated port mappings, env vars, and container config always apply on deploy. -docker compose up -d --force-recreate --remove-orphans +compose up -d --force-recreate --remove-orphans sleep 5 -docker compose ps +compose ps -backend_status="$(docker compose ps backend --format '{{.State}}' 2>/dev/null | head -n 1 | tr '[:upper:]' '[:lower:]')" +backend_status="$(compose ps backend --format '{{.State}}' 2>/dev/null | head -n 1 | tr '[:upper:]' '[:lower:]')" if [ "$backend_status" != "running" ]; then echo "Backend service is not healthy after deploy (state: ${backend_status:-unknown})." - docker compose logs --tail=200 backend || true + compose logs --tail=200 backend || true exit 1 fi +ai_status="$(compose ps ai-service --format '{{.State}}' 2>/dev/null | head -n 1 | tr '[:upper:]' '[:lower:]')" +if [ "$ai_status" != "running" ]; then + echo "AI service is not healthy after deploy (state: ${ai_status:-unknown})." + compose logs --tail=200 ai-service || true + exit 1 +fi + +# Clean up old legacy container name if it still exists from pre-rename deployments. +docker rm -f app-summarizer-1 2>/dev/null || true + echo "Deployment complete: ${APP_VERSION} ${APP_COMMIT_SHA}" diff --git a/docs/jobbjakt-cleanup-tracker.md b/docs/jobbjakt-cleanup-tracker.md index c8e3325..5708613 100644 --- a/docs/jobbjakt-cleanup-tracker.md +++ b/docs/jobbjakt-cleanup-tracker.md @@ -75,6 +75,7 @@ Last updated: 2026-03-23 - [x] Audit production API base URL / proxy setup - [x] Document recommendation to leave `REACT_APP_API_BASE_URL` empty when using bundled proxy - [x] Replace committed dev secret-like values with placeholders in dev config +- [x] Harden deploy script/workflow against transient Docker layer extraction failures - [ ] Rotate any real secrets that may previously have been committed/exposed - [ ] Verify production environment variables match documented setup diff --git a/docs/jobbjakt-next-session.md b/docs/jobbjakt-next-session.md new file mode 100644 index 0000000..8b6dc78 --- /dev/null +++ b/docs/jobbjakt-next-session.md @@ -0,0 +1,100 @@ +# Jobbjakt next session handoff + +Last updated: 2026-03-23 + +## What was completed today +- Added attachment-aware AI context selection across job AI tabs. +- Added attachment metadata: + - purpose + - AI inclusion toggle +- Added overview strategy snapshot in job details. +- Added AI draft variants for: + - cover letters + - recruiter messages +- Added route-level lazy loading/code splitting. +- Added CV section rewrite + replace flow. +- Added CV structure parsing UI and backend parsing endpoint. +- Added persisted structured CV section JSON on user profiles. +- Updated job-tailoring prompts to include structured CV sections. +- Added frontend tests for: + - attachments metadata controls + - job details generated drafts + - profile page CV structure parsing/persistence +- Added `tmp/` to `.gitignore` to protect local/private test files. +- Used local file `tmp/test-data/my-cv.pdf` only for a lightweight private sanity check. + +## Deployment / CI fixes made +- Added `profile-page.test.tsx` to frontend CI test command. +- Hardened remote deploy shell with `set -euo pipefail` in workflow. +- Improved `deploy/deploy.sh` to: + - retry Docker build after cleanup if layer extraction fails + - prune builder/cache on retry + - rebuild `ai-service` with `--no-cache` on retry + - verify both backend and ai-service are running after deploy + - remove old legacy `app-summarizer-1` container if present + +## Important production issue observed +Remote deploy failed with Docker layer extraction error during ai-service image export: +- `unpigz: corrupted -- crc32 mismatch` + +Most likely host-side Docker/cache/storage issue, not app code. +Mitigation has been added in deploy script, but if it happens again check: +- available disk space on host +- Docker storage driver health +- `/var/lib/docker` filesystem integrity +- BuildKit cache corruption +- whether Docker daemon needs restart + +## Outstanding product/code items +### Highest priority +1. Expand structured CV data from JSON persistence into richer first-class usage: + - explicit section chooser in tailoring UI + - section-weighted tailored CV generation + - section-specific missing-keyword analysis +2. Add more tests: + - profile CV rebuild/improve endpoints + - attachment AI filtering defaults + - strategy snapshot regeneration + - structured CV influence on tailoring prompts (backend tests if practical) +3. Final UX polish pass on: + - Profile CV tools + - Job details AI tabs + - Attachments table metadata controls + +### Medium priority +4. Dashboard polish toward requested SaaS references. +5. System/admin page clarity pass. +6. Translation consistency review across EN + NB. +7. Audit username/full-name/email autofill consistency. + +### Lower priority +8. Internal `Summarizer*` → `AiService*` naming cleanup. +9. Broader performance review after latest UI additions. + +## Suggested next implementation order +1. Add structured CV section influence visibility in UI: + - show which sections are being used for tailoring + - allow picking preferred sections for a job package +2. Add tests for attachment AI defaults + profile persistence edge cases +3. Final UX polish pass on profile/job details/attachments +4. Dashboard + system polish + +## Files most relevant next time +- `JobTrackerApi/Controllers/JobApplicationsController.cs` +- `JobTrackerApi/Controllers/ProfileCvController.cs` +- `JobTrackerApi/Controllers/AuthController.cs` +- `Models/ApplicationUser.cs` +- `Models/Attachments.cs` +- `JobTrackerApi/Program.cs` +- `job-tracker-ui/src/pages/ProfilePage.tsx` +- `job-tracker-ui/src/components/JobDetailsDialog.tsx` +- `job-tracker-ui/src/components/Attachments.tsx` +- `job-tracker-ui/src/profile-page.test.tsx` +- `job-tracker-ui/src/attachments.test.tsx` +- `job-tracker-ui/src/job-details-generated-drafts.test.tsx` +- `.gitea/workflows/ci-deploy.yml` +- `deploy/deploy.sh` + +## Local private test asset +- `tmp/test-data/my-cv.pdf` +- Do not commit it.