diff --git a/openapi-internal.yaml b/openapi-internal.yaml
index 83e24a4..0d7f2c5 100644
--- a/openapi-internal.yaml
+++ b/openapi-internal.yaml
@@ -85,8 +85,9 @@ paths:
         - Submissions
       parameters:
         - $ref: '#/components/parameters/SubmissionID'
-        - name: TargetAssetID
+        - name: UploadedAssetID
           in: query
+          required: true
           schema:
             type: integer
             format: int64
@@ -303,7 +304,8 @@ components:
       - Name
       - Hash
       - Source
-      - SubmissionID
+      - ResourceType
+      - ResourceID
       type: object
       properties:
         ID:
@@ -319,14 +321,18 @@ components:
         Source:
           type: string
           maxLength: 1048576
-        SubmissionID:
+        ResourceType:
+          type: integer
+          format: int32
+        ResourceID:
           type: integer
           format: int64
     ScriptCreate:
       required:
       - Name
       - Source
-#     - SubmissionID
+      - ResourceType
+#     - ResourceID
       type: object
       properties:
         Name:
@@ -335,7 +341,10 @@ components:
         Source:
           type: string
           maxLength: 1048576
-        SubmissionID:
+        ResourceType:
+          type: integer
+          format: int32
+        ResourceID:
           type: integer
           format: int64
     ScriptPolicy:
diff --git a/openapi.yaml b/openapi.yaml
index 21e2748..57b3dac 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -737,8 +737,7 @@ components:
       - AssetID
       - AssetVersion
       - Completed
-      - SubmissionType
-#     - TargetAssetID
+#     - UploadedAssetID
       - StatusID
       - StatusMessage
       type: object
@@ -772,10 +771,7 @@ components:
           format: int64
         Completed:
           type: boolean
-        SubmissionType:
-          type: integer
-          format: int32
-        TargetAssetID:
+        UploadedAssetID:
           type: integer
           format: int64
         StatusID:
@@ -791,7 +787,6 @@ components:
       - GameID
       - AssetID
       - AssetVersion
-#     - TargetAssetID
       type: object
       properties:
         DisplayName:
@@ -809,9 +804,6 @@ components:
         AssetVersion:
           type: integer
           format: int64
-        TargetAssetID:
-          type: integer
-          format: int64
     ReleaseInfo:
       required:
       - SubmissionID
@@ -830,7 +822,8 @@ components:
       - Name
       - Hash
       - Source
-      - SubmissionID
+      - ResourceType
+      - ResourceID
       type: object
       properties:
         ID:
@@ -846,14 +839,18 @@ components:
         Source:
           type: string
           maxLength: 1048576
-        SubmissionID:
+        ResourceType:
+          type: integer
+          format: int32
+        ResourceID:
           type: integer
           format: int64
     ScriptCreate:
       required:
       - Name
       - Source
-#     - SubmissionID
+      - ResourceType
+#     - ResourceID
       type: object
       properties:
         Name:
@@ -862,7 +859,10 @@ components:
         Source:
           type: string
           maxLength: 1048576
-        SubmissionID:
+        ResourceType:
+          type: integer
+          format: int32
+        ResourceID:
           type: integer
           format: int64
     ScriptUpdate:
@@ -879,7 +879,10 @@ components:
         Source:
           type: string
           maxLength: 1048576
-        SubmissionID:
+        ResourceType:
+          type: integer
+          format: int32
+        ResourceID:
           type: integer
           format: int64
     ScriptPolicy:
diff --git a/pkg/api/oas_json_gen.go b/pkg/api/oas_json_gen.go
index ab1cd86..1fec134 100644
--- a/pkg/api/oas_json_gen.go
+++ b/pkg/api/oas_json_gen.go
@@ -562,17 +562,22 @@ func (s *Script) encodeFields(e *jx.Encoder) {
 		e.Str(s.Source)
 	}
 	{
-		e.FieldStart("SubmissionID")
-		e.Int64(s.SubmissionID)
+		e.FieldStart("ResourceType")
+		e.Int32(s.ResourceType)
+	}
+	{
+		e.FieldStart("ResourceID")
+		e.Int64(s.ResourceID)
 	}
 }
 
-var jsonFieldsNameOfScript = [5]string{
+var jsonFieldsNameOfScript = [6]string{
 	0: "ID",
 	1: "Name",
 	2: "Hash",
 	3: "Source",
-	4: "SubmissionID",
+	4: "ResourceType",
+	5: "ResourceID",
 }
 
 // Decode decodes Script from json.
@@ -632,17 +637,29 @@ func (s *Script) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Source\"")
 			}
-		case "SubmissionID":
+		case "ResourceType":
 			requiredBitSet[0] |= 1 << 4
 			if err := func() error {
-				v, err := d.Int64()
-				s.SubmissionID = int64(v)
+				v, err := d.Int32()
+				s.ResourceType = int32(v)
 				if err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionID\"")
+				return errors.Wrap(err, "decode field \"ResourceType\"")
+			}
+		case "ResourceID":
+			requiredBitSet[0] |= 1 << 5
+			if err := func() error {
+				v, err := d.Int64()
+				s.ResourceID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ResourceID\"")
 			}
 		default:
 			return d.Skip()
@@ -654,7 +671,7 @@ func (s *Script) Decode(d *jx.Decoder) error {
 	// Validate required fields.
 	var failures []validate.FieldError
 	for i, mask := range [1]uint8{
-		0b00011111,
+		0b00111111,
 	} {
 		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
 			// Mask only required fields and check equality to mask using XOR.
@@ -718,17 +735,22 @@ func (s *ScriptCreate) encodeFields(e *jx.Encoder) {
 		e.Str(s.Source)
 	}
 	{
-		if s.SubmissionID.Set {
-			e.FieldStart("SubmissionID")
-			s.SubmissionID.Encode(e)
+		e.FieldStart("ResourceType")
+		e.Int32(s.ResourceType)
+	}
+	{
+		if s.ResourceID.Set {
+			e.FieldStart("ResourceID")
+			s.ResourceID.Encode(e)
 		}
 	}
 }
 
-var jsonFieldsNameOfScriptCreate = [3]string{
+var jsonFieldsNameOfScriptCreate = [4]string{
 	0: "Name",
 	1: "Source",
-	2: "SubmissionID",
+	2: "ResourceType",
+	3: "ResourceID",
 }
 
 // Decode decodes ScriptCreate from json.
@@ -764,15 +786,27 @@ func (s *ScriptCreate) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Source\"")
 			}
-		case "SubmissionID":
+		case "ResourceType":
+			requiredBitSet[0] |= 1 << 2
 			if err := func() error {
-				s.SubmissionID.Reset()
-				if err := s.SubmissionID.Decode(d); err != nil {
+				v, err := d.Int32()
+				s.ResourceType = int32(v)
+				if err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionID\"")
+				return errors.Wrap(err, "decode field \"ResourceType\"")
+			}
+		case "ResourceID":
+			if err := func() error {
+				s.ResourceID.Reset()
+				if err := s.ResourceID.Decode(d); err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ResourceID\"")
 			}
 		default:
 			return d.Skip()
@@ -784,7 +818,7 @@ func (s *ScriptCreate) Decode(d *jx.Decoder) error {
 	// Validate required fields.
 	var failures []validate.FieldError
 	for i, mask := range [1]uint8{
-		0b00000011,
+		0b00000111,
 	} {
 		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
 			// Mask only required fields and check equality to mask using XOR.
@@ -1280,18 +1314,25 @@ func (s *ScriptUpdate) encodeFields(e *jx.Encoder) {
 		}
 	}
 	{
-		if s.SubmissionID.Set {
-			e.FieldStart("SubmissionID")
-			s.SubmissionID.Encode(e)
+		if s.ResourceType.Set {
+			e.FieldStart("ResourceType")
+			s.ResourceType.Encode(e)
+		}
+	}
+	{
+		if s.ResourceID.Set {
+			e.FieldStart("ResourceID")
+			s.ResourceID.Encode(e)
 		}
 	}
 }
 
-var jsonFieldsNameOfScriptUpdate = [4]string{
+var jsonFieldsNameOfScriptUpdate = [5]string{
 	0: "ID",
 	1: "Name",
 	2: "Source",
-	3: "SubmissionID",
+	3: "ResourceType",
+	4: "ResourceID",
 }
 
 // Decode decodes ScriptUpdate from json.
@@ -1335,15 +1376,25 @@ func (s *ScriptUpdate) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Source\"")
 			}
-		case "SubmissionID":
+		case "ResourceType":
 			if err := func() error {
-				s.SubmissionID.Reset()
-				if err := s.SubmissionID.Decode(d); err != nil {
+				s.ResourceType.Reset()
+				if err := s.ResourceType.Decode(d); err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionID\"")
+				return errors.Wrap(err, "decode field \"ResourceType\"")
+			}
+		case "ResourceID":
+			if err := func() error {
+				s.ResourceID.Reset()
+				if err := s.ResourceID.Decode(d); err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ResourceID\"")
 			}
 		default:
 			return d.Skip()
