Record ALL input orders in history, including resolution failures (not_found)
and ERP query misses (erp_not_found). Add ProductionId column to track original
总排号 input. Add 总排号 column and new status styles to the history UI. Fix
empty result caching that prevented retry on transient query failures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend changes:
- SQL Server dialect: GETDATE() → SYSUTCDATETIME()
- MySQL dialect: NOW() → UTC_TIMESTAMP()
- Ensures OperationTime and EndTime use consistent UTC timezone
Frontend changes:
- formatDateTime: display UTC timestamps in user's local timezone
- Uses getFullYear/getMonth/getDate/getHours (local) instead of UTC methods
Data migration:
- Executed migration script to fix historical OperationTime records
- All existing records now have correct UTC timestamps
- Execution duration now accurate (minutes, not hours)
Impact:
- New executions store UTC timestamps correctly
- UI displays times in user's local timezone (UTC+8 for CN users)
- Historical data corrected via migration
- Time difference between OperationTime and EndTime now accurate
Record materials not in the deletion list as "skipped" with reason
instead of just logging them. Skip inserting material details to
database during dry runs to avoid phantom records.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously only skipped and failed materials were persisted. Now every
material (deleted, uncertain, skipped, failed) is recorded in
CleanerMaterialDetail for full audit traceability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SQL Server does not support MAX() on BIT columns, causing the
getBatches query to fail silently and return empty results.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove generateExecutionId(), generateAndUploadReport(), and all
executionId references from CleanerApplicationService. The service
now accepts batchId, historyDao, and appVersion from the IPC handler
and writes execution/order/material records to the database via
CleanerOperationHistoryDAO instead of generating Markdown reports.
All execution paths (success, failure, outer retry, retry-login-failure)
persist their results to the database with appropriate status tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When CleanerService hits a fatal error (browser crash, timeout), the
outer catch now sets result.crashed=true. CleanerApplicationService
detects this, closes the dead browser session, re-logs into ERP, and
re-runs all orders once. An execution ID (CLN-yyyyMMddHHmmss-XXXX)
generated at startup ensures report files are deduplicated across
retries. Reports now display execution ID and app version.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Admin can now pass selectedManagers to getCleanerData so material codes
are queried from MaterialsToBeDeleted by ManagerName IN (selectedManagers).
When no managers are selected, fallback to DiscreteMaterialPlanData by
orderNumbers. User behavior is unchanged. Includes updated tests and
role-based flow documentation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Export cachedHostname from audit-logger and use it in process-guards,
replacing process.env.COMPUTERNAME so all audit entries use the same value.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace magic strings with AuditAction/AuditStatus enums across all consumers,
add logAuditWithCurrentUser() convenience wrapper, extend audit coverage to
data import, result export, app update, and ERP credentials operations, and
harden crash handlers with try/catch to prevent audit failures from cascading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OrderNumberResolver, validation, and cleaner services had incomplete
PostgreSQL support - they only handled SQL Server and MySQL, causing
PostgreSQL to fall through to MySQL code paths with invalid syntax
(backticks, ? placeholders) and missing schema.table name splitting.
Changes:
- Add PostgreSQL SQL generation ($N params, double-quoted identifiers)
in OrderNumberResolver, validation-application-service,
production-input-service, and validation-database
- Add PostgreSQL to database factory functions in validation-database
and cleaner-application-service
- Add UPPER, LOWER, and 40+ common SQL functions to SQL_KEYWORDS to
prevent prepareSql() from quoting them as identifiers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused imports (run, trackDuration, PerformanceTracker,
ConfigManager, disconnectDb) flagged by ESLint
- Remove unused isSlow variable in performance-monitor catch block
- Add eslint-disable for require() in Playwright JS script
- Fix logger-performance test flakiness by using vi.resetModules()
with dynamic imports to prevent cached logger references across
test files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add prepareSql() to PostgreSqlService that quotes unquoted column names
before execution. PostgreSQL lowercases unquoted identifiers, but
SSMA-migrated tables have uppercase column names requiring double-quoting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded MySqlService/SqlServerService with DatabaseFactory,
enabling PostgreSQL support for user authentication and management.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix dialect files to use relative paths instead of @types alias
- Add 'postgresql' to BIPUsersDAO dbType union
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all isSqlServer checks, buildPlaceholders, and hardcoded table names
with the SqlDialect abstraction. The dialect now handles parameter placeholders,
table name quoting, current timestamp functions, and pagination across all
supported database types.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all isSqlServer/if-else branches with SqlDialect calls:
- Table name via dialect.quoteTableName()
- Placeholders via dialect.param() and dialect.params()
- UPSERT via dialect.upsert() in upsertMaterial(), upsertBatch(), updateManager()
- Remove buildPlaceholders(), TABLE_NAME_SQLSERVER, TABLE_NAME_MYSQL
- Re-export SqlDialect type from dialects barrel
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace all manual isSqlServer checks and inline SQL dialect logic with the
SqlDialect abstraction. Removes buildPlaceholders(), TABLE_NAME_SQLSERVER,
and TABLE_NAME_MYSQL in favor of dialect.params(), dialect.param(), and
dialect.quoteTableName(). Batch size logic now uses dialect.maxBatchRows().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add three SqlDialect implementations with a factory function:
- MySqlDialect: positional ?, ON DUPLICATE KEY UPDATE, LIMIT/OFFSET
- SqlServerDialect: @pN params, MERGE USING, OFFSET/FETCH
- PostgreSqlDialect: $N (1-based), ON CONFLICT DO UPDATE, LIMIT/OFFSET
TDD approach: 43 tests written first, all passing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 'postgresql' to DatabaseType union in database.types.ts
- Add PostgreSqlConfig interface extending DatabaseConfig
- Add postgresqlConfigSchema Zod schema with host, port, database,
username, password, and maxPoolSize fields
- Add 'postgresql' to databaseConfigSchema and type exports
- Create SqlDialect interface with methods for quoteTableName,
param, params, currentTimestamp, upsert, paginate, maxBatchRows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add detailed step-by-step logging in navigation phase with elapsed time tracking
- Enhance query interface setup with individual step logging and timing
- Improve order query and result collection with validation logging
- Add comprehensive processDetailPage logging with 8 tracked steps
- Detail material processing loop with decision tracking (delete/skip reasons)
- Enhance retry mechanism with per-attempt logging and success rate tracking
- Add performance monitoring with slow operation detection (isSlow flags)
- All logs use consistent Chinese labeling with [Phase] prefix format
Total: +437 lines of logging instrumentation across cleaner.ts
Add getLocalIpAddress() that reliably resolves the primary LAN IPv4
address by collecting all non-loopback, non-APIPA addresses and
prioritizing RFC 1918 private ranges (192.168.x.x, 10.x.x.x,
172.16-31.x.x) over public IPs. Falls back to any non-internal
address or 'N/A'.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Winston's default npm levels assign debug=5 and verbose=4, so setting
level to 'verbose' (threshold 4) filtered out debug (5 > 4). Register
PROJECT_LEVELS { error:0, warn:1, info:2, debug:3, verbose:4 } so
Winston's <= threshold filter aligns with the project's intended
semantics where verbose is the most detailed level.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Seq centralized logging transport with async ESM import
- Add appVersion and computerName to logger defaultMeta (all app logs)
- Add appVersion to audit log entries for version-level traceability
- Improve unhandledRejection to capture full stack traces for Error instances
- Add Seq config schema and template configuration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enhance ERP automation error diagnostics by capturing PNG screenshots
on every error and forwarding browser console warnings/errors to the
structured logger. Includes automatic cleanup of old screenshots
aligned with the configured log retention period.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ~45 structured log calls across extractor-core, cleaner, and erp-auth
to cover all automation steps (navigation, query, download, material processing).
Enhance capturePageContext with a step parameter for precise failure localization,
and fix missing capturePageContext calls in error handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Eliminate console.* remnants in bootstrap, session-manager, migrations, and app entry
so startup and login failures are captured in log files. Add log.error before all 14
throw sites in ERP services (auth, extractor, cleaner, browser manager) to ensure
critical automation failures are traceable. Introduce capturePageContext utility for
defensive Playwright page state capture during error logging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add createLogger/trackDuration logging to mysql.ts, sql-server.ts, and
data-source.ts — the only database layer files without observability.
Connect/disconnect, query execution (with duration tracking), and
transaction lifecycle events are now logged. Passwords and parameter
values are excluded; SQL statements are capped at 100 chars.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously getLogDir() only checked app.isReady(), which caused
development builds to write logs to the user data directory instead
of the local project logs/ folder. Now uses app.isPackaged to
correctly distinguish production from development environments.
Also adds comprehensive logging system documentation and a debug
utility for verifying Electron environment detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add headless field to extraction config schema (default: true).
Extractor handler now reads globalConfig.extraction.headless instead
of hardcoding true. Users can set headless: false in config.yaml
to show the browser window during extraction for debugging.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove misleading await from audit-logger tests (functions are sync)
- Add cleanup() to LoggerAPI type definition in index.d.ts
- Fix circular reference fallback to preserve null values
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Make logAudit and closeAuditLogger synchronous (were async for no reason)
- Set audit-logger silent:true initially, enable on applyAuditConfig()
- Add try-catch for circular references in consoleFormat meta JSON
- Update all callers to remove unnecessary await/.catch() on sync functions
- Add comment to shared.ts explaining acceptable sync FS usage
- Fix audit-logger test for sync closeAuditLogger
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add LOGGER_LEVEL_CHANGED IPC channel for broadcasting level changes
- setLogLevel() now notifies all BrowserWindows when level changes
- Add verbose case in IPC forwardToWinston (was falling through to info)
- Renderer logger API listens for level changes and updates cached level
- Add cleanup() method to remove level change listener
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>