Chapter 29 · Production Capstone: Architect, Secure, Tune, Protect, and Operate Oracle

Implement Schema, PL/SQL APIs, Partitioning/Indexes, Security, Services, and Change Automation

Build the capstone relational/partitioned schema and PL/SQL API with least privilege, auditability, encryption/service boundaries and repeatable deployment gates, while keeping licensed or topology-heavy features explicitly optional.

Expert145–170 minutesCapstone schema/API/security deployment labPartitioning + TDE available in FreeNo paid feature required by mandatory pathLast reviewed: August 2026

Learning outcomes

The architecture record is useless if deployment scripts create unconstrained tables, grant the runtime user direct DML, and let every application connect to the owner schema. The capstone now turns the design into a repeatable database contract: constraints enforce invariants, partitioning/indexes follow workload evidence, PL/SQL packages expose approved transactions, and auditing/encryption/service controls protect the operational boundary.

01

Create a ServiceHub capstone schema with relational constraints, partitioned history and workload-aligned indexes.

02

Expose writes through an invoker-facing PL/SQL package while denying the runtime identity direct table DML.

03

Create a focused Unified Audit policy and verify records instead of enabling indiscriminate high-volume auditing.

04

Document TDE/TCPS service security as explicit deployment toggles and current license/keystore requirements.

05

Make the deployment idempotent/checkable with version and post-deploy acceptance tables rather than ad-hoc console history.

Generation-time baseline, licensing, tools, topology, and capstone scope

Mandatory examples target Oracle AI Database Free 26ai and were reviewed against RU 23.26.3 (July 2026), SQL Developer 26.2 build 26.2.0.186.2220, and SQLcl 26.2.1.222.1617. Free is limited to 2 CPU cores for processing, 2 GB RAM, 12 GB user data, and one installation per logical environment. The course environment remains CDB/instance FREE, application PDB/service FREEPDB1, owner SERVICEHUB_OWNER, and a local persistent /opt/oracle/oradata learning path. Current 26ai licensing lists Oracle Partitioning, Advanced Security/TDE, Online Table Redefinition, Diagnostics Pack, and Tuning Pack as available in Free; on EE/EE-ES several of these are separately licensed options/packs. Data Guard Redo Apply, RAC, Transaction Guard, and Application Continuity are not available in Free. Mandatory tuning therefore uses core dynamic-performance and cursor-plan evidence so the method remains portable; AWR/ASH/ADDM/Tuning Pack extensions are labeled by offering. Mandatory resilience work uses RMAN validation/backups where safe and rigorous Data Guard/drill simulations where multi-host licensed infrastructure is unavailable. No lab raises COMPATIBLE, changes hidden parameters, applies an RU to Free, or modifies GitHub.

1. Schema is the first line of correctness

sql · drop prior disposable capstone objects
BEGIN EXECUTE IMMEDIATE 'DROP USER sh29_app CASCADE';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -1918 THEN RAISE; END IF; END;/BEGIN EXECUTE IMMEDIATE 'DROP PACKAGE servicehub_owner.sh29_work_order_api';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END;/BEGIN EXECUTE IMMEDIATE 'DROP TABLE servicehub_owner.sh29_work_order_events PURGE';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;/BEGIN EXECUTE IMMEDIATE 'DROP TABLE servicehub_owner.sh29_work_orders PURGE';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;/BEGIN EXECUTE IMMEDIATE 'DROP TABLE servicehub_owner.sh29_customers PURGE';EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;/
sql · capstone tables
CREATE TABLE servicehub_owner.sh29_customers (  customer_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  tenant_code VARCHAR2(30) NOT NULL,  customer_name VARCHAR2(120) NOT NULL,  status_code VARCHAR2(12) DEFAULT 'ACTIVE' NOT NULL,  created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,  CONSTRAINT sh29_customer_tenant_uq UNIQUE(tenant_code,customer_id),  CONSTRAINT sh29_customer_status_ck    CHECK (status_code IN ('ACTIVE','SUSPENDED')));CREATE TABLE servicehub_owner.sh29_work_orders (  work_order_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  customer_id NUMBER NOT NULL,  tenant_code VARCHAR2(30) NOT NULL,  status_code VARCHAR2(12) DEFAULT 'OPEN' NOT NULL,  priority_code VARCHAR2(10) DEFAULT 'NORMAL' NOT NULL,  description VARCHAR2(1000) NOT NULL,  amount NUMBER(12,2) DEFAULT 0 NOT NULL,  created_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,  updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,  CONSTRAINT sh29_wo_customer_fk    FOREIGN KEY(tenant_code,customer_id)    REFERENCES servicehub_owner.sh29_customers(tenant_code,customer_id),  CONSTRAINT sh29_wo_status_ck    CHECK (status_code IN ('OPEN','HOLD','CLOSED')),  CONSTRAINT sh29_wo_priority_ck    CHECK (priority_code IN ('LOW','NORMAL','HIGH')),  CONSTRAINT sh29_wo_amount_ck CHECK (amount >= 0));CREATE TABLE servicehub_owner.sh29_work_order_events (  event_id NUMBER GENERATED ALWAYS AS IDENTITY,  work_order_id NUMBER NOT NULL,  tenant_code VARCHAR2(30) NOT NULL,  event_type VARCHAR2(30) NOT NULL,  event_ts TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,  payload_json JSON,  CONSTRAINT sh29_woe_pk PRIMARY KEY(event_id,event_ts))PARTITION BY RANGE (event_ts)INTERVAL (NUMTOYMINTERVAL(1,'MONTH'))(  PARTITION p_before_2026  VALUES LESS THAN (TIMESTAMP '2026-01-01 00:00:00'));

