Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions buf.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
version: v2
deps:
- name: buf.build/bufbuild/protovalidate
commit: 80ab13bee0bf4272b6161a72bf7034e0
digest: b5:1aa6a965be5d02d64e1d81954fa2e78ef9d1e33a0c30f92bc2626039006a94deb3a5b05f14ed8893f5c3ffce444ac008f7e968188ad225c4c29c813aa5f2daa1
commit: 50325440f8f24053b047484a6bf60b76
digest: b5:74cb6f5c0853c3c10aafc701614194bbd63326bdb8ef4068214454b8894b03ba4113e04b3a33a8321cdf05336e37db4dc14a5e2495db8462566914f36086ba31
- name: buf.build/googleapis/googleapis
commit: c17df5b2beca46928cc87d5656bd5343
digest: b5:648a01e0170d4512dea7d564016165decd1ed6e34bef79fe54753e51ad7e27545709ad9157d7551270147d551155c595a2fb0bf5bb33b1c83040ddbce915c604
329 changes: 329 additions & 0 deletions finance/v1/oracle_sync.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,329 @@
syntax = "proto3";

package finance.v1;

// Note: go_package is managed by buf.gen.yaml managed mode

import "buf/validate/validate.proto";
import "common/v1/common.proto";
import "google/api/annotations.proto";

// =============================================================================
// ENUMS
// =============================================================================

// JobStatus represents the current state of a job execution.
enum JobStatus {
// Default unspecified value.
JOB_STATUS_UNSPECIFIED = 0;
// Job is queued and waiting for processing.
JOB_STATUS_QUEUED = 1;
// Job is currently being processed.
JOB_STATUS_PROCESSING = 2;
// Job completed successfully.
JOB_STATUS_SUCCESS = 3;
// Job failed.
JOB_STATUS_FAILED = 4;
// Job was cancelled.
JOB_STATUS_CANCELLED = 5;
}

// JobLogStatus represents the status of a job execution log step.
enum JobLogStatus {
// Default unspecified value.
JOB_LOG_STATUS_UNSPECIFIED = 0;
// Step has started.
JOB_LOG_STATUS_STARTED = 1;
// Step completed successfully.
JOB_LOG_STATUS_SUCCESS = 2;
// Step failed.
JOB_LOG_STATUS_FAILED = 3;
// Step was skipped.
JOB_LOG_STATUS_SKIPPED = 4;
}

// =============================================================================
// MESSAGES - Entities
// =============================================================================

// SyncJob represents a job execution for Oracle-to-PostgreSQL sync.
message SyncJob {
// Unique job identifier (UUID).
string job_id = 1;
// Human-readable job code (e.g., "ORACLE_SYNC-202601-001").
string job_code = 2;
// Job type (e.g., "oracle_sync").
string job_type = 3;
// Job subtype for categorization.
string job_subtype = 4;
// Period being synced (YYYYMM format).
string period = 5;
// Current job status.
JobStatus status = 6;
// Priority (1-10, lower is higher priority).
int32 priority = 7;
// Progress percentage (0-100).
int32 progress = 8;
// Error message if the job failed.
string error_message = 9;
// Result summary as JSON string.
string result_summary = 10;
// Number of retry attempts.
int32 retry_count = 11;
// Maximum allowed retries.
int32 max_retries = 12;
// Timestamp when the job was queued (ISO 8601).
string queued_at = 13;
// Timestamp when processing started (ISO 8601).
string started_at = 14;
// Timestamp when the job completed (ISO 8601).
string completed_at = 15;
// User who created the job.
string created_by = 16;
// User who cancelled the job.
string cancelled_by = 17;
// Timestamp when the job was cancelled (ISO 8601).
string cancelled_at = 18;
// Execution logs for this job.
repeated SyncJobLog logs = 19;
}

// SyncJobLog represents a single step log entry within a job execution.
message SyncJobLog {
// Unique log identifier (UUID).
string log_id = 1;
// Parent job identifier (UUID).
string job_id = 2;
// Step name (e.g., "execute_procedure", "fetch_data", "upsert_data").
string step = 3;
// Step status.
JobLogStatus status = 4;
// Log message.
string message = 5;
// Additional metadata as JSON string.
string metadata = 6;
// Timestamp when the step started (ISO 8601).
string started_at = 7;
// Timestamp when the step completed (ISO 8601).
string completed_at = 8;
// Duration of the step in milliseconds.
int32 duration_ms = 9;
}

