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¶
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;