first commit
This commit is contained in:
commit
367533c02b
171 files changed
+101175
No files matched your search
@@ -0,0 +1,325 @@
|
||||
# Entity Relationship Diagram (ERD) & Unified Master Architecture
|
||||
|
||||
This document defines the integrated **Audrix Smart Poultry Platform ERD (`ERD_audrix`)** and how the **Chicken Counting & Weight Estimation Vision System** connects directly into the master farm database.
|
||||
|
||||
---
|
||||
|
||||
## 🗺️ Unified Master Mermaid ERD (`ERD_audrix` Integration)
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
%% ==========================================
|
||||
%% 1. CORE ENTERPRISE HIERARCHY (ERD_audrix)
|
||||
%% ==========================================
|
||||
USER_ACCESS ||--|{ SITES : "manages"
|
||||
SITES ||--|{ KANDANG : "contains"
|
||||
KANDANG ||--|{ CYCLES : "runs"
|
||||
CYCLES ||--|{ FLOCK : "houses"
|
||||
|
||||
%% ==========================================
|
||||
%% 2. OUR DOMAIN: EDGE TOPOLOGY & VISION
|
||||
%% ==========================================
|
||||
KANDANG ||--|{ FLOOR : "has_levels"
|
||||
FLOOR ||--|{ CAMERA : "equipped_with"
|
||||
FLOOR ||--o{ BATCH_RUNS : "executes"
|
||||
CAMERA ||--o{ BATCH_RUNS : "records"
|
||||
BATCH_RUNS ||--o{ DETECTIONS : "captures_tracks"
|
||||
|
||||
%% ==========================================
|
||||
%% 3. VISION ROLLUPS -> MASTER AUDRIX TABLES
|
||||
%% ==========================================
|
||||
CYCLES ||--o{ CHICKEN_COUNTING : "records_daily_count"
|
||||
CYCLES ||--o{ CHICKEN_WEIGHT : "records_daily_weight"
|
||||
BATCH_RUNS ||--o{ CHICKEN_COUNTING : "aggregates_into_cc"
|
||||
BATCH_RUNS ||--o{ CHICKEN_WEIGHT : "aggregates_into_cw"
|
||||
|
||||
%% ==========================================
|
||||
%% 4. NON-VISION EXTERNAL STREAMS (DO NOT TOUCH)
|
||||
%% ==========================================
|
||||
FLOCK ||--o{ IOT_PANEL : "monitored_by"
|
||||
CYCLES ||--o{ FEED_SACKS : "tracks_inventory"
|
||||
CYCLES ||--o{ MANUAL_INPUT : "logs_ground_truth"
|
||||
CYCLES ||--o{ AI_INSIGHT : "generates_alerts"
|
||||
|
||||
%% ==========================================
|
||||
%% 5. MASTER KPI AGGREGATION (ERD_audrix)
|
||||
%% ==========================================
|
||||
CYCLES ||--o{ KPI : "computes_daily_kpi"
|
||||
CHICKEN_COUNTING ||--o{ KPI : "feeds_headcount"
|
||||
CHICKEN_WEIGHT ||--o{ KPI : "feeds_vision_weight"
|
||||
FEED_SACKS ||--o{ KPI : "feeds_feed_usage"
|
||||
MANUAL_INPUT ||--o{ KPI : "feeds_manual_weights"
|
||||
|
||||
%% ==========================================
|
||||
%% ENTITY DEFINITIONS
|
||||
%% ==========================================
|
||||
|
||||
USER_ACCESS {
|
||||
int user_id PK "NOT NULL"
|
||||
varchar user_name "30 NOT NULL"
|
||||
varchar password_hash "255 NOT NULL"
|
||||
varchar status "30 NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
SITES {
|
||||
int site_id PK "NOT NULL"
|
||||
varchar site_name "30 NOT NULL"
|
||||
int user_id FK "References USER_ACCESS"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
KANDANG {
|
||||
int kandang_id PK "NOT NULL"
|
||||
varchar kandang_name "30 NOT NULL"
|
||||
int site_id FK "References SITES"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
CYCLES {
|
||||
int cycle_id PK "NOT NULL (Flock Batch Run)"
|
||||
int kandang_id FK "References KANDANG"
|
||||
int total_days "NOT NULL"
|
||||
date start_date "NOT NULL (Day 0)"
|
||||
date end_date "NOT NULL"
|
||||
int doc_in_weight "NOT NULL (Initial DOC weight for this cycle)"
|
||||
int doc_in_count "NOT NULL (Stocking inventory)"
|
||||
varchar status "30 NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
FLOCK {
|
||||
int flock_id PK "NOT NULL"
|
||||
varchar flock_name "30 NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
FLOOR {
|
||||
string floor_id PK "e.g. K1-L1, K1-L2"
|
||||
int kandang_id FK "References KANDANG"
|
||||
string level "Floor level designation (L1, L2, L3)"
|
||||
json roi_points "Counting gate coordinates"
|
||||
float px_per_cm "Spatial calibration constant"
|
||||
}
|
||||
|
||||
CAMERA {
|
||||
string camera_id PK "e.g. CC1, CC2, CC3, CC4"
|
||||
string floor_id FK "References FLOOR"
|
||||
int camera_num "1 to 4"
|
||||
float px_per_cm "Camera pixel to cm calibration"
|
||||
string stream_url "Source video / RTSP stream"
|
||||
}
|
||||
|
||||
BATCH_RUNS {
|
||||
integer id PK "AUTOINCREMENT (SQLite edge runs)"
|
||||
string date "YYYY-MM-DD"
|
||||
string location FK "References FLOOR(floor_id)"
|
||||
string camera_id FK "References CAMERA(camera_id)"
|
||||
integer total_entered "Headcount count validated"
|
||||
integer frames_processed
|
||||
real elapsed_seconds
|
||||
string stopped_reason
|
||||
string source_video
|
||||
string generated_at
|
||||
integer cycle_day "0 = DOC count only, 1+ = Weight active"
|
||||
real area_cm2_median "Median body area (cm^2)"
|
||||
real minor_axis_cm_median "Median width (cm)"
|
||||
real major_axis_cm_median "Median length (cm)"
|
||||
real predicted_weight_g "Estimated weight (g)"
|
||||
real gompertz_baseline_g "Expected curve weight (g)"
|
||||
real vision_gain_g "Vision allometric gain (g)"
|
||||
integer n_weight_samples "Valid sample count"
|
||||
real rejection_rate "MAD outlier filter rejection rate"
|
||||
}
|
||||
|
||||
DETECTIONS {
|
||||
string date "YYYY-MM-DD"
|
||||
string camera_id FK
|
||||
integer track_id "BoT-SORT track identifier"
|
||||
integer class_id "0 = chicken"
|
||||
float confidence "YOLO confidence score"
|
||||
integer frame_index "Count trigger frame"
|
||||
float bbox_area_cm2 "Area in cm^2"
|
||||
float width_cm "Width in cm"
|
||||
float height_cm "Height in cm"
|
||||
float minor_axis_cm "min(width, height) cm"
|
||||
float major_axis_cm "max(width, height) cm"
|
||||
float aspect_ratio_cm "width / height"
|
||||
float perimeter_cm "Perimeter cm"
|
||||
float mad_zscore "MAD Z-score outlier metric"
|
||||
}
|
||||
|
||||
CHICKEN_COUNTING {
|
||||
int cc_id PK "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
date date "NOT NULL"
|
||||
int total_count "NOT NULL (Aggregated total from edge BATCH_RUNS)"
|
||||
int mortality_count "NOT NULL (Carcasses from vision segmentation)"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
CHICKEN_WEIGHT {
|
||||
int cw_id PK "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
date date "NOT NULL"
|
||||
int age "NOT NULL (Cycle Day: 1+)"
|
||||
int doc_weight "NOT NULL (Cycle-specific initial DOC weight)"
|
||||
float average_weight "NOT NULL (predicted_weight_g from edge)"
|
||||
int chicken_count "NOT NULL (n_weight_samples)"
|
||||
float uniformity "NOT NULL (Flock weight uniformity %)"
|
||||
float average_daily_gain "NOT NULL (ADG in grams/day)"
|
||||
float area_cm2_median "Median body area in cm^2"
|
||||
float minor_axis_cm_median "Median minor axis / width in cm"
|
||||
float major_axis_cm_median "Median major axis / length in cm"
|
||||
float gompertz_baseline_g "Theoretical Gompertz curve baseline"
|
||||
float vision_gain_g "Allometric vision gain residual"
|
||||
float rejection_rate "MAD outlier filter rejection percentage"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
}
|
||||
|
||||
IOT_PANEL {
|
||||
int panel_id PK "NOT NULL"
|
||||
date date "NOT NULL"
|
||||
float wind_speed "NOT NULL"
|
||||
float humidity "NOT NULL"
|
||||
float water_total "NOT NULL"
|
||||
float average_temperature "NOT NULL"
|
||||
float experience_temperature "NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
int flock_id FK "References FLOCK"
|
||||
}
|
||||
|
||||
FEED_SACKS {
|
||||
int fs_id PK "NOT NULL (fc_id)"
|
||||
date date "NOT NULL"
|
||||
int in_today "NOT NULL"
|
||||
int out_today "NOT NULL"
|
||||
int in_total "NOT NULL"
|
||||
int out_total "NOT NULL"
|
||||
int feed_use_today "NOT NULL"
|
||||
int feed_use_total "NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
}
|
||||
|
||||
MANUAL_INPUT {
|
||||
int manual_id PK "NOT NULL"
|
||||
date date "NOT NULL"
|
||||
int age_manual "NOT NULL"
|
||||
int mortality_manual "NOT NULL"
|
||||
int mortality_manual_total "NOT NULL"
|
||||
int feed_in_manual "NOT NULL"
|
||||
int feed_use_manual "NOT NULL"
|
||||
int feed_in_manual_total "NOT NULL"
|
||||
int feed_use_manual_total "NOT NULL"
|
||||
int harverst_manual "NOT NULL"
|
||||
int harverst_manual_total "NOT NULL"
|
||||
float harvest_weight_manual "NOT NULL"
|
||||
float harvest_weight_manual_total "NOT NULL"
|
||||
float manual_weight "NOT NULL"
|
||||
float average_harvest_day_manual "NOT NULL"
|
||||
float average_harvest_weight_manual "NOT NULL"
|
||||
float fcr_manual "NOT NULL"
|
||||
float eef_manual "NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
}
|
||||
|
||||
AI_INSIGHT {
|
||||
int id PK "NOT NULL"
|
||||
date date "NOT NULL"
|
||||
text insight_text "NOT NULL"
|
||||
string alert "NOT NULL"
|
||||
varchar section "100 NOT NULL"
|
||||
varchar session "100 NOT NULL"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
}
|
||||
|
||||
KPI {
|
||||
int kpi_id PK "NOT NULL"
|
||||
date date "NOT NULL"
|
||||
int age "NOT NULL"
|
||||
int mortality "NOT NULL"
|
||||
int mortality_total "NOT NULL"
|
||||
int feed "NOT NULL"
|
||||
int feed_total "NOT NULL"
|
||||
int harverst "NOT NULL"
|
||||
int harverst_total "NOT NULL"
|
||||
float harvest_weight "NOT NULL"
|
||||
float harvest_weight_total "NOT NULL"
|
||||
int chicken_life "NOT NULL"
|
||||
float chicken_life_percentage "NOT NULL"
|
||||
float iot_weight "NOT NULL"
|
||||
float average_harvest_day "NOT NULL"
|
||||
float average_harvest_weight "NOT NULL"
|
||||
float fcr "NOT NULL (Feed Conversion Ratio)"
|
||||
float eef "NOT NULL (European Efficiency Factor)"
|
||||
timestamp created_at "NOT NULL"
|
||||
timestamp updated_at "NOT NULL"
|
||||
int cycle_id FK "References CYCLES"
|
||||
int cc_id FK "References CHICKEN_COUNTING"
|
||||
int cw_id FK "References CHICKEN_WEIGHT"
|
||||
int fs_id FK "References FEED_SACKS"
|
||||
int manual_id FK "References MANUAL_INPUT"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architectural Tier Descriptions & Integration Mapping
|
||||
|
||||
### Tier 1: Farm Hierarchy (`USER_ACCESS` $\to$ `SITES` $\to$ `KANDANG` $\to$ `CYCLES` $\to$ `FLOCK`)
|
||||
|
||||
- Belongs to master `ERD_audrix`.
|
||||
- Defines farm ownership, coops, operational commercial cycles (`CYCLES`), and biological flocks (`FLOCK`).
|
||||
|
||||
---
|
||||
|
||||
### Tier 2: Edge Vision Subsystem (`FLOOR` $\to$ `CAMERA` $\to$ `BATCH_RUNS` $\to$ `DETECTIONS`)
|
||||
|
||||
- **Physical Hierarchy:** Each `KANDANG` has multiple floor levels (`FLOOR`), and each floor operates 4 top-down optical counting cameras (`CAMERA`: CC1, CC2, CC3, CC4) calibrated by `px_per_cm`.
|
||||
- **Execution & Curation:** Daily batch runs process video feeds on the edge and populate SQLite table `BATCH_RUNS` and Parquet observation datasets (`DETECTIONS`).
|
||||
- **Cycle Day 0 Rule:** Day 0 is strictly for initial stocking headcount (`total_entered`), while Day 1+ calculates both headcount and vision-derived geometric body weights.
|
||||
|
||||
---
|
||||
|
||||
### Tier 3: Vision Aggregations to Audrix Tables (`CHICKEN_COUNTING` & `CHICKEN_WEIGHT`)
|
||||
|
||||
Our edge pipeline aggregates floor camera runs and pushes clean daily rollups directly into the two vision tables of `ERD_audrix`:
|
||||
|
||||
1. **`CHICKEN_COUNTING` (`cc_id`)**:
|
||||
- `total_count` $\leftarrow \sum \text{total\_entered}$ across all floor cameras for that date.
|
||||
- `mortality_count` $\leftarrow \text{total dead carcasses detected by mortality segmentation}$.
|
||||
2. **`CHICKEN_WEIGHT` (`cw_id`)**:
|
||||
- `average_weight` $\leftarrow \text{fused predicted weight in grams}$.
|
||||
- `chicken_count` $\leftarrow \sum \text{n\_weight\_samples}$ (valid non-outlier tracks).
|
||||
- `uniformity` $\leftarrow \text{flock size uniformity percentage}$.
|
||||
- `average_daily_gain` $\leftarrow \text{daily weight gain in grams/day}$.
|
||||
- `area_cm2_median`, `minor_axis_cm_median`, `major_axis_cm_median` $\leftarrow \text{calibrated physical dimensions}$.
|
||||
- `gompertz_baseline_g`, `vision_gain_g` $\leftarrow \text{audited growth model residual breakdown}$.
|
||||
|
||||
---
|
||||
|
||||
### Tier 4: Master Analytics & KPI Synthesis (`KPI`)
|
||||
|
||||
- `KPI` is the central analytics ledger that combines:
|
||||
- Vision counts from `CHICKEN_COUNTING` (`cc_id`).
|
||||
- Vision body weights from `CHICKEN_WEIGHT` (`cw_id`).
|
||||
- Daily feed intake from `FEED_SACKS` (`fs_id`).
|
||||
- Human ground truth logs from `MANUAL_INPUT` (`manual_id`).
|
||||
- Computes macro biological & economic efficiency indicators:
|
||||
$$\text{FCR} = \frac{\text{Total Feed Consumed (kg)}}{\text{Total Harvest / Live Weight (kg)}}$$
|
||||
$$\text{EEF} = \frac{\text{Livability \%} \times \text{Average Weight (kg)}}{\text{Age (Days)} \times \text{FCR}} \times 100$$
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 292 KiB |
@@ -0,0 +1,290 @@
|
||||
-- =============================================================================
|
||||
-- PostgreSQL Schema — CPSP Dashboard ERD
|
||||
-- Source: ERD_dashboard.png (updated 2026-08-20)
|
||||
--
|
||||
-- user_access.status: active | inactive | superadmin
|
||||
-- (Django syncs is_active/is_staff/is_superuser from status for auth internals)
|
||||
-- user_access → sites → kandang → cycles
|
||||
-- cycles → flock (flock.cycle_id, required; cycles has no flock_id)
|
||||
-- flock → iot_panel
|
||||
-- cycles → ai_insight, feed_sacks, chicken_counting, chicken_weight,
|
||||
-- manual_input, kpi
|
||||
-- kpi → chicken_counting, chicken_weight, feed_sacks, manual_input
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. User Access
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS user_access (
|
||||
user_id SERIAL PRIMARY KEY,
|
||||
user_name VARCHAR(30) NOT NULL UNIQUE,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
status VARCHAR(30) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_access_status ON user_access (status);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. Sites
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS sites (
|
||||
site_id SERIAL PRIMARY KEY,
|
||||
site_name VARCHAR(30) NOT NULL,
|
||||
user_id INTEGER NOT NULL REFERENCES user_access (user_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_sites_user_id ON sites (user_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. Kandang (Coop / Pen)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS kandang (
|
||||
kandang_id SERIAL PRIMARY KEY,
|
||||
kandang_name VARCHAR(30) NOT NULL,
|
||||
site_id INTEGER NOT NULL REFERENCES sites (site_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_kandang_site_id ON kandang (site_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. Cycles
|
||||
-- No flock_id — flock belongs to cycle via flock.cycle_id.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS cycles (
|
||||
cycle_id SERIAL PRIMARY KEY,
|
||||
total_days INTEGER NOT NULL,
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE NOT NULL,
|
||||
doc_in_weight INTEGER NOT NULL,
|
||||
doc_in_count INTEGER NOT NULL,
|
||||
feed_initial_balance INTEGER NOT NULL DEFAULT 0,
|
||||
status VARCHAR(30) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
kandang_id INTEGER NOT NULL REFERENCES kandang (kandang_id) ON DELETE CASCADE,
|
||||
CONSTRAINT chk_cycles_date_range CHECK (end_date >= start_date)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_kandang_id ON cycles (kandang_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_status ON cycles (status);
|
||||
CREATE INDEX IF NOT EXISTS idx_cycles_start_date ON cycles (start_date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. Flock
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS flock (
|
||||
flock_id SERIAL PRIMARY KEY,
|
||||
flock_name VARCHAR(30) NOT NULL,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_flock_cycle_id ON flock (cycle_id);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 6. IoT Panel
|
||||
-- One row per sensor reading; the panel polls every 10 minutes, so a cycle
|
||||
-- day holds up to 144 rows. `timestamp` carries the reading time; `date` is
|
||||
-- kept denormalized for fast daily grouping.
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS iot_panel (
|
||||
panel_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
timestamp TIMESTAMP WITH TIME ZONE,
|
||||
wind_speed FLOAT NOT NULL,
|
||||
humidity FLOAT NOT NULL,
|
||||
water_total FLOAT NOT NULL,
|
||||
average_temperature FLOAT NOT NULL,
|
||||
experience_temperature FLOAT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
flock_id INTEGER NOT NULL REFERENCES flock (flock_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_iot_panel_flock_id ON iot_panel (flock_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_iot_panel_date ON iot_panel (date);
|
||||
CREATE INDEX IF NOT EXISTS idx_iot_panel_timestamp ON iot_panel (timestamp);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_iot_panel_flock_timestamp ON iot_panel (flock_id, timestamp);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 7. AI Insight
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS ai_insight (
|
||||
id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
insight_text TEXT NOT NULL,
|
||||
alert VARCHAR(100) NOT NULL,
|
||||
section VARCHAR(100) NOT NULL,
|
||||
session VARCHAR(100) NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_insight_cycle_id ON ai_insight (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_ai_insight_date ON ai_insight (date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 8. Feed Sacks
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS feed_sacks (
|
||||
fs_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
in_today INTEGER NOT NULL DEFAULT 0,
|
||||
out_today INTEGER NOT NULL DEFAULT 0,
|
||||
in_total INTEGER NOT NULL DEFAULT 0,
|
||||
out_total INTEGER NOT NULL DEFAULT 0,
|
||||
feed_use_today INTEGER NOT NULL DEFAULT 0,
|
||||
feed_use_total INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_feed_sacks_cycle_id ON feed_sacks (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_feed_sacks_date ON feed_sacks (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_feed_sacks_cycle_date ON feed_sacks (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 9. Chicken Counting
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS chicken_counting (
|
||||
cc_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
total_count INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_counting_cycle_id ON chicken_counting (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_counting_date ON chicken_counting (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_chicken_counting_cycle_date ON chicken_counting (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 10. Chicken Weight
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS chicken_weight (
|
||||
cw_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age INTEGER NOT NULL,
|
||||
doc_weight INTEGER NOT NULL,
|
||||
average_weight FLOAT NOT NULL,
|
||||
chicken_count INTEGER NOT NULL,
|
||||
uniformity FLOAT NOT NULL,
|
||||
average_daily_gain FLOAT NOT NULL,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_weight_cycle_id ON chicken_weight (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chicken_weight_date ON chicken_weight (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_chicken_weight_cycle_date ON chicken_weight (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 11. Manual Input
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS manual_input (
|
||||
manual_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age_manual INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_manual INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
feed_in_manual INTEGER NOT NULL DEFAULT 0,
|
||||
feed_use_manual INTEGER NOT NULL DEFAULT 0,
|
||||
feed_in_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
feed_use_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
feed_out_manual INTEGER NOT NULL DEFAULT 0,
|
||||
feed_out_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_manual INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_manual_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight_manual_total FLOAT NOT NULL DEFAULT 0,
|
||||
manual_weight FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_day_manual FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_weight_manual FLOAT NOT NULL DEFAULT 0,
|
||||
fcr_manual FLOAT NOT NULL DEFAULT 0,
|
||||
eef_manual FLOAT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_manual_input_cycle_id ON manual_input (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_manual_input_date ON manual_input (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_manual_input_cycle_date ON manual_input (cycle_id, date);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 12. KPI (aggregates data from cycle + source records)
|
||||
-- -----------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS kpi (
|
||||
kpi_id SERIAL PRIMARY KEY,
|
||||
date DATE NOT NULL,
|
||||
age INTEGER NOT NULL DEFAULT 0,
|
||||
mortality INTEGER NOT NULL DEFAULT 0,
|
||||
mortality_total INTEGER NOT NULL DEFAULT 0,
|
||||
feed INTEGER NOT NULL DEFAULT 0,
|
||||
feed_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_total INTEGER NOT NULL DEFAULT 0,
|
||||
harvest_weight FLOAT NOT NULL DEFAULT 0,
|
||||
harvest_weight_total FLOAT NOT NULL DEFAULT 0,
|
||||
chicken_life INTEGER NOT NULL DEFAULT 0,
|
||||
chicken_life_percentage FLOAT NOT NULL DEFAULT 0,
|
||||
iot_weight FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_day FLOAT NOT NULL DEFAULT 0,
|
||||
average_harvest_weight FLOAT NOT NULL DEFAULT 0,
|
||||
fcr FLOAT NOT NULL DEFAULT 0,
|
||||
eef FLOAT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
cycle_id INTEGER NOT NULL REFERENCES cycles (cycle_id) ON DELETE CASCADE,
|
||||
cc_id INTEGER NOT NULL REFERENCES chicken_counting (cc_id) ON DELETE RESTRICT,
|
||||
cw_id INTEGER NOT NULL REFERENCES chicken_weight (cw_id) ON DELETE RESTRICT,
|
||||
fs_id INTEGER NOT NULL REFERENCES feed_sacks (fs_id) ON DELETE RESTRICT,
|
||||
manual_id INTEGER NOT NULL REFERENCES manual_input (manual_id) ON DELETE RESTRICT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_kpi_cycle_id ON kpi (cycle_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_kpi_date ON kpi (date);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_kpi_cycle_date ON kpi (cycle_id, date);
|
||||
|
||||
-- =============================================================================
|
||||
-- Auto-update updated_at on row changes
|
||||
-- =============================================================================
|
||||
CREATE OR REPLACE FUNCTION erd_set_updated_at()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = CURRENT_TIMESTAMP;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
tbl TEXT;
|
||||
BEGIN
|
||||
FOREACH tbl IN ARRAY ARRAY[
|
||||
'user_access', 'sites', 'kandang', 'cycles', 'flock',
|
||||
'iot_panel', 'ai_insight', 'feed_sacks', 'chicken_counting',
|
||||
'chicken_weight', 'manual_input', 'kpi'
|
||||
]
|
||||
LOOP
|
||||
EXECUTE format('DROP TRIGGER IF EXISTS trg_%I_updated_at ON %I', tbl, tbl);
|
||||
EXECUTE format(
|
||||
'CREATE TRIGGER trg_%I_updated_at BEFORE UPDATE ON %I
|
||||
FOR EACH ROW EXECUTE FUNCTION erd_set_updated_at()',
|
||||
tbl, tbl
|
||||
);
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
Reference in new issue
Block a user