@@ -1451,13 +1502,9 @@ func (s *Submission) encodeFields(e *jx.Encoder) {
 		e.Bool(s.Completed)
 	}
 	{
-		e.FieldStart("SubmissionType")
-		e.Int32(s.SubmissionType)
-	}
-	{
-		if s.TargetAssetID.Set {
-			e.FieldStart("TargetAssetID")
-			s.TargetAssetID.Encode(e)
+		if s.UploadedAssetID.Set {
+			e.FieldStart("UploadedAssetID")
+			s.UploadedAssetID.Encode(e)
 		}
 	}
 	{
@@ -1470,7 +1517,7 @@ func (s *Submission) encodeFields(e *jx.Encoder) {
 	}
 }
 
-var jsonFieldsNameOfSubmission = [14]string{
+var jsonFieldsNameOfSubmission = [13]string{
 	0:  "ID",
 	1:  "DisplayName",
 	2:  "Creator",
@@ -1481,10 +1528,9 @@ var jsonFieldsNameOfSubmission = [14]string{
 	7:  "AssetID",
 	8:  "AssetVersion",
 	9:  "Completed",
-	10: "SubmissionType",
-	11: "TargetAssetID",
-	12: "StatusID",
-	13: "StatusMessage",
+	10: "UploadedAssetID",
+	11: "StatusID",
+	12: "StatusMessage",
 }
 
 // Decode decodes Submission from json.
@@ -1616,30 +1662,18 @@ func (s *Submission) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Completed\"")
 			}
-		case "SubmissionType":
-			requiredBitSet[1] |= 1 << 2
+		case "UploadedAssetID":
 			if err := func() error {
-				v, err := d.Int32()
-				s.SubmissionType = int32(v)
-				if err != nil {
+				s.UploadedAssetID.Reset()
+				if err := s.UploadedAssetID.Decode(d); err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionType\"")
-			}
-		case "TargetAssetID":
-			if err := func() error {
-				s.TargetAssetID.Reset()
-				if err := s.TargetAssetID.Decode(d); err != nil {
-					return err
-				}
-				return nil
-			}(); err != nil {
-				return errors.Wrap(err, "decode field \"TargetAssetID\"")
+				return errors.Wrap(err, "decode field \"UploadedAssetID\"")
 			}
 		case "StatusID":
-			requiredBitSet[1] |= 1 << 4
+			requiredBitSet[1] |= 1 << 3
 			if err := func() error {
 				v, err := d.Int32()
 				s.StatusID = int32(v)
@@ -1651,7 +1685,7 @@ func (s *Submission) Decode(d *jx.Decoder) error {
 				return errors.Wrap(err, "decode field \"StatusID\"")
 			}
 		case "StatusMessage":
-			requiredBitSet[1] |= 1 << 5
+			requiredBitSet[1] |= 1 << 4
 			if err := func() error {
 				v, err := d.Str()
 				s.StatusMessage = string(v)
@@ -1673,7 +1707,7 @@ func (s *Submission) Decode(d *jx.Decoder) error {
 	var failures []validate.FieldError
 	for i, mask := range [2]uint8{
 		0b11111111,
-		0b00110111,
+		0b00011011,
 	} {
 		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
 			// Mask only required fields and check equality to mask using XOR.
@@ -1748,21 +1782,14 @@ func (s *SubmissionCreate) encodeFields(e *jx.Encoder) {
 		e.FieldStart("AssetVersion")
 		e.Int64(s.AssetVersion)
 	}
-	{
-		if s.TargetAssetID.Set {
-			e.FieldStart("TargetAssetID")
-			s.TargetAssetID.Encode(e)
-		}
-	}
 }
 
-var jsonFieldsNameOfSubmissionCreate = [6]string{
+var jsonFieldsNameOfSubmissionCreate = [5]string{
 	0: "DisplayName",
 	1: "Creator",
 	2: "GameID",
 	3: "AssetID",
 	4: "AssetVersion",
-	5: "TargetAssetID",
 }
 
 // Decode decodes SubmissionCreate from json.
@@ -1834,16 +1861,6 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"AssetVersion\"")
 			}
-		case "TargetAssetID":
-			if err := func() error {
-				s.TargetAssetID.Reset()
-				if err := s.TargetAssetID.Decode(d); err != nil {
-					return err
-				}
-				return nil
-			}(); err != nil {
-				return errors.Wrap(err, "decode field \"TargetAssetID\"")
-			}
 		default:
 			return d.Skip()
 		}
diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go
index b463864..ce8774f 100644
--- a/pkg/api/oas_schemas_gen.go
+++ b/pkg/api/oas_schemas_gen.go
@@ -314,7 +314,8 @@ type Script struct {
 	Name         string `json:"Name"`
 	Hash         string `json:"Hash"`
 	Source       string `json:"Source"`
-	SubmissionID int64  `json:"SubmissionID"`
+	ResourceType int32  `json:"ResourceType"`
+	ResourceID   int64  `json:"ResourceID"`
 }
 
 // GetID returns the value of ID.
@@ -337,9 +338,14 @@ func (s *Script) GetSource() string {
 	return s.Source
 }
 
-// GetSubmissionID returns the value of SubmissionID.
-func (s *Script) GetSubmissionID() int64 {
-	return s.SubmissionID
+// GetResourceType returns the value of ResourceType.
+func (s *Script) GetResourceType() int32 {
+	return s.ResourceType
+}
+
+// GetResourceID returns the value of ResourceID.
+func (s *Script) GetResourceID() int64 {
+	return s.ResourceID
 }
 
 // SetID sets the value of ID.
@@ -362,16 +368,22 @@ func (s *Script) SetSource(val string) {
 	s.Source = val
 }
 
-// SetSubmissionID sets the value of SubmissionID.
-func (s *Script) SetSubmissionID(val int64) {
-	s.SubmissionID = val
+// SetResourceType sets the value of ResourceType.
+func (s *Script) SetResourceType(val int32) {
+	s.ResourceType = val
+}
+
+// SetResourceID sets the value of ResourceID.
+func (s *Script) SetResourceID(val int64) {
+	s.ResourceID = val
 }
 
 // Ref: #/components/schemas/ScriptCreate
 type ScriptCreate struct {
 	Name         string   `json:"Name"`
 	Source       string   `json:"Source"`
-	SubmissionID OptInt64 `json:"SubmissionID"`
+	ResourceType int32    `json:"ResourceType"`
+	ResourceID   OptInt64 `json:"ResourceID"`
 }
 
 // GetName returns the value of Name.
@@ -384,9 +396,14 @@ func (s *ScriptCreate) GetSource() string {
 	return s.Source
 }
 
-// GetSubmissionID returns the value of SubmissionID.
-func (s *ScriptCreate) GetSubmissionID() OptInt64 {
-	return s.SubmissionID
+// GetResourceType returns the value of ResourceType.
+func (s *ScriptCreate) GetResourceType() int32 {
+	return s.ResourceType
+}
+
+// GetResourceID returns the value of ResourceID.
+func (s *ScriptCreate) GetResourceID() OptInt64 {
+	return s.ResourceID
 }
 
 // SetName sets the value of Name.
@@ -399,9 +416,14 @@ func (s *ScriptCreate) SetSource(val string) {
 	s.Source = val
 }
 
-// SetSubmissionID sets the value of SubmissionID.
-func (s *ScriptCreate) SetSubmissionID(val OptInt64) {
-	s.SubmissionID = val
+// SetResourceType sets the value of ResourceType.
+func (s *ScriptCreate) SetResourceType(val int32) {
+	s.ResourceType = val
+}
+
+// SetResourceID sets the value of ResourceID.
+func (s *ScriptCreate) SetResourceID(val OptInt64) {
+	s.ResourceID = val
 }
 
 // Ref: #/components/schemas/ScriptPolicy
@@ -542,7 +564,8 @@ type ScriptUpdate struct {
 	ID           int64     `json:"ID"`
 	Name         OptString `json:"Name"`
 	Source       OptString `json:"Source"`
-	SubmissionID OptInt64  `json:"SubmissionID"`
+	ResourceType OptInt32  `json:"ResourceType"`
+	ResourceID   OptInt64  `json:"ResourceID"`
 }
 
 // GetID returns the value of ID.
@@ -560,9 +583,14 @@ func (s *ScriptUpdate) GetSource() OptString {
 	return s.Source
 }
 
-// GetSubmissionID returns the value of SubmissionID.
-func (s *ScriptUpdate) GetSubmissionID() OptInt64 {
-	return s.SubmissionID
+// GetResourceType returns the value of ResourceType.
+func (s *ScriptUpdate) GetResourceType() OptInt32 {
+	return s.ResourceType
+}
+
+// GetResourceID returns the value of ResourceID.
+func (s *ScriptUpdate) GetResourceID() OptInt64 {
+	return s.ResourceID
 }
 
 // SetID sets the value of ID.
@@ -580,9 +608,14 @@ func (s *ScriptUpdate) SetSource(val OptString) {
 	s.Source = val
 }
 
-// SetSubmissionID sets the value of SubmissionID.
-func (s *ScriptUpdate) SetSubmissionID(val OptInt64) {
-	s.SubmissionID = val
+// SetResourceType sets the value of ResourceType.
+func (s *ScriptUpdate) SetResourceType(val OptInt32) {
+	s.ResourceType = val
+}
+
+// SetResourceID sets the value of ResourceID.
+func (s *ScriptUpdate) SetResourceID(val OptInt64) {
+	s.ResourceID = val
 }
 
 // SetSubmissionCompletedNoContent is response for SetSubmissionCompleted operation.
@@ -590,20 +623,19 @@ type SetSubmissionCompletedNoContent struct{}
 
 // Ref: #/components/schemas/Submission
 type Submission struct {
-	ID             int64    `json:"ID"`
-	DisplayName    string   `json:"DisplayName"`
-	Creator        string   `json:"Creator"`
-	GameID         int32    `json:"GameID"`
-	CreatedAt      int64    `json:"CreatedAt"`
-	UpdatedAt      int64    `json:"UpdatedAt"`
-	Submitter      int64    `json:"Submitter"`
-	AssetID        int64    `json:"AssetID"`
-	AssetVersion   int64    `json:"AssetVersion"`
-	Completed      bool     `json:"Completed"`
-	SubmissionType int32    `json:"SubmissionType"`
-	TargetAssetID  OptInt64 `json:"TargetAssetID"`
-	StatusID       int32    `json:"StatusID"`
-	StatusMessage  string   `json:"StatusMessage"`
+	ID              int64    `json:"ID"`
+	DisplayName     string   `json:"DisplayName"`
+	Creator         string   `json:"Creator"`
+	GameID          int32    `json:"GameID"`
+	CreatedAt       int64    `json:"CreatedAt"`
+	UpdatedAt       int64    `json:"UpdatedAt"`
+	Submitter       int64    `json:"Submitter"`
+	AssetID         int64    `json:"AssetID"`
+	AssetVersion    int64    `json:"AssetVersion"`
+	Completed       bool     `json:"Completed"`
+	UploadedAssetID OptInt64 `json:"UploadedAssetID"`
+	StatusID        int32    `json:"StatusID"`
+	StatusMessage   string   `json:"StatusMessage"`
 }
 
 // GetID returns the value of ID.
@@ -656,14 +688,9 @@ func (s *Submission) GetCompleted() bool {
 	return s.Completed
 }
 
-// GetSubmissionType returns the value of SubmissionType.
-func (s *Submission) GetSubmissionType() int32 {
-	return s.SubmissionType
-}
-
-// GetTargetAssetID returns the value of TargetAssetID.
-func (s *Submission) GetTargetAssetID() OptInt64 {
-	return s.TargetAssetID
+// GetUploadedAssetID returns the value of UploadedAssetID.
+func (s *Submission) GetUploadedAssetID() OptInt64 {
+	return s.UploadedAssetID
 }
 
 // GetStatusID returns the value of StatusID.
@@ -726,14 +753,9 @@ func (s *Submission) SetCompleted(val bool) {
 	s.Completed = val
 }
 
-// SetSubmissionType sets the value of SubmissionType.
-func (s *Submission) SetSubmissionType(val int32) {
-	s.SubmissionType = val
-}
-
-// SetTargetAssetID sets the value of TargetAssetID.
-func (s *Submission) SetTargetAssetID(val OptInt64) {
-	s.TargetAssetID = val
+// SetUploadedAssetID sets the value of UploadedAssetID.
+func (s *Submission) SetUploadedAssetID(val OptInt64) {
+	s.UploadedAssetID = val
 }
 
 // SetStatusID sets the value of StatusID.
@@ -748,12 +770,11 @@ func (s *Submission) SetStatusMessage(val string) {
 
 // Ref: #/components/schemas/SubmissionCreate
 type SubmissionCreate struct {
-	DisplayName   string   `json:"DisplayName"`
-	Creator       string   `json:"Creator"`
-	GameID        int32    `json:"GameID"`
-	AssetID       int64    `json:"AssetID"`
-	AssetVersion  int64    `json:"AssetVersion"`
-	TargetAssetID OptInt64 `json:"TargetAssetID"`
+	DisplayName  string `json:"DisplayName"`
+	Creator      string `json:"Creator"`
+	GameID       int32  `json:"GameID"`
+	AssetID      int64  `json:"AssetID"`
+	AssetVersion int64  `json:"AssetVersion"`
 }
 
 // GetDisplayName returns the value of DisplayName.
@@ -781,11 +802,6 @@ func (s *SubmissionCreate) GetAssetVersion() int64 {
 	return s.AssetVersion
 }
 
-// GetTargetAssetID returns the value of TargetAssetID.
-func (s *SubmissionCreate) GetTargetAssetID() OptInt64 {
-	return s.TargetAssetID
-}
-
 // SetDisplayName sets the value of DisplayName.
 func (s *SubmissionCreate) SetDisplayName(val string) {
 	s.DisplayName = val
@@ -811,11 +827,6 @@ func (s *SubmissionCreate) SetAssetVersion(val int64) {
 	s.AssetVersion = val
 }
 
-// SetTargetAssetID sets the value of TargetAssetID.
-func (s *SubmissionCreate) SetTargetAssetID(val OptInt64) {
-	s.TargetAssetID = val
-}
-
 // UpdateScriptNoContent is response for UpdateScript operation.
 type UpdateScriptNoContent struct{}
 
diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go
index eb7ca73..8a256b1 100644
--- a/pkg/datastore/datastore.go
+++ b/pkg/datastore/datastore.go
@@ -9,7 +9,16 @@ import (
 var (
 	ErrNotExist        = errors.New("resource does not exist")
 	ErroNoRowsAffected = errors.New("query did not affect any rows")
-	ErrInvalidSubmissionListSort = errors.New("invalid submission list sort parameter [1,2,3,4]")
+	ErrInvalidListSort = errors.New("invalid list sort parameter [1,2,3,4]")
+)
+
+type ListSort uint32
+const (
+	ListSortDisabled ListSort = 0
+	ListSortDisplayNameAscending ListSort = 1
+	ListSortDisplayNameDescending ListSort = 2
+	ListSortDateAscending ListSort = 3
+	ListSortDateDescending ListSort = 4
 )
 
 type Datastore interface {
@@ -23,10 +32,10 @@ type Submissions interface {
 	GetList(ctx context.Context, id []int64) ([]model.Submission, error)
 	Create(ctx context.Context, smap model.Submission) (model.Submission, error)
 	Update(ctx context.Context, id int64, values OptionalMap) error
-	IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) error
-	IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) (model.Submission, error)
+	IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) error
+	IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) (model.Submission, error)
 	Delete(ctx context.Context, id int64) error
-	List(ctx context.Context, filters OptionalMap, page model.Page, sort model.SubmissionListSort) ([]model.Submission, error)
+	List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Submission, error)
 }
 
 type Scripts interface {
diff --git a/pkg/datastore/gormstore/scripts.go b/pkg/datastore/gormstore/scripts.go
index 1aa7f1f..600d107 100644
--- a/pkg/datastore/gormstore/scripts.go
+++ b/pkg/datastore/gormstore/scripts.go
@@ -53,7 +53,7 @@ func (env *Scripts) Update(ctx context.Context, id int64, values datastore.Optio
 }
 
 // the update can only occur if the status matches one of the provided values.
-func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error {
+func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error {
 	if err := env.db.Model(&model.Script{}).Where("id = ?", id).Where("status IN ?", statuses).Updates(values.Map()).Error; err != nil {
 		if err == gorm.ErrRecordNotFound {
 			return datastore.ErrNotExist
diff --git a/pkg/datastore/gormstore/submissions.go b/pkg/datastore/gormstore/submissions.go
index b7073ab..dc384c6 100644
--- a/pkg/datastore/gormstore/submissions.go
+++ b/pkg/datastore/gormstore/submissions.go
@@ -54,7 +54,7 @@ func (env *Submissions) Update(ctx context.Context, id int64, values datastore.O
 }
 
 // the update can only occur if the status matches one of the provided values.
-func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error {
+func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error {
 	if err := env.db.Model(&model.Submission{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map()).Error; err != nil {
 		if err == gorm.ErrRecordNotFound {
 			return datastore.ErrNotExist
@@ -67,7 +67,7 @@ func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, status
 
 // the update can only occur if the status matches one of the provided values.
 // returns the updated value
-func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) (model.Submission, error) {
+func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) (model.Submission, error) {
 	var submission model.Submission
 	result := env.db.Model(&submission).
 		Clauses(clause.Returning{}).
@@ -99,29 +99,29 @@ func (env *Submissions) Delete(ctx context.Context, id int64) error {
 	return nil
 }
 
-func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort model.SubmissionListSort) ([]model.Submission, error) {
+func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) ([]model.Submission, error) {
 	var maps []model.Submission
 
 	db := env.db
 
 	switch sort {
-	case model.SubmissionListSortDisabled:
+	case datastore.ListSortDisabled:
 		// No sort
 		break
-	case model.SubmissionListSortDisplayNameAscending:
+	case datastore.ListSortDisplayNameAscending:
 		db=db.Order("display_name ASC")
 		break
-	case model.SubmissionListSortDisplayNameDescending:
+	case datastore.ListSortDisplayNameDescending:
 		db=db.Order("display_name DESC")
 		break
-	case model.SubmissionListSortDateAscending:
+	case datastore.ListSortDateAscending:
 		db=db.Order("created_at ASC")
 		break
-	case model.SubmissionListSortDateDescending:
+	case datastore.ListSortDateDescending:
 		db=db.Order("created_at DESC")
 		break
 	default:
-		return nil, datastore.ErrInvalidSubmissionListSort
+		return nil, datastore.ErrInvalidListSort
 	}
 
 	if err := db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
diff --git a/pkg/internal/oas_client_gen.go b/pkg/internal/oas_client_gen.go
index 7350ba5..26e4930 100644
--- a/pkg/internal/oas_client_gen.go
+++ b/pkg/internal/oas_client_gen.go
@@ -312,18 +312,15 @@ func (c *Client) sendActionSubmissionUploaded(ctx context.Context, params Action
 	stage = "EncodeQueryParams"
 	q := uri.NewQueryEncoder()
 	{
-		// Encode "TargetAssetID" parameter.
+		// Encode "UploadedAssetID" parameter.
 		cfg := uri.QueryParameterEncodingConfig{
-			Name:    "TargetAssetID",
+			Name:    "UploadedAssetID",
 			Style:   uri.QueryStyleForm,
 			Explode: true,
 		}
 
 		if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
-			if val, ok := params.TargetAssetID.Get(); ok {
-				return e.EncodeValue(conv.Int64ToString(val))
-			}
-			return nil
+			return e.EncodeValue(conv.Int64ToString(params.UploadedAssetID))
 		}); err != nil {
 			return res, errors.Wrap(err, "encode query")
 		}
diff --git a/pkg/internal/oas_handlers_gen.go b/pkg/internal/oas_handlers_gen.go
index 0a85800..e783223 100644
--- a/pkg/internal/oas_handlers_gen.go
+++ b/pkg/internal/oas_handlers_gen.go
@@ -282,9 +282,9 @@ func (s *Server) handleActionSubmissionUploadedRequest(args [1]string, argsEscap
 					In:   "path",
 				}: params.SubmissionID,
 				{
-					Name: "TargetAssetID",
+					Name: "UploadedAssetID",
 					In:   "query",
-				}: params.TargetAssetID,
+				}: params.UploadedAssetID,
 			},
 			Raw: r,
 		}
diff --git a/pkg/internal/oas_json_gen.go b/pkg/internal/oas_json_gen.go
index 47793c8..7b03e7b 100644
--- a/pkg/internal/oas_json_gen.go
+++ b/pkg/internal/oas_json_gen.go
@@ -282,17 +282,22 @@ func (s *Script) encodeFields(e *jx.Encoder) {
 		e.Str(s.Source)
 	}
 	{
-		e.FieldStart("SubmissionID")
-		e.Int64(s.SubmissionID)
+		e.FieldStart("ResourceType")
+		e.Int32(s.ResourceType)
+	}
+	{
+		e.FieldStart("ResourceID")
+		e.Int64(s.ResourceID)
 	}
 }
 
-var jsonFieldsNameOfScript = [5]string{
+var jsonFieldsNameOfScript = [6]string{
 	0: "ID",
 	1: "Name",
 	2: "Hash",
 	3: "Source",
-	4: "SubmissionID",
+	4: "ResourceType",
+	5: "ResourceID",
 }
 
 // Decode decodes Script from json.
@@ -352,17 +357,29 @@ func (s *Script) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Source\"")
 			}
-		case "SubmissionID":
+		case "ResourceType":
 			requiredBitSet[0] |= 1 << 4
 			if err := func() error {
-				v, err := d.Int64()
-				s.SubmissionID = int64(v)
+				v, err := d.Int32()
+				s.ResourceType = int32(v)
 				if err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionID\"")
+				return errors.Wrap(err, "decode field \"ResourceType\"")
+			}
+		case "ResourceID":
+			requiredBitSet[0] |= 1 << 5
+			if err := func() error {
+				v, err := d.Int64()
+				s.ResourceID = int64(v)
+				if err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ResourceID\"")
 			}
 		default:
 			return d.Skip()
@@ -374,7 +391,7 @@ func (s *Script) Decode(d *jx.Decoder) error {
 	// Validate required fields.
 	var failures []validate.FieldError
 	for i, mask := range [1]uint8{
-		0b00011111,
+		0b00111111,
 	} {
 		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
 			// Mask only required fields and check equality to mask using XOR.
@@ -438,17 +455,22 @@ func (s *ScriptCreate) encodeFields(e *jx.Encoder) {
 		e.Str(s.Source)
 	}
 	{
-		if s.SubmissionID.Set {
-			e.FieldStart("SubmissionID")
-			s.SubmissionID.Encode(e)
+		e.FieldStart("ResourceType")
+		e.Int32(s.ResourceType)
+	}
+	{
+		if s.ResourceID.Set {
+			e.FieldStart("ResourceID")
+			s.ResourceID.Encode(e)
 		}
 	}
 }
 
-var jsonFieldsNameOfScriptCreate = [3]string{
+var jsonFieldsNameOfScriptCreate = [4]string{
 	0: "Name",
 	1: "Source",
-	2: "SubmissionID",
+	2: "ResourceType",
+	3: "ResourceID",
 }
 
 // Decode decodes ScriptCreate from json.
@@ -484,15 +506,27 @@ func (s *ScriptCreate) Decode(d *jx.Decoder) error {
 			}(); err != nil {
 				return errors.Wrap(err, "decode field \"Source\"")
 			}
-		case "SubmissionID":
+		case "ResourceType":
+			requiredBitSet[0] |= 1 << 2
 			if err := func() error {
-				s.SubmissionID.Reset()
-				if err := s.SubmissionID.Decode(d); err != nil {
+				v, err := d.Int32()
+				s.ResourceType = int32(v)
+				if err != nil {
 					return err
 				}
 				return nil
 			}(); err != nil {
-				return errors.Wrap(err, "decode field \"SubmissionID\"")
+				return errors.Wrap(err, "decode field \"ResourceType\"")
+			}
+		case "ResourceID":
+			if err := func() error {
+				s.ResourceID.Reset()
+				if err := s.ResourceID.Decode(d); err != nil {
+					return err
+				}
+				return nil
+			}(); err != nil {
+				return errors.Wrap(err, "decode field \"ResourceID\"")
 			}
 		default:
 			return d.Skip()
@@ -504,7 +538,7 @@ func (s *ScriptCreate) Decode(d *jx.Decoder) error {
 	// Validate required fields.
 	var failures []validate.FieldError
 	for i, mask := range [1]uint8{
-		0b00000011,
+		0b00000111,
 	} {
 		if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
 			// Mask only required fields and check equality to mask using XOR.
diff --git a/pkg/internal/oas_parameters_gen.go b/pkg/internal/oas_parameters_gen.go
index 5bc3afd..c127a23 100644
--- a/pkg/internal/oas_parameters_gen.go
+++ b/pkg/internal/oas_parameters_gen.go
@@ -145,8 +145,8 @@ func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *h
 // ActionSubmissionUploadedParams is parameters of actionSubmissionUploaded operation.
 type ActionSubmissionUploadedParams struct {
 	// The unique identifier for a submission.
-	SubmissionID  int64
-	TargetAssetID OptInt64
+	SubmissionID    int64
+	UploadedAssetID int64
 }
 
 func unpackActionSubmissionUploadedParams(packed middleware.Parameters) (params ActionSubmissionUploadedParams) {
@@ -159,12 +159,10 @@ func unpackActionSubmissionUploadedParams(packed middleware.Parameters) (params
 	}
 	{
 		key := middleware.ParameterKey{
-			Name: "TargetAssetID",
+			Name: "UploadedAssetID",
 			In:   "query",
 		}
-		if v, ok := packed[key]; ok {
-			params.TargetAssetID = v.(OptInt64)
-		}
+		params.UploadedAssetID = packed[key].(int64)
 	}
 	return params
 }
@@ -216,43 +214,38 @@ func decodeActionSubmissionUploadedParams(args [1]string, argsEscaped bool, r *h
 			Err:  err,
 		}
 	}
-	// Decode query: TargetAssetID.
+	// Decode query: UploadedAssetID.
 	if err := func() error {
 		cfg := uri.QueryParameterDecodingConfig{
-			Name:    "TargetAssetID",
+			Name:    "UploadedAssetID",
 			Style:   uri.QueryStyleForm,
 			Explode: true,
 		}
 
 		if err := q.HasParam(cfg); err == nil {
 			if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
-				var paramsDotTargetAssetIDVal int64
-				if err := func() error {
-					val, err := d.DecodeValue()
-					if err != nil {
-						return err
-					}
-
-					c, err := conv.ToInt64(val)
-					if err != nil {
-						return err
-					}
-
-					paramsDotTargetAssetIDVal = c
-					return nil
-				}(); err != nil {
+				val, err := d.DecodeValue()
+				if err != nil {
 					return err
 				}
-				params.TargetAssetID.SetTo(paramsDotTargetAssetIDVal)
+
+				c, err := conv.ToInt64(val)
+				if err != nil {
+					return err
+				}
+
+				params.UploadedAssetID = c
 				return nil
 			}); err != nil {
 				return err
 			}
+		} else {
+			return err
 		}
 		return nil
 	}(); err != nil {
 		return params, &ogenerrors.DecodeParamError{
-			Name: "TargetAssetID",
+			Name: "UploadedAssetID",
 			In:   "query",
 			Err:  err,
 		}
diff --git a/pkg/internal/oas_schemas_gen.go b/pkg/internal/oas_schemas_gen.go
index c2bcdad..4805a04 100644
--- a/pkg/internal/oas_schemas_gen.go
+++ b/pkg/internal/oas_schemas_gen.go
@@ -231,7 +231,8 @@ type Script struct {
 	Name         string `json:"Name"`
 	Hash         string `json:"Hash"`
 	Source       string `json:"Source"`
-	SubmissionID int64  `json:"SubmissionID"`
+	ResourceType int32  `json:"ResourceType"`
+	ResourceID   int64  `json:"ResourceID"`
 }
 
 // GetID returns the value of ID.
@@ -254,9 +255,14 @@ func (s *Script) GetSource() string {
 	return s.Source
 }
 
-// GetSubmissionID returns the value of SubmissionID.
-func (s *Script) GetSubmissionID() int64 {
-	return s.SubmissionID
+// GetResourceType returns the value of ResourceType.
+func (s *Script) GetResourceType() int32 {
+	return s.ResourceType
+}
+
+// GetResourceID returns the value of ResourceID.
+func (s *Script) GetResourceID() int64 {
+	return s.ResourceID
 }
 
 // SetID sets the value of ID.
@@ -279,16 +285,22 @@ func (s *Script) SetSource(val string) {
 	s.Source = val
 }
 
-// SetSubmissionID sets the value of SubmissionID.
-func (s *Script) SetSubmissionID(val int64) {
-	s.SubmissionID = val
+// SetResourceType sets the value of ResourceType.
+func (s *Script) SetResourceType(val int32) {
+	s.ResourceType = val
+}
+
+// SetResourceID sets the value of ResourceID.
+func (s *Script) SetResourceID(val int64) {
+	s.ResourceID = val
 }
 
 // Ref: #/components/schemas/ScriptCreate
 type ScriptCreate struct {
 	Name         string   `json:"Name"`
 	Source       string   `json:"Source"`
-	SubmissionID OptInt64 `json:"SubmissionID"`
+	ResourceType int32    `json:"ResourceType"`
+	ResourceID   OptInt64 `json:"ResourceID"`
 }
 
 // GetName returns the value of Name.
@@ -301,9 +313,14 @@ func (s *ScriptCreate) GetSource() string {
 	return s.Source
 }
 
-// GetSubmissionID returns the value of SubmissionID.
-func (s *ScriptCreate) GetSubmissionID() OptInt64 {
-	return s.SubmissionID
+// GetResourceType returns the value of ResourceType.
+func (s *ScriptCreate) GetResourceType() int32 {
+	return s.ResourceType
+}
+
+// GetResourceID returns the value of ResourceID.
+func (s *ScriptCreate) GetResourceID() OptInt64 {
+	return s.ResourceID
 }
 
 // SetName sets the value of Name.
@@ -316,9 +333,14 @@ func (s *ScriptCreate) SetSource(val string) {
 	s.Source = val
 }
 
-// SetSubmissionID sets the value of SubmissionID.
-func (s *ScriptCreate) SetSubmissionID(val OptInt64) {
-	s.SubmissionID = val
+// SetResourceType sets the value of ResourceType.
+func (s *ScriptCreate) SetResourceType(val int32) {
+	s.ResourceType = val
+}
+
+// SetResourceID sets the value of ResourceID.
+func (s *ScriptCreate) SetResourceID(val OptInt64) {
+	s.ResourceID = val
 }
 
 // Ref: #/components/schemas/ScriptPolicy
diff --git a/pkg/model/script.go b/pkg/model/script.go
index e736c98..61b011e 100644
--- a/pkg/model/script.go
+++ b/pkg/model/script.go
@@ -23,12 +23,20 @@ func HashParse(hash string) (uint64, error){
 	return strconv.ParseUint(hash, 16, 64)
 }
 
+type ResourceType int32
+const (
+	ResourceUnknown    ResourceType = 0
+	ResourceMapfix     ResourceType = 1
+	ResourceSubmission ResourceType = 2
+)
+
 type Script struct {
 	ID           int64 `gorm:"primaryKey"`
 	Name         string
 	Hash         int64 // postgres does not support unsigned integers, so we have to pretend
 	Source       string
-	SubmissionID int64 // which submission did this script first appear in
+	ResourceType ResourceType // is this a submission or is it a mapfix
+	ResourceID   int64 // which submission / mapfix did this script first appear in
 	CreatedAt    time.Time
 	UpdatedAt    time.Time
 }
diff --git a/pkg/model/submission.go b/pkg/model/submission.go
index a01e1cd..aa2c708 100644
--- a/pkg/model/submission.go
+++ b/pkg/model/submission.go
@@ -2,34 +2,24 @@ package model
 
 import "time"
 
-type Status int32
+type SubmissionStatus int32
 
 const (
-	// Phase: Final Status
-	StatusReleased  Status = 9
-	StatusRejected  Status = 8
+	// Phase: Final SubmissionStatus
+	SubmissionStatusReleased  SubmissionStatus = 9
+	SubmissionStatusRejected  SubmissionStatus = 8
 
 	// Phase: Testing
-	StatusUploaded   Status = 7 // uploaded to the group, but pending release
-	StatusUploading  Status = 6
-	StatusValidated  Status = 5
-	StatusValidating Status = 4
-	StatusAccepted   Status = 3 // pending script review, can re-trigger validation
+	SubmissionStatusUploaded   SubmissionStatus = 7 // uploaded to the group, but pending release
+	SubmissionStatusUploading  SubmissionStatus = 6
+	SubmissionStatusValidated  SubmissionStatus = 5
+	SubmissionStatusValidating SubmissionStatus = 4
+	SubmissionStatusAccepted   SubmissionStatus = 3 // pending script review, can re-trigger validation
 
 	// Phase: Creation
-	StatusChangesRequested  Status = 2
-	StatusSubmitted         Status = 1
-	StatusUnderConstruction Status = 0
-)
-
-type SubmissionListSort uint32
-
-const (
-	SubmissionListSortDisabled SubmissionListSort = 0
-	SubmissionListSortDisplayNameAscending SubmissionListSort = 1
-	SubmissionListSortDisplayNameDescending SubmissionListSort = 2
-	SubmissionListSortDateAscending SubmissionListSort = 3
-	SubmissionListSortDateDescending SubmissionListSort = 4
+	SubmissionStatusChangesRequested  SubmissionStatus = 2
+	SubmissionStatusSubmitted         SubmissionStatus = 1
+	SubmissionStatusUnderConstruction SubmissionStatus = 0
 )
 
 type Submission struct {
@@ -40,16 +30,12 @@ type Submission struct {
 	CreatedAt     time.Time
 	UpdatedAt     time.Time
 	Submitter     int64 // UserID
-	// Who clicked the Accept button
-	AcceptedBy    int64 // UserID
-	// Who clicked the Upload button
-	UploadedBy    int64 // UserID
 	AssetID       int64
 	AssetVersion  int64
 	ValidatedAssetID       int64
 	ValidatedAssetVersion  int64
 	Completed     bool   // Has this version of the map been completed at least once on maptest
-	TargetAssetID int64 // where to upload map fix.  if the TargetAssetID is 0, it's a new map.
-	StatusID      Status
+	UploadedAssetID        int64 // where to upload map fix.  if the TargetAssetID is 0, it's a new map.
+	StatusID      SubmissionStatus
 	StatusMessage string
 }
diff --git a/pkg/service/scripts.go b/pkg/service/scripts.go
index 2a67e84..931d607 100644
--- a/pkg/service/scripts.go
+++ b/pkg/service/scripts.go
@@ -32,7 +32,8 @@ func (svc *Service) CreateScript(ctx context.Context, req *api.ScriptCreate) (*a
 		Name:         req.Name,
 		Hash:         int64(model.HashSource(req.Source)),
 		Source:       req.Source,
-		SubmissionID: req.SubmissionID.Or(0),
+		ResourceType: model.ResourceType(req.ResourceType),
+		ResourceID:   req.ResourceID.Or(0),
 	})
 	if err != nil {
 		return nil, err
@@ -82,7 +83,8 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
 			ID:           item.ID,
 			Hash:         model.HashFormat(uint64(item.Hash)),
 			Source:       item.Source,
-			SubmissionID: item.SubmissionID,
+			ResourceType: int32(item.ResourceType),
+			ResourceID:   item.ResourceID,
 		})
 	}
 
@@ -134,7 +136,8 @@ func (svc *Service) GetScript(ctx context.Context, params api.GetScriptParams) (
 		Name:         script.Name,
 		Hash:         model.HashFormat(uint64(script.Hash)),
 		Source:       script.Source,
-		SubmissionID: script.SubmissionID,
+		ResourceType: int32(script.ResourceType),
+		ResourceID:   script.ResourceID,
 	}, nil
 }
 
@@ -165,8 +168,11 @@ func (svc *Service) UpdateScript(ctx context.Context, req *api.ScriptUpdate, par
 		pmap.Add("source", source)
 		pmap.Add("hash", int64(model.HashSource(source))) // No type safety!
 	}
-	if SubmissionID, ok := req.SubmissionID.Get(); ok {
-		pmap.Add("submission_id", SubmissionID)
+	if ResourceType, ok := req.ResourceType.Get(); ok {
+		pmap.Add("resource_type", ResourceType)
+	}
+	if ResourceID, ok := req.ResourceID.Get(); ok {
+		pmap.Add("resource_id", ResourceID)
 	}
 	return svc.DB.Scripts().Update(ctx, req.ID, pmap)
 }
diff --git a/pkg/service/security.go b/pkg/service/security.go
index 9584672..8bc2efb 100644
--- a/pkg/service/security.go
+++ b/pkg/service/security.go
@@ -19,8 +19,8 @@ type Roles int32
 var (
 	RolesSubmissionRelease Roles = 1<<4
 	RolesScriptWrite Roles = 1<<3
-	RolesSubmissionUpload Roles = 1<<2
-	RolesSubmissionReview Roles = 1<<1
+	RolesMapUpload Roles = 1<<2
+	RolesMapReview Roles = 1<<1
 	RolesMapDownload Roles = 1<<0
 	RolesEmpty Roles = 0
 )
@@ -32,13 +32,13 @@ var (
 	RoleQuat GroupRole = 255
 	RoleItzaname GroupRole = 254
 	RoleStagingDeveloper GroupRole = 240
-	RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
+	RolesAll Roles = RolesScriptWrite|RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload
 	// has SubmissionUpload
 	RoleMapAdmin GroupRole = 128
-	RolesMapAdmin Roles = RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapDownload
+	RolesMapAdmin Roles = RolesSubmissionRelease|RolesMapUpload|RolesMapReview|RolesMapDownload
 	// has SubmissionReview
 	RoleMapCouncil GroupRole = 64
-	RolesMapCouncil Roles = RolesSubmissionReview|RolesSubmissionUpload|RolesMapDownload
+	RolesMapCouncil Roles = RolesMapReview|RolesMapUpload|RolesMapDownload
 	// access to downloading maps
 	RoleMapAccess GroupRole = 32
 	RolesMapAccess Roles = RolesMapDownload
@@ -128,17 +128,23 @@ func (usr UserInfoHandle) GetRoles() (Roles, error) {
 }
 
 // RoleThumbnail
+func (usr UserInfoHandle) HasRoleMapfixUpload() (bool, error) {
+	return usr.hasRoles(RolesMapUpload)
+}
+func (usr UserInfoHandle) HasRoleMapfixReview() (bool, error) {
+	return usr.hasRoles(RolesMapReview)
+}
+func (usr UserInfoHandle) HasRoleMapDownload() (bool, error) {
+	return usr.hasRoles(RolesMapDownload)
+}
 func (usr UserInfoHandle) HasRoleSubmissionRelease() (bool, error) {
 	return usr.hasRoles(RolesSubmissionRelease)
 }
 func (usr UserInfoHandle) HasRoleSubmissionUpload() (bool, error) {
-	return usr.hasRoles(RolesSubmissionUpload)
+	return usr.hasRoles(RolesMapUpload)
 }
 func (usr UserInfoHandle) HasRoleSubmissionReview() (bool, error) {
-	return usr.hasRoles(RolesSubmissionReview)
-}
-func (usr UserInfoHandle) HasRoleMapDownload() (bool, error) {
-	return usr.hasRoles(RolesMapDownload)
+	return usr.hasRoles(RolesMapReview)
 }
 func (usr UserInfoHandle) HasRoleScriptWrite() (bool, error) {
 	return usr.hasRoles(RolesScriptWrite)
diff --git a/pkg/service/service.go b/pkg/service/service.go
index ac0c2f6..1815060 100644
--- a/pkg/service/service.go
+++ b/pkg/service/service.go
@@ -3,6 +3,7 @@ package service
 import (
 	"context"
 	"errors"
+	"fmt"
 
 	"git.itzana.me/strafesnet/go-grpc/maps"
 	"git.itzana.me/strafesnet/maps-service/pkg/api"
@@ -15,6 +16,14 @@ var (
 	ErrPermissionDenied = errors.New("Permission denied")
 	// ErrUserInfo user info is missing for some reason
 	ErrUserInfo = errors.New("Missing user info")
+	ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
+	ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMapUpload = fmt.Errorf("%w: Need Role MapUpload", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMapReview = fmt.Errorf("%w: Need Role MapReview", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
+	ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
 )
 
 type Service struct {
diff --git a/pkg/service/submissions.go b/pkg/service/submissions.go
index 940d39f..430e6d0 100644
--- a/pkg/service/submissions.go
+++ b/pkg/service/submissions.go
@@ -15,45 +15,37 @@ import (
 
 var(
 	CreationPhaseSubmissionsLimit = 20
-	CreationPhaseSubmissionStatuses = []model.Status{
-		model.StatusChangesRequested,
-		model.StatusSubmitted,
-		model.StatusUnderConstruction,
+	CreationPhaseSubmissionStatuses = []model.SubmissionStatus{
+		model.SubmissionStatusChangesRequested,
+		model.SubmissionStatusSubmitted,
+		model.SubmissionStatusUnderConstruction,
 	}
 	// prevent two mapfixes with same asset id
-	ActiveSubmissionStatuses = []model.Status{
-		model.StatusUploading,
-		model.StatusValidated,
-		model.StatusValidating,
-		model.StatusAccepted,
-		model.StatusChangesRequested,
-		model.StatusSubmitted,
-		model.StatusUnderConstruction,
+	ActiveSubmissionStatuses = []model.SubmissionStatus{
+		model.SubmissionStatusUploading,
+		model.SubmissionStatusValidated,
+		model.SubmissionStatusValidating,
+		model.SubmissionStatusAccepted,
+		model.SubmissionStatusChangesRequested,
+		model.SubmissionStatusSubmitted,
+		model.SubmissionStatusUnderConstruction,
 	}
 	// limit mapfixes in the pipeline to one per target map
-	ActiveAcceptedSubmissionStatuses = []model.Status{
-		model.StatusUploading,
-		model.StatusValidated,
-		model.StatusValidating,
-		model.StatusAccepted,
+	ActiveAcceptedSubmissionStatuses = []model.SubmissionStatus{
+		model.SubmissionStatusUploading,
+		model.SubmissionStatusValidated,
+		model.SubmissionStatusValidating,
+		model.SubmissionStatusAccepted,
 	}
 )
 
 var (
 	ErrCreationPhaseSubmissionsLimit = errors.New("Active submissions limited to 20")
 	ErrActiveSubmissionSameAssetID = errors.New("There is an active submission with the same AssetID")
-	ErrActiveSubmissionSameTargetAssetID = errors.New("There is an active submission with the same TargetAssetID")
+	ErrUploadedAssetIDAlreadyExists = errors.New("The submission UploadedAssetID is already set")
 	ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released")
-	ErrReleaseNoTargetAssetID = errors.New("Only submissions with a TargetAssetID can be released")
+	ErrReleaseNoUploadedAssetID = errors.New("Only submissions with a UploadedAssetID can be released")
 	ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
-	ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
-	ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
-	ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
 )
 
 // POST /submissions
@@ -76,7 +68,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
 		creation_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
 			Number: 1,
 			Size:   int32(CreationPhaseSubmissionsLimit),
-		},model.SubmissionListSortDisabled)
+		},datastore.ListSortDisabled)
 		if err != nil {
 			return nil, err
 		}
@@ -95,7 +87,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
 		active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
 			Number: 1,
 			Size:   1,
-		},model.SubmissionListSortDisabled)
+		},datastore.ListSortDisabled)
 		if err != nil {
 			return nil, err
 		}
@@ -113,8 +105,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
 		AssetID:       request.AssetID,
 		AssetVersion:  request.AssetVersion,
 		Completed:     false,
-		TargetAssetID: request.TargetAssetID.Value,
-		StatusID:      model.StatusUnderConstruction,
+		StatusID:      model.SubmissionStatusUnderConstruction,
 	})
 	if err != nil {
 		return nil, err
@@ -145,7 +136,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
 		AssetID:       int64(submission.AssetID),
 		AssetVersion:  int64(submission.AssetVersion),
 		Completed:     submission.Completed,
-		TargetAssetID: api.NewOptInt64(int64(submission.TargetAssetID)),
+		UploadedAssetID: api.NewOptInt64(int64(submission.UploadedAssetID)),
 		StatusID:      int32(submission.StatusID),
 		StatusMessage: submission.StatusMessage,
 	}, nil
@@ -169,7 +160,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
 		filter.Add("game_id", params.GameID.Value)
 	}
 
-	sort := model.SubmissionListSort(params.Sort.Or(int32(model.SubmissionListSortDisabled)))
+	sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
 
 	items, err := svc.DB.Submissions().List(ctx, filter, model.Page{
 		Number: params.Page,
@@ -192,7 +183,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
 			AssetID:       int64(item.AssetID),
 			AssetVersion:  int64(item.AssetVersion),
 			Completed:     item.Completed,
-			TargetAssetID: api.NewOptInt64(int64(item.TargetAssetID)),
+			UploadedAssetID: api.NewOptInt64(int64(item.UploadedAssetID)),
 			StatusID:      int32(item.StatusID),
 		})
 	}
@@ -257,7 +248,7 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
 	pmap.AddNotNil("asset_version", params.VersionID)
 	//always reset completed when model changes
 	pmap.Add("completed", false)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusChangesRequested, model.StatusSubmitted, model.StatusUnderConstruction}, pmap)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusSubmitted, model.SubmissionStatusUnderConstruction}, pmap)
 }
 
 // ActionSubmissionReject invokes actionSubmissionReject operation.
@@ -277,13 +268,13 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionReview
+		return ErrPermissionDeniedNeedRoleMapReview
 	}
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusRejected)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap)
+	smap.Add("status_id", model.SubmissionStatusRejected)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
 }
 
 // ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
@@ -303,13 +294,13 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionReview
+		return ErrPermissionDeniedNeedRoleMapReview
 	}
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusChangesRequested)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidated, model.StatusAccepted, model.StatusSubmitted}, smap)
+	smap.Add("status_id", model.SubmissionStatusChangesRequested)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAccepted, model.SubmissionStatusSubmitted}, smap)
 }
 
 // ActionSubmissionRevoke invokes actionSubmissionRevoke operation.
