Skip to content

Database schema

The plugin owns four tables, created by Migration1717000000CreateFujinShuttleTables (with fujin_job.heartbeat_at and fujin_job.phase added by two follow-up migrations). All use BINARY(16) UUID primary keys and utf8mb4.

fujin_profile ──1:N──► fujin_profile_column
      │
      └──1:N──► fujin_job ──1:N──► fujin_job_log

fujin_profile

A saved import/export configuration.

Column Type Notes
id BINARY(16) PK.
name VARCHAR(255) Human label.
data_type VARCHAR(64) One of the seven types.
transfer_mode VARCHAR(16) import or export.
options JSON nullable Per-run options (batch size, reindex mode, concurrency, parent category, …).
file_path VARCHAR(1024) nullable Attached CSV path.
created_at DATETIME(3)
updated_at DATETIME(3) nullable

fujin_profile_column

The columns detected from the profile's CSV header (ON DELETE CASCADE with the profile).

Column Type Notes
id BINARY(16) PK.
profile_id BINARY(16) FK → fujin_profile.id.
field VARCHAR(255) CSV header name.
alias VARCHAR(255) Mapped logical field.
position INT (default 0) Column order.
options JSON nullable Column-level options.
created_at DATETIME(3)

fujin_job

One execution of a profile. profile_id is ON DELETE SET NULL, so a job's history survives deleting its profile.

Column Type Notes
id BINARY(16) PK.
profile_id BINARY(16) nullable FK → fujin_profile.id (SET NULL).
status VARCHAR(16) (default pending) See lifecycle.
phase VARCHAR(32) nullable resolving → importing → reindexing.
total INT (default 0) Total source rows.
processed INT (default 0) Rows processed so far.
progress INT (default 0) Percent (live caps below 100; 100 on finish).
heartbeat_at DATETIME(3) nullable Liveness stamp bumped by the run monitor.
stats JSON nullable Final per-status counts (success, no-change, errors, warnings, empty).
lock_token VARCHAR(64) nullable Internal lock for the duplicate-run guard.
started_at DATETIME(3) nullable
finished_at DATETIME(3) nullable
created_at DATETIME(3)

fujin_job_log

Per-row notices and errors (ON DELETE CASCADE with the job).

Column Type Notes
id BINARY(16) PK.
job_id BINARY(16) FK → fujin_job.id.
level VARCHAR(16) ERROR / WARNING / INFO / DEBUG.
row_no INT (default 0) Source row number (0 for non-row messages).
action VARCHAR(32) nullable e.g. created / updated / skipped.
message TEXT The message.
created_at DATETIME(3)

Job lifecycle

stateDiagram-v2
    [*] --> pending
    pending --> running
    running --> finished
    running --> stopping: Stop pressed
    stopping --> stopped
    running --> error
    pending --> error: stale heartbeat reaped
Status Meaning
pending Created; queued, waiting for a worker (or about to run inline).
running Executing — phase, processed, progress and heartbeat_at update live.
stopping A stop was requested; the run ends at the next batch boundary.
stopped Stopped by request — partial data is kept (no cross-batch transaction).
finished Completed; progress = 100, stats finalised.
error Failed, or reaped because its heartbeat went stale (worker crashed/killed).

The duplicate-run guard refuses a new run while a profile has an active job (pending/running/stopping); a stale heartbeat_at lets a dead job be reaped so the profile isn't blocked forever. See Concepts → tracking a run.

Querying jobs directly

-- Recent runs
SELECT HEX(id) AS job, HEX(profile_id) AS profile, status, phase,
       processed, total, progress, started_at, finished_at
FROM fujin_job ORDER BY created_at DESC LIMIT 20;

-- Errors for a job
SELECT row_no, action, message
FROM fujin_job_log
WHERE job_id = UNHEX('<jobHex>') AND level = 'ERROR'
ORDER BY row_no;