diff --git a/sift/workspace/metadatabase.py b/sift/workspace/metadatabase.py
index 4ec7147e8dd6b947a5e0c12098012a2b064b2fe3..5755b6935d77319ff8efa89fa63c028f2c462aef 100644
--- a/sift/workspace/metadatabase.py
+++ b/sift/workspace/metadatabase.py
@@ -206,7 +206,12 @@ class Product(Base):
     A StoredProduct's kind determines how its cached data is transformed to different representations for display
     additional information is stored in a key-value table addressable as product[key:str]
     """
-    __tablename__ = 'products_v0'
+    __tablename__ = 'products_v1'
+
+    # FAMILY_COLUMNS are used to group products together when assigning color maps
+    FAMILY_COLUMNS = ('platform', 'instrument', 'name', 'standard_name')
+    # TRACK_COLUMNS are used to group products together when placing them into a timeline track
+    TRACK_COLUMNS = FAMILY_COLUMNS + ('scene',)
 
     # identity information
     id = Column(Integer, primary_key=True)
@@ -226,14 +231,15 @@ class Product(Base):
     # kind = Column(PickleType)  # class or callable which can perform transformations on this data in workspace
     atime = Column(DateTime, nullable=False)  # last time this file was accessed by application
 
-    # cached metadata provided by the file format handler
+    # cached identifying metadata provided by the file format handler
     name = Column(String, nullable=False)  # product identifier eg "B01", "B02"  # resource + shortname should be sufficient to identify the data
+    standard_name = Column(String, nullable=True)  # CF metadata standard_name, or an underscore-prefixed consistent assigned name
+    instrument = Column(String, nullable=True)  # "ABI", "AHI" - physical or virtual instrument
+    platform = Column(String, nullable=True)  # platform or satellite name e.g. "GOES-16", "Himawari-8"; should match PLATFORM enum
+    scene = Column(String, nullable=True)  # "HFD", "EM1", "ECONUS"
 
-    # platform = Column(String)  # platform or satellite name e.g. "GOES-16", "Himawari-8"; should match PLATFORM enum
-    # standard_name = Column(String, nullable=True)
-    #
-    # times
     # display_time = Column(DateTime)  # normalized instantaneous scheduled observation time e.g. 20170122T2310
+    # When placing products into timeline view, TRACK_COLUMNS determine which track to place them in, and obs_time and obs_duration determine breadth/placement
     obs_time = Column(DateTime, nullable=False)  # actual observation time start
     obs_duration = Column(Interval, nullable=False)  # duration of the observation
 
@@ -401,6 +407,10 @@ class Product(Base):
         INFO.PROJ: 'proj4',
         INFO.OBS_TIME: 'obs_time',
         INFO.OBS_DURATION: 'obs_duration',
+        INFO.PLATFORM: 'platform',
+        INFO.INSTRUMENT: 'instrument',
+        INFO.SCENE: 'scene',
+        INFO.STANDARD_NAME: 'standard_name',
         INFO.CELL_WIDTH: 'cell_width',
         INFO.CELL_HEIGHT: 'cell_height',
         INFO.ORIGIN_X: 'origin_x',
@@ -411,6 +421,16 @@ class Product(Base):
         self.atime = when = when or datetime.utcnow()
         [x.touch(when) for x in self.resource]
 
+    @property
+    def family(self):
+        """Products in the same family typically have the same color mapping"""
+        return tuple(getattr(self, colname) for colname in self.FAMILY_COLUMNS)
+
+    @property
+    def track(self):
+        """Products in the same track typically represent a time series of one scene observations"""
+        return tuple(getattr(self, colname) for colname in self.TRACK_COLUMNS)
+
 class ProductKeyValue(Base):
     """
     key-value pairs associated with a product