@@ -340,8 +331,8 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusUnderConstruction)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted, model.StatusChangesRequested}, smap)
+	smap.Add("status_id", model.SubmissionStatusUnderConstruction)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap)
 }
 
 // ActionSubmissionSubmit invokes actionSubmissionSubmit operation.
@@ -372,8 +363,8 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusSubmitted)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUnderConstruction, model.StatusChangesRequested}, smap)
+	smap.Add("status_id", model.SubmissionStatusSubmitted)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
 }
 
 // ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation.
@@ -393,26 +384,19 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionUpload
-	}
-
-	// track who is performing the upload action
-	userId, err := userInfo.GetUserID()
-	if err != nil {
-		return err
+		return ErrPermissionDeniedNeedRoleMapUpload
 	}
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusUploading)
-	smap.Add("uploaded_by", userId)
-	submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap)
+	smap.Add("status_id", model.SubmissionStatusUploading)
+	submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated}, smap)
 	if err != nil {
 		return err
 	}
 
 	// sentinel value because we are not using rust
-	if submission.TargetAssetID == 0 {
+	if submission.UploadedAssetID == 0 {
 		// this is a new map
 		upload_new_request := model.UploadNewRequest{
 			SubmissionID: submission.ID,
@@ -427,22 +411,10 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
 			return err
 		}
 
-		svc.Nats.Publish("maptest.submissions.uploadnew", []byte(j))
+		svc.Nats.Publish("maptest.submissions.upload", []byte(j))
 	} else {
-		// this is a map fix
-		upload_fix_request := model.UploadFixRequest{
-			SubmissionID:  submission.ID,
-			ModelID:       submission.ValidatedAssetID,
-			ModelVersion:  submission.ValidatedAssetVersion,
-			TargetAssetID: submission.TargetAssetID,
-		}
-
-		j, err := json.Marshal(upload_fix_request)
-		if err != nil {
-			return err
-		}
-
-		svc.Nats.Publish("maptest.submissions.uploadfix", []byte(j))
+		// refuse to operate
+		return ErrUploadedAssetIDAlreadyExists
 	}
 
 	return nil
@@ -465,7 +437,7 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionUpload
+		return ErrPermissionDeniedNeedRoleMapUpload
 	}
 
 	// check when submission was updated