// ItemConsStockPO represents a synced item consumption, stock, and PO record.
message ItemConsStockPO {
// Period (YYYYMM format).
string period = 1;
// Item code.
string item_code = 2;
// Grade code.
string grade_code = 3;
// Grade name.
string grade_name = 4;
// Item name.
string item_name = 5;
// Unit of measure.
string uom = 6;
// Consumption quantity.
double cons_qty = 7;
// Consumption value.
double cons_val = 8;
// Consumption rate.
double cons_rate = 9;
// Stores quantity.
double stores_qty = 10;
// Stores value.
double stores_val = 11;
// Stores rate.
double stores_rate = 12;
// Department quantity.
double dept_qty = 13;
// Department value.
double dept_val = 14;
// Department rate.
double dept_rate = 15;
// Last PO 1 quantity.
double last_po_qty1 = 16;
// Last PO 1 value.
double last_po_val1 = 17;
// Last PO 1 rate.
double last_po_rate1 = 18;
// Last PO 1 date (ISO 8601).
string last_po_dt1 = 19;
// Last PO 2 quantity.
double last_po_qty2 = 20;
// Last PO 2 value.
double last_po_val2 = 21;
// Last PO 2 rate.
double last_po_rate2 = 22;
// Last PO 2 date (ISO 8601).
string last_po_dt2 = 23;
// Last PO 3 quantity.
double last_po_qty3 = 24;
// Last PO 3 value.
double last_po_val3 = 25;
// Last PO 3 rate.
double last_po_rate3 = 26;
// Last PO 3 date (ISO 8601).
string last_po_dt3 = 27;
// Timestamp when the record was synced (ISO 8601).
string synced_at = 28;
// Job ID that synced this record (UUID).
string synced_by_job = 29;
}

// =============================================================================
// MESSAGES - Requests and Responses
// =============================================================================

// TriggerSyncRequest initiates an Oracle-to-PostgreSQL sync job.
message TriggerSyncRequest {
// Period to sync (YYYYMM format). If empty, auto-resolved based on current date.
string period = 1 [(buf.validate.field).string.max_len = 6];
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

period is documented as YYYYMM (or empty), but the validation only enforces max_len = 6, so values like "abc" or "2026" will pass. Consider validating the format when provided (e.g., digits-only YYYYMM) while still allowing empty for auto-resolve.

Suggested change
string period = 1 [(buf.validate.field).string.max_len = 6];
string period = 1 [(buf.validate.field).string.pattern = "^(\\d{4}(0[1-9]|1[0-2]))?$"];

Copilot uses AI. Check for mistakes.
}

// TriggerSyncResponse returns the created job.
message TriggerSyncResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// The created sync job.
SyncJob data = 2;
}

// GetSyncJobRequest retrieves a specific sync job by ID.
message GetSyncJobRequest {
// Job identifier (UUID).
string job_id = 1 [(buf.validate.field).string.uuid = true];
}

// GetSyncJobResponse returns a single sync job with logs.
message GetSyncJobResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// The sync job with logs.
SyncJob data = 2;
}

// ListSyncJobsRequest retrieves a paginated list of sync jobs.
message ListSyncJobsRequest {
// Page number (1-indexed).
int32 page = 1 [(buf.validate.field).int32.gte = 1];
// Number of items per page.
int32 page_size = 2 [(buf.validate.field).int32 = {
gte: 1
lte: 100
}];
// Filter by job type.
string job_type = 3 [(buf.validate.field).string.max_len = 50];
// Filter by status.
JobStatus status = 4;
// Filter by period (YYYYMM).
string period = 5 [(buf.validate.field).string.max_len = 6];
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

period is described as YYYYMM but only has max_len = 6; invalid values (non-digits / wrong length) will pass validation. Suggest adding a stricter validation (e.g., digits-only, exactly 6 when non-empty) to keep filtering behavior consistent across clients.

Suggested change
string period = 5 [(buf.validate.field).string.max_len = 6];
string period = 5 [(buf.validate.field).string = {
len: 6
pattern: "^[0-9]{6}$"
ignore_empty: true
}];

Copilot uses AI. Check for mistakes.
// Search in job code or error message.
string search = 6 [(buf.validate.field).string.max_len = 100];
}

