Changes between Initial Version and Version 1 of Security&Optimization


Ignore:
Timestamp:
09/04/25 23:23:38 (4 days ago)
Author:
221128
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Security&Optimization

    v1 v1  
     1
     2= Security and Optimization =
     3
     4
     5== Assertions (CHECK Constraints) ==
     6To guarantee fundamental data validity at the lowest level, we utilize '''CHECK constraints'''. These declarative rules prevent invalid data from ever being written to the database, ensuring a baseline of data quality across the system.
     7
     8||= Table =||= Constraint Name =||= Rule =||= Purpose =||
     9|| employees || employees_net_salary_nonneg || net_salary >= 0 (or NULL) || Prevents negative payroll values while allowing them to be unset. ||
     10|| employees || employees_gross_salary_nonneg || gross_salary >= 0 (or NULL) || Prevents negative payroll values while allowing them to be unset. ||
     11|| inventories || inventories_qty_nonneg || quantity >= 0 || Ensures that product stock levels cannot be negative. ||
     12|| inventories || inventories_restock_nonneg || restock_level >= 0 (or NULL) || Ensures that restock thresholds cannot be negative. ||
     13|| products || products_price_nonneg || price >= 0 || Disallows products from having negative prices. ||
     14|| order_items || order_items_qty_pos || quantity > 0 || Requires that every item added to an order has a positive quantity. ||
     15|| order_items || order_items_price_nonneg || price >= 0 || Disallows negative unit prices on ordered items. ||
     16|| payments || payments_amount_nonneg || amount >= 0 || Ensures all payment and tip amounts are non-negative. ||
     17|| payments || payments_tip_nonneg || tip_amount >= 0 || Ensures all payment and tip amounts are non-negative. ||
     18|| tables || tables_capacity_pos || seat_capacity > 0 || Requires that every restaurant table has a positive seating capacity. ||
     19|| reservations || reservations_people_pos || number_of_people > 0 || Ensures that a reservation is made for at least one person. ||
     20|| front_staff || front_staff_tip_pct || tip_percent BETWEEN 0 AND 100 (or NULL) || Confines the tip percentage to a valid range if specified. ||
     21
     22== Triggered Business Rules ==
     23For more complex, state-dependent business logic that cannot be handled by simple CHECK constraints, we leverage '''triggers'''. These automatically execute procedural functions in response to specific data modification events (e.g., INSERT, UPDATE), thereby enforcing sophisticated application rules directly within the database.
     24
     25=== TRIGGER: Prevent Overlapping Table Bookings ===
     26
     27'''Objective''': To guarantee that a single restaurant table cannot be assigned to two different reservations that overlap in time.
     28
     29'''Associated Function''': enforce_no_double_booking()
     30
     31'''Events''': AFTER INSERT, AFTER UPDATE on the frontstaff_managed_reservations table. This is implemented as a CONSTRAINT trigger, which is DEFERRABLE INITIALLY DEFERRED.
     32
     33'''Implementation Details''':
     34The trigger calculates the time interval of the incoming reservation using PostgreSQL's tsrange type, with a default stay length of 2 hours if not specified. The range is defined with inclusive start and exclusive end bounds ([)) to allow for back-to-back bookings. It then queries existing reservations for the same table to check for any temporal overlap using the && operator. If a conflict is detected, the transaction is rolled back with an exception.
     35
     36Critically, the use of DEFERRABLE INITIALLY DEFERRED means the constraint is checked at the end of the transaction, not after each row modification. This is essential for correctly handling multi-row inserts or updates that might otherwise fail prematurely.
     37
     38{{{
     39CREATE OR REPLACE FUNCTION enforce_no_double_booking()
     40RETURNS trigger AS $$
     41DECLARE
     42new_span tsrange;
     43conflict_exists boolean;
     44BEGIN
     45SELECT tsrange(
     46r.datetime,
     47r.datetime + (COALESCE(r.stay_length, 2) * INTERVAL '1 hour'),
     48'[)'
     49)
     50INTO new_span
     51FROM reservations r
     52WHERE r.id = NEW.reservation_id;
     53
     54IF new_span IS NULL THEN
     55RAISE EXCEPTION 'Reservation % not found or invalid', NEW.reservation_id;
     56END IF;
     57
     58SELECT EXISTS (
     59SELECT 1
     60FROM frontstaff_managed_reservations fmr
     61JOIN reservations r2 ON r2.id = fmr.reservation_id
     62WHERE fmr.table_number = NEW.table_number
     63AND (NEW.id IS NULL OR fmr.id <> NEW.id) -- Exclude self in UPDATE
     64AND tsrange(
     65r2.datetime,
     66r2.datetime + (COALESCE(r2.stay_length, 2) * INTERVAL '1 hour'),
     67'[)'
     68) && new_span
     69)
     70INTO conflict_exists;
     71
     72IF conflict_exists THEN
     73RAISE EXCEPTION 'Double booking prevented: table % has overlapping reservations', NEW.table_number;
     74END IF;
     75
     76RETURN NEW;
     77END;
     78$$ LANGUAGE plpgsql;
     79}}}
     80
     81'''Supporting Indexes for Performance''':
     82
     83An index on frontstaff_managed_reservations(table_number) to rapidly locate all reservations for the target table.
     84
     85A functional GiST index on the tsrange expression (reservations_span_expr_gist) to allow for highly efficient range overlap (&&) searches.
     86
     87=== TRIGGER: Enforce Seating Capacity ===
     88
     89'''Objective''': To prevent a reservation from being assigned to a table that has insufficient seating capacity for the party size.
     90
     91'''Associated Function''': fmr_capacity_guard()
     92
     93'''Events''': BEFORE INSERT, BEFORE UPDATE on frontstaff_managed_reservations.
     94
     95'''Implementation Details''':
     96Before a row is written, this trigger fetches the seat_capacity of the target table and the number_of_people from the associated reservation. It verifies that the party size does not exceed the table's capacity. If it does, an exception is raised, preventing the invalid assignment.
     97
     98{{{
     99CREATE OR REPLACE FUNCTION fmr_capacity_guard() RETURNS trigger AS $$
     100DECLARE
     101cap   int;
     102party bigint;
     103BEGIN
     104SELECT seat_capacity INTO cap FROM tables WHERE table_number = NEW.table_number;
     105SELECT number_of_people INTO party FROM reservations WHERE id = NEW.reservation_id;
     106
     107IF cap IS NULL OR party IS NULL THEN
     108RAISE EXCEPTION 'Invalid reservation % or table %', NEW.reservation_id, NEW.table_number;
     109END IF;
     110
     111IF party > cap THEN
     112RAISE EXCEPTION 'Party size % exceeds capacity % for table %', party, cap, NEW.table_number;
     113END IF;
     114
     115RETURN NEW;
     116END;
     117$$ LANGUAGE plpgsql;
     118}}}
     119
     120'''Supporting Indexes for Performance''':
     121
     122No special indexes are needed. The trigger's lookups are highly efficient as they operate on the primary keys of the tables and reservations tables.
     123
     124=== TRIGGER: Update Order Status Upon Payment ===
     125
     126'''Objective''': To automate the business process of marking an order as 'PAID' as soon as a payment is recorded for it.
     127
     128'''Associated Function''': payments_mark_order_paid()
     129
     130'''Events''': AFTER INSERT on the payments table.
     131
     132'''Implementation Details''':
     133Immediately after a new record is successfully inserted into the payments table, this trigger fires an UPDATE statement on the orders table. It sets the status of the corresponding order (identified by NEW.order_id) to 'PAID', ensuring the system state remains consistent.
     134
     135{{{
     136CREATE OR REPLACE FUNCTION payments_mark_order_paid() RETURNS trigger AS $$
     137BEGIN
     138UPDATE orders
     139SET status = 'PAID'
     140WHERE id = NEW.order_id;
     141RETURN NEW;
     142END;
     143$$ LANGUAGE plpgsql;
     144}}}
     145
     146'''Supporting Indexes for Performance''':
     147
     148The UPDATE operation is optimized by the primary key index on orders(id).
     149
     150'''Future Considerations''':
     151
     152This implementation assumes that any single payment settles the full order amount. For a system supporting partial payments, this logic would need to be enhanced to check if the sum of payments for an order meets or exceeds the order's total before changing the status.
     153
     154== MATERIALIZED VIEW: Pre-Aggregated Daily Sales Analytics ==
     155To support high-frequency analytical queries without imposing a heavy real-time aggregation load on the core transactional tables, we employ a '''materialized view'''. This view, mv_payments_daily_channel, pre-computes daily revenue, tips, and order counts, segmented by the sales channel (TAB or ONLINE).
     156
     157{{{
     158CREATE MATERIALIZED VIEW IF NOT EXISTS mv_payments_daily_channel AS
     159WITH orders_channel AS (
     160SELECT
     161o.id AS order_id,
     162CASE
     163WHEN EXISTS (SELECT 1 FROM tab_orders t WHERE t.order_id = o.id) THEN 'TAB'
     164WHEN EXISTS (SELECT 1 FROM online_orders oo WHERE oo.order_id = o.id) THEN 'ONLINE'
     165ELSE 'UNKNOWN'
     166END AS channel
     167FROM orders o
     168)
     169SELECT
     170(date_trunc('day', p.created_at))::date AS day,
     171oc.channel,
     172COUNT(DISTINCT p.order_id)            AS paid_orders_cnt,
     173SUM(p.amount)::numeric(14,2)          AS revenue,
     174SUM(p.tip_amount)::numeric(14,2)      AS tip_total
     175FROM payments p
     176JOIN orders_channel oc ON oc.order_id = p.order_id
     177GROUP BY (date_trunc('day', p.created_at))::date, oc.channel;
     178}}}
     179
     180'''Indexing Strategy''':
     181
     182A UNIQUE index on (day, channel) (ux_mv_payments_daily_channel) ensures data integrity within the view and is a prerequisite for enabling concurrent refreshes (REFRESH MATERIALIZED VIEW CONCURRENTLY).
     183
     184Indexes on payments(order_id) and payments(created_at) are crucial for efficiently building and refreshing the materialized view's data from the underlying base tables.