@@ -480,8 +452,8 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusValidated)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploading}, smap)
+	smap.Add("status_id", model.SubmissionStatusValidated)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
 }
 
 // ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation.
@@ -501,7 +473,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionReview
+		return ErrPermissionDeniedNeedRoleMapReview
 	}
 
 	// read submission (this could be done with a transaction WHERE clause)
@@ -510,38 +482,19 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
 		return err
 	}
 
-	// track who is performing the accept action
-	userId, err := userInfo.GetUserID()
+	has_role, err = userInfo.IsSubmitter(uint64(submission.Submitter))
 	if err != nil {
 		return err
 	}
 	// check if caller is NOT the submitter
-	if userId == uint64(submission.Submitter) {
+	if has_role {
 		return ErrAcceptOwnSubmission
 	}
 
-	// Check if an active submission with the same target asset id exists
-	if submission.TargetAssetID != 0 {
-		filter := datastore.Optional()
-		filter.Add("target_asset_id", submission.TargetAssetID)
-		filter.Add("status_id", ActiveAcceptedSubmissionStatuses)
-		active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
-			Number: 1,
-			Size:   1,
-		},model.SubmissionListSortDisabled)
-		if err != nil {
-			return err
-		}
-		if len(active_submissions) != 0{
-			return ErrActiveSubmissionSameTargetAssetID
-		}
-	}
-
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusValidating)
-	smap.Add("accepted_by", userId)
-	submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap)
+	smap.Add("status_id", model.SubmissionStatusValidating)
+	submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
 	if err != nil {
 		return err
 	}
