Repository: furiko-io/furiko
Pull request #36 (2022-04-08 19:09:28)

chore: Use config.furiko.io/v1alpha1 for all Config API types
We change the `config.furiko.io/v1` API group to `config.furiko.io/v1alpha1` first.

The API version of `config.furiko.io` is NOT the same as the API version of other APIs, e.g. `execution.furiko.io`. It is simply meant to signify that the configuration format is currently in alpha state.


Patch:
diff --git a/apis/config/v1/configurationname_types.go b/apis/config/v1alpha1/configurationname_types.go
similarity index 67%
rename from apis/config/v1/configurationname_types.go
rename to apis/config/v1alpha1/configurationname_types.go
index 608b264..b030597 100644
--- a/apis/config/v1/configurationname_types.go
+++ b/apis/config/v1alpha1/configurationname_types.go
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-package v1
+package v1alpha1
 
-// ConfigName denotes a named configuration, and refers to the name in the
-// ConfigMap configuration.
+// ConfigName refers to the name of a dynamic configuration.
 type ConfigName string
 
 const (
-	ConfigNameJobController  ConfigName = "job-controller"
-	ConfigNameCronController ConfigName = "cron-controller"
+	// JobExecutionConfigName refers to JobExecutionConfig.
+	JobExecutionConfigName ConfigName = "execution-job"
+
+	// CronExecutionConfigName refers to CronExecutionConfig.
+	CronExecutionConfigName ConfigName = "execution-cron"
 )
diff --git a/apis/config/v1/doc.go b/apis/config/v1alpha1/doc.go
similarity index 97%
rename from apis/config/v1/doc.go
rename to apis/config/v1alpha1/doc.go
index 3427825..16bd464 100644
--- a/apis/config/v1/doc.go
+++ b/apis/config/v1alpha1/doc.go
@@ -17,4 +17,4 @@
 // Package v1 contains API Schema definitions for the config v1 API group
 // +kubebuilder:object:generate=true
 // +groupName=config.furiko.io
