Skip to content
PersonalFrontend + backend web · 15 scheduled current-date slots · singleton KST · fixed DTO projection

Daesin Logistics Dispatch Operations Ledger

Sole owner of planning, frontend, backend, deployment, and operations

2026-01-01 — present

Separated collection into a singleton and deployed the dispatch ledger’s web and collector on ARM64. Recovered the previous collector after a failed first attempt, then verified backup integrity and real changed-row API parity on redeployment. Published the owner-recorded single-deployment observation separately from ten synthetic scenarios.

Verified outcomes

Current-day collection

Current date · Mon–Sat 06:00–20:00 · 15 scheduled slots

Morning and later updates rechecked

Before: Previous day before 14:00

Replica duplication

15 singleton slots

Duplicate runs removed

Before: 15 slots per replica

Browser data boundary

Vehicle details public · internal IDs and credential URL excluded

Fixed public route DTO

Before: Source and internal fields not separated

← Scroll horizontally to view the scenario →

Three-step user journey for dispatch overview, route search, and route detail rendered with synthetic data
This user scenario reproduces the actual React UI structure with a deterministic synthetic fixture and is not presented as evidence of live data.

Problem Solving

1

Current-day source data was already available in the morning, but the rule that selected the previous day before 14:00 skipped it

Solution Process

Fixed the default collection date to the current date and made the singleton KST scheduler recheck it in 15 scheduled hourly slots from Mon–Sat 06:00–20:00

Result

Subsequent runs can capture morning data and later source changes without maintaining static date or row-count claims

← Scroll horizontally to view the scenario →

Current-date recheck prevents morning gaps
Current-date recheck prevents morning gaps.Removes the rule that selected the previous day before 14:00 and independently rechecks the current date in 15 scheduled hourly slots from Mon–Sat 06:00–20:00. Failures are logged; the next scheduled run checks again without immediate retry or backoff.
2

Each web replica started a scheduler, duplicating the same collection job

Solution Process

Moved collection responsibility out of web processes into one singleton KST scheduler

Result

Reduced per-replica 15-slot schedules to one singleton's 15 slots, excluding the one startup sync

← Scroll horizontally to view the scenario →

Move per-replica collection into one singleton owner
Move per-replica collection into one singleton owner.Moves 15 scheduled slots registered by every web replica into one separate singleton KST scheduler.
3

Source fields needed by the operational UI had to remain useful while internal and credential-bearing fields stayed blocked

Solution Process

Used a method/path allowlist, required-field validation, a fixed output projection, and source-URL contracts to pass only operational UI fields while excluding internal IDs, unknown fields, and the credential-bearing tracking URL

Result

Verified the fixed output projection and source-URL allowlist together with redirect, payload, and deployment regression boundaries

← Scroll horizontally to view the scenario →

Separate public route responses from authenticated routes
Separate public route responses from authenticated routes.Applies allowlist projection only to public route responses, not the whole Next.js proxy. It enforces exact method and path, schema, payload limits, and redirect rejection while forwarding only allowlisted methods and paths for authenticated routes.
4

A synthetic source with one valid route returned no rows, while grouped counts 1,234 and 2,345 became 1 and 2

Solution Process

Removed the minimum-five-row rejection and stripped grouping commas before integer parsing. Exercised the real EUC-KR crawler and temporary SQLite through loopback HTTP

Result

Preserved the single route and values 1234 and 2345; duplicate rows and replayed collection retained one row per date/code and the original creation time

5

After a separate writer corrected a stored value from 10 to 20, the same reader still returned 10 from its one-hour process-local cache

Solution Process

Switched code search to direct database reads, matching other search paths, and removed the cache and its DI dependencies. Used two independent Prisma connections to reproduce delayed additions and current/historical corrections

Result

Across ten public synthetic scenarios, the same reader observed the correction from 1234 to 1250 on its next request. Both HTTP 503 and a mid-batch database write failure preserved prior storage; an explicit replay applied changes after the failure cause was removed

6

Needed to verify that a writer-lock rejection preserves existing data and allows the same work to be replayed

Solution Process

Extended the 100/1,000-row loads and 150ms-target lock contention with a rejection experiment. Set a one-second SQLite wait budget only on a separate fixture client while holding a real UPDATE lock. Checked state with an independent reader, released the lock, and explicitly replayed the same response once. Ran the whole experiment twice with fresh temporary databases

Result

Synthetic Node 24/macOS arm64 observation: all six short-lock contenders committed after release. All six separate rejection samples returned P1008 and preserved every existing row, ID, and timestamp. Each explicit replay then applied the correction and addition while preserving prior IDs and timestamps. This is not a production throughput, SLA, or failure-recovery guarantee

7

The first ARM64 production rollout failed with OperationalError; the previous collector and route were recovered. The original SQLite subcode was not recorded

Solution Process

A synthetic cross-runtime reproduction supported moving live SQL observation and backup into the writers’ Linux VM, with the host opening only completed backup copies; it did not prove the exact original cause. Redeployed after verifying a read-only source backup’s integrity and isolated readability

Result

The owner-recorded single deployment verified native ARM64 web and collector, health gates, and real changed-row API parity. DB-change detection→API equality took 115.4ms (observed poll interval 1.287s); 10 sequential data reads at least 1s apart had a 27.178ms median and 23.487–34.199ms range. After all gates passed, the previous slot was stopped and retained; no database restore occurred

System architecture and operating boundary

Collection independently rechecks the current date on each scheduled run and sends it through the crawler into SQLite. Queries project public fields in the public route DTO branch inside the Next.js proxy before passing through Traefik and the active Express slot. Authenticated routes pass separately, and the inactive slot must pass health checks before switching.

← Scroll horizontally to view the collection, query, and deployment flows →

Current-date independent recheck flow, public route DTO branch inside the Next.js proxy, and the health-gated slot switch with manual rollback

Operating limits

Production evidence is a bounded, owner-recorded single-deployment smoke observation, not independent attestation. It is separate from public source, CI, and ten synthetic scenarios, and proves neither freshness SLA nor uptime.
These synthetic experiments use small samples on one macOS arm64 host; with n=3 per invocation and size, p95 is the observed maximum. The one-second rejection budget is fixture-only, not the production configuration. BEGIN IMMEDIATE may reject before any write, so the existing trigger scenario remains the separate evidence for mid-batch rollback.
Upsert-only storage retains rows omitted by later source responses; createdAt is first insertion. Failures are checked on the next scheduled run, without immediate retry or backoff.
Code search reads SQLite on every request. Ten sequential reads establish neither capacity, throughput, p95, nor before/after improvement; horizontal write scaling remains limited.
The 115.4ms interval runs from DB-change detection to API equality. The observed poll interval was 1.287s; DB commit time was unobserved, so this is not source-change/commit-to-API latency.
The inactive slot must pass health checks before switching; the previous slot is recovered on failure. The first OperationalError’s exact SQLite subcode was unrecorded; synthetic reproduction supports same-VM observation and backup, not proof of the original cause.

Claim → public evidence

Evidence links support individual claims. Source and test coverage are distinct from owner-recorded operating observations.

Rollout source revision — separate from execution evidence

Which source revision is pinned? (Source alone is not proof of production execution)

Ingestion and production-dependency CI

Did regressions, synthetic ingestion, the production-dependency audit, and final-image execution pass?

Tech Stack

TypeScriptExpressNext.jsReactPrismaSQLiteCheerioTSyringeTanStack QueryDockerTraefikTailwind CSSVitest