@@ -585,13 +538,13 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionReview
+		return ErrPermissionDeniedNeedRoleMapReview
 	}
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusValidating)
-	submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusAccepted}, smap)
+	smap.Add("status_id", model.SubmissionStatusValidating)
+	submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAccepted}, smap)
 	if err != nil {
 		return err
 	}
@@ -635,7 +588,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
 	}
 	// check if caller has required role
 	if !has_role {
-		return ErrPermissionDeniedNeedRoleSubmissionReview
+		return ErrPermissionDeniedNeedRoleMapReview
 	}
 
 	// check when submission was updated
@@ -650,9 +603,9 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
 
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusAccepted)
+	smap.Add("status_id", model.SubmissionStatusAccepted)
 	smap.Add("status_message", "Manually forced reset")
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
 }
 
 // ReleaseSubmissions invokes releaseSubmissions operation.
@@ -688,11 +641,11 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 
 	// check each submission to make sure it is ready to release
 	for _,submission := range submissions{
-		if submission.StatusID != model.StatusUploaded{
+		if submission.StatusID != model.SubmissionStatusUploaded{
 			return ErrReleaseInvalidStatus
 		}
-		if submission.TargetAssetID == 0{
-			return ErrReleaseNoTargetAssetID
+		if submission.UploadedAssetID == 0{
+			return ErrReleaseNoUploadedAssetID
 		}
 	}
 
@@ -700,7 +653,7 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 		date := request[i].Date.Unix()
 		// create each map with go-grpc
 		_, err := svc.Client.Create(ctx, &maps.MapRequest{
-			ID:          submission.TargetAssetID,
+			ID:          submission.UploadedAssetID,
 			DisplayName: &submission.DisplayName,
 			Creator:     &submission.Creator,
 			GameID:      &submission.GameID,
@@ -712,8 +665,8 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
 
 		// update each status to Released
 		smap := datastore.Optional()
-		smap.Add("status_id", model.StatusReleased)
-		err = svc.DB.Submissions().IfStatusThenUpdate(ctx, submission.ID, []model.Status{model.StatusUploaded}, smap)
+		smap.Add("status_id", model.SubmissionStatusReleased)
+		err = svc.DB.Submissions().IfStatusThenUpdate(ctx, submission.ID, []model.SubmissionStatus{model.SubmissionStatusUploaded}, smap)
 		if err != nil {
 			return err
 		}
diff --git a/pkg/service_internal/scripts.go b/pkg/service_internal/scripts.go
index 3cb0280..afa4868 100644
--- a/pkg/service_internal/scripts.go
+++ b/pkg/service_internal/scripts.go
@@ -19,7 +19,8 @@ func (svc *Service) CreateScript(ctx context.Context, req *api.ScriptCreate) (*a
 		Name:         req.Name,
 		Hash:         int64(model.HashSource(req.Source)),
 		Source:       req.Source,
-		SubmissionID: req.SubmissionID.Or(0),
+		ResourceType: model.ResourceType(req.ResourceType),
+		ResourceID:   req.ResourceID.Or(0),
 	})
 	if err != nil {
 		return nil, err
@@ -69,7 +70,8 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
 			ID:           item.ID,
 			Hash:         model.HashFormat(uint64(item.Hash)),
 			Source:       item.Source,
-			SubmissionID: item.SubmissionID,
+			ResourceType: int32(item.ResourceType),
+			ResourceID:   item.ResourceID,
 		})
 	}
 
@@ -92,6 +94,7 @@ func (svc *Service) GetScript(ctx context.Context, params api.GetScriptParams) (
 		Name:         script.Name,
 		Hash:         model.HashFormat(uint64(script.Hash)),
 		Source:       script.Source,
-		SubmissionID: script.SubmissionID,
+		ResourceType: int32(script.ResourceType),
+		ResourceID:   script.ResourceID,
 	}, nil
 }
diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go
index 0d3a33a..c9846d1 100644
--- a/pkg/service_internal/submissions.go
+++ b/pkg/service_internal/submissions.go
@@ -20,7 +20,7 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i
 	pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
 	// DO NOT reset completed when validated model is updated
 	// pmap.Add("completed", false)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, pmap)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
 }
 
 // ActionSubmissionValidate invokes actionSubmissionValidate operation.
@@ -29,12 +29,10 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i
 //
 // POST /submissions/{SubmissionID}/status/validator-validated
 func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error {
-	println("[ActionSubmissionValidated] Implicit Validator permission granted!")
-
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusValidated)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
+	smap.Add("status_id", model.SubmissionStatusValidated)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
 }
 
 // ActionSubmissionAccepted implements actionSubmissionAccepted operation.
@@ -43,13 +41,11 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params intern
 //
 // POST /submissions/{SubmissionID}/status/validator-failed
 func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params internal.ActionSubmissionAcceptedParams) error {
-	println("[ActionSubmissionAccepted] Implicit Validator permission granted!")
-
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusAccepted)
+	smap.Add("status_id", model.SubmissionStatusAccepted)
 	smap.Add("status_message", params.StatusMessage)
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
 }
 
 // ActionSubmissionUploaded implements actionSubmissionUploaded operation.
@@ -58,13 +54,9 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna
 //
 // POST /submissions/{SubmissionID}/status/validator-uploaded
 func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error {
-	println("[ActionSubmissionUploaded] Implicit Validator permission granted!")
-
 	// transaction
 	smap := datastore.Optional()
-	smap.Add("status_id", model.StatusUploaded)
-	if params.TargetAssetID.IsSet() {
-		smap.AddNotNil("target_asset_id", params.TargetAssetID.Value)
-	}
-	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUploading}, smap)
+	smap.Add("status_id", model.SubmissionStatusUploaded)
+	smap.Add("uploaded_asset_id", params.UploadedAssetID)
+	return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
 }
