# How Career-Ops Differentiates User-Layer and System-Layer Files During Updates

> Career-ops employs a dual-layer protection system to differentiate user and system files during updates. Learn how it safeguards your personal data while updating system files.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: how-to-guide
- Published: 2026-06-10

---

**Career-ops uses a dual-layer protection system defined in [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) and enforced by `update-system.mjs` through hardcoded `SYSTEM_PATHS` and `USER_PATHS` arrays to ensure personal files like [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) and [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) are never overwritten while system files are safely updated.**

The `santifer/career-ops` repository manages personal career data through a strict separation between customizable user content and core system logic. This architecture ensures that running updates refreshes the underlying framework without risking personal CVs, profile configurations, or tracked data. Understanding this boundary is essential for safely maintaining your career management system across releases.

## Data Contract Definition: The User Layer Foundation

The separation starts with a formal data contract that codifies which files belong to the **User Layer**. In [`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md) (lines 5-9), the project explicitly lists every file designated as user-owned and declares that *"no update process may read, modify, or delete"* any of them. This document serves as the authoritative source of truth for what constitutes personal data versus replaceable system code.

User-layer files typically include your actual career content and personal settings—items that would be catastrophic to overwrite during a routine update. The contract ensures these remain under your exclusive control regardless of how the underlying system evolves.

## Update Script Enforcement: SYSTEM_PATHS and USER_PATHS

The practical enforcement happens in `update-system.mjs`, which contains two hardcoded arrays that govern the update behavior:

- **`SYSTEM_PATHS`** – A whitelist of files and directories that *may* be replaced when an update is applied. These include mode files and utility scripts that constitute the core application logic.
- **`USER_PATHS`** – A blacklist of paths that the updater must never touch. According to lines 24-32 and 30-38 of the script, these include [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md), [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml), [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md), [`portals.yml`](https://github.com/santifer/career-ops/blob/main/portals.yml), and the entire `data/` directory tree.

When you run `node update-system.mjs apply`, the script clones the remote repository but only copies the paths listed in `SYSTEM_PATHS` to your local checkout. It explicitly skips any path matching `USER_PATHS`, ensuring personal content remains intact. If a path were mistakenly matched in both lists, the script aborts with an error as a safety mechanism.

## How the Update Process Works

The differentiation manifests in a three-stage workflow that protects your data while refreshing system components:

1. **Check availability** – Running `node update-system.mjs check` compares your local version against the remote repository and returns a JSON response showing both versions.

2. **Apply selective updates** – The `apply` command fetches only the system-layer files. It updates core logic like [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) while leaving your [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) and profile configurations untouched.

3. **Verify integrity** – After updating, you can confirm user files remain unchanged:

```bash

# Check for any modifications to protected user files

git diff --name-only | grep -E '^cv\.md|^config/profile\.yml|^modes/_profile\.md'

# No output confirms user-layer files were preserved

```

## Protected vs. Updated File Examples

Understanding which files fall into each category helps you know where to safely store custom content:

**User-Layer Files (NEVER overwritten):**
- [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) – Your personal curriculum vitae
- [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) – Personal configuration settings
- [`modes/_profile.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.md) – Your custom mode profile
- [`portals.yml`](https://github.com/santifer/career-ops/blob/main/portals.yml) – Job portal tracking data
- `data/` – Entire directory of personal career data

**System-Layer Files (REFRESHED on update):**
- [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) – Shared mode utilities
- Mode definition files and utility scripts listed in `SYSTEM_PATHS`
- System configuration templates like [`modes/_profile.template.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.template.md) and [`config/profile.example.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.example.yml)

## Summary

- **[`DATA_CONTRACT.md`](https://github.com/santifer/career-ops/blob/main/DATA_CONTRACT.md)** defines the theoretical boundary between user and system layers, explicitly protecting personal files from any update process.
- **`update-system.mjs`** implements practical enforcement through `SYSTEM_PATHS` and `USER_PATHS` arrays that whitelist system files and blacklist user content.
- The update command selectively refreshes only whitelisted paths, ensuring your CV, profiles, and data remain untouched across releases.
- Safety mechanisms abort the process if path conflicts occur between the two layers.

## Frequently Asked Questions

### What happens if I accidentally place a user file in a system directory?

The updater will treat it as a system file only if it matches an entry in `SYSTEM_PATHS`. If the file path matches `USER_PATHS`, it remains protected regardless of its location. However, to avoid confusion, keep user content in the standard locations like [`cv.md`](https://github.com/santifer/career-ops/blob/main/cv.md) or the `data/` directory as defined in the data contract.

### Can I modify system-layer files like [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) without breaking updates?

While you can technically edit system files, your changes will be overwritten on the next update since these paths are listed in `SYSTEM_PATHS`. For permanent customizations, create user-layer files (such as custom modes in your personal directories) that are protected by `USER_PATHS`.

### How do I verify that an update did not touch my personal data?

After running `node update-system.mjs apply`, use the git diff command to check for modifications to protected paths: `git diff --name-only | grep -E '^cv\.md|^config/profile\.yml'`. If no output appears, your user-layer files remain exactly as you left them.

### Where are the template files for user-layer configuration?

The repository provides [`config/profile.example.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.example.yml) and [`modes/_profile.template.md`](https://github.com/santifer/career-ops/blob/main/modes/_profile.template.md) as system-layer templates that demonstrate the expected format. These templates are updated with the system, but your actual user-layer files (created by copying these templates) are protected by the `USER_PATHS` blacklist.