The child foreign key includes tenant_code so a work order cannot silently reference a customer through the wrong tenant identifier. The event history is partitioned by time because retention/purge and time-range reporting are the evidence-backed use cases; partitioning is not added merely because it exists.

2. Index for the OLTP access path you intend to protect

sql · selective tenant/recent-order indexes
CREATE INDEX servicehub_owner.sh29_wo_tenant_created_ixON servicehub_owner.sh29_work_orders(  tenant_code,created_at,work_order_id);CREATE INDEX servicehub_owner.sh29_wo_customer_ixON servicehub_owner.sh29_work_orders(  tenant_code,customer_id);CREATE INDEX servicehub_owner.sh29_woe_work_ts_ixON servicehub_owner.sh29_work_order_events(  work_order_id,event_ts)LOCAL;

The history index is LOCAL because each index partition aligns with a table partition. The work-order indexes match key access paths from the architecture record. Lesson 3 will verify whether the selective index actually reduces work.

3. Seed a small controlled domain

sql · seed
INSERT INTO servicehub_owner.sh29_customers(  tenant_code,customer_name) VALUES('TENANT_A','North Service Group');INSERT INTO servicehub_owner.sh29_customers(  tenant_code,customer_name) VALUES('TENANT_B','South Service Group');COMMIT;SELECT customer_id,tenant_code,customer_nameFROM servicehub_owner.sh29_customersORDER BY customer_id;

4. Package the write transaction

sql · server-side API specification
CREATE OR REPLACE PACKAGE servicehub_owner.sh29_work_order_apiAUTHID DEFINERAS  PROCEDURE create_work_order(    p_tenant_code   IN VARCHAR2,    p_customer_id   IN NUMBER,    p_description   IN VARCHAR2,    p_priority_code IN VARCHAR2 DEFAULT 'NORMAL',    p_amount        IN NUMBER DEFAULT 0,    p_work_order_id OUT NUMBER  );  PROCEDURE close_work_order(    p_tenant_code  IN VARCHAR2,    p_work_order_id IN NUMBER  );END sh29_work_order_api;/
sql · server-side API body
CREATE OR REPLACE PACKAGE BODY servicehub_owner.sh29_work_order_apiAS  PROCEDURE create_work_order(    p_tenant_code   IN VARCHAR2,    p_customer_id   IN NUMBER,    p_description   IN VARCHAR2,    p_priority_code IN VARCHAR2 DEFAULT 'NORMAL',    p_amount        IN NUMBER DEFAULT 0,    p_work_order_id OUT NUMBER  )  AS  BEGIN    INSERT INTO sh29_work_orders(      customer_id,tenant_code,description,      priority_code,amount    ) VALUES(      p_customer_id,p_tenant_code,p_description,      p_priority_code,p_amount    )    RETURNING work_order_id INTO p_work_order_id;    INSERT INTO sh29_work_order_events(      work_order_id,tenant_code,event_type,payload_json    ) VALUES(      p_work_order_id,p_tenant_code,'CREATED',      JSON_OBJECT(        'priority' VALUE p_priority_code,        'amount' VALUE p_amount        RETURNING JSON      )    );  END;  PROCEDURE close_work_order(    p_tenant_code   IN VARCHAR2,    p_work_order_id IN NUMBER  )  AS  BEGIN    UPDATE sh29_work_orders    SET status_code='CLOSED',        updated_at=SYSTIMESTAMP    WHERE tenant_code=p_tenant_code      AND work_order_id=p_work_order_id      AND status_code <> 'CLOSED';    IF SQL%ROWCOUNT = 0 THEN      RAISE_APPLICATION_ERROR(        -20029,'work order not found or already closed'      );    END IF;    INSERT INTO sh29_work_order_events(      work_order_id,tenant_code,event_type,payload_json    ) VALUES(      p_work_order_id,p_tenant_code,'CLOSED',      JSON_OBJECT('source' VALUE 'SH29_API' RETURNING JSON)    );  END;END sh29_work_order_api;/