diff --git a/validation/api/src/external.rs b/validation/api/src/external.rs
index d89c2f9..8aa00d2 100644
--- a/validation/api/src/external.rs
+++ b/validation/api/src/external.rs
@@ -14,7 +14,7 @@ impl Context{
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_scripts<'a>(&self,config:GetScriptsRequest<'a>)->Result<Vec<ScriptResponse>,Error>{
 		let url_raw=format!("{}/scripts",self.0.base_url);
@@ -33,15 +33,18 @@ impl Context{
 			if let Some(source)=config.Source{
 				query_pairs.append_pair("Source",source);
 			}
-			if let Some(submission_id)=config.SubmissionID{
-				query_pairs.append_pair("SubmissionID",submission_id.to_string().as_str());
+			if let Some(resource_type)=config.ResourceType{
+				query_pairs.append_pair("ResourceType",(resource_type as i32).to_string().as_str());
+			}
+			if let Some(resource_id)=config.ResourceID{
+				query_pairs.append_pair("ResourceID",resource_id.to_string().as_str());
 			}
 		}
 
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptResponse>,SingleItemError>{
 		let scripts=self.get_scripts(GetScriptsRequest{
@@ -50,7 +53,8 @@ impl Context{
 			Hash:Some(config.hash),
 			Name:None,
 			Source:None,
-			SubmissionID:None,
+			ResourceType:None,
+			ResourceID:None,
 		}).await.map_err(SingleItemError::Other)?;
 		if 1<scripts.len(){
 			return Err(SingleItemError::DuplicateItems);
@@ -66,7 +70,7 @@ impl Context{
 		response_ok(
 			self.0.post(url,body).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_policies<'a>(&self,config:GetScriptPoliciesRequest<'a>)->Result<Vec<ScriptPolicyResponse>,Error>{
 		let url_raw=format!("{}/script-policy",self.0.base_url);
@@ -90,7 +94,7 @@ impl Context{
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_policy_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptPolicyResponse>,SingleItemError>{
 		let policies=self.get_script_policies(GetScriptPoliciesRequest{
@@ -114,7 +118,7 @@ impl Context{
 		response_ok(
 			self.0.post(url,body).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn update_script_policy(&self,config:UpdateScriptPolicyRequest)->Result<(),Error>{
 		let url_raw=format!("{}/script-policy/{}",self.0.base_url,config.ID.0);
diff --git a/validation/api/src/internal.rs b/validation/api/src/internal.rs
index b4bf484..990466d 100644
--- a/validation/api/src/internal.rs
+++ b/validation/api/src/internal.rs
@@ -29,7 +29,7 @@ impl Context{
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_scripts<'a>(&self,config:GetScriptsRequest<'a>)->Result<Vec<ScriptResponse>,Error>{
 		let url_raw=format!("{}/scripts",self.0.base_url);
@@ -48,15 +48,18 @@ impl Context{
 			if let Some(source)=config.Source{
 				query_pairs.append_pair("Source",source);
 			}
-			if let Some(submission_id)=config.SubmissionID{
-				query_pairs.append_pair("SubmissionID",submission_id.to_string().as_str());
+			if let Some(resource_type)=config.ResourceType{
+				query_pairs.append_pair("ResourceType",(resource_type as i32).to_string().as_str());
+			}
+			if let Some(resource_id)=config.ResourceID{
+				query_pairs.append_pair("ResourceID",resource_id.to_string().as_str());
 			}
 		}
 
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptResponse>,SingleItemError>{
 		let scripts=self.get_scripts(GetScriptsRequest{
@@ -65,7 +68,8 @@ impl Context{
 			Hash:Some(config.hash),
 			Name:None,
 			Source:None,
-			SubmissionID:None,
+			ResourceType:None,
+			ResourceID:None,
 		}).await.map_err(SingleItemError::Other)?;
 		if 1<scripts.len(){
 			return Err(SingleItemError::DuplicateItems);
@@ -81,7 +85,7 @@ impl Context{
 		response_ok(
 			self.0.post(url,body).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_policies<'a>(&self,config:GetScriptPoliciesRequest<'a>)->Result<Vec<ScriptPolicyResponse>,Error>{
 		let url_raw=format!("{}/script-policy",self.0.base_url);
@@ -105,7 +109,7 @@ impl Context{
 		response_ok(
 			self.0.get(url).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn get_script_policy_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptPolicyResponse>,SingleItemError>{
 		let policies=self.get_script_policies(GetScriptPoliciesRequest{
@@ -129,7 +133,7 @@ impl Context{
 		response_ok(
 			self.0.post(url,body).await.map_err(Error::Reqwest)?
 		).await.map_err(Error::Response)?
-		.json().await.map_err(Error::Reqwest)
+		.json().await.map_err(Error::ReqwestJson)
 	}
 	pub async fn update_submission_validated_model(&self,config:UpdateSubmissionModelRequest)->Result<(),Error>{
 		let url_raw=format!("{}/submissions/{}/validated-model",self.0.base_url,config.SubmissionID);
@@ -151,9 +155,9 @@ impl Context{
 		let url_raw=format!("{}/submissions/{}/status/validator-uploaded",self.0.base_url,config.SubmissionID);
 		let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
 
-		if let Some(target_asset_id)=config.TargetAssetID{
+		{
 			url.query_pairs_mut()
-				.append_pair("TargetAssetID",target_asset_id.to_string().as_str());
+				.append_pair("UploadedAssetID",config.UploadedAssetID.to_string().as_str());
 		}
 		response_ok(
 			self.0.post_empty_body(url).await.map_err(Error::Reqwest)?
diff --git a/validation/api/src/types.rs b/validation/api/src/types.rs
index 41e282e..60d1f4c 100644
--- a/validation/api/src/types.rs
+++ b/validation/api/src/types.rs
@@ -2,6 +2,7 @@
 pub enum Error{
 	Parse(url::ParseError),
 	Reqwest(reqwest::Error),
+	ReqwestJson(reqwest::Error),
 	Response(ResponseError),
 	JSON(serde_json::Error),
 }
@@ -65,6 +66,14 @@ pub struct ScriptID(pub(crate)i64);
 #[derive(Clone,Copy,Debug,serde::Serialize,serde::Deserialize)]
 pub struct ScriptPolicyID(pub(crate)i64);
 
+#[derive(Clone,Copy,Debug,PartialEq,Eq,serde_repr::Serialize_repr,serde_repr::Deserialize_repr)]
+#[repr(i32)]
+pub enum ResourceType{
+	Unknown=0,
+	Mapfix=1,
+	Submission=2,
+}
+
 #[allow(nonstandard_style)]
 pub struct GetScriptRequest{
 	pub ScriptID:ScriptID,
@@ -81,7 +90,9 @@ pub struct GetScriptsRequest<'a>{
 	#[serde(skip_serializing_if="Option::is_none")]
 	pub Source:Option<&'a str>,
 	#[serde(skip_serializing_if="Option::is_none")]
-	pub SubmissionID:Option<i64>,
+	pub ResourceType:Option<ResourceType>,
+	#[serde(skip_serializing_if="Option::is_none")]
+	pub ResourceID:Option<i64>,
 }
 #[derive(Clone,Copy,Debug)]
 pub struct HashRequest<'a>{
@@ -94,15 +105,17 @@ pub struct ScriptResponse{
 	pub Name:String,
 	pub Hash:String,
 	pub Source:String,
-	pub SubmissionID:i64,
+	pub ResourceType:ResourceType,
+	pub ResourceID:i64,
 }
 #[allow(nonstandard_style)]
 #[derive(Clone,Debug,serde::Serialize)]
 pub struct CreateScriptRequest<'a>{
 	pub Name:&'a str,
 	pub Source:&'a str,
+	pub ResourceType:ResourceType,
 	#[serde(skip_serializing_if="Option::is_none")]
-	pub SubmissionID:Option<i64>,
+	pub ResourceID:Option<i64>,
 }
 #[allow(nonstandard_style)]
 #[derive(Clone,Debug,serde::Deserialize)]
@@ -177,7 +190,7 @@ pub struct UpdateSubmissionModelRequest{
 #[derive(Clone,Debug)]
 pub struct ActionSubmissionUploadedRequest{
 	pub SubmissionID:i64,
-	pub TargetAssetID:Option<u64>,
+	pub UploadedAssetID:u64,
 }
 
 #[allow(nonstandard_style)]
diff --git a/validation/src/main.rs b/validation/src/main.rs
index 2ee02e1..681e529 100644
--- a/validation/src/main.rs
+++ b/validation/src/main.rs
@@ -1,10 +1,12 @@
 use futures::StreamExt;
 
-mod nats_types;
-mod validator;
-mod upload_new;
-mod upload_fix;
 mod message_handler;
+mod nats_types;
+mod types;
+mod uploader;
+mod upload_submission;
+mod validator;
+mod validate_submission;
 
 #[allow(dead_code)]
 #[derive(Debug)]
@@ -52,7 +54,7 @@ async fn main()->Result<(),StartupError>{
 			.get_or_create_consumer("validation",async_nats::jetstream::consumer::pull::Config{
 				name:Some("validation".to_owned()),
 				durable_name:Some("validation".to_owned()),
-				filter_subject:"maptest.submissions.>".to_owned(),
+				filter_subject:"maptest.>".to_owned(),
 				..Default::default()
 			}).await.map_err(StartupError::NatsConsumer)?
 			.messages().await.map_err(StartupError::NatsStream)
diff --git a/validation/src/message_handler.rs b/validation/src/message_handler.rs
index c0a5dc2..3b7bdb8 100644
--- a/validation/src/message_handler.rs
+++ b/validation/src/message_handler.rs
@@ -5,9 +5,8 @@ pub enum HandleMessageError{
 	DoubleAck(async_nats::Error),
 	Json(serde_json::Error),
 	UnknownSubject(String),
-	UploadNew(crate::upload_new::UploadError),
-	UploadFix(crate::upload_fix::UploadError),
-	Validation(crate::validator::ValidateError),
+	UploadSubmission(crate::upload_submission::UploadError),
+	ValidateSubmission(crate::validate_submission::ValidateSubmissionError),
 }
 impl std::fmt::Display for HandleMessageError{
 	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -23,9 +22,8 @@ fn from_slice<'a,T:serde::de::Deserialize<'a>>(slice:&'a [u8])->Result<T,HandleM
 }
 
 pub struct MessageHandler{
-	upload_new:crate::upload_new::Uploader,
-	upload_fix:crate::upload_fix::Uploader,
-	validator:crate::validator::Validator,
+	upload_submission:crate::upload_submission::Uploader,
+	validate_submission:crate::validate_submission::Validator,
 }
 
 impl MessageHandler{
@@ -35,18 +33,16 @@ impl MessageHandler{
 		api:submissions_api::internal::Context,
 	)->Self{
 		Self{
-			upload_new:crate::upload_new::Uploader::new(cookie_context.clone(),group_id,api.clone()),
-			upload_fix:crate::upload_fix::Uploader::new(cookie_context.clone(),group_id,api.clone()),
-			validator:crate::validator::Validator::new(cookie_context,api),
+			upload_submission:crate::upload_submission::Uploader::new(crate::uploader::Uploader::new(cookie_context.clone(),group_id,api.clone())),
+			validate_submission:crate::validate_submission::Validator::new(crate::validator::Validator::new(cookie_context,api)),
 		}
 	}
 	pub async fn handle_message_result(&self,message_result:MessageResult)->Result<(),HandleMessageError>{
 		let message=message_result.map_err(HandleMessageError::Messages)?;
 		message.double_ack().await.map_err(HandleMessageError::DoubleAck)?;
 		match message.subject.as_str(){
-			"maptest.submissions.uploadnew"=>self.upload_new.upload(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadNew),
-			"maptest.submissions.uploadfix"=>self.upload_fix.upload(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadFix),
-			"maptest.submissions.validate"=>self.validator.validate(from_slice(&message.payload)?).await.map_err(HandleMessageError::Validation),
+			"maptest.submissions.upload"=>self.upload_submission.upload(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadSubmission),
+			"maptest.submissions.validate"=>self.validate_submission.validate(from_slice(&message.payload)?).await.map_err(HandleMessageError::ValidateSubmission),
 			other=>Err(HandleMessageError::UnknownSubject(other.to_owned()))
 		}
 	}
diff --git a/validation/src/nats_types.rs b/validation/src/nats_types.rs
index de41e7d..dc2369c 100644
--- a/validation/src/nats_types.rs
+++ b/validation/src/nats_types.rs
@@ -6,7 +6,7 @@
 
 #[allow(nonstandard_style)]
 #[derive(serde::Deserialize)]
-pub struct ValidateRequest{
+pub struct ValidateSubmissionRequest{
 	// submission_id is passed back in the response message
 	pub SubmissionID:i64,
 	pub ModelID:u64,
@@ -14,21 +14,22 @@ pub struct ValidateRequest{
 	pub ValidatedModelID:Option<u64>,
 }
 
+#[allow(nonstandard_style)]
+#[derive(serde::Deserialize)]
+pub struct ValidateMapfixRequest{
+	// submission_id is passed back in the response message
+	pub MapfixID:i64,
+	pub ModelID:u64,
+	pub ModelVersion:u64,
+	pub ValidatedModelID:Option<u64>,
+}
+
 // Create a new map
 #[allow(nonstandard_style)]
 #[derive(serde::Deserialize)]
-pub struct UploadNewRequest{
+pub struct UploadSubmissionRequest{
 	pub SubmissionID:i64,
 	pub ModelID:u64,
 	pub ModelVersion:u64,
 	pub ModelName:String,
 }
-
-#[allow(nonstandard_style)]
-#[derive(serde::Deserialize)]
-pub struct UploadFixRequest{
-	pub SubmissionID:i64,
-	pub ModelID:u64,
-	pub ModelVersion:u64,
-	pub TargetAssetID:u64,
-}
diff --git a/validation/src/types.rs b/validation/src/types.rs
new file mode 100644
index 0000000..875c18e
--- /dev/null
+++ b/validation/src/types.rs
@@ -0,0 +1,4 @@
+pub enum ResourceID{
+	Mapfix(i64),
+	Submission(i64),
+}
diff --git a/validation/src/upload_fix.rs b/validation/src/upload_fix.rs
deleted file mode 100644
index 8aa3bac..0000000
--- a/validation/src/upload_fix.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use crate::nats_types::UploadFixRequest;
-
-#[allow(dead_code)]
-#[derive(Debug)]
-pub enum UploadError{
-	Get(rbx_asset::cookie::GetError),
-	Json(serde_json::Error),
-	Upload(rbx_asset::cookie::UploadError),
-	ApiActionSubmissionUploaded(submissions_api::Error),
-}
-impl std::fmt::Display for UploadError{
-	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
-		write!(f,"{self:?}")
-	}
-}
-impl std::error::Error for UploadError{}
-
-pub struct Uploader{
-	roblox_cookie:rbx_asset::cookie::CookieContext,
-	group_id:Option<u64>,
-	api_internal:submissions_api::internal::Context,
-}
-impl Uploader{
-	pub const fn new(
-		roblox_cookie:rbx_asset::cookie::CookieContext,
-		group_id:Option<u64>,
-		api_internal:submissions_api::internal::Context,
-	)->Self{
-		Self{
-			roblox_cookie,
-			group_id,
-			api_internal,
-		}
-	}
-	pub async fn upload(&self,upload_info:UploadFixRequest)->Result<(),UploadError>{
-		// download the map model version
-		let model_data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
-			asset_id:upload_info.ModelID,
-			version:Some(upload_info.ModelVersion),
-		}).await.map_err(UploadError::Get)?;
-
-		// upload the map to the strafesnet group
-		let _upload_response=self.roblox_cookie.upload(rbx_asset::cookie::UploadRequest{
-			assetid:upload_info.TargetAssetID,
-			groupId:self.group_id,
-			name:None,
-			description:None,
-			ispublic:None,
-			allowComments:None,
-		},model_data).await.map_err(UploadError::Upload)?;
-
-		// that's it, the database entry does not need to be changed.
-
-		// mark submission as uploaded, TargetAssetID is unchanged
-		self.api_internal.action_submission_uploaded(submissions_api::types::ActionSubmissionUploadedRequest{
-			SubmissionID:upload_info.SubmissionID,
-			TargetAssetID:None,
-		}).await.map_err(UploadError::ApiActionSubmissionUploaded)?;
-
-		Ok(())
-	}
-}
diff --git a/validation/src/upload_mapfix.rs b/validation/src/upload_mapfix.rs
new file mode 100644
index 0000000..71c37fd
--- /dev/null
+++ b/validation/src/upload_mapfix.rs
@@ -0,0 +1,50 @@
+use crate::nats_types::UploadMapfixRequest;
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub enum UploadError{
+	Get(rbx_asset::cookie::GetError),
+	Json(serde_json::Error),
+	Upload(rbx_asset::cookie::UploadError),
+	ApiActionMapfixUploaded(submissions_api::Error),
+}
+impl std::fmt::Display for UploadError{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for UploadError{}
+
+pub struct Uploader(crate::uploader::Uploader);
+impl Uploader{
+	pub const fn new(inner:crate::uploader::Uploader)->Self{
+		Self(inner)
+	}
+	pub async fn upload(&self,upload_info:UploadMapfixRequest)->Result<(),UploadError>{
+		let Self(uploader)=self;
+		// download the map model version
+		let model_data=uploader.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
+			asset_id:upload_info.ModelID,
+			version:Some(upload_info.ModelVersion),
+		}).await.map_err(UploadError::Get)?;
+
+		// upload the map to the strafesnet group
+		let _upload_response=uploader.roblox_cookie.upload(rbx_asset::cookie::UploadRequest{
+			assetid:upload_info.TargetAssetID,
+			groupId:uploader.group_id,
+			name:None,
+			description:None,
+			ispublic:None,
+			allowComments:None,
+		},model_data).await.map_err(UploadError::Upload)?;
+
+		// that's it, the database entry does not need to be changed.
+
+		// mark mapfix as uploaded, TargetAssetID is unchanged
+		uploader.api.action_mapfix_uploaded(submissions_api::types::ActionMapfixUploadedRequest{
+			MapfixID:upload_info.MapfixID,
+		}).await.map_err(UploadError::ApiActionMapfixUploaded)?;
+
+		Ok(())
+	}
+}
diff --git a/validation/src/upload_new.rs b/validation/src/upload_submission.rs
similarity index 56%
rename from validation/src/upload_new.rs
rename to validation/src/upload_submission.rs
index 6e4f074..d5c0983 100644
--- a/validation/src/upload_new.rs
+++ b/validation/src/upload_submission.rs
@@ -1,4 +1,4 @@
-use crate::nats_types::UploadNewRequest;
+use crate::nats_types::UploadSubmissionRequest;
 
 #[allow(dead_code)]
 #[derive(Debug)]
@@ -16,43 +16,32 @@ impl std::fmt::Display for UploadError{
 }
 impl std::error::Error for UploadError{}
 
-pub struct Uploader{
-	roblox_cookie:rbx_asset::cookie::CookieContext,
-	group_id:Option<u64>,
-	api:submissions_api::internal::Context,
-}
+pub struct Uploader(crate::uploader::Uploader);
 impl Uploader{
-	pub const fn new(
-		roblox_cookie:rbx_asset::cookie::CookieContext,
-		group_id:Option<u64>,
-		api:submissions_api::internal::Context,
-	)->Self{
-		Self{
-			roblox_cookie,
-			group_id,
-			api,
-		}
+	pub const fn new(inner:crate::uploader::Uploader)->Self{
+		Self(inner)
 	}
-	pub async fn upload(&self,upload_info:UploadNewRequest)->Result<(),UploadError>{
+	pub async fn upload(&self,upload_info:UploadSubmissionRequest)->Result<(),UploadError>{
+		let Self(uploader)=self;
 		// download the map model version
-		let model_data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
+		let model_data=uploader.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
 			asset_id:upload_info.ModelID,
 			version:Some(upload_info.ModelVersion),
 		}).await.map_err(UploadError::Get)?;
 
 		// upload the map to the strafesnet group
-		let upload_response=self.roblox_cookie.create(rbx_asset::cookie::CreateRequest{
+		let upload_response=uploader.roblox_cookie.create(rbx_asset::cookie::CreateRequest{
 			name:upload_info.ModelName.clone(),
 			description:"".to_owned(),
 			ispublic:false,
 			allowComments:false,
-			groupId:self.group_id,
+			groupId:uploader.group_id,
 		},model_data).await.map_err(UploadError::Create)?;
 
 		// note the asset id of the created model for later release, and mark the submission as uploaded
-		self.api.action_submission_uploaded(submissions_api::types::ActionSubmissionUploadedRequest{
+		uploader.api.action_submission_uploaded(submissions_api::types::ActionSubmissionUploadedRequest{
 			SubmissionID:upload_info.SubmissionID,
-			TargetAssetID:Some(upload_response.AssetId),
+			UploadedAssetID:upload_response.AssetId,
 		}).await.map_err(UploadError::ApiActionSubmissionUploaded)?;
 
 		Ok(())
diff --git a/validation/src/uploader.rs b/validation/src/uploader.rs
new file mode 100644
index 0000000..ca1ba06
--- /dev/null
+++ b/validation/src/uploader.rs
@@ -0,0 +1,18 @@
+pub struct Uploader{
+	pub(crate) roblox_cookie:rbx_asset::cookie::CookieContext,
+	pub(crate) group_id:Option<u64>,
+	pub(crate) api:submissions_api::internal::Context,
+}
+impl Uploader{
+	pub const fn new(
+		roblox_cookie:rbx_asset::cookie::CookieContext,
+		group_id:Option<u64>,
+		api:submissions_api::internal::Context,
+	)->Self{
+		Self{
+			roblox_cookie,
+			group_id,
+			api,
+		}
+	}
+}
diff --git a/validation/src/validate_mapfix.rs b/validation/src/validate_mapfix.rs
new file mode 100644
index 0000000..f9334d5
--- /dev/null
+++ b/validation/src/validate_mapfix.rs
@@ -0,0 +1,45 @@
+use crate::nats_types::ValidateMapfixRequest;
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub enum ValidateMapfixError{
+	ApiActionMapfixValidate(submissions_api::Error),
+}
+impl std::fmt::Display for ValidateMapfixError{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for ValidateMapfixError{}
+
+pub struct Validator(crate::validator::Validator);
+impl Validator{
+	pub const fn new(inner:crate::validator::Validator)->Self{
+		Self(inner)
+	}
+	pub async fn validate(&self,validate_info:ValidateMapfixRequest)->Result<(),ValidateMapfixError>{
+		let Self(validator)=self;
+
+		let mapfix_id=validate_info.MapfixID;
+		let validate_result=validator.validate(validate_info.into()).await;
+
+		// update the mapfix depending on the result
+		match &validate_result{
+			Ok(())=>{
+				// update the mapfix model status to validated
+				validator.api.action_mapfix_validated(
+					submissions_api::types::MapfixID(mapfix_id)
+				).await.map_err(ValidateMapfixError::ApiActionMapfixValidate)?;
+			},
+			Err(e)=>{
+				// update the mapfix model status to accepted
+				validator.api.action_mapfix_accepted(submissions_api::types::ActionMapfixAcceptedRequest{
+					MapfixID:mapfix_id,
+					StatusMessage:format!("{e}"),
+				}).await.map_err(ValidateMapfixError::ApiActionMapfixValidate)?;
+			},
+		}
+
+		Ok(())
+	}
+}
diff --git a/validation/src/validate_submission.rs b/validation/src/validate_submission.rs
new file mode 100644
index 0000000..51ae1f3
--- /dev/null
+++ b/validation/src/validate_submission.rs
@@ -0,0 +1,45 @@
+use crate::nats_types::ValidateSubmissionRequest;
+
+#[allow(dead_code)]
+#[derive(Debug)]
+pub enum ValidateSubmissionError{
+	ApiActionSubmissionValidate(submissions_api::Error),
+}
+impl std::fmt::Display for ValidateSubmissionError{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{self:?}")
+	}
+}
+impl std::error::Error for ValidateSubmissionError{}
+
+pub struct Validator(crate::validator::Validator);
+impl Validator{
+	pub const fn new(inner:crate::validator::Validator)->Self{
+		Self(inner)
+	}
+	pub async fn validate(&self,validate_info:ValidateSubmissionRequest)->Result<(),ValidateSubmissionError>{
+		let Self(validator)=self;
+
+		let submission_id=validate_info.SubmissionID;
+		let validate_result=validator.validate(validate_info.into()).await;
+
+		// update the submission depending on the result
+		match &validate_result{
+			Ok(())=>{
+				// update the submission model status to validated
+				validator.api.action_submission_validated(
+					submissions_api::types::SubmissionID(submission_id)
+				).await.map_err(ValidateSubmissionError::ApiActionSubmissionValidate)?;
+			},
+			Err(e)=>{
+				// update the submission model status to accepted
+				validator.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{
+					SubmissionID:submission_id,
+					StatusMessage:format!("{e}"),
+				}).await.map_err(ValidateSubmissionError::ApiActionSubmissionValidate)?;
+			},
+		}
+
+		Ok(())
+	}
+}
diff --git a/validation/src/validator.rs b/validation/src/validator.rs
index 3b9e58f..6babbf4 100644
--- a/validation/src/validator.rs
+++ b/validation/src/validator.rs
@@ -1,6 +1,7 @@
 use futures::TryStreamExt;
+use submissions_api::types::ResourceType;
 
-use crate::nats_types::ValidateRequest;
+use crate::types::ResourceID;
 
 const SCRIPT_CONCURRENCY:usize=16;
 
@@ -41,8 +42,8 @@ pub enum ValidateError{
 	ApiCreateScript(submissions_api::Error),
 	ApiCreateScriptPolicy(submissions_api::Error),
 	ApiGetScriptFromHash(submissions_api::types::SingleItemError),
+	ApiUpdateMapfixModelUnimplemented,
 	ApiUpdateSubmissionModel(submissions_api::Error),
-	ApiActionSubmissionValidate(submissions_api::Error),
 	ModelFileRootMustHaveOneChild,
 	ModelFileChildRefIsNil,
 	ModelFileEncode(rbx_binary::EncodeError),
@@ -56,9 +57,38 @@ impl std::fmt::Display for ValidateError{
 }
 impl std::error::Error for ValidateError{}
 
+#[allow(nonstandard_style)]
+pub struct ValidateRequest{
+	pub ModelID:u64,
+	pub ModelVersion:u64,
+	pub ValidatedModelID:Option<u64>,
+	pub ResourceID:ResourceID,
+}
+
+impl From<crate::nats_types::ValidateMapfixRequest> for ValidateRequest{
+	fn from(value:crate::nats_types::ValidateMapfixRequest)->Self{
+		Self{
+			ModelID:value.ModelID,
+			ModelVersion:value.ModelVersion,
+			ValidatedModelID:value.ValidatedModelID,
+			ResourceID:ResourceID::Mapfix(value.MapfixID),
+		}
+	}
+}
+impl From<crate::nats_types::ValidateSubmissionRequest> for ValidateRequest{
+	fn from(value:crate::nats_types::ValidateSubmissionRequest)->Self{
+		Self{
+			ModelID:value.ModelID,
+			ModelVersion:value.ModelVersion,
+			ValidatedModelID:value.ValidatedModelID,
+			ResourceID:ResourceID::Submission(value.SubmissionID),
+		}
+	}
+}
+
 pub struct Validator{
-	roblox_cookie:rbx_asset::cookie::CookieContext,
-	api:submissions_api::internal::Context,
+	pub(crate) roblox_cookie:rbx_asset::cookie::CookieContext,
+	pub(crate) api:submissions_api::internal::Context,
 }
 
 impl Validator{
@@ -72,29 +102,6 @@ impl Validator{
 		}
 	}
 	pub async fn validate(&self,validate_info:ValidateRequest)->Result<(),ValidateError>{
-		let submission_id=validate_info.SubmissionID;
-		let validate_result=self.validate_inner(validate_info).await;
-
-		// update the submission depending on the result
-		match &validate_result{
-			Ok(())=>{
-				// update the submission model status to validated
-				self.api.action_submission_validated(
-					submissions_api::types::SubmissionID(submission_id)
-				).await.map_err(ValidateError::ApiActionSubmissionValidate)?;
-			},
-			Err(e)=>{
-				// update the submission model status to accepted
-				self.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{
-					SubmissionID:submission_id,
-					StatusMessage:format!("{e}"),
-				}).await.map_err(ValidateError::ApiActionSubmissionValidate)?;
-			},
-		}
-
-		validate_result
-	}
-	pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),ValidateError>{
 		// download map
 		let data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
 			asset_id:validate_info.ModelID,
@@ -155,11 +162,17 @@ impl Validator{
 					},
 				};
 			}else{
+				let (resource_type,resource_id)=match validate_info.ResourceID{
+					ResourceID::Mapfix(mapfix_id)=>(ResourceType::Mapfix,mapfix_id),
+					ResourceID::Submission(submission_id)=>(ResourceType::Submission,submission_id),
+				};
+
 				// upload the script
 				let script=self.api.create_script(submissions_api::types::CreateScriptRequest{
 					Name:name.as_str(),
 					Source:source.as_str(),
-					SubmissionID:Some(validate_info.SubmissionID),
+					ResourceType:resource_type,
+					ResourceID:Some(resource_id),
 				}).await.map_err(ValidateError::ApiCreateScript)?;
 
 				// create a None policy (pending review by yours truly)
@@ -252,13 +265,21 @@ impl Validator{
 				response.AssetId
 			};
 
-			// update the submission to use the validated model
-			self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
-				SubmissionID:validate_info.SubmissionID,
-				ModelID:model_id,
-				ModelVersion:1, //TODO
-			}).await.map_err(ValidateError::ApiUpdateSubmissionModel)?;
-		};
+			match validate_info.ResourceID{
+				ResourceID::Mapfix(_mapfix_id)=>{
+					// update the mapfix to use the validated model
+					return Err(ValidateError::ApiUpdateMapfixModelUnimplemented);
+				},
+				ResourceID::Submission(submission_id)=>{
+					// update the submission to use the validated model
+					self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
+						SubmissionID:submission_id,
+						ModelID:model_id,
+						ModelVersion:1, //TODO
+					}).await.map_err(ValidateError::ApiUpdateSubmissionModel)?;
+				},
+			}
+		}
 
 		Ok(())
 	}
diff --git a/web/src/app/submit/page.tsx b/web/src/app/submit/page.tsx
index 6f3c1b7..38cc9e3 100644
--- a/web/src/app/submit/page.tsx
+++ b/web/src/app/submit/page.tsx
@@ -1,6 +1,6 @@
 "use client"
 
-import { FormControl, FormControlLabel, Button, TextField, Checkbox } from "@mui/material"
+import { Button, TextField } from "@mui/material"
 
 import GameSelection from "./_game";
 import SendIcon from '@mui/icons-material/Send';
@@ -15,7 +15,6 @@ interface SubmissionPayload {
 	GameID: number;
 	AssetID: number;
 	AssetVersion: number;
-	TargetAssetID: number;
 }
 interface IdResponse {
 	ID: number;
@@ -23,7 +22,6 @@ interface IdResponse {
 
 export default function SubmissionInfoPage() {
 	const [game, setGame] = useState(1);
-	const [isFixingMap, setIsFixingMap] = useState(false);
 
 	const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
 		event.preventDefault();
@@ -37,7 +35,6 @@ export default function SubmissionInfoPage() {
 			GameID: game,
 			AssetID: Number((formData.get("asset-id") as string) ?? "0"),
 			AssetVersion: 0,
-			TargetAssetID: isFixingMap ? Number((formData.get("target-asset-id") as string) ?? "0") : 0,
 		};
 
 		console.log(payload)
@@ -84,15 +81,6 @@ export default function SubmissionInfoPage() {
 					<TextField className="form-field" id="asset-id"     name="asset-id"     label="Asset ID"     variant="outlined"/>
 					{/* I think this is Quat's job to figure this one out (to be set when someone clicks review(?)) */} {/* <TextField className="form-field" id="asset-version" label="Asset Version" variant="outlined"/> */}
 					<GameSelection game={game} setGame={setGame} />
-					<FormControl>
-						<FormControlLabel control={<Checkbox sx={{
-							color: "#646464",
-							'&.Mui-checked': {
-								color: "#66BB6A",
-							},
-						}} onChange={(e) => setIsFixingMap(e.target.checked)} />} label="Fixing an Existing Map?" />
-					</FormControl>
-					<TextField className="form-field" id="target-asset-id" name="target-asset-id" label="Target Asset ID (group model)" variant="outlined"/>
 					<span className="spacer form-spacer"></span>
 					<Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{
 						width: "400px",