// ListSyncJobsResponse returns a paginated list of sync jobs.
message ListSyncJobsResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// List of sync jobs.
repeated SyncJob data = 2;
// Pagination metadata.
common.v1.PaginationResponse pagination = 3;
Comment on lines +227 to +233
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SyncJob includes repeated SyncJobLog logs, and ListSyncJobsResponse returns repeated SyncJob, which means the list endpoint can inadvertently include full execution logs for every job (potentially very large payloads). Consider splitting into a summary message for list responses (without logs) and reserving logs for GetSyncJob, or add a dedicated ListSyncJobLogs RPC with pagination/limits.

Copilot uses AI. Check for mistakes.
}

// CancelSyncJobRequest cancels a queued or processing sync job.
message CancelSyncJobRequest {
// Job identifier (UUID).
string job_id = 1 [(buf.validate.field).string.uuid = true];
}

// CancelSyncJobResponse returns the cancelled job.
message CancelSyncJobResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// The cancelled sync job.
SyncJob data = 2;
}

// ListItemConsStockPORequest retrieves synced item consumption data.
message ListItemConsStockPORequest {
// Page number (1-indexed).
int32 page = 1 [(buf.validate.field).int32.gte = 1];
// Number of items per page.
int32 page_size = 2 [(buf.validate.field).int32 = {
gte: 1
lte: 100
}];
// Filter by period (YYYYMM).
string period = 3 [(buf.validate.field).string.max_len = 6];
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

period is documented as YYYYMM but the request validation only caps length at 6. If the backend expects strict YYYYMM filtering, add format validation (digits-only, exactly 6 when non-empty) so clients get consistent errors instead of silent no-match results.

Suggested change
string period = 3 [(buf.validate.field).string.max_len = 6];
string period = 3 [(buf.validate.field).string = {
ignore_empty: true
len: 6
pattern: "^[0-9]{6}$"
}];

Copilot uses AI. Check for mistakes.
// Filter by item code.
string item_code = 4 [(buf.validate.field).string.max_len = 20];
// Full-text search on item name, item code, grade name.
string search = 5 [(buf.validate.field).string.max_len = 100];
}

// ListItemConsStockPOResponse returns synced item consumption data.
message ListItemConsStockPOResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// List of synced records.
repeated ItemConsStockPO data = 2;
// Pagination metadata.
common.v1.PaginationResponse pagination = 3;
}

// ListSyncPeriodsRequest retrieves available sync periods.
message ListSyncPeriodsRequest {}

// ListSyncPeriodsResponse returns the list of distinct periods.
message ListSyncPeriodsResponse {
// Standard response envelope.
common.v1.BaseResponse base = 1;
// List of periods in YYYYMM format, ordered descending.
repeated string periods = 2;
}

// =============================================================================
// SERVICE
// =============================================================================

// OracleSyncService manages Oracle-to-PostgreSQL data synchronization.
service OracleSyncService {
// TriggerSync initiates a manual Oracle sync job.
rpc TriggerSync(TriggerSyncRequest) returns (TriggerSyncResponse) {
option (google.api.http) = {
post: "/api/v1/finance/oracle-sync/trigger"
body: "*"
};
}

// GetSyncJob retrieves a specific sync job by ID with execution logs.
rpc GetSyncJob(GetSyncJobRequest) returns (GetSyncJobResponse) {
option (google.api.http) = {get: "/api/v1/finance/oracle-sync/jobs/{job_id}"};
}

// ListSyncJobs retrieves a paginated list of sync job executions.
rpc ListSyncJobs(ListSyncJobsRequest) returns (ListSyncJobsResponse) {
option (google.api.http) = {get: "/api/v1/finance/oracle-sync/jobs"};
}

// CancelSyncJob cancels a queued or in-progress sync job.
rpc CancelSyncJob(CancelSyncJobRequest) returns (CancelSyncJobResponse) {
option (google.api.http) = {
post: "/api/v1/finance/oracle-sync/jobs/{job_id}/cancel"
body: "*"
};
}

// ListItemConsStockPO retrieves synced item consumption, stock, and PO data.
rpc ListItemConsStockPO(ListItemConsStockPORequest) returns (ListItemConsStockPOResponse) {
option (google.api.http) = {get: "/api/v1/finance/item-cons-stock-po"};
}

// ListSyncPeriods retrieves all available sync periods.
rpc ListSyncPeriods(ListSyncPeriodsRequest) returns (ListSyncPeriodsResponse) {
option (google.api.http) = {get: "/api/v1/finance/oracle-sync/periods"};
}
}
Loading