CREATE TABLE "visualization_platforms" ( "platform_key" TEXT NOT NULL, "type" TEXT NOT NULL, "display_name" TEXT NOT NULL, "description" TEXT, "default_config" JSONB NOT NULL, "sort_order" INTEGER NOT NULL DEFAULT 0, "enabled" BOOLEAN NOT NULL DEFAULT true, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "visualization_platforms_pkey" PRIMARY KEY ("platform_key") ); CREATE UNIQUE INDEX "visualization_platforms_type_key" ON "visualization_platforms"("type"); CREATE INDEX "visualization_platforms_enabled_sort_order_idx" ON "visualization_platforms"("enabled", "sort_order"); CREATE TABLE "course_week_visualization_platforms" ( "id" UUID NOT NULL DEFAULT gen_random_uuid(), "course_id" UUID NOT NULL, "week" INTEGER NOT NULL, "platform_key" TEXT NOT NULL, "enabled" BOOLEAN NOT NULL DEFAULT true, "created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMPTZ(3) NOT NULL, CONSTRAINT "course_week_visualization_platforms_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX "course_week_visualization_platforms_course_id_week_platform_key_key" ON "course_week_visualization_platforms"("course_id", "week", "platform_key"); CREATE INDEX "course_week_visualization_platforms_course_id_week_idx" ON "course_week_visualization_platforms"("course_id", "week"); CREATE INDEX "course_week_visualization_platforms_platform_key_idx" ON "course_week_visualization_platforms"("platform_key"); ALTER TABLE "course_week_visualization_platforms" ADD CONSTRAINT "course_week_visualization_platforms_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "courses"("id") ON DELETE CASCADE ON UPDATE CASCADE; ALTER TABLE "course_week_visualization_platforms" ADD CONSTRAINT "course_week_visualization_platforms_platform_key_fkey" FOREIGN KEY ("platform_key") REFERENCES "visualization_platforms"("platform_key") ON DELETE CASCADE ON UPDATE CASCADE; INSERT INTO "visualization_platforms" ("platform_key", "type", "display_name", "description", "default_config", "sort_order", "updated_at") VALUES ( 'AUTOWARE', 'AUTOWARE', 'Autoware', 'Autoware 기반 자율주행 시각화와 제어 실습 환경', '{ "type": "AUTOWARE", "runtime": { "containers": [], "steps": [] }, "bridge": { "name": "autoware-ros-bridge", "image": "autoware-ros-bridge", "port": 8765, "env": { "ROBOT_STACK": "autoware", "MAP_POINT_STRIDE": "8", "MAP_POINT_LIMIT": "80000", "AUTOWARE_ROUTE_INPUT": "rviz_topic", "INITIAL_POSE_TOPIC": "/initialpose", "GOAL_POSE_TOPIC": "/planning/mission_planning/goal", "VEHICLE_POSE_TOPIC": "/localization/kinematic_state", "TRAJECTORY_TOPIC": "/planning/scenario_planning/trajectory", "ROUTE_TOPIC": "/planning/mission_planning/route" } }, "viewer": { "stack": "autoware" } }'::jsonb, 1, CURRENT_TIMESTAMP ), ( 'NAV2', 'NAV2', 'Nav2', 'Nav2 기반 주행 알고리즘 시각화 실습 환경', '{ "type": "NAV2", "runtime": { "containers": [], "steps": [] }, "bridge": { "name": "nav2-ros-bridge", "image": "nav2-ros-bridge", "port": 8765, "env": { "ROBOT_STACK": "nav2" } }, "viewer": { "stack": "nav2" } }'::jsonb, 2, CURRENT_TIMESTAMP ), ( 'SLAM', 'SLAM', 'SLAM', 'TurtleBot3 SLAM 지도 생성 시각화 실습 환경', '{ "type": "SLAM", "runtime": { "containers": [ { "name": "nav2-slam", "image": "nav2-slam:humble", "network": "host" }, { "name": "slam-ros-bridge", "image": "slam-ros-bridge", "network": "host" } ] }, "bridge": { "url": "http://localhost:8765" }, "viewer": { "stack": "slam" }, "ros": { "turtlebotModel": "burger" } }'::jsonb, 3, CURRENT_TIMESTAMP ) ON CONFLICT ("platform_key") DO UPDATE SET "type" = EXCLUDED."type", "display_name" = EXCLUDED."display_name", "description" = EXCLUDED."description", "default_config" = EXCLUDED."default_config", "sort_order" = EXCLUDED."sort_order", "enabled" = true, "updated_at" = CURRENT_TIMESTAMP; INSERT INTO "course_week_visualization_platforms" ("course_id", "week", "platform_key", "enabled", "updated_at") SELECT DISTINCT profile."course_id", profile."week", upper(profile."profile_type"), true, CURRENT_TIMESTAMP FROM "course_environment_profiles" profile JOIN "visualization_platforms" platform ON platform."platform_key" = upper(profile."profile_type") WHERE profile."enabled" = true ON CONFLICT ("course_id", "week", "platform_key") DO UPDATE SET "enabled" = true, "updated_at" = CURRENT_TIMESTAMP;