The package deliberately does not COMMIT. The application owns the transaction boundary from Chapter 27, allowing a larger business transaction to commit/rollback atomically.

5. Least privilege: runtime user executes API, not owner DML

text · runtime principal
CREATE USER sh29_app NO AUTHENTICATION;GRANT CREATE SESSION TO sh29_app;GRANT EXECUTEON servicehub_owner.sh29_work_order_apiTO sh29_app;GRANT SELECTON servicehub_owner.sh29_customersTO sh29_app;-- For an interactive lab login only:PASSWORD sh29_app-- Set a disposable password interactively; never store it here.

There is no INSERT/UPDATE/DELETE grant on SH29_WORK_ORDERS or SH29_WORK_ORDER_EVENTS. The definer-rights package performs approved owner operations while the caller has only EXECUTE.

6. Deliberate security failure: direct DML should fail

sql · as SH29_APP
INSERT INTO servicehub_owner.sh29_work_orders(  customer_id,tenant_code,description,amount) VALUES(  1,'TENANT_A','Bypass API',10);-- Expected:-- ORA-01031: insufficient privileges-- (or object-not-visible behavior depending on privilege resolution)

If this INSERT succeeds, the least-privilege invariant failed. Repair by revoking direct DML and verify with DBA_TAB_PRIVS.

sql · privilege proof as administrator
SELECT  grantee,owner,table_name,privilegeFROM dba_tab_privsWHERE grantee='SH29_APP'ORDER BY owner,table_name,privilege;

7. Execute the approved transaction through the package

sql · as SH29_APP
VARIABLE new_id NUMBERBEGIN  servicehub_owner.sh29_work_order_api.create_work_order(    p_tenant_code   => 'TENANT_A',    p_customer_id   => 1,    p_description   => 'Compressor restart inspection',    p_priority_code => 'HIGH',    p_amount        => 125.50,    p_work_order_id => :new_id  );  COMMIT;END;/PRINT new_id

The foreign key/check constraints still protect the package. A PL/SQL API is not a bypass around relational integrity.

8. Unified audit: audit the high-value API action

sql · administrator — focused custom policy
BEGIN  EXECUTE IMMEDIATE 'NOAUDIT POLICY sh29_api_audit';EXCEPTION WHEN OTHERS THEN NULL;END;/BEGIN  EXECUTE IMMEDIATE 'DROP AUDIT POLICY sh29_api_audit';EXCEPTION WHEN OTHERS THEN NULL;END;/CREATE AUDIT POLICY sh29_api_audit  ACTIONS EXECUTE ON servicehub_owner.sh29_work_order_api;AUDIT POLICY sh29_api_audit BY sh29_app;
sql · review audit evidence
SELECT  event_timestamp,  dbusername,  action_name,  object_schema,  object_name,  return_code,  client_program_nameFROM unified_audit_trailWHERE audit_type='Unified Audit'  AND dbusername='SH29_APP'  AND object_name='SH29_WORK_ORDER_API'ORDER BY event_timestamp DESCFETCH FIRST 20 ROWS ONLY;

Audit records show the database action/identity/result; they do not automatically capture full business intent. Audit only what you can retain/review, archive according to policy, and protect audit access.

9. Encryption and transport are explicit deployment toggles