-package v1
+package v1alpha1
diff --git a/apis/config/v1/dynamicconfig_types.go b/apis/config/v1alpha1/dynamicconfig_types.go
similarity index 94%
rename from apis/config/v1/dynamicconfig_types.go
rename to apis/config/v1alpha1/dynamicconfig_types.go
index 48b2f71..e9dc1e1 100644
--- a/apis/config/v1/dynamicconfig_types.go
+++ b/apis/config/v1alpha1/dynamicconfig_types.go
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package v1
+package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -23,8 +23,8 @@ import (
 // +kubebuilder:object:root=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
-// JobControllerConfig defines runtime configuration for the Job controller.
-type JobControllerConfig struct {
+// JobExecutionConfig defines runtime global configuration for Jobs in the cluster.
+type JobExecutionConfig struct {
 	metav1.TypeMeta `json:",inline"`
 
 	// DefaultTTLSecondsAfterFinished is the default time-to-live (TTL) for a Job
@@ -64,8 +64,8 @@ type JobControllerConfig struct {
 // +kubebuilder:object:root=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
 
-// CronControllerConfig defines runtime configuration for the Cron controller.
-type CronControllerConfig struct {
+// CronExecutionConfig defines runtime global configuration for Cron in the cluster.
+type CronExecutionConfig struct {
 	metav1.TypeMeta `json:",inline"`
 
 	// CronFormat specifies the format used to parse cron expressions. Select
@@ -147,5 +147,5 @@ type CronControllerConfig struct {
 }
 
 func init() {
-	SchemeBuilder.Register(&JobControllerConfig{}, &CronControllerConfig{})
+	SchemeBuilder.Register(&JobExecutionConfig{}, &CronExecutionConfig{})
 }
diff --git a/apis/config/v1/groupversion_info.go b/apis/config/v1alpha1/groupversion_info.go
similarity index 98%
rename from apis/config/v1/groupversion_info.go
rename to apis/config/v1alpha1/groupversion_info.go
index 0828e7f..71227d6 100644
--- a/apis/config/v1/groupversion_info.go
+++ b/apis/config/v1alpha1/groupversion_info.go
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package v1
+package v1alpha1
 
 import (
 	"k8s.io/apimachinery/pkg/runtime/schema"
diff --git a/apis/config/v1/managerconfig_types.go b/apis/config/v1alpha1/managerconfig_types.go
similarity index 99%
rename from apis/config/v1/managerconfig_types.go
rename to apis/config/v1alpha1/managerconfig_types.go
index a710668..da3bccd 100644
--- a/apis/config/v1/managerconfig_types.go
+++ b/apis/config/v1alpha1/managerconfig_types.go
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package v1
+package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/apis/config/v1/webhookconfig_types.go b/apis/config/v1alpha1/webhookconfig_types.go
similarity index 99%
rename from apis/config/v1/webhookconfig_types.go
rename to apis/config/v1alpha1/webhookconfig_types.go
index 261b9e2..d33b308 100644
--- a/apis/config/v1/webhookconfig_types.go
+++ b/apis/config/v1alpha1/webhookconfig_types.go
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package v1
+package v1alpha1
 
 import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/apis/config/v1/zz_generated.deepcopy.go b/apis/config/v1alpha1/zz_generated.deepcopy.go
similarity index 95%
rename from apis/config/v1/zz_generated.deepcopy.go
rename to apis/config/v1alpha1/zz_generated.deepcopy.go
index dc253ff..19eb58d 100644
--- a/apis/config/v1/zz_generated.deepcopy.go
+++ b/apis/config/v1alpha1/zz_generated.deepcopy.go
@@ -19,7 +19,7 @@
 
 // Code generated by controller-gen. DO NOT EDIT.
 
-package v1
+package v1alpha1
 
 import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
@@ -87,7 +87,7 @@ func (in *ControllerManagerConfigSpec) DeepCopy() *ControllerManagerConfigSpec {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *CronControllerConfig) DeepCopyInto(out *CronControllerConfig) {
+func (in *CronExecutionConfig) DeepCopyInto(out *CronExecutionConfig) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	if in.CronHashNames != nil {
@@ -117,18 +117,18 @@ func (in *CronControllerConfig) DeepCopyInto(out *CronControllerConfig) {
 	}
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronControllerConfig.
-func (in *CronControllerConfig) DeepCopy() *CronControllerConfig {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronExecutionConfig.
+func (in *CronExecutionConfig) DeepCopy() *CronExecutionConfig {
 	if in == nil {
 		return nil
 	}
-	out := new(CronControllerConfig)
+	out := new(CronExecutionConfig)
 	in.DeepCopyInto(out)
 	return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *CronControllerConfig) DeepCopyObject() runtime.Object {
+func (in *CronExecutionConfig) DeepCopyObject() runtime.Object {
 	if c := in.DeepCopy(); c != nil {
 		return c
 	}
@@ -302,7 +302,7 @@ func (in *HealthSpec) DeepCopy() *HealthSpec {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *JobControllerConfig) DeepCopyInto(out *JobControllerConfig) {
+func (in *JobExecutionConfig) DeepCopyInto(out *JobExecutionConfig) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	if in.DefaultTTLSecondsAfterFinished != nil {
@@ -327,18 +327,18 @@ func (in *JobControllerConfig) DeepCopyInto(out *JobControllerConfig) {
 	}
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobControllerConfig.
-func (in *JobControllerConfig) DeepCopy() *JobControllerConfig {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobExecutionConfig.
+func (in *JobExecutionConfig) DeepCopy() *JobExecutionConfig {
 	if in == nil {
 		return nil
 	}
-	out := new(JobControllerConfig)
+	out := new(JobExecutionConfig)
 	in.DeepCopyInto(out)
 	return out
 }
 
 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *JobControllerConfig) DeepCopyObject() runtime.Object {
+func (in *JobExecutionConfig) DeepCopyObject() runtime.Object {
 	if c := in.DeepCopy(); c != nil {
 		return c
 	}
diff --git a/cmd/execution-controller/main.go b/cmd/execution-controller/main.go
index 09e6e1e..4b17bbb 100644
--- a/cmd/execution-controller/main.go
+++ b/cmd/execution-controller/main.go
@@ -25,7 +25,7 @@ import (
 	"k8s.io/klog/v2"
 	ctrl "sigs.k8s.io/controller-runtime"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/bootstrap"
 	"github.com/furiko-io/furiko/pkg/execution/controllers/croncontroller"
 	"github.com/furiko-io/furiko/pkg/execution/controllers/jobconfigcontroller"
@@ -69,7 +69,7 @@ func main() {
 	// ConfigMap or some dynamic configuration source.
 	//
 	// Changes will not take effect until the server is restarted.
-	var options configv1.ExecutionControllerConfig
+	var options configv1alpha1.ExecutionControllerConfig
 	if configFile != "" {
 		klog.Infof("loading configuration from %v", configFile)
 		if err := bootstrap.UnmarshalFromFile(configFile, &options); err != nil {
@@ -122,7 +122,7 @@ func main() {
 	for _, factory := range GetControllerFactories() {
 		concurrencySpec := options.ControllerConcurrency
 		if concurrencySpec == nil {
-			concurrencySpec = &configv1.ExecutionControllerConcurrencySpec{}
+			concurrencySpec = &configv1alpha1.ExecutionControllerConcurrencySpec{}
 		}
 		klog.Infof("setting up controller %v", factory.Name())
 		controller, err := factory.New(ctrlContext, concurrencySpec)
@@ -163,7 +163,7 @@ func main() {
 type ControllerFactory interface {
 	Name() string
 	New(ctx controllercontext.ContextInterface,
-		concurrency *configv1.ExecutionControllerConcurrencySpec) (controllermanager.Controller, error)
+		concurrency *configv1alpha1.ExecutionControllerConcurrencySpec) (controllermanager.Controller, error)
 }
 
 // GetControllerFactories returns a list of ControllerFactory implementations
diff --git a/cmd/execution-webhook/main.go b/cmd/execution-webhook/main.go
index 976cc78..cb60433 100644
--- a/cmd/execution-webhook/main.go
+++ b/cmd/execution-webhook/main.go
@@ -25,7 +25,7 @@ import (
 	"k8s.io/klog/v2"
 	ctrl "sigs.k8s.io/controller-runtime"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/bootstrap"
 	"github.com/furiko-io/furiko/pkg/execution/webhooks/jobconfigmutatingwebhook"
 	"github.com/furiko-io/furiko/pkg/execution/webhooks/jobconfigvalidatingwebhook"
@@ -65,7 +65,7 @@ func main() {
 	// ConfigMap or some dynamic configuration source.
 	//
 	// Changes will not take effect until the server is restarted.
-	var options configv1.ExecutionWebhookConfig
+	var options configv1alpha1.ExecutionWebhookConfig
 	if configFile != "" {
 		klog.Infof("loading configuration from %v", configFile)
 		if err := bootstrap.UnmarshalFromFile(configFile, &options); err != nil {
diff --git a/config/execution/controller/config.yaml b/config/execution/controller/config.yaml
index 67b3caa..8af8f2f 100644
--- a/config/execution/controller/config.yaml
+++ b/config/execution/controller/config.yaml
@@ -2,7 +2,7 @@
 # These values are used for bootstrapping of the controller manager at startup,
 # so changing any values here require a restart of execution-controller in order
 # to take effect.
-apiVersion: config.furiko.io/v1
+apiVersion: config.furiko.io/v1alpha1
 kind: ExecutionControllerConfig
 
 # defaultResync controls the default resync duration.
diff --git a/config/execution/dynamic/config.yaml b/config/execution/dynamic/config.yaml
index fd06c57..5c87f4f 100644
--- a/config/execution/dynamic/config.yaml
+++ b/config/execution/dynamic/config.yaml
@@ -1,36 +1,41 @@
-# Here we define the dynamic config for execution-controller.
-# We can tune several knobs in execution-controller without requiring a restart.
-# Each file in the ConfigMap defines a group of configuration knobs available for
-# the user to tweak as desired. As a start, we have populated a set of sane default
-# values for you.
 apiVersion: v1
 kind: ConfigMap
 metadata:
   name: dynamic-config
 data:
-  job-controller: |
+  execution-job: |
+    # Here we define the dynamic config for execution-controller without requiring
+    # a restart. This config file configures dynamic configuration for Jobs.
+    apiVersion: config.furiko.io/v1alpha1
+    kind: JobExecutionConfig
+
     # defaultTTLSecondsAfterFinished is the default time-to-live (TTL) for a Job
     # after it has finished. Lower this value to reduce the strain on the
-    # cluster/kubelet. This field can be set separately on each Job as well.
+    # cluster/kubelet. Set to 0 to delete immediately after the Job is finished.
     defaultTTLSecondsAfterFinished: 3600
 
     # defaultPendingTimeoutSeconds is default timeout to use if job does not
     # specify the pending timeout. By default, this is a non-zero value to prevent
-    # permanently stuck jobs. To disable default pending timeout, set this to 0 or
-    # a negative number.
+    # permanently stuck jobs. To disable default pending timeout, set this to 0.
     defaultPendingTimeoutSeconds: 900
 
     # deleteKillingTasksTimeoutSeconds is the duration we delete the task to kill
     # it instead of using active deadline, if previous efforts were ineffective.
+    # Set this value to 0 to immediately use deletion.
     deleteKillingTasksTimeoutSeconds: 180
 
     # forceDeleteKillingTasksTimeoutSeconds is the duration before we use force
     # deletion instead of normal deletion. This timeout is computed from the
     # deletionTimestamp of the object, which may also include an additional delay
-    # of deletionGracePeriodSeconds.
+    # of deletionGracePeriodSeconds. Set this value to 0 to disable force deletion.
     forceDeleteKillingTasksTimeoutSeconds: 120
 
-  cron-controller: |
+  execution-cron: |
+    # Here we define the dynamic config for execution-controller without requiring
+    # a restart. This config file configures dynamic configuration for Cron.
+    apiVersion: config.furiko.io/v1alpha1
+    kind: CronExecutionConfig
+
     # cronFormat specifies the format used to parse cron expressions. Select
     # between "standard" (default) or "quartz".
     cronFormat: "standard"
@@ -76,7 +81,8 @@ data:
     # maxMissedSchedules defines a maximum number of jobs that the controller
     # should back-schedule, or attempt to create after coming back up from
     # downtime. Having a sane value here would prevent a thundering herd of jobs
-    # being scheduled that would exhaust resources in the cluster.
+    # being scheduled that would exhaust resources in the cluster. Set this to 0 to
+    # disable back-scheduling.
     maxMissedSchedules: 5
 
     # maxDowntimeThresholdSeconds defines the maximum downtime that the controller
diff --git a/config/execution/webhook/config.yaml b/config/execution/webhook/config.yaml
index 18a9327..d926271 100644
--- a/config/execution/webhook/config.yaml
+++ b/config/execution/webhook/config.yaml
@@ -2,7 +2,7 @@
 # These values are used for bootstrapping of the webhook server at startup,
 # so changing any values here require a restart of execution-webhook in order
 # to take effect.
-apiVersion: config.furiko.io/v1
+apiVersion: config.furiko.io/v1alpha1
 kind: ExecutionWebhookConfig
 
 # defaultResync controls the default resync duration.
diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go
index 03db3ce..34d875b 100644
--- a/pkg/config/defaults.go
+++ b/pkg/config/defaults.go
@@ -19,18 +19,18 @@ package config
 import (
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 var (
-	DefaultJobControllerConfig = &configv1.JobControllerConfig{
+	DefaultJobControllerConfig = &configv1alpha1.JobExecutionConfig{
 		DefaultTTLSecondsAfterFinished:        pointer.Int64(3600),
 		DefaultPendingTimeoutSeconds:          pointer.Int64(900),
 		DeleteKillingTasksTimeoutSeconds:      pointer.Int64(180),
 		ForceDeleteKillingTasksTimeoutSeconds: pointer.Int64(120),
 	}
 
-	DefaultCronControllerConfig = &configv1.CronControllerConfig{
+	DefaultCronControllerConfig = &configv1alpha1.CronExecutionConfig{
 		CronFormat:                  "standard",
 		CronHashNames:               pointer.Bool(true),
 		CronHashSecondsByDefault:    pointer.Bool(false),
diff --git a/pkg/execution/controllers/croncontroller/controller.go b/pkg/execution/controllers/croncontroller/controller.go
index 7c8b39f..53b3b9c 100644
--- a/pkg/execution/controllers/croncontroller/controller.go
+++ b/pkg/execution/controllers/croncontroller/controller.go
@@ -30,7 +30,7 @@ import (
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 	executioninformers "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/execution/v1alpha1"
@@ -105,7 +105,7 @@ func NewRecorder(context controllercontext.ContextInterface) record.EventRecorde
 
 func NewController(
 	ctrlContext controllercontext.ContextInterface,
-	concurrency *configv1.Concurrency,
+	concurrency *configv1alpha1.Concurrency,
 ) (*Controller, error) {
 	ctrl := &Controller{
 		Context: NewContext(ctrlContext),
diff --git a/pkg/execution/controllers/croncontroller/cron.go b/pkg/execution/controllers/croncontroller/cron.go
index 9c194fb..d26cb9e 100644
--- a/pkg/execution/controllers/croncontroller/cron.go
+++ b/pkg/execution/controllers/croncontroller/cron.go
@@ -28,7 +28,7 @@ import (
 
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/core/tzutils"
 	"github.com/furiko-io/furiko/pkg/execution/util/cronparser"
@@ -135,7 +135,7 @@ func (w *CronWorker) flushKeys() {
 // syncOne reconciles a single JobConfig and enqueues Jobs to be created.
 func (w *CronWorker) syncOne(
 	jobConfig *execution.JobConfig,
-	cfg *configv1.CronControllerConfig,
+	cfg *configv1alpha1.CronExecutionConfig,
 	parser *cronparser.Parser,
 ) error {
 	schedule := jobConfig.Spec.Schedule
@@ -227,7 +227,7 @@ func (w *CronWorker) enqueueJob(jobConfig *execution.JobConfig, scheduleTime tim
 }
 
 // getTimezone returns the timezone for the given JobConfig.
-func (w *CronWorker) getTimezone(cronSchedule *execution.CronSchedule, cfg *configv1.CronControllerConfig) string {
+func (w *CronWorker) getTimezone(cronSchedule *execution.CronSchedule, cfg *configv1alpha1.CronExecutionConfig) string {
 	// Read from spec.
 	if cronSchedule.Timezone != "" {
 		return cronSchedule.Timezone
diff --git a/pkg/execution/controllers/croncontroller/factory.go b/pkg/execution/controllers/croncontroller/factory.go
index b293135..a029d3c 100644
--- a/pkg/execution/controllers/croncontroller/factory.go
+++ b/pkg/execution/controllers/croncontroller/factory.go
@@ -17,7 +17,7 @@
 package croncontroller
 
 import (
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllermanager"
 )
diff --git a/pkg/execution/controllers/croncontroller/reconciler.go b/pkg/execution/controllers/croncontroller/reconciler.go
index 5fb14d9..8955c17 100644
--- a/pkg/execution/controllers/croncontroller/reconciler.go
+++ b/pkg/execution/controllers/croncontroller/reconciler.go
@@ -26,7 +26,7 @@ import (
 	"k8s.io/klog/v2"
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllerutil"
@@ -39,7 +39,7 @@ import (
 // same JobConfig concurrently.
 type Reconciler struct {
 	*Context
-	concurrency *configv1.Concurrency
+	concurrency *configv1alpha1.Concurrency
 	client      ExecutionControlInterface
 	store       controllercontext.ActiveJobStore
 }
@@ -48,7 +48,7 @@ func NewReconciler(
 	ctrlContext *Context,
 	client ExecutionControlInterface,
 	store controllercontext.ActiveJobStore,
-	concurrency *configv1.Concurrency,
+	concurrency *configv1alpha1.Concurrency,
 ) *Reconciler {
 	return &Reconciler{
 		Context:     ctrlContext,
diff --git a/pkg/execution/controllers/jobconfigcontroller/controller.go b/pkg/execution/controllers/jobconfigcontroller/controller.go
index 2d60b20..e239bf1 100644
--- a/pkg/execution/controllers/jobconfigcontroller/controller.go
+++ b/pkg/execution/controllers/jobconfigcontroller/controller.go
@@ -29,7 +29,7 @@ import (
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/execution/taskexecutor"
 	"github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 	executioninformers "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/execution/v1alpha1"
@@ -96,7 +96,7 @@ func NewContext(context controllercontext.ContextInterface) *Context {
 
 func NewController(
 	ctrlContext controllercontext.ContextInterface,
-	concurrency *configv1.Concurrency,
+	concurrency *configv1alpha1.Concurrency,
 ) (*Controller, error) {
 	ctrl := &Controller{
 		Context: NewContext(ctrlContext),
diff --git a/pkg/execution/controllers/jobconfigcontroller/factory.go b/pkg/execution/controllers/jobconfigcontroller/factory.go
index 1524849..cbdfa89 100644
--- a/pkg/execution/controllers/jobconfigcontroller/factory.go
+++ b/pkg/execution/controllers/jobconfigcontroller/factory.go
@@ -17,7 +17,7 @@
 package jobconfigcontroller
 
 import (
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllermanager"
 )
diff --git a/pkg/execution/controllers/jobconfigcontroller/reconciler.go b/pkg/execution/controllers/jobconfigcontroller/reconciler.go
index b279f81..dcbc691 100644
--- a/pkg/execution/controllers/jobconfigcontroller/reconciler.go
+++ b/pkg/execution/controllers/jobconfigcontroller/reconciler.go
@@ -29,7 +29,7 @@ import (
 	"k8s.io/klog/v2"
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllerutil"
 	"github.com/furiko-io/furiko/pkg/utils/execution/job"
@@ -40,10 +40,10 @@ import (
 
 type Reconciler struct {
 	*Context
-	concurrency *configv1.Concurrency
+	concurrency *configv1alpha1.Concurrency
 }
 
-func NewReconciler(ctrlContext *Context, concurrency *configv1.Concurrency) *Reconciler {
+func NewReconciler(ctrlContext *Context, concurrency *configv1alpha1.Concurrency) *Reconciler {
 	return &Reconciler{
 		Context:     ctrlContext,
 		concurrency: concurrency,
diff --git a/pkg/execution/controllers/jobcontroller/controller.go b/pkg/execution/controllers/jobcontroller/controller.go
index 875c7f7..60817f2 100644
--- a/pkg/execution/controllers/jobcontroller/controller.go
+++ b/pkg/execution/controllers/jobcontroller/controller.go
@@ -30,7 +30,7 @@ import (
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/execution/taskexecutor"
 	"github.com/furiko-io/furiko/pkg/execution/tasks"
 	"github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
@@ -108,7 +108,7 @@ func NewContextWithRecorder(context controllercontext.ContextInterface, recorder
 
 func NewController(
 	ctrlContext controllercontext.ContextInterface,
-	concurrency *configv1.Concurrency,
+	concurrency *configv1alpha1.Concurrency,
 ) (*Controller, error) {
 	ctrl := &Controller{
 		Context: NewContext(ctrlContext),
diff --git a/pkg/execution/controllers/jobcontroller/factory.go b/pkg/execution/controllers/jobcontroller/factory.go
index a998d6a..9d2cc34 100644
--- a/pkg/execution/controllers/jobcontroller/factory.go
+++ b/pkg/execution/controllers/jobcontroller/factory.go
@@ -17,7 +17,7 @@
 package jobcontroller
 
 import (
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllermanager"
 )
diff --git a/pkg/execution/controllers/jobcontroller/reconciler.go b/pkg/execution/controllers/jobcontroller/reconciler.go
index e7e98cd..72c5ea7 100644
--- a/pkg/execution/controllers/jobcontroller/reconciler.go
+++ b/pkg/execution/controllers/jobcontroller/reconciler.go
@@ -29,7 +29,7 @@ import (
 	"k8s.io/klog/v2"
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	executiongroup "github.com/furiko-io/furiko/apis/execution"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	rerrors "github.com/furiko-io/furiko/pkg/errors"
@@ -45,10 +45,10 @@ import (
 type Reconciler struct {
 	*Context
 	client      *ExecutionControl
-	concurrency *configv1.Concurrency
+	concurrency *configv1alpha1.Concurrency
 }
 
-func NewReconciler(ctrlContext *Context, concurrency *configv1.Concurrency) *Reconciler {
+func NewReconciler(ctrlContext *Context, concurrency *configv1alpha1.Concurrency) *Reconciler {
 	worker := &Reconciler{
 		Context:     ctrlContext,
 		concurrency: concurrency,
@@ -124,7 +124,7 @@ func (w *Reconciler) SyncOne(ctx context.Context, namespace, name string, _ int)
 // sync performs the main logic for the controller.
 // IMPORTANT: This method MUST returns the latest Job we want to update, even if an error was met midway.
 func (w *Reconciler) sync(
-	ctx context.Context, rj *execution.Job, cfg *configv1.JobControllerConfig, trace *utiltrace.Trace,
+	ctx context.Context, rj *execution.Job, cfg *configv1alpha1.JobExecutionConfig, trace *utiltrace.Trace,
 ) (*execution.Job, error) {
 	// Main logic: Perform task creation/adoption and reconciliation. If Job is not
 	// started or is being deleted, this is a no-op.
@@ -161,7 +161,7 @@ func (w *Reconciler) sync(
 
 // syncJobTasks performs the main reconciliation logic for managing tasks and reconciling the status with the tasks.
 func (w *Reconciler) syncJobTasks(
-	ctx context.Context, rj *execution.Job, cfg *configv1.JobControllerConfig, trace *utiltrace.Trace,
+	ctx context.Context, rj *execution.Job, cfg *configv1alpha1.JobExecutionConfig, trace *utiltrace.Trace,
 ) (*execution.Job, error) {
 	taskMgr, err := w.tasks.ForJob(rj)
 	if err != nil {
@@ -427,7 +427,7 @@ func (w *Reconciler) createTask(ctx context.Context, rj *execution.Job) (jobtask
 // handlePendingTasks looks for pending tasks that have exceeded their pending timeout, and subsequently
 // kill those tasks.
 func (w *Reconciler) handlePendingTasks(ctx context.Context, rj *execution.Job, tasks []jobtasks.Task,
-	cfg *configv1.JobControllerConfig) error {
+	cfg *configv1alpha1.JobExecutionConfig) error {
 	now := ktime.Now().Time
 
 	pendingTimeout := jobutil.GetPendingTimeout(rj, cfg)
@@ -539,7 +539,7 @@ func (w *Reconciler) handleKillJob(ctx context.Context, rj *execution.Job, tasks
 
 // handleDeleteKillingTasks uses deletion to kill tasks if prior efforts to set kill timestamp on tasks are ineffective.
 func (w *Reconciler) handleDeleteKillingTasks(
-	ctx context.Context, rj *execution.Job, tasks []jobtasks.Task, cfg *configv1.JobControllerConfig,
+	ctx context.Context, rj *execution.Job, tasks []jobtasks.Task, cfg *configv1alpha1.JobExecutionConfig,
 ) (*execution.Job, error) {
 	timeout := jobutil.GetDeleteKillingTimeout(cfg)
 	needDelete := make([]jobtasks.Task, 0, len(tasks))
@@ -624,7 +624,7 @@ func (w *Reconciler) handleDeleteKillingTasks(
 // handleForceDeleteKillingTasks will perform non-graceful deletion of tasks if it cannot be deleted gracefully.
 // For example, when kubelet is not running, normal deletion will not be effective.
 func (w *Reconciler) handleForceDeleteKillingTasks(
-	ctx context.Context, rj *execution.Job, tasks []jobtasks.Task, cfg *configv1.JobControllerConfig,
+	ctx context.Context, rj *execution.Job, tasks []jobtasks.Task, cfg *configv1alpha1.JobExecutionConfig,
 ) (*execution.Job, error) {
 	timeout := jobutil.GetForceDeleteKillingTimeout(cfg)
 
@@ -714,7 +714,7 @@ func (w *Reconciler) handleForceDeleteKillingTasks(
 func (w *Reconciler) handleTTLAfterFinished(
 	ctx context.Context,
 	rj *execution.Job,
-	cfg *configv1.JobControllerConfig,
+	cfg *configv1alpha1.JobExecutionConfig,
 ) error {
 	ttl := jobutil.GetTTLAfterFinished(rj, cfg)
 
diff --git a/pkg/execution/controllers/jobqueuecontroller/controller.go b/pkg/execution/controllers/jobqueuecontroller/controller.go
index 92af5aa..f6b0d95 100644
--- a/pkg/execution/controllers/jobqueuecontroller/controller.go
+++ b/pkg/execution/controllers/jobqueuecontroller/controller.go
@@ -29,7 +29,7 @@ import (
 	"k8s.io/client-go/util/workqueue"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 	executioninformers "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
@@ -91,7 +91,7 @@ func NewContext(context controllercontext.ContextInterface) *Context {
 
 func NewController(
 	ctrlContext controllercontext.ContextInterface,
-	concurrency *configv1.Concurrency,
+	concurrency *configv1alpha1.Concurrency,
 ) (*Controller, error) {
 	ctrl := &Controller{
 		Context: NewContext(ctrlContext),
diff --git a/pkg/execution/controllers/jobqueuecontroller/factory.go b/pkg/execution/controllers/jobqueuecontroller/factory.go
index 8375236..a903715 100644
--- a/pkg/execution/controllers/jobqueuecontroller/factory.go
+++ b/pkg/execution/controllers/jobqueuecontroller/factory.go
@@ -17,7 +17,7 @@
 package jobqueuecontroller
 
 import (
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllermanager"
 )
diff --git a/pkg/execution/controllers/jobqueuecontroller/reconciler_independent.go b/pkg/execution/controllers/jobqueuecontroller/reconciler_independent.go
index 39f4b87..d7f8cde 100644
--- a/pkg/execution/controllers/jobqueuecontroller/reconciler_independent.go
+++ b/pkg/execution/controllers/jobqueuecontroller/reconciler_independent.go
@@ -26,18 +26,18 @@ import (
 	"k8s.io/klog/v2"
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllerutil"
 )
 
 // IndependentReconciler reconciles independent Jobs that do not have any JobConfig.
 type IndependentReconciler struct {
 	*Context
-	concurrency *configv1.Concurrency
+	concurrency *configv1alpha1.Concurrency
 	client      JobControlInterface
 }
 
-func NewIndependentReconciler(ctrlContext *Context, concurrency *configv1.Concurrency) *IndependentReconciler {
+func NewIndependentReconciler(ctrlContext *Context, concurrency *configv1alpha1.Concurrency) *IndependentReconciler {
 	reconciler := &IndependentReconciler{
 		Context:     ctrlContext,
 		concurrency: concurrency,
diff --git a/pkg/execution/controllers/jobqueuecontroller/reconciler_perjobconfig.go b/pkg/execution/controllers/jobqueuecontroller/reconciler_perjobconfig.go
index 11182a9..5c302d0 100644
--- a/pkg/execution/controllers/jobqueuecontroller/reconciler_perjobconfig.go
+++ b/pkg/execution/controllers/jobqueuecontroller/reconciler_perjobconfig.go
@@ -29,7 +29,7 @@ import (
 	"k8s.io/klog/v2"
 	utiltrace "k8s.io/utils/trace"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/controllerutil"
@@ -44,11 +44,11 @@ import (
 // JobConfig.
 type PerConfigReconciler struct {
 	*Context
-	concurrency *configv1.Concurrency
+	concurrency *configv1alpha1.Concurrency
 	client      JobControlInterface
 }
 
-func NewPerConfigReconciler(ctrlContext *Context, concurrency *configv1.Concurrency) *PerConfigReconciler {
+func NewPerConfigReconciler(ctrlContext *Context, concurrency *configv1alpha1.Concurrency) *PerConfigReconciler {
 	reconciler := &PerConfigReconciler{
 		Context:     ctrlContext,
 		concurrency: concurrency,
diff --git a/pkg/execution/util/cronparser/parser.go b/pkg/execution/util/cronparser/parser.go
index 735d5b9..c56b405 100644
--- a/pkg/execution/util/cronparser/parser.go
+++ b/pkg/execution/util/cronparser/parser.go
@@ -19,7 +19,7 @@ package cronparser
 import (
 	"github.com/furiko-io/cronexpr"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 // Parser wraps the raw cronexpr parser to encapsulate common configuration.
@@ -29,7 +29,7 @@ type Parser struct {
 	opts      []cronexpr.ParseOption
 }
 
-func NewParser(cfg *configv1.CronControllerConfig) *Parser {
+func NewParser(cfg *configv1alpha1.CronExecutionConfig) *Parser {
 	format := cronexpr.CronFormatStandard
 	if cronexpr.CronFormat(cfg.CronFormat) == cronexpr.CronFormatQuartz {
 		format = cronexpr.CronFormatQuartz
diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go
index 2f481a7..28bc305 100644
--- a/pkg/generated/clientset/versioned/clientset.go
+++ b/pkg/generated/clientset/versioned/clientset.go
@@ -22,11 +22,10 @@ import (
 	"fmt"
 	"net/http"
 
+	executionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
 	discovery "k8s.io/client-go/discovery"
 	rest "k8s.io/client-go/rest"
 	flowcontrol "k8s.io/client-go/util/flowcontrol"
-
-	executionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
 )
 
 type Interface interface {
diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go
index 99f37bb..5c6cc9e 100644
--- a/pkg/generated/clientset/versioned/fake/clientset_generated.go
+++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go
@@ -19,15 +19,14 @@
 package fake
 
 import (
+	clientset "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
+	executionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
+	fakeexecutionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/watch"
 	"k8s.io/client-go/discovery"
 	fakediscovery "k8s.io/client-go/discovery/fake"
 	"k8s.io/client-go/testing"
-
-	clientset "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
-	executionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
-	fakeexecutionv1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake"
 )
 
 // NewSimpleClientset returns a clientset that will respond with the provided objects.
diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go
index ce06e84..49a44d3 100644
--- a/pkg/generated/clientset/versioned/fake/register.go
+++ b/pkg/generated/clientset/versioned/fake/register.go
@@ -19,13 +19,12 @@
 package fake
 
 import (
+	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-
-	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 var scheme = runtime.NewScheme()
diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go
index 9d72ae6..272e4ca 100644
--- a/pkg/generated/clientset/versioned/scheme/register.go
+++ b/pkg/generated/clientset/versioned/scheme/register.go
@@ -19,13 +19,12 @@
 package scheme
 
 import (
+	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	serializer "k8s.io/apimachinery/pkg/runtime/serializer"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
-
-	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 var Scheme = runtime.NewScheme()
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/execution_client.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/execution_client.go
index 619dad1..8cac3bc 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/execution_client.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/execution_client.go
@@ -21,10 +21,9 @@ package v1alpha1
 import (
 	"net/http"
 
-	rest "k8s.io/client-go/rest"
-
 	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
+	rest "k8s.io/client-go/rest"
 )
 
 type ExecutionV1alpha1Interface interface {
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_execution_client.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_execution_client.go
index 5909ab9..6bca5d9 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_execution_client.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_execution_client.go
@@ -19,10 +19,9 @@
 package fake
 
 import (
+	v1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
 	rest "k8s.io/client-go/rest"
 	testing "k8s.io/client-go/testing"
-
-	v1alpha1 "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/typed/execution/v1alpha1"
 )
 
 type FakeExecutionV1alpha1 struct {
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_job.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_job.go
index 7ffea43..c12c370 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_job.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_job.go
@@ -21,14 +21,13 @@ package fake
 import (
 	"context"
 
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
 	testing "k8s.io/client-go/testing"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // FakeJobs implements JobInterface
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_jobconfig.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_jobconfig.go
index da4b48e..3660d52 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_jobconfig.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/fake/fake_jobconfig.go
@@ -21,14 +21,13 @@ package fake
 import (
 	"context"
 
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	labels "k8s.io/apimachinery/pkg/labels"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
 	testing "k8s.io/client-go/testing"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // FakeJobConfigs implements JobConfigInterface
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/job.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/job.go
index 4ab5087..a41a4b1 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/job.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/job.go
@@ -22,13 +22,12 @@ import (
 	"context"
 	"time"
 
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
+	scheme "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
 	rest "k8s.io/client-go/rest"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
-	scheme "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 )
 
 // JobsGetter has a method to return a JobInterface.
diff --git a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/jobconfig.go b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/jobconfig.go
index f7490d5..f408173 100644
--- a/pkg/generated/clientset/versioned/typed/execution/v1alpha1/jobconfig.go
+++ b/pkg/generated/clientset/versioned/typed/execution/v1alpha1/jobconfig.go
@@ -22,13 +22,12 @@ import (
 	"context"
 	"time"
 
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
+	scheme "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	types "k8s.io/apimachinery/pkg/types"
 	watch "k8s.io/apimachinery/pkg/watch"
 	rest "k8s.io/client-go/rest"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
-	scheme "github.com/furiko-io/furiko/pkg/generated/clientset/versioned/scheme"
 )
 
 // JobConfigsGetter has a method to return a JobConfigInterface.
diff --git a/pkg/generated/informers/externalversions/execution/v1alpha1/job.go b/pkg/generated/informers/externalversions/execution/v1alpha1/job.go
index 403479d..503d569 100644
--- a/pkg/generated/informers/externalversions/execution/v1alpha1/job.go
+++ b/pkg/generated/informers/externalversions/execution/v1alpha1/job.go
@@ -22,15 +22,14 @@ import (
 	"context"
 	time "time"
 
-	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	runtime "k8s.io/apimachinery/pkg/runtime"
-	watch "k8s.io/apimachinery/pkg/watch"
-	cache "k8s.io/client-go/tools/cache"
-
 	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
 	internalinterfaces "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/internalinterfaces"
 	v1alpha1 "github.com/furiko-io/furiko/pkg/generated/listers/execution/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+	watch "k8s.io/apimachinery/pkg/watch"
+	cache "k8s.io/client-go/tools/cache"
 )
 
 // JobInformer provides access to a shared informer and lister for
diff --git a/pkg/generated/informers/externalversions/execution/v1alpha1/jobconfig.go b/pkg/generated/informers/externalversions/execution/v1alpha1/jobconfig.go
index 595cf16..508dfab 100644
--- a/pkg/generated/informers/externalversions/execution/v1alpha1/jobconfig.go
+++ b/pkg/generated/informers/externalversions/execution/v1alpha1/jobconfig.go
@@ -22,15 +22,14 @@ import (
 	"context"
 	time "time"
 
-	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	runtime "k8s.io/apimachinery/pkg/runtime"
-	watch "k8s.io/apimachinery/pkg/watch"
-	cache "k8s.io/client-go/tools/cache"
-
 	executionv1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
 	internalinterfaces "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/internalinterfaces"
 	v1alpha1 "github.com/furiko-io/furiko/pkg/generated/listers/execution/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+	watch "k8s.io/apimachinery/pkg/watch"
+	cache "k8s.io/client-go/tools/cache"
 )
 
 // JobConfigInformer provides access to a shared informer and lister for
diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go
index f1d886c..e60792c 100644
--- a/pkg/generated/informers/externalversions/factory.go
+++ b/pkg/generated/informers/externalversions/factory.go
@@ -23,14 +23,13 @@ import (
 	sync "sync"
 	time "time"
 
+	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
+	execution "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/execution"
+	internalinterfaces "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/internalinterfaces"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	cache "k8s.io/client-go/tools/cache"
-
-	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
-	execution "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/execution"
-	internalinterfaces "github.com/furiko-io/furiko/pkg/generated/informers/externalversions/internalinterfaces"
 )
 
 // SharedInformerOption defines the functional option type for SharedInformerFactory.
diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go
index 5432c5e..afd84a9 100644
--- a/pkg/generated/informers/externalversions/generic.go
+++ b/pkg/generated/informers/externalversions/generic.go
@@ -21,10 +21,9 @@ package externalversions
 import (
 	"fmt"
 
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	schema "k8s.io/apimachinery/pkg/runtime/schema"
 	cache "k8s.io/client-go/tools/cache"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // GenericInformer is type of SharedIndexInformer which will locate and delegate to other
diff --git a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
index 464e785..827fd34 100644
--- a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
+++ b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go
@@ -21,11 +21,10 @@ package internalinterfaces
 import (
 	time "time"
 
+	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 	cache "k8s.io/client-go/tools/cache"
-
-	versioned "github.com/furiko-io/furiko/pkg/generated/clientset/versioned"
 )
 
 // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
diff --git a/pkg/generated/listers/execution/v1alpha1/job.go b/pkg/generated/listers/execution/v1alpha1/job.go
index 89f4316..8f63e76 100644
--- a/pkg/generated/listers/execution/v1alpha1/job.go
+++ b/pkg/generated/listers/execution/v1alpha1/job.go
@@ -19,11 +19,10 @@
 package v1alpha1
 
 import (
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/client-go/tools/cache"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // JobLister helps list Jobs.
diff --git a/pkg/generated/listers/execution/v1alpha1/jobconfig.go b/pkg/generated/listers/execution/v1alpha1/jobconfig.go
index 7020baa..31f3ff2 100644
--- a/pkg/generated/listers/execution/v1alpha1/jobconfig.go
+++ b/pkg/generated/listers/execution/v1alpha1/jobconfig.go
@@ -19,11 +19,10 @@
 package v1alpha1
 
 import (
+	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/client-go/tools/cache"
-
-	v1alpha1 "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // JobConfigLister helps list JobConfigs.
diff --git a/pkg/runtime/configloader/configmap_loader.go b/pkg/runtime/configloader/configmap_loader.go
index 29b78be..7fef7a3 100644
--- a/pkg/runtime/configloader/configmap_loader.go
+++ b/pkg/runtime/configloader/configmap_loader.go
@@ -30,7 +30,7 @@ import (
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/klog/v2"
 
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/utils/eventhandler"
 )
 
diff --git a/pkg/runtime/configloader/defaults_loader.go b/pkg/runtime/configloader/defaults_loader.go
index 8368c4b..27157eb 100644
--- a/pkg/runtime/configloader/defaults_loader.go
+++ b/pkg/runtime/configloader/defaults_loader.go
@@ -24,7 +24,7 @@ import (
 
 	"k8s.io/apimachinery/pkg/runtime"
 
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/config"
 )
 
@@ -43,8 +43,8 @@ var _ Loader = (*DefaultsLoader)(nil)
 func NewDefaultsLoader() *DefaultsLoader {
 	return &DefaultsLoader{
 		Defaults: map[v1.ConfigName]runtime.Object{
-			v1.ConfigNameJobController:  config.DefaultJobControllerConfig,
-			v1.ConfigNameCronController: config.DefaultCronControllerConfig,
+			v1.JobExecutionConfigName:  config.DefaultJobControllerConfig,
+			v1.CronExecutionConfigName: config.DefaultCronControllerConfig,
 		},
 	}
 }
diff --git a/pkg/runtime/configloader/manager.go b/pkg/runtime/configloader/manager.go
index fa571d1..acd7343 100644
--- a/pkg/runtime/configloader/manager.go
+++ b/pkg/runtime/configloader/manager.go
@@ -26,7 +26,7 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 // ConfigManager manages ConfigLoaders and merges structured configuration
@@ -62,7 +62,7 @@ func (c *ConfigManager) Start(ctx context.Context) error {
 // If an error is encountered, it will return a previously known good value if
 // available, and log the error. Otherwise, if there is no previously cached
 // value for configName, then the error will be propagated back to the caller.
-func (c *ConfigManager) LoadAndUnmarshalConfig(configName configv1.ConfigName, out interface{}) error {
+func (c *ConfigManager) LoadAndUnmarshalConfig(configName configv1alpha1.ConfigName, out interface{}) error {
 	err := c.loadAndUnmarshalConfigWithError(configName, out)
 
 	// Return cached value and log error.
@@ -106,7 +106,7 @@ func (c *ConfigManager) LoadAndUnmarshalConfig(configName configv1.ConfigName, o
 	return nil
 }
 
-func (c *ConfigManager) loadAndUnmarshalConfigWithError(configName configv1.ConfigName, out interface{}) error {
+func (c *ConfigManager) loadAndUnmarshalConfigWithError(configName configv1alpha1.ConfigName, out interface{}) error {
 	decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
 		TagName: "json",
 		Result:  out,
@@ -125,7 +125,7 @@ func (c *ConfigManager) loadAndUnmarshalConfigWithError(configName configv1.Conf
 }
 
 // loadConfig will load the given config name from all loaders.
-func (c *ConfigManager) loadConfig(configName configv1.ConfigName) (res Config, err error) {
+func (c *ConfigManager) loadConfig(configName configv1alpha1.ConfigName) (res Config, err error) {
 	if !c.started {
 		return nil, errors.New("config manager is not started")
 	}
diff --git a/pkg/runtime/configloader/secret_loader.go b/pkg/runtime/configloader/secret_loader.go
index 4b12933..ec10ad0 100644
--- a/pkg/runtime/configloader/secret_loader.go
+++ b/pkg/runtime/configloader/secret_loader.go
@@ -26,7 +26,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/klog/v2"
 
-	v1 "github.com/furiko-io/furiko/apis/config/v1"
+	v1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/utils/eventhandler"
 )
 
diff --git a/pkg/runtime/configloader/types.go b/pkg/runtime/configloader/types.go
index a1875b1..4df8261 100644
--- a/pkg/runtime/configloader/types.go
+++ b/pkg/runtime/configloader/types.go
@@ -19,7 +19,7 @@ package configloader
 import (
 	"context"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 // Config is a dynamic config value.
@@ -29,5 +29,5 @@ type Config map[string]interface{}
 type Loader interface {
 	Name() string
 	Start(context.Context) error
-	Load(configName configv1.ConfigName) (Config, error)
+	Load(configName configv1alpha1.ConfigName) (Config, error)
 }
diff --git a/pkg/runtime/controllercontext/context.go b/pkg/runtime/controllercontext/context.go
index d910083..c2a8552 100644
--- a/pkg/runtime/controllercontext/context.go
+++ b/pkg/runtime/controllercontext/context.go
@@ -22,7 +22,7 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/client-go/rest"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 // Context is a shared controller context that can be safely shared between controllers.
@@ -37,7 +37,7 @@ type Context struct {
 var _ ContextInterface = &Context{}
 
 // NewForConfig prepares a new Context from a kubeconfig and controller manager config spec.
-func NewForConfig(cfg *rest.Config, ctrlConfig *configv1.BootstrapConfigSpec) (*Context, error) {
+func NewForConfig(cfg *rest.Config, ctrlConfig *configv1alpha1.BootstrapConfigSpec) (*Context, error) {
 	ctrlContext := &Context{
 		restConfig: cfg,
 	}
diff --git a/pkg/runtime/controllercontext/context_configs.go b/pkg/runtime/controllercontext/context_configs.go
index 14570bf..c74c449 100644
--- a/pkg/runtime/controllercontext/context_configs.go
+++ b/pkg/runtime/controllercontext/context_configs.go
@@ -23,7 +23,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/kubernetes"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 )
 
@@ -34,9 +34,9 @@ func (c *Context) Configs() Configs {
 
 type Configs interface {
 	Start(ctx context.Context) error
-	AllConfigs() (map[configv1.ConfigName]runtime.Object, error)
-	JobController() (*configv1.JobControllerConfig, error)
-	CronController() (*configv1.CronControllerConfig, error)
+	AllConfigs() (map[configv1alpha1.ConfigName]runtime.Object, error)
+	JobController() (*configv1alpha1.JobExecutionConfig, error)
+	CronController() (*configv1alpha1.CronExecutionConfig, error)
 }
 
 type ContextConfigs struct {
@@ -48,17 +48,17 @@ func NewContextConfigs(mgr *configloader.ConfigManager) *ContextConfigs {
 }
 
 // AllConfigs returns a map of all configs.
-func (c *ContextConfigs) AllConfigs() (map[configv1.ConfigName]runtime.Object, error) {
-	configNameMap := map[configv1.ConfigName]func() (runtime.Object, error){
-		configv1.ConfigNameJobController: func() (runtime.Object, error) {
+func (c *ContextConfigs) AllConfigs() (map[configv1alpha1.ConfigName]runtime.Object, error) {
+	configNameMap := map[configv1alpha1.ConfigName]func() (runtime.Object, error){
+		configv1alpha1.JobExecutionConfigName: func() (runtime.Object, error) {
 			return c.JobController()
 		},
-		configv1.ConfigNameCronController: func() (runtime.Object, error) {
+		configv1alpha1.CronExecutionConfigName: func() (runtime.Object, error) {
 			return c.CronController()
 		},
 	}
 
-	configs := make(map[configv1.ConfigName]runtime.Object)
+	configs := make(map[configv1alpha1.ConfigName]runtime.Object)
 	for configName, load := range configNameMap {
 		cfg, err := load()
 		if err != nil {
@@ -71,25 +71,25 @@ func (c *ContextConfigs) AllConfigs() (map[configv1.ConfigName]runtime.Object, e
 }
 
 // JobController returns the job controller configuration.
-func (c *ContextConfigs) JobController() (*configv1.JobControllerConfig, error) {
-	var config configv1.JobControllerConfig
-	if err := c.LoadAndUnmarshalConfig(configv1.ConfigNameJobController, &config); err != nil {
+func (c *ContextConfigs) JobController() (*configv1alpha1.JobExecutionConfig, error) {
+	var config configv1alpha1.JobExecutionConfig
+	if err := c.LoadAndUnmarshalConfig(configv1alpha1.JobExecutionConfigName, &config); err != nil {
 		return nil, err
 	}
 	return &config, nil
 }
 
 // CronController returns the cron controller configuration.
-func (c *ContextConfigs) CronController() (*configv1.CronControllerConfig, error) {
-	var config configv1.CronControllerConfig
-	if err := c.LoadAndUnmarshalConfig(configv1.ConfigNameCronController, &config); err != nil {
+func (c *ContextConfigs) CronController() (*configv1alpha1.CronExecutionConfig, error) {
+	var config configv1alpha1.CronExecutionConfig
+	if err := c.LoadAndUnmarshalConfig(configv1alpha1.CronExecutionConfigName, &config); err != nil {
 		return nil, err
 	}
 	return &config, nil
 }
 
 // SetUpConfigManager sets up the ConfigManager and returns a composed Configs interface.
-func SetUpConfigManager(cfg *configv1.BootstrapConfigSpec, client kubernetes.Interface) Configs {
+func SetUpConfigManager(cfg *configv1alpha1.BootstrapConfigSpec, client kubernetes.Interface) Configs {
 	configManager := configloader.NewConfigManager()
 	var configMapNamespace, configMapName, secretNamespace, secretName string
 	if cfg := cfg.DynamicConfigs; cfg != nil {
diff --git a/pkg/runtime/controllercontext/context_informers.go b/pkg/runtime/controllercontext/context_informers.go
index 84904ca..3ef354d 100644
--- a/pkg/runtime/controllercontext/context_informers.go
+++ b/pkg/runtime/controllercontext/context_informers.go
@@ -22,7 +22,7 @@ import (
 
 	kubernetes "k8s.io/client-go/informers"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	furiko "github.com/furiko-io/furiko/pkg/generated/informers/externalversions"
 )
 
@@ -56,7 +56,7 @@ func (c *contextInformers) Furiko() furiko.SharedInformerFactory {
 	return c.furiko
 }
 
-func SetUpInformers(clientsets Clientsets, cfg *configv1.BootstrapConfigSpec) Informers {
+func SetUpInformers(clientsets Clientsets, cfg *configv1alpha1.BootstrapConfigSpec) Informers {
 	defaultResync := cfg.DefaultResync.Duration
 	if defaultResync == 0 {
 		defaultResync = defaultDefaultResync
diff --git a/pkg/runtime/controllercontext/mock/context_configs.go b/pkg/runtime/controllercontext/mock/context_configs.go
index 2bb93b8..7500557 100644
--- a/pkg/runtime/controllercontext/mock/context_configs.go
+++ b/pkg/runtime/controllercontext/mock/context_configs.go
@@ -23,7 +23,7 @@ import (
 
 	"k8s.io/apimachinery/pkg/runtime"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 )
@@ -56,7 +56,7 @@ func (c *Configs) MockConfigLoader() *ConfigLoader {
 var _ controllercontext.Configs = (*Configs)(nil)
 
 type ConfigLoader struct {
-	configs map[configv1.ConfigName]runtime.Object
+	configs map[configv1alpha1.ConfigName]runtime.Object
 	mu      sync.RWMutex
 }
 
@@ -64,7 +64,7 @@ var _ configloader.Loader = (*ConfigLoader)(nil)
 
 func NewMockConfigLoader() *ConfigLoader {
 	return &ConfigLoader{
-		configs: make(map[configv1.ConfigName]runtime.Object),
+		configs: make(map[configv1alpha1.ConfigName]runtime.Object),
 	}
 }
 
@@ -76,7 +76,7 @@ func (c *ConfigLoader) Start(ctx context.Context) error {
 	return nil
 }
 
-func (c *ConfigLoader) Load(configName configv1.ConfigName) (configloader.Config, error) {
+func (c *ConfigLoader) Load(configName configv1alpha1.ConfigName) (configloader.Config, error) {
 	config, ok := c.configs[configName]
 	if !ok {
 		return nil, nil
@@ -92,7 +92,7 @@ func (c *ConfigLoader) Load(configName configv1.ConfigName) (configloader.Config
 	return m, nil
 }
 
-func (c *ConfigLoader) SetConfig(configName configv1.ConfigName, config runtime.Object) {
+func (c *ConfigLoader) SetConfig(configName configv1alpha1.ConfigName, config runtime.Object) {
 	c.mu.Lock()
 	defer c.mu.Unlock()
 	c.configs[configName] = config
diff --git a/pkg/runtime/controllermanager/controller.go b/pkg/runtime/controllermanager/controller.go
index 1cc2e1c..25d5169 100644
--- a/pkg/runtime/controllermanager/controller.go
+++ b/pkg/runtime/controllermanager/controller.go
@@ -24,7 +24,7 @@ import (
 	"golang.org/x/sync/errgroup"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext"
 	"github.com/furiko-io/furiko/pkg/runtime/leaderelection"
 )
@@ -53,7 +53,7 @@ type ControllerManager struct {
 
 func NewManager(
 	ctrlContext *controllercontext.Context,
-	ctrlCfg configv1.ControllerManagerConfigSpec,
+	ctrlCfg configv1alpha1.ControllerManagerConfigSpec,
 	defaultLeaseName string,
 ) (*ControllerManager, error) {
 	m := &ControllerManager{
diff --git a/pkg/runtime/controllerutil/concurrency.go b/pkg/runtime/controllerutil/concurrency.go
index 47e92b6..6d5c4db 100644
--- a/pkg/runtime/controllerutil/concurrency.go
+++ b/pkg/runtime/controllerutil/concurrency.go
@@ -19,18 +19,18 @@ package controllerutil
 import (
 	"runtime"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 // GetConcurrencyOrDefaultCPUFactor returns the configured concurrency, or a
 // default factor on the number of CPUs.
-func GetConcurrencyOrDefaultCPUFactor(concurrency *configv1.Concurrency, defaultFactor int) int {
+func GetConcurrencyOrDefaultCPUFactor(concurrency *configv1alpha1.Concurrency, defaultFactor int) int {
 	return GetConcurrencyOrDefaultNumber(concurrency, runtime.NumCPU()*defaultFactor)
 }
 
 // GetConcurrencyOrDefaultNumber returns the configured concurrency, or a
 // default number.
-func GetConcurrencyOrDefaultNumber(concurrency *configv1.Concurrency, defaultNumber int) int {
+func GetConcurrencyOrDefaultNumber(concurrency *configv1alpha1.Concurrency, defaultNumber int) int {
 	if concurrency != nil {
 		if num := concurrency.Workers; num > 0 {
 			return int(num)
diff --git a/pkg/runtime/httphandler/health.go b/pkg/runtime/httphandler/health.go
index 94768f2..947e4bf 100644
--- a/pkg/runtime/httphandler/health.go
+++ b/pkg/runtime/httphandler/health.go
@@ -23,7 +23,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 const (
@@ -32,7 +32,7 @@ const (
 )
 
 // ServeHealth adds health probe handlers to the given serve mux.
-func ServeHealth(mux *http.ServeMux, cfg *configv1.HealthSpec, mgr Manager) {
+func ServeHealth(mux *http.ServeMux, cfg *configv1alpha1.HealthSpec, mgr Manager) {
 	// Not enabled.
 	if cfg == nil {
 		return
diff --git a/pkg/runtime/httphandler/metrics.go b/pkg/runtime/httphandler/metrics.go
index e3aaa3f..a466bc9 100644
--- a/pkg/runtime/httphandler/metrics.go
+++ b/pkg/runtime/httphandler/metrics.go
@@ -23,7 +23,7 @@ import (
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/controller-runtime/pkg/metrics"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 const (
@@ -31,7 +31,7 @@ const (
 )
 
 // ServeMetrics adds Prometheus metrics handlers to the given serve mux.
-func ServeMetrics(mux *http.ServeMux, cfg *configv1.MetricsSpec) {
+func ServeMetrics(mux *http.ServeMux, cfg *configv1alpha1.MetricsSpec) {
 	// Not enabled.
 	if cfg == nil {
 		return
diff --git a/pkg/runtime/httphandler/server.go b/pkg/runtime/httphandler/server.go
index 9863c9d..70f857a 100644
--- a/pkg/runtime/httphandler/server.go
+++ b/pkg/runtime/httphandler/server.go
@@ -24,16 +24,16 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/klog/v2"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/controllermanager"
 )
 
 var (
-	defaultHTTPConfig = &configv1.HTTPSpec{
+	defaultHTTPConfig = &configv1alpha1.HTTPSpec{
 		BindAddress: ":8080",
 	}
 
-	defaultWebhooksConfig = &configv1.WebhookServerSpec{
+	defaultWebhooksConfig = &configv1alpha1.WebhookServerSpec{
 		BindAddress: ":9443",
 	}
 )
@@ -45,7 +45,7 @@ type Manager interface {
 
 // ListenAndServe listens on the given TCP address and gracefully stops when the
 // given context is canceled, setting up all HTTP handlers.
-func ListenAndServe(ctx context.Context, config *configv1.HTTPSpec, mgr Manager) error {
+func ListenAndServe(ctx context.Context, config *configv1alpha1.HTTPSpec, mgr Manager) error {
 	if config == nil {
 		config = defaultHTTPConfig
 	}
@@ -69,7 +69,7 @@ func ListenAndServe(ctx context.Context, config *configv1.HTTPSpec, mgr Manager)
 // given context is canceled, setting up all webhooks handlers.
 func ListenAndServeWebhooks(
 	ctx context.Context,
-	config *configv1.WebhookServerSpec,
+	config *configv1alpha1.WebhookServerSpec,
 	webhooks []controllermanager.Webhook,
 ) error {
 	if config == nil {
diff --git a/pkg/utils/execution/job/timeout.go b/pkg/utils/execution/job/timeout.go
index dedb695..04992eb 100644
--- a/pkg/utils/execution/job/timeout.go
+++ b/pkg/utils/execution/job/timeout.go
@@ -19,12 +19,12 @@ package job
 import (
 	"time"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 )
 
 // GetPendingTimeout returns the pending timeout for the given Job.
-func GetPendingTimeout(rj *execution.Job, cfg *configv1.JobControllerConfig) time.Duration {
+func GetPendingTimeout(rj *execution.Job, cfg *configv1alpha1.JobExecutionConfig) time.Duration {
 	var sec int64
 	if spec := cfg.DefaultPendingTimeoutSeconds; spec != nil {
 		sec = *spec
@@ -36,7 +36,7 @@ func GetPendingTimeout(rj *execution.Job, cfg *configv1.JobControllerConfig) tim
 }
 
 // GetDeleteKillingTimeout returns the timeout before the controller starts killing tasks with deletion.
-func GetDeleteKillingTimeout(cfg *configv1.JobControllerConfig) time.Duration {
+func GetDeleteKillingTimeout(cfg *configv1alpha1.JobExecutionConfig) time.Duration {
 	var sec int64
 	if spec := cfg.DeleteKillingTasksTimeoutSeconds; spec != nil {
 		sec = *spec
@@ -45,7 +45,7 @@ func GetDeleteKillingTimeout(cfg *configv1.JobControllerConfig) time.Duration {
 }
 
 // GetForceDeleteKillingTimeout returns the timeout before the controller starts force deletion.
-func GetForceDeleteKillingTimeout(cfg *configv1.JobControllerConfig) time.Duration {
+func GetForceDeleteKillingTimeout(cfg *configv1alpha1.JobExecutionConfig) time.Duration {
 	var sec int64
 	if spec := cfg.ForceDeleteKillingTasksTimeoutSeconds; spec != nil {
 		sec = *spec
@@ -54,7 +54,7 @@ func GetForceDeleteKillingTimeout(cfg *configv1.JobControllerConfig) time.Durati
 }
 
 // GetTTLAfterFinished returns the TTL after a Job is finished.
-func GetTTLAfterFinished(rj *execution.Job, cfg *configv1.JobControllerConfig) time.Duration {
+func GetTTLAfterFinished(rj *execution.Job, cfg *configv1alpha1.JobExecutionConfig) time.Duration {
 	var sec int64
 	if spec := cfg.DefaultTTLSecondsAfterFinished; spec != nil {
 		sec = *spec


Test patch:
diff --git a/pkg/execution/controllers/jobcontroller/reconciler_test.go b/pkg/execution/controllers/jobcontroller/reconciler_test.go
index aeab809..57a6576 100644
--- a/pkg/execution/controllers/jobcontroller/reconciler_test.go
+++ b/pkg/execution/controllers/jobcontroller/reconciler_test.go
@@ -31,7 +31,7 @@ import (
 	"k8s.io/client-go/tools/record"
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	executiongroup "github.com/furiko-io/furiko/apis/execution"
 	execution "github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/config"
@@ -60,7 +60,7 @@ func TestReconciler(t *testing.T) {
 		coreReactors     []*ktesting.SimpleReactor
 		coreActions      runtimetesting.ActionTest
 		executionActions runtimetesting.ActionTest
-		configs          map[configv1.ConfigName]runtime.Object
+		configs          map[configv1alpha1.ConfigName]runtime.Object
 	}{
 		{
 			name:   "create pod",
@@ -157,8 +157,8 @@ func TestReconciler(t *testing.T) {
 			initialPods: []*corev1.Pod{
 				fakePodPending,
 			},
-			configs: map[configv1.ConfigName]runtime.Object{
-				configv1.ConfigNameJobController: &configv1.JobControllerConfig{
+			configs: map[configv1alpha1.ConfigName]runtime.Object{
+				configv1alpha1.JobExecutionConfigName: &configv1alpha1.JobExecutionConfig{
 					DefaultPendingTimeoutSeconds: pointer.Int64(0),
 				},
 			},
@@ -250,8 +250,8 @@ func TestReconciler(t *testing.T) {
 			initialPods: []*corev1.Pod{
 				fakePodDeleting,
 			},
-			configs: map[configv1.ConfigName]runtime.Object{
-				configv1.ConfigNameJobController: &configv1.JobControllerConfig{
+			configs: map[configv1alpha1.ConfigName]runtime.Object{
+				configv1alpha1.JobExecutionConfigName: &configv1alpha1.JobExecutionConfig{
 					ForceDeleteKillingTasksTimeoutSeconds: pointer.Int64(0),
 				},
 			},
@@ -350,8 +350,8 @@ func TestReconciler(t *testing.T) {
 					runtimetesting.NewDeleteAction(resourceJob, jobNamespace, fakeJob.Name),
 				},
 			},
-			configs: map[configv1.ConfigName]runtime.Object{
-				configv1.ConfigNameJobController: &configv1.JobControllerConfig{
+			configs: map[configv1alpha1.ConfigName]runtime.Object{
+				configv1alpha1.JobExecutionConfigName: &configv1alpha1.JobExecutionConfig{
 					DefaultTTLSecondsAfterFinished: pointer.Int64(0),
 				},
 			},
@@ -378,7 +378,7 @@ func TestReconciler(t *testing.T) {
 
 			c := mock.NewContext()
 			ctrlCtx := jobcontroller.NewContextWithRecorder(c, &record.FakeRecorder{})
-			reconciler := jobcontroller.NewReconciler(ctrlCtx, &configv1.Concurrency{
+			reconciler := jobcontroller.NewReconciler(ctrlCtx, &configv1alpha1.Concurrency{
 				Workers: 1,
 			})
 			for configName, cfg := range tt.configs {
diff --git a/pkg/execution/mutation/mutation_test.go b/pkg/execution/mutation/mutation_test.go
index 362263b..1943d42 100644
--- a/pkg/execution/mutation/mutation_test.go
+++ b/pkg/execution/mutation/mutation_test.go
@@ -35,7 +35,7 @@ import (
 	"k8s.io/utils/pointer"
 	"sigs.k8s.io/yaml"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/apis/execution"
 	"github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/config"
@@ -584,7 +584,7 @@ func TestMutator_MutateUpdateJobConfig(t *testing.T) {
 func TestMutator_MutateJob(t *testing.T) {
 	tests := []struct {
 		name         string
-		cfgs         map[configv1.ConfigName]runtime.Object
+		cfgs         map[configv1alpha1.ConfigName]runtime.Object
 		rj           *v1alpha1.Job
 		want         *v1alpha1.Job
 		wantErrors   string
@@ -648,7 +648,7 @@ func TestMutator_MutateJob(t *testing.T) {
 func TestMutator_MutateCreateJob(t *testing.T) {
 	tests := []struct {
 		name         string
-		cfgs         map[configv1.ConfigName]runtime.Object
+		cfgs         map[configv1alpha1.ConfigName]runtime.Object
 		rj           *v1alpha1.Job
 		want         *v1alpha1.Job
 		rjcs         []*v1alpha1.JobConfig
@@ -1201,7 +1201,7 @@ func (m *mockProvider) MakeVariablesFromTask(rj *v1alpha1.Job, task *tasks.TaskT
 	return nil
 }
 
-func setup(t *testing.T, cfgs map[configv1.ConfigName]runtime.Object, rjcs []*v1alpha1.JobConfig) *mutation.Mutator {
+func setup(t *testing.T, cfgs map[configv1alpha1.ConfigName]runtime.Object, rjcs []*v1alpha1.JobConfig) *mutation.Mutator {
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
diff --git a/pkg/execution/validation/validation_test.go b/pkg/execution/validation/validation_test.go
index 053cbac..02e30de 100644
--- a/pkg/execution/validation/validation_test.go
+++ b/pkg/execution/validation/validation_test.go
@@ -31,7 +31,7 @@ import (
 	"k8s.io/client-go/tools/cache"
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/apis/execution/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/execution/validation"
 	"github.com/furiko-io/furiko/pkg/runtime/controllercontext/mock"
@@ -220,7 +220,7 @@ func TestValidateJobConfig(t *testing.T) {
 	tests := []struct {
 		name    string
 		rjc     *v1alpha1.JobConfig
-		cfgs    map[configv1.ConfigName]runtime.Object
+		cfgs    map[configv1alpha1.ConfigName]runtime.Object
 		wantErr string
 	}{
 		{
@@ -275,8 +275,8 @@ func TestValidateJobConfig(t *testing.T) {
 					Schedule:    &scheduleSpecWithHash,
 				},
 			},
-			cfgs: map[configv1.ConfigName]runtime.Object{
-				configv1.ConfigNameCronController: &configv1.CronControllerConfig{
+			cfgs: map[configv1alpha1.ConfigName]runtime.Object{
+				configv1alpha1.CronExecutionConfigName: &configv1alpha1.CronExecutionConfig{
 					CronHashNames: pointer.Bool(false),
 				},
 			},
@@ -1038,7 +1038,7 @@ func TestValidateJobCreate(t *testing.T) {
 	}
 }
 
-func setup(t *testing.T, cfgs map[configv1.ConfigName]runtime.Object, rjcs []*v1alpha1.JobConfig) *validation.Validator {
+func setup(t *testing.T, cfgs map[configv1alpha1.ConfigName]runtime.Object, rjcs []*v1alpha1.JobConfig) *validation.Validator {
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
 
diff --git a/pkg/runtime/configloader/configmap_loader_test.go b/pkg/runtime/configloader/configmap_loader_test.go
index a0765c3..84cced0 100644
--- a/pkg/runtime/configloader/configmap_loader_test.go
+++ b/pkg/runtime/configloader/configmap_loader_test.go
@@ -28,7 +28,7 @@ import (
 	fakeclientset "k8s.io/client-go/kubernetes/fake"
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 )
 
@@ -63,7 +63,7 @@ func (c *configMapLoaderTest) Update(ctx context.Context, client kubernetes.Inte
 			Name:      configMapName,
 		},
 		Data: map[string]string{
-			string(configv1.ConfigNameJobController): data,
+			string(configv1alpha1.JobExecutionConfigName): data,
 		},
 	}, metav1.UpdateOptions{})
 	return err
diff --git a/pkg/runtime/configloader/defaults_loader_test.go b/pkg/runtime/configloader/defaults_loader_test.go
index f4ba85b..f8a3fb9 100644
--- a/pkg/runtime/configloader/defaults_loader_test.go
+++ b/pkg/runtime/configloader/defaults_loader_test.go
@@ -25,7 +25,7 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 )
 
@@ -34,8 +34,8 @@ func TestDefaultsLoader(t *testing.T) {
 	defer cancel()
 
 	loader := configloader.NewDefaultsLoader()
-	loader.Defaults = map[configv1.ConfigName]runtime.Object{
-		configv1.ConfigNameJobController: &configv1.JobControllerConfig{
+	loader.Defaults = map[configv1alpha1.ConfigName]runtime.Object{
+		configv1alpha1.JobExecutionConfigName: &configv1alpha1.JobExecutionConfig{
 			DefaultTTLSecondsAfterFinished: pointer.Int64(123),
 			DefaultPendingTimeoutSeconds:   pointer.Int64(234),
 		},
@@ -67,14 +67,14 @@ func TestDefaultsLoader_LoaderOverride(t *testing.T) {
 	defer cancel()
 
 	defaultLoader := configloader.NewDefaultsLoader()
-	defaultLoader.Defaults = map[configv1.ConfigName]runtime.Object{
-		configv1.ConfigNameJobController: &configv1.JobControllerConfig{
+	defaultLoader.Defaults = map[configv1alpha1.ConfigName]runtime.Object{
+		configv1alpha1.JobExecutionConfigName: &configv1alpha1.JobExecutionConfig{
 			DefaultTTLSecondsAfterFinished: pointer.Int64(123),
 			DefaultPendingTimeoutSeconds:   pointer.Int64(234),
 		},
 	}
 	mockLoader := newMockConfigLoader(MockConfig{
-		configv1.ConfigNameCronController: map[string]interface{}{
+		configv1alpha1.CronExecutionConfigName: map[string]interface{}{
 			"maxMissedSchedules": 100,
 		},
 	})
@@ -84,7 +84,7 @@ func TestDefaultsLoader_LoaderOverride(t *testing.T) {
 	err := mgr.Start(ctx)
 	assert.NoError(t, err)
 
-	// Non-empty CronControllerConfig overridden by mock loader.
+	// Non-empty CronExecutionConfig overridden by mock loader.
 	cronCfg, err := loadCronControllerConfig(mgr)
 	assert.NoError(t, err)
 	assert.Equal(t, pointer.Int64(100), cronCfg.MaxMissedSchedules)
diff --git a/pkg/runtime/configloader/manager_test.go b/pkg/runtime/configloader/manager_test.go
index aaf4427..3c75afc 100644
--- a/pkg/runtime/configloader/manager_test.go
+++ b/pkg/runtime/configloader/manager_test.go
@@ -26,7 +26,7 @@ import (
 	"github.com/pkg/errors"
 	"k8s.io/utils/pointer"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 )
 
@@ -35,7 +35,7 @@ const (
 )
 
 type Config struct {
-	// Fields from JobControllerConfig.
+	// Fields from JobExecutionConfig.
 	DefaultTTLSecondsAfterFinished   int64 `json:"defaultTTLSecondsAfterFinished,omitempty"`
 	DefaultPendingTimeoutSeconds     int64 `json:"defaultPendingTimeoutSeconds,omitempty"`
 	DeleteKillingTasksTimeoutSeconds int64 `json:"deleteKillingTasksTimeoutSeconds,omitempty"`
@@ -47,7 +47,7 @@ type Config struct {
 	IntPtr  *int  `json:"intPtr,omitempty"`
 }
 
-type MockConfig map[configv1.ConfigName]configloader.Config
+type MockConfig map[configv1alpha1.ConfigName]configloader.Config
 
 type mockLoader struct {
 }
@@ -70,7 +70,7 @@ func newMockErrorLoader() *mockErrorLoader {
 	}
 }
 
-func (m *mockErrorLoader) Load(_ configv1.ConfigName) (configloader.Config, error) {
+func (m *mockErrorLoader) Load(_ configv1alpha1.ConfigName) (configloader.Config, error) {
 	return nil, errors.New("load config error")
 }
 
@@ -86,7 +86,7 @@ func newMockConfigLoader(values MockConfig) *mockConfigLoader {
 	}
 }
 
-func (m *mockConfigLoader) Load(configName configv1.ConfigName) (configloader.Config, error) {
+func (m *mockConfigLoader) Load(configName configv1alpha1.ConfigName) (configloader.Config, error) {
 	return m.values[configName], nil
 }
 
@@ -498,17 +498,17 @@ func TestConfigManager_Dynamic(t *testing.T) {
 	}
 }
 
-func loadJobControllerConfig(mgr *configloader.ConfigManager) (*configv1.JobControllerConfig, error) {
-	var config configv1.JobControllerConfig
-	if err := mgr.LoadAndUnmarshalConfig(configv1.ConfigNameJobController, &config); err != nil {
+func loadJobControllerConfig(mgr *configloader.ConfigManager) (*configv1alpha1.JobExecutionConfig, error) {
+	var config configv1alpha1.JobExecutionConfig
+	if err := mgr.LoadAndUnmarshalConfig(configv1alpha1.JobExecutionConfigName, &config); err != nil {
 		return nil, err
 	}
 	return &config, nil
 }
 
-func loadCronControllerConfig(mgr *configloader.ConfigManager) (*configv1.CronControllerConfig, error) {
-	var config configv1.CronControllerConfig
-	if err := mgr.LoadAndUnmarshalConfig(configv1.ConfigNameCronController, &config); err != nil {
+func loadCronControllerConfig(mgr *configloader.ConfigManager) (*configv1alpha1.CronExecutionConfig, error) {
+	var config configv1alpha1.CronExecutionConfig
+	if err := mgr.LoadAndUnmarshalConfig(configv1alpha1.CronExecutionConfigName, &config); err != nil {
 		return nil, err
 	}
 	return &config, nil
diff --git a/pkg/runtime/configloader/secret_loader_test.go b/pkg/runtime/configloader/secret_loader_test.go
index 12e308f..38548cc 100644
--- a/pkg/runtime/configloader/secret_loader_test.go
+++ b/pkg/runtime/configloader/secret_loader_test.go
@@ -26,7 +26,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	fakeclientset "k8s.io/client-go/kubernetes/fake"
 
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 	"github.com/furiko-io/furiko/pkg/runtime/configloader"
 )
 
@@ -54,7 +54,7 @@ func (c *secretLoaderTest) Update(ctx context.Context, client kubernetes.Interfa
 			Name:      secretName,
 		},
 		Data: map[string][]byte{
-			string(configv1.ConfigNameJobController): []byte(base64.StdEncoding.EncodeToString([]byte(data))),
+			string(configv1alpha1.JobExecutionConfigName): []byte(base64.StdEncoding.EncodeToString([]byte(data))),
 		},
 	}, metav1.UpdateOptions{})
 	return err
diff --git a/pkg/runtime/testing/concurrency.go b/pkg/runtime/testing/concurrency.go
index 8ce80a0..ab8160c 100644
--- a/pkg/runtime/testing/concurrency.go
+++ b/pkg/runtime/testing/concurrency.go
@@ -17,13 +17,13 @@
 package testing
 
 import (
-	configv1 "github.com/furiko-io/furiko/apis/config/v1"
+	configv1alpha1 "github.com/furiko-io/furiko/apis/config/v1alpha1"
 )
 
 var (
 	// ReconcilerDefaultConcurrency is the default concurrency to use for tests.
 	// For simplicity, reconcilers should not have concurrent workers.
-	ReconcilerDefaultConcurrency = &configv1.Concurrency{
+	ReconcilerDefaultConcurrency = &configv1alpha1.Concurrency{
 		Workers: 1,
 	}
 )