+FROM nodenetworks_ordered
+GROUP BY node_id;
+
+--------------------------------------------------------------------------------
+-- Power control units (PCUs)
+--------------------------------------------------------------------------------
+
+CREATE TABLE pcus (
+ -- Mandatory
+ pcu_id serial PRIMARY KEY, -- PCU identifier
+ site_id integer REFERENCES sites NOT NULL, -- Site identifier
+ hostname text NOT NULL, -- Hostname, not necessarily unique (multiple logical sites could use the same PCU)
+ ip text NOT NULL, -- IP, not necessarily unique
+
+ -- Optional
+ protocol text, -- Protocol, e.g. ssh or https or telnet
+ username text, -- Username, if applicable
+ "password" text, -- Password, if applicable
+ model text, -- Model, e.g. BayTech or iPal
+ notes text -- Random notes
+) WITH OIDS;
+
+CREATE TABLE pcu_node (
+ pcu_id integer REFERENCES pcus NOT NULL, -- PCU identifier
+ node_id integer REFERENCES nodes NOT NULL, -- Node identifier
+ port integer NOT NULL, -- Port number
+ PRIMARY KEY (pcu_id, node_id)
+);
+CREATE INDEX pcu_node_pcu_id_key ON pcu_node (pcu_id);
+CREATE INDEX pcu_node_node_id_key ON pcu_node (node_id);
+
+CREATE VIEW pcu_nodes AS
+SELECT pcu_id,
+array_to_string(array_accum(node_id), ',') AS node_ids,
+array_to_string(array_accum(port), ',') AS ports
+FROM pcu_node
+GROUP BY pcu_id;
+
+--------------------------------------------------------------------------------
+-- Slices
+--------------------------------------------------------------------------------
+
+CREATE TABLE slice_instantiations (
+ instantiation text PRIMARY KEY
+) WITH OIDS;
+INSERT INTO slice_instantiations (instantiation) VALUES ('not-instantiated'); -- Placeholder slice
+INSERT INTO slice_instantiations (instantiation) VALUES ('plc-instantiated'); -- Instantiated by Node Manager
+INSERT INTO slice_instantiations (instantiation) VALUES ('delegated'); -- Manually instantiated
+
+-- Slices
+CREATE TABLE slices (
+ slice_id serial PRIMARY KEY, -- Slice identifier
+ site_id integer REFERENCES sites NOT NULL, -- Site identifier
+ name text NOT NULL, -- Slice name
+ instantiation text REFERENCES slice_instantiations NOT NULL DEFAULT 'plc-instantiated', -- Slice state, e.g. plc-instantiated
+ url text, -- Project URL
+ description text, -- Project description
+
+ max_nodes integer NOT NULL DEFAULT 100, -- Maximum number of nodes that can be assigned to this slice
+
+ creator_person_id integer REFERENCES persons NOT NULL, -- Creator
+ created timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP, -- Creation date
+ expires timestamp without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP + '2 weeks', -- Expiration date
+
+ is_deleted boolean NOT NULL DEFAULT false
+) WITH OIDS;
+CREATE INDEX slices_site_id_key ON slices (site_id) WHERE is_deleted IS false;
+CREATE INDEX slices_name_key ON slices (name) WHERE is_deleted IS false;
+
+-- Slivers
+CREATE TABLE slice_node (
+ slice_id integer REFERENCES slices NOT NULL, -- Slice identifier
+ node_id integer REFERENCES nodes NOT NULL -- Node identifier
+) WITH OIDS;
+CREATE INDEX slice_node_slice_id_key ON slice_node (slice_id);
+CREATE INDEX slice_node_node_id_key ON slice_node (node_id);
+
+-- Synonym for slice_node
+CREATE VIEW slivers AS
+SELECT * FROM slice_node;
+
+-- Nodes in each slice
+CREATE VIEW slice_nodes AS
+SELECT slice_id,
+array_to_string(array_accum(node_id), ',') AS node_ids
+FROM slice_node
+GROUP BY slice_id;
+
+-- Slices on each node
+CREATE VIEW node_slices AS
+SELECT node_id,
+array_to_string(array_accum(slice_id), ',') AS slice_ids
+FROM slice_node