Current 26ai Free includes Oracle Advanced Security features such as Transparent Data Encryption (TDE). TDE protects database files/backups according to keystore configuration; it does not replace TLS for network transport or application authorization. A production deployment should configure a keystore, key ownership/rotation/recovery and encrypted tablespaces according to policy before moving sensitive data.

sql · read-only TDE evidence
SELECT  wallet_type,  status,  wrl_parameter,  con_idFROM v$encryption_walletORDER BY con_id;SELECT  tablespace_name,  encryptedFROM dba_tablespacesORDER BY tablespace_name;

The mandatory lab does not create/rotate a TDE master key because keystore path/backup policy is environment-specific. Chapter 27's TCPS/TLS rules remain the transport requirement.

10. Service naming is a deployable application boundary

Production should expose an application service such as servicehub_oltp with planned pool/reset/HA attributes. Standalone PDB service creation uses DBMS_SERVICE; Clusterware-managed RAC/Data Guard environments use the supported SRVCTL/broker/service workflow. The mandatory Free lab keeps using FREEPDB1 and records service identity rather than mutating a shared built-in service.

sql · verify current service
SELECT  SYS_CONTEXT('USERENV','SERVICE_NAME') AS service_name,  SYS_CONTEXT('USERENV','CON_NAME') AS con_nameFROM dual;

11. Repeatable change automation has a schema version and acceptance gates

sql · deployment record
CREATE TABLE servicehub_owner.sh29_schema_release (  release_id VARCHAR2(30) PRIMARY KEY,  applied_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL,  applied_by VARCHAR2(128) NOT NULL,  artifact_hash VARCHAR2(64) NOT NULL,  acceptance_status VARCHAR2(12) NOT NULL    CHECK (acceptance_status IN ('PENDING','PASSED','FAILED')));INSERT INTO servicehub_owner.sh29_schema_release(  release_id,applied_by,artifact_hash,acceptance_status) VALUES(  'SH29-001',  SYS_CONTEXT('USERENV','SESSION_USER'),  '6a2f9a7c74db6d88472f615b31b2070f3b630d93d9f1bb5651248713506c47c3',  'PENDING');COMMIT;

The sample SHA-256 value is a deterministic lab identifier; production CI/CD must record the hash of the actual deployment artifact. Production scripts should be version controlled, idempotent where practical, stop on SQL errors, and run post-deploy checks before changing acceptance to PASSED.

12. Post-deploy acceptance

sql · structure and privilege checks
SELECT table_name,partitionedFROM user_tablesWHERE table_name LIKE 'SH29_%'ORDER BY table_name;SELECT index_name,table_name,uniqueness,statusFROM user_indexesWHERE table_name LIKE 'SH29_%'ORDER BY table_name,index_name;SELECT object_name,object_type,statusFROM user_objectsWHERE object_name LIKE 'SH29_%'  AND status <> 'VALID';SELECT grantee,table_name,privilegeFROM dba_tab_privsWHERE grantee='SH29_APP'ORDER BY table_name,privilege;

Only after structural, package, privilege and smoke-test checks pass should deployment automation mark the release PASSED.

13. Production judgment

Enforce invariants in schema constraints, expose only the transactions the application needs, and treat partitioning/indexes as workload/retention tools rather than decorations. Use Unified Audit selectively and keep TDE/TLS/secrets as separate controls. The capstone mandatory path needs no paid option in Free, but commercial production must map Partitioning/Advanced Security/audit/management features to the exact offering.

No hidden parameters or restart are required. The table/index/API objects remain for Lessons 3–5. Lesson 3 now measures whether the implemented access paths and transaction behavior actually meet the architecture intent.

Check your understanding

  1. Why does the package omit COMMIT?
  2. What should happen when SH29_APP attempts direct table INSERT?
  3. Why was the event table partitioned by time?
  4. Does TDE replace TLS?
  5. What proves a deployment artifact was accepted rather than merely executed?
Review the answers

The caller/application owns the business transaction boundary and can commit/rollback multiple API calls atomically.

It should fail because the runtime user has EXECUTE on the package, not direct DML privileges.

Retention and time-range history access justify a time-based lifecycle boundary.

No. TDE protects data at rest; TLS protects transport.

Post-deploy structural/privilege/application checks recorded against a versioned release artifact.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.