Documentation / {{ group_label }} / {{ active_label }}

Start with Single File FREE

Learn how to create and deploy a web page using AI prompts and templates. This is the fastest way to get started with QuickStart.

Estimated time: ~5 minutes
1
Open Editor
2
Template
3
Edit & Preview
4
Account
5
Deploy
6
Done!
1
Open the Coder Editor

Log in to QuickStart and click Single File from the left menu. The AI Coder Editor opens with an integrated development environment for HTML, SCSS, and Vue.js — all in one screen.

TIP If this is your first time, we recommend starting with a template instead of a blank editor.
2
Choose a Template

Click the template dropdown at the top of the editor. Browse pre-built templates like landing pages, portfolios, dashboards, and more. You can also use community-shared templates.

TIP Community templates are available under the "Shared Templates" tab.
3
Edit Code & Preview

Once the template loads, HTML, SCSS, and JavaScript code appear in the editor. Modify anything you like and hit the Run button to see live results. You can also ask AI to generate code via prompts.

TIP AI prompt example: "Create a responsive header with 3 card sections"
4
Connect Railway Account

For your first deployment, you'll need a Railway account. Go to Settings > Account and register your Railway API token. This is a one-time setup that applies to all future deployments.

TIP Railway offers a free plan, so you can start without worrying about costs.
5
Deploy

Click the Deploy button at the top of the editor. The deployment progress is shown step by step — file generation, server upload, build — all handled automatically. It usually takes 1-2 minutes.

TIP When deployment finishes, a domain is provisioned alongside so your page has a live URL immediately.
6
Done! Free Domain Ready

Once deployed, QuickStart automatically assigns a free domain. Click the domain link to see your web page live on the internet. Congratulations!

TIP You can change the domain name anytime in the Domain Management menu.

Start with Project

Build a full-stack web application with frontend and backend. Project is not a standalone entry point — it deploys on top of a container (domain) that must already be provisioned via the Database or Macro path. Complete one of those paths first, then come back here.

Estimated time: ~15 minutes (once container is ready)
1
Create Project
2
Write Programs
3
Set Routers
4
Deploy
5
Verify Domain
1
Select Container & Create Project

From the Project menu, click "New Project". Enter a name and description, then select an existing domain (container) and dataset — the project structure will be scaffolded on top of that container. A domain represents the Docker container where your project runtime lives, so it must be provisioned in advance through the Database or Macro path.

TIP If no domains are available to select, go to "Start with Database" or "Start with Macro" first to provision a container.
2
Write Programs

Add programs inside your project. Each program represents a page or feature unit. Create the UI with HTML/CSS and write server logic in PHP. AI can auto-generate code from prompts.

TIP Forking an existing project is much faster than starting from scratch.
3
Configure Routers

Set up routers to map programs to URLs. For example, connect a "Board" program to /board. Visitors can access it through that URL. You can specify GET/POST methods too.

TIP With the VSCode extension, routes are auto-generated from function names.
4
Deploy

Click Deploy to start the 8-step automatic deployment: Pack creation → DB setup → Data encryption → Server upload → Build → Configure → Test → Complete. Watch real-time progress for each step.

TIP First deployment takes 2-3 minutes; subsequent updates take about 1 minute.
5
Verify Domain

After deployment, visit the domain connected to your project. Test that all programs, routers, and database connections work correctly.

TIP If something's wrong, use "Remote Management" to directly inspect and edit server files.

Start with Database PRO

The lightest entry point. Choosing this path provisions a Docker container (domain) bundled with one database engine (MySQL, MariaDB, PostgreSQL, or MongoDB) + a PHP/Laravel backend + npm — a deliberately minimal-feature stack. Ideal when you only need a DB plus a simple web backend and want to keep the footprint small. Start by storing data, running SQL, and auto-generating REST APIs. Switch to the Macro path later if you need a richer runtime.

Estimated time: ~10 minutes
1
Create Dataset
2
Explore Tables
3
Run SQL
4
Generate API
5
Use Data
1
Create a Dataset

From the Database menu, click "New Dataset" to open the wizard. In step 1 pick either Deploy (provision a fresh DB container via Railway) or Connect (supply host / port / credentials of an existing DB you already run), then choose the engine — MySQL, MariaDB, PostgreSQL, or MongoDB.

TIP QuickStart does not bundle a default DB of its own. If you don't already operate a database, Deploy mode is the fastest way to start.
2
Explore Tables

Browse table lists in the DB Editor and inspect field structures. You can also create new tables or modify existing ones.

TIP Click a table name to see its field list and data preview.
3
Run SQL

Enter SQL in the query editor and execute it for instant results. All SQL statements are supported — SELECT, INSERT, UPDATE, DELETE. You can even ask AI to write queries in natural language.

TIP A common pattern: ask an AI to draft the SQL for you, then paste the result into the query editor and run it.
4
Auto-Generate APIs

Pick a table and click Generate API — a mapping interface opens where you can review the API structure. Accept the defaults to produce CRUD (create / read / update / delete) endpoints in one shot, or restructure exposed fields, parameters, and response shape to match exactly what your frontend needs before generating.

TIP Generated APIs can be directly connected to Layout Builder blocks or Project programs.
5
Use Your Data

Bind the generated APIs to Layout Builder blocks or call them from project programs to build data-driven web services. Import/export data via CSV or JSON.

TIP Google Sheets integration lets you pull spreadsheet data in real-time.

Start with Macro MAX

Pick this path when you need a far richer runtime than the Database path offers. It provisions a Docker container (domain) with MariaDB and PostgreSQL bundled automatically, MongoDB available as an optional add-on, and Python, Node.js, curl, jq, recurring timer automation, ffmpeg, and most of the tooling you may or may not need down the road — preinstalled and ready. Well-suited for composite workloads: data scraping/processing, external API orchestration, media transcoding, scheduled automation. If you're torn between "DB + PHP is enough" and "I might need more later", this is the safer choice.

Estimated time: ~10 minutes
1
Create Macro
2
Write Code
3
Quick Test
4
Set Schedule
5
Deploy
1
Create a Macro

From the Macro menu, click "New Macro" and enter a name. If you need input parameters, define their names, types, and default values. Parameters are variables that receive values at runtime.

TIP A macro runs against its parameters, so you must define at least one. If writing parameters from scratch feels tedious, pick one of the 24 built-in common scenarios — parameters and starter code get filled in together for a fast start.
2
Write Code

Write your automation logic in Node.js or PHP using the code editor. Call external APIs, process data, handle files — anything you need. Access parameters and execution context through the run_data object.

TIP Return { success: true, data: [...] } to display results as a table.
3
Quick Test

Test your code instantly. Click Quick Test and the macro runs immediately, showing results in the bottom panel. Supports multiple result formats: tables, JSON, download links, and messages.

TIP Errors show the exact line number where the problem occurred.
4
Set Schedule

To run a macro automatically on a recurring basis, set two values: a start time (HH:MM) and an interval in minutes. Examples: 00:00 + 5 → every 5 minutes from midnight; 03:30 + 1440 → once daily at 3:30 AM.

TIP Scheduled execution results are available in the logs.
5
Deploy

Deploy your macro to a Railway server for reliable, independent execution. After deployment, an API endpoint is created so you can trigger the macro via HTTP requests from external systems.

TIP Deployed macros can be updated without server restarts.

QuickStart Overview

Understanding the core concepts below first makes it much easier to see how QuickStart's features interlock — and you'll get far more value out of the service. Scan the concept map up top by category, then click any chip to jump into a detailed card. Cross-links inside each description let you move fluidly between related concepts.

Concept Map

Core Concepts

Domain

A Docker container unit where your project runtime lives. Provisioned on Railway with a unique URL (e.g. happycat.apidealder.net). It's created automatically when you go through the Database or Macro Deploy path, and every Project is installed on top of an existing domain. One user can own multiple domains; multiple projects can share a single domain.

Deploy

The automated 8-step pipeline that takes your locally-edited code and schema into a live running state: Pack → DB setup → encryption → upload → build → configure → test → done. Results are reflected on the target Domain and every run is recorded in deploy_logs. Re-deploys usually complete in about a minute.

Agent

A remote executor that runs inside every user's Domain container. Rather than proxying large data through the QuickStart server, the agent operates directly on the customer's container DB and filesystem. Most regular-user CRUD is handled by sending SQL or commands straight to the agent.

Project

The top-level execution unit of a full-stack web application. Bundles several Programs, Routers, Dataset bindings, Translations, Revision history, and Team members. A project is not a standalone entry point — it requires a Domain (container) to be ready before it can be installed.

Program

An individual page or feature unit inside a Project. Pairs a frontend (HTML / SCSS / Vue.js) with a backend (PHP) and is mapped to a URL through a Router. You can generate or iterate on programs via AI prompts, and revert to previous Revisions at any time.

Program Builder

A tool for assembling a Program visually with blocks instead of code. Drag and drop Blocks, bind data sources, and the builder emits real program files. You can switch freely between no-code authoring and direct code editing, and ultimately a build command converts the entire builder configuration into source code and consolidates it as a regular Program.

Hook

Lifecycle customization points inside the Program Builder. 28 hooks cover the full component lifecycle — mounted, beforeUpdate, updated, and so on — and each hook is a slot where you can inject "code to run at that moment". You keep the builder's default behaviour while surgically adding your own logic exactly where it fits, giving no-code assemblies a clean extensibility escape hatch.

Scaffold

A reusable structural template used at two layers. A project scaffold is a blueprint that produces a pre-configured bundle of programs, schema, and seed data when you create a new Project. A block scaffold ships a starting skeleton of SCSS design tokens and style templates so Blocks stay visually consistent. Pick the scaffold closest to your goal and tweak — no need to start from scratch.

Router

A route rule that maps a Program to a URL — e.g. /board → the Board program. Supports GET/POST methods, URL parameters, and auth requirements. With the VSCode extension, routes are auto-derived from function names.

Revision

The change history of a Program, Project, or Block. Every save creates a snapshot you can roll back to at any time. Diff views across revisions let you see exactly who changed what.

Solution

A special flavour of Project obtained by purchasing a permanent license for an admin-authored private project. Unlike regular projects, solutions cannot be forked or made public — buyers get lifetime usage rights. Solutions are traded on the Solution Market and, once purchased, can be deployed straight onto your own Domain.

Dataset

A connection unit to a data store — MySQL, MariaDB, PostgreSQL, or MongoDB. Create it in Deploy mode (provision a fresh DB container on Railway) or Connect mode (supply credentials for an existing external DB). It belongs to a Domain and gives you table/field management plus a SQL editor.

Parser

A web-scraping rule that automatically collects data from external websites. Define URI patterns for listing pages and CSS/XPath selectors for detail pages; running the rule saves the results straight into a Dataset. Attach a schedule for periodic runs, and it can also execute inside the Agent environment.

Block

A reusable UI component used by the layout builder. Authored as an independent HTML/CSS fragment and placed into Frames or Programs. Bind it to a Dataset API and it renders live data. A Preset is embedded inside each block to help AI-driven authoring stay focused and consistent.

Preset

An AI-prompt helper embedded inside a Block. When you ask AI to generate or modify block-related content, the preset automatically packages the relevant context (block type, purpose, data shape, design tokens, and so on) into the prompt for you. You don't have to re-explain the setup every time, and AI outputs stay consistent across iterations so the generate-and-tweak loop goes much faster.

Frame

A layout template that holds Blocks. Defines the structural regions — header, body, footer — and is reused across multiple pages. Framing your blocks at this level keeps design consistent across the project.

Scene

A single slide within a slideshow. Link layout pages as scenes to build presentations or display channels, and control transition effects, timing, and interactions per scene.

Macro

A server-side automation script. Write it in Node.js or PHP, declare input parameters, and Quick Test it instantly. Once deployed it exposes an HTTP endpoint on your Domain (callable externally) and can run on a recurring schedule (start time + interval in minutes — no cron needed). Results are returned through a standard protocol: table, JSON, download links, or message.

Translation

The system that renders every string in your Project, Program, or Block into 40 languages. Translation keys are extracted, translated by AI, and synced back as per-project language files. Preview, manual edits, and VSCode-based syncing are all supported.

Patch

A lightweight update that applies only selected changes to an already-deployed Project. Instead of a full redeploy, a patch sends just the modified programs, routers, or translations to the agent for immediate effect — ideal for emergency hotfixes or small tweaks.

User

A QuickStart account. Users are split into Free · Pro · Max tiers based on their subscription plan, and each tier has access to a different set of service plans and features. You can upgrade at any time — see the Pricing page for the full breakdown.

Team

A permission group that lets multiple Users collaborate on a Project. Teams share read/write access, and a single project can be linked to several teams. Teams are optional — you can work solo without any team at all.

Architecture

QuickStart is split into 4 tiers with clearly separated communication responsibilities. In particular, bulk data flows directly between the client and the Agent without passing through the QuickStart server — the design is intentionally optimized to minimize server traffic and storage.

Layer Breakdown

Client (Browser)

Role Service screens, user input, and direct file transfer
  • Dedicated editors for Single File · Project · Database · Macro · Data Collection
  • Chat with AI and preview the result instantly
  • 40-language switching and preview inside the Project feature
  • Safely stores login info, in-progress edits, and theme settings in the browser
  • Drag-and-drop canvas for placing blocks in the Layout Builder
  • Large files upload and download directly to the user's container, bypassing the central server

QuickStart Server

Role Control tower orchestrating accounts and service operations
  • Account · pricing plans · payments management
  • Keeps track of project · solution · domain lists and their current state
  • When a deploy starts, each step runs automatically in the right order
  • Issues the temporary transfer permits browsers need for direct container transfers
  • Serves the pages and resources needed to render the UI
  • Regular-user data never passes through the central server, keeping load and cost low

Docker Agent (User Server)

Role Handles real data, files, and execution directly inside each user's own container
  • Always on, running inside the user's domain (container)
  • Directly creates, reads, updates, and deletes the real data for programs · blocks · routers · datasets
  • Remote file operations — upload · edit · download
  • Runs deployed programs · macros · data-collection tasks directly
  • Verifies requests via a dedicated security key and temporary permit
  • User data stays isolated inside this container, never mixed with anyone else's

Railway Hosting

Role Infrastructure partner providing container hosting, deploy environments, and domains
  • Provisions new containers and provides the deploy environment
  • Auto-assigns a default domain and supports connecting your own
  • Scales processing power and memory automatically with traffic
  • Aggregates execution logs and status metrics
  • QuickStart drives container operations through an official integration channel

Network Flows Between Layers

Channel Endpoints Protocol What Flows
Control Channel Client ↔ QuickStart Server Secure, session-backed connection Carries everyday requests like logins, project listings, and settings changes. Payloads are small, so the UI feels snappy and server load stays low.
Data Channel (server-bypassing) Client ↔ Docker Agent Single-use transfer authorization File uploads, downloads, remote editing, and large query results travel here. The user's browser communicates directly with the user's own container — the central QuickStart server is not in the path, so large transfers incur zero server storage or bandwidth cost and stay fast.
Coordination Channel QuickStart Server ↔ Docker Agent Container-scoped security key Used to check that a user's container is healthy, probe available capabilities, and exchange the management signals needed around deployments. No real user data ever flows here.
Provisioning Channel QuickStart Server ↔ Railway Official integration with the infrastructure provider Delivers infrastructure instructions — new container creation, deploy requests, domain wiring. If a user registers their own Railway account with QuickStart, these actions run inside that account.
Containment Docker Agent ⊂ Railway The agent runs inside a container that Railway manages. Railway owns the container's lifecycle, resources, and network, so infrastructure-level issues are absorbed there and users can focus on their service logic.
Structural advantages

The central server handles only control and coordination, while actual data is exchanged directly between the user's browser and the user's own container. That keeps transfers fast under heavy load because there is no central bottleneck, and it drives server storage and bandwidth cost down sharply. Most importantly, each user's data stays isolated inside their own container — there is simply no path for it to mix with another user's or with the central server, so data security is a property of the architecture itself.

Pricing & Plans

Start free with QuickStart, then expand to PRO or MAX as needed. The table below captures the core differences at a glance.

Plan Available Services Best For
FREE
Single File Layout Builder Slideshow Basic Domain Management Community Support
Individuals publishing ideas as quick single-file pages
PRO
+ Everything in FREE Full-stack Project Database Web Crawling Slideshow Parameter Cursor
Operators running full-stack web apps who also need database and web crawling
MAX
+ Everything in PRO Coder Builder Macro Automation Scheduled Crawling Display Channel
Power users who need scheduled automation and advanced builder features
View detailed pricing

Single File

The simplest way to create a web page from a single file.

Single File
Key Features
1
Open Editor
2
Template/Prompt
3
Edit Code
4
Run Preview
5
Deploy/Share
1
Step 1 · Editor screen layout

Go to /service/single. The top toolbar is split into three zones.

  • Left — History · Guide · App title · Save (💾)
  • Center — Template dropdown (11 options)
  • Right — Shared list · Share · Copy · Run ▶ · Deploy 📦

The body has four editor tabs (prompt · html · scss · vuejs) and a live preview on the right.

TIP A small dot (●) next to a tab means unsaved changes. Press Ctrl+S before Run.
2
Step 2 · Pick a template or write a prompt

Two ways to start:

  1. Prebuilt templates — 11 options in the dropdown: E-Commerce · Realtime Stock Chart · Favorites Dashboard · SaaS Pricing · Kiosk Menu · Restaurant Booking · YouTube Creator Hub · Product Detail · Chat App · Event Countdown · Admin Dashboard. Selecting one fills all four tabs instantly.
  2. AI prompt from scratch — describe what you want in the prompt tab (e.g. "a cafe menu page with 3 category tabs"), then use the AI button to auto-generate the HTML/SCSS/Vue tabs.
TIP The "Shared list" button gives access to templates other users have published. Starting from someone else's completed example is the fastest path.
3
Step 3 · Edit code (4 tabs)

Switch tabs to edit each layer.

  • prompt — the description used for AI regeneration. Editing + regenerating refreshes the code.
  • html — structure and text. Line numbers + Ctrl+F search.
  • scss — colors, fonts, spacing. Most templates define theme variables at the top of the file.
  • vuejs — data and interactivity. Uses data() { return { ... } }, methods: { ... }, mounted().
TIP Vue 3 Options API only — const/let, arrow functions, and template literals are forbidden. Use var and function.
4
Step 4 · Preview with Run ▶ and the History button

Click Run ▶ on the right side of the toolbar to render the page live in the preview panel. Click again after edits to refresh.

The History button on the top left opens your recent saved versions. The → Load icon on a row restores that state — your safety net when an edit breaks things.

TIP Links and buttons are actually clickable inside the preview. Experience what a visitor will see, end to end.
5
Step 5 · Deploy or share with the community

Two ways to get your work out:

  • Deploy 📦 — the rightmost toolbar button. After connecting a Railway account, a deploy progress modal runs; in 1–3 minutes your page is live on a free domain.
  • Share — the share icon in the toolbar. Add title/description/tags and publish to the community; other users can fork your work (this is a template share, not a live deploy).
TIP Each save becomes a history entry, so if a Deploy fails you can restore the previous state from History and try again.

Project

Develop full-stack web applications with both frontend and backend.

Project
Key Features
1
List
2
Create
3
Add Program
4
Router
5
Deploy
1
Step 1 · Project list screen

Open Service > Project from the menu. The layout:

  • Left sidebar — blue [+ New Project] / [+ New Team] buttons plus Recent, Public Solutions, My Projects, Teams sections.
  • Top breadcrumb — switches between list ↔ detail ↔ programs ↔ deploy views.
  • Body — cards showing each project's domain badge, DB type, and program/router counts.
TIP A project always sits on top of an existing domain (container). If you don't have one yet, deploy Database or Macro first to provision one.
2
Step 2 · Create a new project (2-step wizard)

Click [+ New Project] → wizard modal.

  1. Step 1 — feature cards and a flow diagram.
  2. Step 2 — config
    • Domain (required) — one of your existing domains
    • Dataset (required) — the DB this project will use
    • Project name / description
    • Team assignment (checkboxes)
  3. [Save] at the bottom — only enabled once both domain and dataset are selected.
TIP Multiple projects can share one domain — useful for splitting a public front-end and an admin page onto the same container.
3
Step 3 · Add a program & develop in the code editor

A program is one page or one piece of functionality inside a project. Fill in basic info in the creation form, then jump straight into the code editor to author Blade + SCSS + Vue on a single screen.

1) Creating a new program

The project detail toolbar shows [+ New Program] and [+ New Router]. Clicking New Program opens a form modal.

  • Program name (e.g. home, admin_dashboard)
  • Description — one-line note about what this screen/feature is
  • Typefrontend (HTML/CSS/JS) / backend (PHP)
  • Router — pick an existing router, or inline-create one with alias + URL path + HTTP method

2) Opening the code editor & screen layout

Click the icon on a program row to switch into the editor view. The screen is divided into three zones.

  • Top breadcrumb + tool bar — current program name, save-state indicator, and a group of tool buttons all on one row.
  • Left sidebar — list of other programs in the same project. Each item has (Code) and (Builder) quick icons that jump between views.
  • Center 3-column editor — three CodeMirror 6 panels (HTML / CSS / JavaScript) laid out side by side. Clicking a panel highlights it as focused, and the editor theme follows your Dark/Light setting automatically.

3) What each tab actually holds

  • HTML — plain HTML plus Blade directives (@if, @foreach) and @{{ ... }} output. Server-side variables, conditions, and loops are expressed directly in the template.
  • CSSSCSS syntax (nesting, & references, variables, mixins) straight through. Compiled automatically on deploy.
  • JavaScriptVue 3 Options API shape (data / computed / methods / mounted). The runtime picks this up automatically and binds it to the template in the HTML column.

Standard CodeMirror shortcuts work as expected: Ctrl+F for in-editor search, Ctrl+Z undo, Ctrl+/ comment, automatic bracket/tag closing, and soft line wrapping.

4) Edit state & the save cycle

The moment you change a single character, Unsaved appears in the top bar to tell you there are unsaved changes. Click [ Save] and all three tabs are shipped at once; on success a Saved check briefly appears.

Each save writes the three columns into the program body and simultaneously records the moment as a revision. Save = an automatic version snapshot — you can roll back to any of them later.

5) Deploy on Save — straight to live on every save

Flip the [Deploy on Save] toggle next to Save to ON and every save also auto-deploys the change to the project's destination (e.g. the main server). A short "N deployed" badge briefly appears after the push, so you never have to click a separate Deploy button — the "edit → live" loop closes itself. The toggle is remembered per project, so turning it on once sticks.

6) The top tool cluster at a glance

  • Database — opens the dataset binding popup. Name a variable, pick a table, set WHERE/LIMIT/ORDER, and the query result is auto-injected into the program under that variable.
  • Builder — switches to a block-based editing view of the same program. Code view and Builder view share the same output.
  • Code Search — project-wide search & replace panel (see 7 below).
  • Revisions — revision history with diff panel (see 8 below).
  • Extension Guide — popup explaining how to edit and deploy the same project locally via the VSCode extension.

7) Project-wide Search & Replace

Type a keyword at the top and press Enter or the button. The scope tabs give you two choices — Project (all programs in the current project) or Revisions (include past snapshots).

  • Results show a type badge (HTML / CSS / JS), program ID, program name, and match count.
  • Type filter tabs All / HTML / CSS / JS narrow results to a single column, with the match count on each tab.
  • Click the arrow next to a program name to jump straight into that program's editor.
  • Click [Show More] on a row to open the context panel on the right showing the surrounding code for every match.

Replace lives on the second row. Pick a scope (All / HTML / CSS / JS), fill in search and replace terms, hit the button — a "changes will be made in N files" confirmation appears, and on Yes the project-wide replace runs in one shot.

8) Revisions · history and rollback

Every save adds a snapshot here. The moment the panel opens it auto-diffs the latest revision ↔ your current edits on the right-hand side.

  • Left: the revision list (paginated). Each row has three action icons:
    • Revert — overwrite the editor with this revision (unsaved changes are lost).
    • Diff with current — this revision ↔ what's in the editor right now.
    • Diff with previous — this revision ↔ the revision immediately before it.
  • Right: side-by-side diff with HTML / CSS / JS tabs. The tab that actually changed is auto-selected.

9) The actual order an author follows

  1. Open the editor from a program row's icon.
  2. Author in the HTML(Blade) → CSS(SCSS) → JS(Vue) tabs, whichever the change needs.
  3. Reach for Database when data is needed, Code Search for cross-program lookups, Revisions to compare against history.
  4. Hit [Save] → wait for "Saved". If Deploy on Save is ON, the deploy goes out too.
  5. If something breaks, revert to the right snapshot via the Revisions panel.
  6. For a rename that spans many programs, use Code Search → Replace to do it in one confirmed action.
TIP A program without a router acts as a shared layout / partial that other programs include internally. Because every save piles up as a revision, you can experiment freely — and when you need the shortest possible edit-to-live loop on a hotfix, turn Deploy on Save on briefly and each save reaches the live server immediately.
4
Step 4 · Map programs to URLs via routers

Register routers in the collapsible router section of the detail view or via [+ New Router].

  • alias — internal identifier (e.g. home, api_orders)
  • URL path — public path (e.g. /home, /api/orders)
  • HTTP method — GET / POST / PUT / DELETE / ANY

Connect a router to a program in the program form's Router selector — visitors hitting that URL will trigger the program.

TIP With the VSCode extension, router entries are auto-suggested from function names like function list_orders().
5
Step 5 · Deploy (9-step pipeline)

Click the 🚀 (rocket) icon on a project list card to open the deploy modal.

  1. Pick a deploy mode: integrate (reuse existing Docker) · rebuild · new
  2. Click [Start deploy] → the 9-step pipeline runs (each turns green on completion):
    ① Pack create → ② DB prepare → ③ Data prepare → ④ Server transfer → ⑤ Docker build → ⑥ Docker deploy → ⑦ Domain connect → ⑧ Install complete → ⑨ Service stabilization
  3. When finished, the domain URL is live and immediately reachable.
TIP First deploy takes 2–3 min; subsequent integrate-mode deploys are usually under a minute. On failure, check the red lines in the logs under the progress bar.

Code Builder

A tab-based wizard that designs the list · detail · search · CRUD screens around one (or several) DB tables, plus any needed PHP/Vue code, and turns the whole thing into a finished program (Blade + Vue Script) with one click of the [Builder] button. You enter it via the icon from the program list. You never hand-write boilerplate — the path from DB schema → UI → interaction is automated end-to-end.

Code Builder
Key Features
1
DB connection
2
List design
3
Detail · Search
4
Hook & Codegen
5
Menu · Shortcode
1
Step 1 · Connect the DB and pick tables / fields

Open the Code Builder via the icon on a program row. Eight step tabs sit at the top (DB · List · Detail · Search · Hook · Style · Code · Menu); most programs are finished by going through them left-to-right just once.

The flow at a glance

  • [1] DB
    pick tables
    pick fields
    WHERE · ORDER
  • [2] List
    place fields
    groups · sort
    five layouts
  • [3] Detail · Search
    shape the form
    choose components
    insert / update split
  • [4] Hook · Code
    inject hooks
    [Builder] emits code
    reuse snippets
  • [5] Menu
    4-level tree
    [menu:code]
    common include

DB tab in detail — if the connection is down you first see a "DB not connected" banner with a reconnect guide. Once it is live, the panel opens up like this:

  • #list (editable) — one main table. Pick from the dropdown and press [Select]. This is the table whose rows you will edit / delete / insert.
  • #list2 (view-only) — a secondary table for joins (e.g. pulling labels or names).
  • #list3, #list4 … — click the in the sidebar to add additional tables.
  • Three field pickers — from the same column list you separately multi-select "fields for List", "fields for Detail", and "fields for Search". A checkbox next to each toggles all on / off.
  • DB Search OptionWHERE · ORDER BY · LIMIT three lines, plus an optional Raw Query. These become the default query filter for the list.
  • Bottom [Update] saves the step; [Reset] starts over.
TIP If a single program has to handle multiple tables, add #list2, #list3 … as needed. Picking fields here is the raw material — "do we use this column?" is all that is decided now; display names, order, and formatting get refined in the List / Detail / Search tabs.
2
Step 2 · Design the list page (List tab)

The "fields for List" you picked in the DB tab appear as candidates on the left. This tab defines what the list screen looks like and how each column behaves.

Pick one of five layouts first. The options below auto-adjust to your choice.

  • datatable — table with built-in sorting and pagination.
  • table — plain table with per-column sort toggle.
  • grid — card grid.
  • modal — list that opens rows as modals in place.
  • slots — embedded into slots of a layout frame.

Add items (field columns) — click [+ Add Item] on the left to open the candidate dropdown. Pick an existing field, or use + new to add a virtual one (for computed or composed values).

  • Per row: header_value (display label) · header_text (description) · width · mutator (per-field custom code) · sortable · linkable · use_opt (option value) · (show / hide toggle).
  • Use ↑↓ to reorder, to remove, the wand for AI-assisted code.

Grouping — the top-right [Create Group] bundles selected fields into 1–5 groups. Tap to assign items into a group.

  • In group mode, [Toggle Panel] switches the view to a group edit panel. There you fill in, per group, a group name (internal identifier), a group header (title shown on screen) and a layout (how columns inside the group are arranged). At the top of the panel the group display method decides how multiple groups are shown — tabs, side-by-side boxes or a single input group row.

[Update] at the bottom saves the step.

TIP The mutator field holds the post-processing snippet that runs on a cell value before it is rendered (date formatting, thousands separator, badge coloring, etc.). If it grows long, double-click the row to pop up a layer editor with more room.
3
Step 3 · Detail / edit popup & Search (Detail · Search tabs)

The Detail tab defines the detail / edit popup (modal) that opens when you click a row in the list. The layout looks almost identical to the List tab; the key extra is picking an input component per field.

  • Component dropdown — choose the input type per field: text · textarea · select · checkbox · radio · date · datetime · file · editor · hidden
  • opt_name / opt_value — extra options specific to the component (option list for select, allowed extensions for file, format for date …).
  • insert / update triangle icon — toggles whether the field shows up on the Add form, the Edit form, or both. e.g. id / created_at are normally edit-only.
  • required (+/-) toggle — required-input flag.
  • layout — cell placement / width (1/2, 1/3, full-width, …).
  • In the top toolbar pick the primary key column (the column that uniquely identifies a row) and the detail page key (the column that will be carried in the URL when a detail page opens).

The Search tab shares the same editor. Differences:

  • Match mode — how the typed value is looked up against the DB: contains (partial match) · equals (exact match) · one-of (match against a comma list) · full-text (word search in long text), and so on.
  • Components reflect search UX — free-text inputs, dropdown filters, …

Search inputs are auto-placed above the list; submitting them AND-combines with the DB-tab WHERE you set earlier.

TIP The mcode A/D/C/E icons on the header are helpers for component_opts: Extract · Decode · Concat · Encode. When options get complex, extract them into plain text, edit, then encode back — much easier to manage long JSON-ish option strings.
4
Step 4 · Hook · session conditions · [Builder] code generation

By now steps 1–3 have filled in the screen "ingredients". Time to add fine-grained behavior, permissions, and custom logic, then emit the code.

Hook tab — shows a small diagram of the generated HTML and JavaScript scaffold, with a set of hook points (badges) where you can inject custom code.

  • Mini HTML / JavaScript skeleton at the top — <?php ... ?>, <style>, <body>, modal, data / computed / mounted / methods positions are marked so you can see exactly where your hook ends up.
  • Expand any hook row with to reveal its editor. Double-click for wide mode.
  • Right-click in the editor → Save Snippet / Load Snippet. Save recurring logic (login checks, permission guards, upload preprocessing …) under an ident and reuse it in any other program.

Style tab — CSS / SCSS editor for this program. Flip css_integrate to merge with the project's global CSS bundle; flip Backend Code to attach a PHP snippet too.

Code tab · the actual generation — this is where you press [Builder].

  • Two CodeMirror editors — Blade template on the left, Vue Script on the right. They preview the code assembled from steps 1–3 and your hook inputs.
  • Session Condition, four cells — Add / Delete / Read / Detail. Each takes a session predicate (e.g. user_level>=3) guarding that CRUD operation.
  • Feature toggle grid — turn on reusable features (CSV / Excel export, multi-delete, sort persistence, …) and set any needed parameters.
  • The [Builder] button at the bottom assembles everything into Blade + Vue Script and writes it straight into the program's actual code. From there the regular code editor takes over — edit, save, deploy as usual.
TIP Typical loop: "fill steps 1–3 → hit [Builder] once → add session / custom snippets in Hook → press [Builder] again to regenerate". Hook contents stay pinned to their named positions across regenerations, so you can iterate freely. Keep snippets tidy and the next program becomes many times faster.
5
Step 5 · Menu wizard & [menu:code] shortcode

Once you have several programs you'll want a shared navigation. The Menu tab is a wizard that builds a menu tree up to 4 levels deep and lets you drop it anywhere via a one-line shortcode.

Menu group — a namespace that holds one menu definition inside the project.

  • Pick an existing group from the dropdown, or type a new group code (alphanumeric + underscore, 2–9 chars) and press [Create Menu Group].

4-depth tree editor — selecting a group reveals a Depth 0 table on the left. Drilling into a row opens the next depth to its right; up to four columns line up as you go deeper (Depth 0 → Depth 3).

  Depth 0 ┐
          ├─ Depth 1 ┐
          │          ├─ Depth 2 ┐
          │          │          └─ Depth 3   ← max 4 levels
          └─ Depth 1'
           ...
  • Each depth table has its own [+ Add Menu] button — the popup lets you fill name, URL alias, and optional session condition.
  • Per row: edit, delete, arrows to reorder.
  • Click the check button at the end of a row to drill into that item's children in the column on the right.

Inject as a shortcode — once the tree is in place, drop it onto your actual pages. In a common include area (a layout frame, a header / sidebar partial) a single line is all you need:

<?php echo get_menus_by_code($project_id, 'group_code', 'nav nav-menu', 'role="navigation"'); ?>

At render time, the get_menus_by_code() helper reads the project_menu table and assembles <ul>/<li> up to four levels deep. Menu rows that carry a session_condition are only shown when the user's session satisfies it. The item whose URL matches the current page automatically receives the active class.

TIP To place a shared menu on every page, put get_menus_by_code($project_id, 'main') into the header / sidebar slot of a layout frame. From that point on all menu edits happen only in the Menu tab, and every page picks them up immediately. The custom_class and custom_attr arguments let you hand the renderer your design theme's class names and attributes, so the same menu adapts to dark / light, sidebar / topbar without touching the helper.

Layout Builder

Build web page layouts by assembling blocks — no coding required.

Layout Builder
Key Features
1
Page list
2
Open builder
3
Drop blocks
4
API binding
5
Deploy
1
Step 1 · Page list screen

Go to /layout/page.

  • Left sidebar[+ New Page] button + Recent / Shared / My Pages sections.
  • Top toolbar — search (field + keyword), Block/Frame/Page switcher tabs, Grid/List toggle, rows per page (20/50/100).
  • Body — page cards with title, description, frame, deployed-or-not indicator.
TIP A Block is a reusable component, a Frame is a responsive template with slots, a Page composes the two. Switch tabs to manage each kind.
2
Step 2 · Open the page builder modal

Click a page card or the grid icon to open the full-screen builder. It has three areas.

  • Left panel — top: Frame filmstrip (pick the responsive template), middle: Frame canvas (iframe + slot overlays), bottom: Block filmstrip (draggable blocks).
  • Center panel — Data sampler (Architecture / Data tabs) for API binding.
  • Right panel — Deploy + AI assist.
TIP Unsaved changes show a red "Unsaved" badge at the top. Always save right after Frame or Block changes.
3
Step 3 · Drag blocks into frame slots

After picking a Frame, transparent drop slots appear over the iframe. Start dragging a block from the Block filmstrip and the slots highlight blue — drop to install the block in that slot.

Installed slots become "filled"; click the slot again to swap. The same block can fill multiple slots, and one page can mix different blocks freely.

TIP If no existing block fits your need, go to the Block tab first, create one, and come back — new blocks appear in the filmstrip automatically.
4
Step 4 · Bind API data (⚡ icon)

In the center panel's Architecture tab, pair each block's sample data keys with actual API response keys.

  1. Each block card's left column shows the sample key tree the block expects.
  2. The center ⚡ (lightning) toggle switches on API-binding mode.
  3. On the right, pick an endpoint you built in the Database service → that API's response key tree expands.
  4. Click to pair a sample key with an API key — a mapping line connects them and appears in the "Pair Map" at the bottom as sample_key → api_key.

The Data tab shows raw JSON responses for debugging.

TIP If an endpoint isn't visible in the dropdown, confirm it's actually deployed in the Database service. APIs saved but not deployed don't show here.
5
Step 5 · Deploy — URL slug & Expose parameters

Use the right panel to deploy.

  • Expose parameters — list of query/path parameters to expose in the URL. Each row has an enabled checkbox, name, source (query/path), default value. [Add] to grow the list.
  • Deploy URL — typing a slug like /my-page updates the preview live.
  • [Deploy] — shows a progress bar + step label; when done, it's live on the domain.
  • Below, the Deploy history accumulates past URLs you can revisit.
TIP Exposing category as a path parameter lets the same page code serve /product/beverage and /product/dessert with different data — no code duplication.

Slideshow

A channel service for managing presentations and display content.

Slideshow
Key Features
1
List
2
Register
3
Timeline
4
Params/Channels
5
Deploy
1
Step 1 · Slideshow list

Open Display > Slideshow from the menu. Left sidebar has a [+ Register slideshow] button and a "Community slideshows" filter; the body is a Grid/List view.

Each card shows title, scene count, total play duration, and deploy status.

TIP Slideshow's core use case is broadcasting the same content to many displays at once — store signage, classroom monitors, event screens.
2
Step 2 · Register a new slideshow (2-step wizard)

Click [+ Register slideshow].

  1. Step 1 — Introduction: cards + flow diagram (Remote → Upload → Slideshow → Browser) explaining URI mapping, channels, 67 transitions, and timeline control.
  2. Step 2 — Register: enter title + description → [Save] → lands in the detail editor.
TIP Slides are typically pages built in the Layout Builder. Prepare the pages to be displayed before you register.
3
Step 3 · Timeline & transitions

The center Timeline panel defines playback.

  • Total duration — slider, 10–3600 s.
  • Scene count — range slider; per-scene duration auto-calculates.
  • Transitions — pick from a catalog of 67 (fade, slide, cube, page flip, etc.).
  • Confirm with the [Save] button.
TIP More scenes means less time per scene. Do the math in advance: "5 min total / 10 scenes = 30 s each."
4
Step 4 · Parametric cursor & display channels

Parametric cursor (Page Sequencer) auto-generates N scenes from a single layout page by varying one parameter.

  • Parameter name (e.g. month), algorithm (by_range / by_comma / by_json), values (e.g. 1-12 step 1).
  • Result: 12 auto-generated scenes, one per month.

Display channels (MAX only) — broadcast the same slideshow with different mixes to different displays.

  • Channel name (e.g. "Category A", "Category B") + multi-select slides to include.
  • Toggling "Use query parameter" maps channels to URLs via ?keyword=value.
TIP Single channel = all displays show the same thing. Multi-channel = different menus/promos per kiosk from one slideshow.
5
Step 5 · Deploy & share

The right deploy panel (se-deploy) publishes the show.

  1. Type a URL path (e.g. /menu-signage) + pick a domain from the dropdown.
  2. Click [Deploy slideshow] — progress bar, "Deploying..." and "Deploy complete" messages.
  3. A deploy history card records domain / path / timestamp.

Point each display's browser at the URL in fullscreen — you're done.

TIP Chrome's "Kiosk" mode or a Raspberry Pi running Chromium in fullscreen makes autoplay reliable.

Data Collection (Parser)

Automatically crawl websites and save data to your database.

Data Collection (Parser)
Key Features
1
Rule list
2
Wizard
3
Extract setup
4
Item test
5
Run
6
Schedule
1
Step 1 · Parser rules list

Open Data > Parser from the menu. Left sidebar has [+ New Parser Rule] plus Recent / Public / My rules sections; the body is Grid/List view.

Each card has (Run) · (Item test) · (Schedule — MAX) · (Edit) · (Duplicate) · (Delete) icons.

TIP Forking a rule from "Public rules" for a similar site is fastest — the selectors are already tuned.
2
Step 2 · Create rule wizard (3 steps)

[+ New Parser Rule] opens a 3-step wizard. The wizard only registers the base rule info (name, description, target dataset) — the actual crawl URL, selectors, and field mapping are filled in afterwards on the parser settings screen that opens automatically when the wizard finishes.

  1. Step 1 — Overview: A "What is a Parser Rule?" intro followed by four feature cards side-by-side (Data Extraction, Advanced Web Crawling, Field Mapping, Reusability) and a "Parser Pipeline" diagram showing the four supported flows at a glance (Parser Rule → DB / → Macro → DB / → Scheduler → DB / → API Endpoint → Service Launch). Press [Next] to continue.
  2. Step 2 — Database Connection: Click a dataset card (shows db_type badge, table name, domain) to pick where extracted rows will land. If no datasets are registered, only a "Go to Dataset" link is shown. Pressing [Next] auto-runs a 3-step deploy progress ("Agent connect → Parser engine deploy → Deploy complete") that provisions the parser engine on the selected docker agent.
  3. Step 3 — Create Rule: Enter the rule name and optional description, then press [Create Rule]. The base info (name, description, dataset, share flag) is saved, the wizard closes, and the settings screen of the newly created rule opens automatically.

That is where the wizard ends. On the parser settings screen you then fill in the target URL, HTTP options, Loop Splitter, XPath/JSON selectors, and field mapping (see ▶︎ Step 3 · Target URL & extraction selectors), verify results on the "Test" tab, and save — only then is the parser ready to actually run.

A step bar at the top tracks progress; [Back] returns to the previous step (disabled while deployment is running). The wizard modal closes only via the top-right [x] button.

TIP No dataset yet? Close the wizard, hop to the Database service, create one (even an empty table is fine) — the parser creates columns automatically.
3
Step 3 · Target URL & extraction selectors

Enter the Target URL at the top of the editor and combine three techniques to extract rows.

  • Loop Splitter (3 inputs — primary + 2 secondary) — string patterns that chop HTML into repeated units.
  • XPath selectors — up to 3 levels, extracting fields inside each unit. The selector should point at a node set (array), not a leaf value — if the actual data sits at //h3/a/text(), enter just //h3/a so the result comes out as an array.
  • JSON selectors — for JSON APIs, dot/bracket paths. Same idea: point at the array path. If the data has a shape like data.items[0].title, enter data.items as the selector so the item array is produced.
  • Post-processing functions — chain trim(@p), replace(...), regex(...), strtoupper(@p), slice(), remove() per column.

The fastest path is to feed a slice of the source (via the Loop Splitter) into the AI Prompt and let the AI response auto-register the rule. Hand-tuning selectors one by one is much slower — especially when the page structure is non-trivial.


Auto-register with an AI prompt (recommended)

Instead of hand-filling selectors, hand the sample to an AI and apply the completed rule it returns.

  1. Prerequisite — enter the Target URL and run the extract test once from the "Test" tab so a response body exists. That body is injected into the prompt automatically.
  2. Click the highlighted "AI Prompt" button (wand icon) at the top of the test result panel. A prompt is auto-built in the editor area just below it, picking the right language for the document out of 8 supported (Korean · English · Japanese · Chinese · Russian · German · French · Spanish) and the right document type (HTML / JSON / XML).
  3. Click inside the editor panel → Ctrl+ACtrl+C to copy everything.
  4. Paste into an AI such as ChatGPT / Claude / Gemini and run → the AI returns a rule JSON.
  5. Copy the response, then click the "Import Pattern" button (import icon) in the same panel — a paste-in textarea opens. Paste and click [Apply Pattern].
  6. Loop splitter, selectors, unique key, and every column are mapped into the right slots of the rule automatically; the editor switches to the "fields" tab so you can check the result immediately. A summary toast like "Pattern applied: N fields" appears at the bottom.

If the AI response isn't valid, you'll see an "Invalid JSON" toast and your existing values stay untouched — safe to retry.

TIP JS-heavy SPAs have empty HTML on a plain request. Open the Network tab in devtools and target the internal JSON API the site itself calls — far more stable.
4
Step 4 · Item test

The (vial) icon on a card — or the Test tab in the editor — opens the test modal.

  • Top bar: "N items / M columns"
  • Exports: CSV · XLSX · JSON · HTML
  • Grid: Row# + auto-detected columns
  • Cell hover → "Copy" button

Tweak selectors, test, adjust, test — repeat until the output looks right.

TIP "Only 1 row extracted" means your Loop Splitter is too broad; "rows look right but cells are empty" means the XPath/JSON selectors are wrong. Diagnose which before editing.
5
Step 5 · Parse Run (Run modal)

Clicking the (Play) icon on a rule card opens the Run modal — the single screen where you decide where to hit, with what parameter combinations, how to run, and where to store results, then launch and monitor in place.

  • [1] URI
    Target address
    {param} tokens
    path · query
  • [2] Fuzzer
    Parameter mix
    1-N · A,B · DB
    combine / pair
  • [3] Preview
    Expand URLs
    Fill left panel
    Verify count
  • [4] Run · Save
    Runtime / Schedule
    DB / CSV / JSON
    Items per run
  • [5] Start
    Flow checks
    [Start] enables
    Pause anytime
  • [6] Feedback
    Progress · stats
    Per-URL log
    Macro chain

Interface at a glance — 3-panel layout

  • Left panel · URL list — shows the preview URLs generated from the center panel, numbered. While a run is in progress the current row is highlighted and finished rows show a check, so you can see progress at a glance. Each row has a button to test-parse that single URL in isolation, and a at the top-right loads past run configurations for reuse.
  • Center panel · Plan & Execute — the main body: define URI, fuzzer parameters, run/save mode, then launch from the flow diagram's [Start] button.
  • Right panel · Result feedback — two tabs. "Results" shows live statistics and log during a run; "Parse Test" shows the cell-level preview when you click on the left.

Step-by-step

  1. URI input — first card in the center panel. Two example styles — path-token (/category/{param}/list) and query-string (?param={param}) — are pinned to the header as clickable hint badges. Names inside the curly braces {...} must match the parameter names defined in the next card so substitution works.
  2. Fuzzer parameters — the card that builds the list of values injected into each {...}. A top toggle picks one of two modes:
    • Combination — cartesian product of every parameter's values. E.g. {page}=1..10 × {cat}=A,B → 20 URLs.
    • Paired — zip-style: the n-th value of every parameter together. All lists must have the same length.
    For each parameter pick a name and a generator1-N (range with step), A,B (comma list), DB (pull from a dataset column with optional WHERE/ORDER/LIMIT), [,] (JSON array), or \n (newline list). adds another parameter.
  3. URL preview — the [URL preview] button at the bottom of the card expands the URI + parameter combinations into real URLs listed in the left panel. The count shows in the header badge, so you can immediately verify the expected size (e.g. range 10 × categories 2 = 20).
  4. Run mode & Save mode — the third card.
    • Run: Runtime (one-off) / Schedule (periodic, MAX plan). Schedule reveals start-time and interval (minutes) inputs inline.
    • Items per run: Page / PK.
    • Save: DB (dataset, or a custom external DB via host/user/password/database), CSV, JSON, or SQL. DB mode also surfaces table (collection) name and a DBMS badge so you can confirm the destination visually.
  5. Visual flow guide & Start — below the cards, a small flow diagram chains URI → Parameter → Preview → Save → [Start] → Macro. Each node lights up with a green check as its input is filled. Once required nodes are valid the [Start] button at the top-right activates. (If you pin a macro on the trailing node, it runs automatically right after the scrape.)
  6. Live feedback while running — the moment you press Start, the top progress bar fills up (parsed / total) and the right-panel "Results" tab updates in real time.
    • Stat cards: Total · Passed · Failed · Remaining — the red "Failed" card only appears when a failure actually happens.
    • Log view: one line per URL as it's processed, latest highlighted, each showing time · URL · +rows added; failed URLs carry an badge.
    • Pause / Resume: the Start button switches to [Pause] during a run — stop at any time safely.
    • File-save modes (CSV/JSON/SQL): the Output textarea below fills with the generated file body; a button grabs it immediately.

What this run screen buys you

  • Plan, run and observe in one screen — no tab hopping. Tweak the URI, parameter list, or save target and immediately re-run. The configure → run → verify loop is as tight as it gets.
  • A fuzzer that scales — generate tens of thousands of URLs without writing one by hand. Ranges, comma lists, DB columns, JSON arrays, newline lists — category × page × date combinations are ready in seconds.
  • DB-backed parameters (by_db_field) read a key table column and iterate detail pages on top of it — the classic "list → detail" two-stage crawl works end-to-end without spreadsheets or glue scripts.
  • Transparent live feedback — per-URL checkmarks, streaming log, and success/fail counters make it easy to spot exactly where things stalled. Rerun a failed row on its own via to isolate the cause.
  • Resource-friendly architecture — the actual HTTP and parsing runs on your docker agent, not the QuickStart server. Large crawls don't affect the service's bandwidth.
  • Macro chaining — attach a macro to run right after the scrape for notifications, aggregation, or post-processing, turning collect → clean → notify into a single action.
TIP Start small. On the Fuzzer card try a tiny range first (e.g. by_range 1-5), press "URL preview", confirm the expected count, then scale up. This saves you from accidentally firing thousands of requests because of one bad config.
6
Step 6 · Scheduled runs (MAX)

Scheduled runs are a hands-off mode: the docker agent executes the rule on a fixed interval on its own, even while the screen is closed. Rows flow straight into the dataset (DB), so to actually see the results you open the target table in the Database editor.

  • [1] Schedule setup
    Start time
    Interval (min)
    Active toggle
  • [2] Agent sync
    [Save] pushes
    config to the
    docker agent
  • [3] Auto periodic run
    Agent runs alone
    QuickStart idle
    Background task
  • [4] DB accumulation
    Rows INSERT into
    dataset table
    Dup keys skipped
  • [5] Check in Database editor
    Data > Database
    Open the table
    Query with WHERE/ORDER

The (clock) icon on a card opens the schedule modal (FREE/PRO plans show a "Max" ribbon).

  • Start time (hour 0–23, minute 0–59)
  • Interval (minutes)
  • Active toggle
  • Run mode: Single URL / URL list (batch)

[Save] persists to QuickStart and auto-syncs to the selected docker agent. The agent is what actually runs the schedule — QuickStart never sits in the traffic path.


Verify results in the "Database editor"

Because scheduled runs are headless, the way to check the output is to open the target dataset directly and inspect the rows that piled up.

  1. Open Data > Database from the left menu.
  2. Click the dataset card that the parser rule is linked to — this opens the Database editor.
  3. Pick the target table from the left table list (e.g. items, products, etc.).
  4. Use WHERE / ORDER BY at the top to bring recent rows to the top (ORDER BY created_at DESC, ORDER BY id DESC) and inspect what the last scheduled run added.
  5. A quick row count (COUNT) or a date-range filter is enough to sanity-check trend — if the count grows each interval, the schedule is healthy.

The run log itself is shown as a table in the Run modal's right-panel "Results" tab when schedule mode is active, but for content verification of the actual harvested data, the Database editor is always the source of truth.

TIP In the editor's flow diagram, pick a macro from the "Select macro" dropdown. That macro fires right after each scrape — perfect for alerts, aggregation, and similar post-processing. Chain a macro into a Database-editor query once and every scheduled run repeats collect → refine → inspect automatically.

Automation Macro

Write and execute server-side scripts to automate repetitive tasks.

Automation Macro
Key Features
1
List
2
Wizard
3
Write code
4
Quick Test
5
Schedule
1
Step 1 · Macro list

Open Data > Macro from the menu. Left sidebar with Recent / Community / My macros sections; body is Grid/List view. The top toolbar supports search by name or description.

Click the sidebar's [+ New Macro] button to open the create wizard immediately.

TIP A macro automates repetitive work (ETL, batch APIs, migrations, CSV imports). It's server-side PHP/Node.js/Python with no visible UI by default.
2
Step 2 · Create a new macro (4-step wizard)

[+ New Macro] opens a 4-step wizard. This single wizard covers both registering the macro's base info and preparing its runtime server.

  1. Step 1 — Macro intro: A "What is a Macro?" intro with four feature cards (Pipeline Chaining, Adapter Pattern, Input → Output, Code Gen) and a flow diagram showing four supported topologies (DB Query · Chaining · Parser · Scheduler). No input — press [Next].
  2. Step 2 — Connection method: Prepare where the macro will actually run. Two options:
    • Deploy new macro server — Connect your Railway account (paste token), then pick language · framework · core stack · optional addons (MongoDB / FFmpeg / Puppeteer / WebSocket, etc.) · DB credentials. Clicking [Deploy server] runs a 6-step pipeline (Receive → Decrypt → Docker build → Deploying → Network → Verify) and your account gets a dedicated macro runtime.
    • Connect existing macro server — If you already have a server running your macro code, enter its connection info to attach to it.
    Once the server is ready the wizard auto-advances.
  3. Step 3 — Type selection: Pick one of 24 macro types (ETL pipeline · Batch API · Data migration · CSV/Excel import · and more). Starter code matching the type — with input parameters, loop scaffolding, and output structure — is auto-generated as a starting point for the next step.
  4. Step 4 — Register: Enter a macro name (e.g. "Nightly DB sync", "Bulk translate") and a short description, then press [Create]. The macro is saved, the wizard closes, and the detail view (code editor) opens automatically.

A step bar at the top tracks progress; [Back] returns to a previous step (disabled while deployment is running). The wizard closes only via the top-right [x] button.

TIP A macro server is shared across many macros — you deploy "your macro server" once and run many macros inside it. For every macro after the first, pick Connect existing macro server in the wizard's Step 2 to attach to the same server.
3
Step 3 · Write code (PHP · Node.js · Python)

When the wizard closes, a 3-pane editor opens: on the left, the input-field definition; in the center, the code editor with PHP / Node.js / Python tabs; on the right, the AI Prompt pane. The editor is pre-filled with a scaffold for the macro type you chose in Step 3, so you usually just edit the important parts.

  • [1] Receive run_data
    input_data
    conn_string
    table_name · user_id
  • [2] Normalize inputs
    array → object
    Type cast
    Defaults
  • [3] Core logic
    API · DB
    Files · shell
    Data transforms
  • [4] Assemble result
    success flag
    data / json
    download_links
  • [5] Return
    Match the
    output type
    picked in wizard
  • [6] AI Prompt
    Right pane
    Pick a scenario
    AI → paste code

The variable you automatically receive — run_data

Your function always takes a single argument called run_data. The server fills it in just before running, and it carries at least these keys.

  • run_data.input_data — the values the user typed into Quick Test or the scheduler. It first arrives as an array of { item_name, item_value, item_type } entries, so the first job of every macro is to flip it to a plain key/value object.
  • run_data.conn_string — DB connection string of the dataset you picked in the wizard (AES-decrypted by the server). DB-oriented macros use it as-is.
  • run_data.table_name, run_data.file_name — target table / file name from the wizard.
  • run_data.user_id, run_data.app_id — the caller and the macro id. Handy for logging and permission checks.
  • run_data.save_type, run_data.app_type — the save mode and macro type selected in the wizard. Use for branching.

Recommended coding pattern

This is the minimal skeleton even a hobbyist developer can copy straight. Keep the function name you set in the wizard (e.g. macro_run) — the server calls it by that exact name.

Node.js example — distilled from the real _sample/code39.js:

async function macro_run(run_data) {
    // ── 1) Normalize inputs — accept both array and object ──
    const raw = run_data.input_data || {};
    const params = {};
    if (Array.isArray(raw)) {
        raw.forEach(f => { params[f.item_name] = f.item_value; });
    } else {
        Object.assign(params, raw);
    }

    // ── 2) Defaults · type casting ──
    const output_format = params.output_format || 'svg';
    const style         = params.style || 'default';
    const max_items     = Number(params.max_items || 10);

    // ── 3) Core logic ──
    try {
        // ... API call, DB query, file transform, etc.
        const results = [ /* collected results */ ];

        // ── 4) Build result & return (success) ──
        return {
            success: true,
            data: results,                        // array renders as table
            message: results.length + ' item(s) processed',
        };
    } catch (e) {
        // ── 4') Failure uses the same shape ──
        return { success: false, error: e.message, data: [] };
    }
}

PHP / Python follow the same shape — a function taking run_data and returning ['success' => true, 'data' => [...]] / {'success': True, 'data': [...]}. Define your fields in the left Input pane, then press the scaffold button in the center pane's header — the tool generates a language-specific skeleton that already unpacks every declared field for you.


The return shape follows the output type you picked in the wizard

The return protocol is the same for every macro, but which fields you fill depends on the output form you chose in Step 3 of the wizard. The Quick Test result panel looks at those fields to decide how to render.

  • success: true/false (required · all macros)
  • data: [{...}, {...}] — when output type is "table / grid". The panel auto-detects columns and renders a table.
  • json: {...} — when output type is "JSON / raw". Rendered in a JSON viewer (textarea + copy button).
  • download_links: [{ url, name, size }] — when output type is "file download". Rendered as a list of download buttons.
  • message (success) / error (failure) — text block (<pre>). Safe to include alongside any of the above.

You can fill multiple fields at once — e.g. show a data table and also hand over a CSV via download_links (the real code39.js returns data + download_links + message together).


Getting code from AI — the right pane

When the logic gets tricky or an external library feels unfamiliar, ask for help from the "AI Prompt" pane on the right.

  1. First, define the required input fields (name, type, description) in the left Input pane. This definition is baked into the prompt automatically.
  2. Click a scenario badge at the top of the right pane (examples tailored to your macro type — e.g. "Scrape a URL and INSERT into DB", "Migrate table A → B") and the scenario template fills the prompt textarea.
  3. In the textarea, add specifics (which URL, which columns, which edge cases to handle, etc.).
  4. Click the header's copy button to copy the whole prompt, paste it into ChatGPT / Claude / Gemini, and run.
  5. Paste the AI's code into the center editor and press Save.
  6. Jump to Step 4 (Quick Test) and iterate.

Combine the scaffold button () with the AI Prompt and the code you actually have to write shrinks down to just the core-logic lines.

TIP The "input array → object" snippet at the top of your function is the shared standard across every sample macro. Copy that block once and the same code works for both Quick Test and scheduled runs. While debugging, a single console.log(params) / print($input_data) line shows the actual received values — they stream straight into the terminal pane below.
4
Step 4 · Quick Test

Switch to the Quick Test tab (🧪 flask icon) at the top of the left pane. Quick Test runs the code through the macro server you prepared in Step 2.

  1. Fill in the input parameters row by row.
  2. Click [Run] → "Running..." spinner.
  3. Result display depends on the return shape:
    • data → table
    • json → JSON viewer
    • download_links → list of download buttons
    • message/error<pre> text block

Stdout and stderr stream into the terminal pane below in real time — great for debugging.

TIP When the code misbehaves, check the terminal output first — the usual culprits are missing dependencies, typos in DB credentials, or forgetting success in the return object.
5
Step 5 · Scheduled auto-run

Once Quick Test looks good, hand the macro off to a schedule for unattended execution. In the detail view's Schedule section, two values are all you need.

  • Start time (offset)HH:MM format (e.g. 00:00 = midnight, 03:30 = 3:30 AM). This is the anchor for the repeating schedule.
  • Interval N (minutes) — the macro runs every N minutes from the start time. Enter 5 for every 5 minutes, 60 for hourly, 1440 for once a day.
  • Active toggle — pause or resume without losing the config.

Examples: start time 00:00 + interval 5 → runs every 5 minutes from midnight (00:00, 00:05, 00:10 …). Start time 09:00 + interval 1440 → runs once a day at 9 AM.

Once saved, the macro server runs this macro on this cadence on its own. QuickStart only signals — actual execution and traffic live on the macro server. (There are no cron expressions — start time + interval is all the scheduler uses.)

TIP Only schedule after the server is ready and Quick Test has passed at least once. The first unattended run may not leave terminal output behind, so only point a schedule at code you've already verified.

Database

Create and manage databases with automatic REST API generation.

Database
Key Features
1
Open
2
Wizard
3
DB editor
4
API auto-gen
5
Security & call
1
Step 1 · Database service screen

Open Data > Database from the menu. Left sidebar has a blue [+ New Dataset] button and Recent / Public / My / Team sections; the body is Grid/List view cards.

Each card's four icons: (DB editor) · table (cell editor) · (API settings) · copy/delete.

TIP A dataset is just "a DB connection + an optional WHERE/ORDER view." Think of it as "the slice of a table you want to expose," not the whole DB.
2
Step 2 · 3-step wizard (connect → pick → register)

[+ New Dataset] → wizard modal.

  1. Step 1 — three connection options: Deploy new DB (Railway) · Connect existing DB · Local file (JSON/CSV/Excel). DB type dropdown (MySQL 3306 · MariaDB 3306 · PostgreSQL 5432 · MongoDB 27017) · host · port · DB · user · password → [Test connection] verifies the credentials reach the database.
  2. Step 2 — on success, pick a table; its fields expand.
  3. Step 3 — register the dataset: name · description · table · PK · columns (* or comma-separated) · WHERE · LIMIT · ORDER BY · shared. The right panel's [Test query] previews results; then [Save].
TIP Applying WHERE here is the strongest security you can do. "Only in-stock products" set at the dataset level automatically propagates to all downstream APIs.
3
Step 3 · Database Editor

Click the ▶ (play) icon on a dataset card to open the full-screen editor, which has three panels.

  • Left — tabs (Tables/Views/Procedures/Functions), table structure inspector, command icons (Copy CREATE · Drop · Update · Insert · Delete · Join · Reverse · Refresh).
  • Center — multi-tab SQL editor. ▶ Run or F5/F9. Export as TSV/CSV/JSON/SQL, or send straight to a macro with "Send to Macro".
  • Right — result grid with cell-level editing.
TIP Natural-language SQL: use the Ask button (speech-bubble icon) at the top of the editor to ask something like "total sales this month by table" — an AI prompt combining the selected table's schema with your question is copied to the clipboard. Paste it into an AI such as ChatGPT / Claude / Gemini and you get a ready-to-run SQL back.
4
Step 4 · Auto-generate REST API

Click the API settings button (plug icon) on a card and the API settings modal opens.

  1. Basics: Namespace (required, URL tail) · Table · JOIN Table · Page var (default page) · Per Page (50) · cache (0–1440 min).
  2. [Auto generate] → assembles the JSON shape (main_container → main_fields → item_container → item_fields → detail). Each field is a "JSON key → SQL variable" pair.
  3. [Save][Deploy] activates the endpoint.
TIP "Auto layout" generates a Layout Builder block that consumes this API immediately — instant page without writing a front-end.
5
Step 5 · ACL security & external calls

Endpoints go live at GET https://happycat.apidealder.net/endpoint/{namespace}. The modal's ACL section locks them down.

  • API Key (auto-generate button · header/param delivery · header name X-API-KEY)
  • IP whitelist — wildcards / CIDR
  • Referer restriction — allowed domains
  • Rate limit — max req/min

Example: curl -H "X-API-KEY: ..." https://happycat.apidealder.net/endpoint/menu_list

TIP A key placed in browser JS is visible from the page source. On public pages, scope usage with Referer + Rate limit; when you want to keep the key private, call from the PHP side in your Project so the key stays server-side only.

Remote Management

Open, edit and manage files on your deployed server from the browser — no FTP or SSH client needed. Folder browsing, code editing, uploads, and a live shell all share the same screen.

Remote Management
Key Features
1
Layout
2
Pick server
3
Browse
4
Edit
5
Act & shell
1
Step 1 · Get your bearings on the screen

Remote Management is split into four zones. Know where to look before you start clicking.

  • Left server list — every domain you're managing, each with a small status dot. You can collapse this panel to just icons when you need more room.
  • Center file area — the file browser for the selected server. The toolbar at the top holds the path bar, sort buttons, and the terminal toggle; the folder content below expands into columns as you drill in.
  • Bottom action bar — Upload · New folder · New file · Download · Delete. Buttons light up only after you pick a file or folder.
  • Terminal panel — a console that slides up from the bottom on demand. Use the terminal icon in the top toolbar to show/hide it.
TIP If the left server list feels cramped, hit the collapse button at its top to shrink it down to icon-only. Handy on narrow laptop screens.
2
Step 2 · Pick the server to manage

Click a domain in the left list. The dot next to the domain name tells you its current state:

  • Green dot — online. The file list opens immediately.
  • Gray dot — offline. The container may be sleeping or the network may be blocked.
  • White dot — still checking, or the status is unknown.

If the list is empty you'll see a "Deploy a server first" prompt with shortcut buttons to the single-file, project, and database deployment screens.

TIP If a dot stays gray or white for a while, wait 1–2 minutes and click the domain again. A container that has been idle can take a few seconds to wake up.
3
Step 3 · Find the folder, pick the files

The center area is a column-style browser — each folder you click expands into a new column on the right. Up to four columns are visible at once; deeper paths collapse the leftmost column automatically.

  • Path bar — the house icon jumps back to the root (/), and each slash-separated segment above is clickable to jump to that exact spot.
  • Path input — type a full path such as /var/www/html/storage/logs and press Enter to jump straight there without clicking through.
  • Sort buttons — name · size · modified time. Press the same button again to flip the order.
  • Selecting — a single click selects one item, Shift+click picks a range, Ctrl/+click adds or removes items one by one. Once more than one item is picked, an "N selected" badge appears in the top-right of the action bar.
TIP If you already know the path, pasting it into the path input is by far the fastest way in — one Enter replaces half a dozen clicks.
4
Step 4 · Open a file to view or edit it

Click a file once to select it. Click it a second time and it opens — the right view pops up automatically based on the file type.

  • Text / code files → a syntax-highlighted editor opens in the center. HTML, PHP, Vue, CSS/SCSS, JavaScript/TypeScript, JSON and more are detected automatically.
  • Images (PNG · JPG · GIF · SVG · WebP · BMP · ICO) → open in a preview viewer so you can confirm them visually.
  • Binary / executable files trigger a "Cannot edit binary file" message and don't open.
  • The [Save] button in the top-right of the editor pushes the change to the server on the spot — no redeploy needed. Esc or [Cancel] closes without saving.
  • Only files up to 10 MB can be opened in the editor; larger files show a "too large" notice instead.
TIP For small production fixes like .env, config tweaks, or log inspection, editing right here is the fastest path. Saves go live the moment you hit Save — no full redeploy required.
5
Step 5 · Upload, download, delete, and the shell

Combine the bottom action bar with the terminal panel to get actual work done.

  • Upload archive — drag or click to pick a .zip · .tar · .tar.gz · .tgz file. A preview of the archive contents appears; once you hit Start Upload, the file is sent in 1 MB chunks with a percent bar, and the current folder auto-refreshes when it finishes.
  • Upload file — pick one or many files at once and they're uploaded as-is into the current folder (no extraction).
  • New folder / New file — prompts for a name. Letters, digits, dot, hyphen, and underscore only.
  • Download — files download as-is; pick a folder and it's zipped into a single ZIP automatically.
  • Delete — confirms once; with multiple items selected, all of them go in a single operation.
  • Move / copy — drag a file onto a folder and a confirm dialog opens. Or press Ctrl+X/Ctrl+C to stash a selection, then Ctrl+V in a different folder to paste with the same confirm dialog.
  • Terminal — the terminal icon in the top toolbar slides up the bottom panel and connects you to the selected server's shell. Type a command and press Enter — stdout shows in white, stderr in red. / recalls previous commands, and the current working directory is tracked for you, so after cd some/path the next command runs from there.
TIP Containers are based on lightweight Alpine Linux, so /bin/sh is the default shell — not bash. Install new packages with apk add package-name.

AI Prompt Guide

QuickStart doesn't bundle an AI and query it directly. Instead, AI Prompt buttons throughout the product capture the context you're looking at (table schema, HTML sample, layout structure, etc.) and copy a structured prompt to the clipboard. Paste it into an external AI such as ChatGPT, Claude, or Gemini — the adjacent Import button then applies the response back into the UI. The prompt is already scaffolded for the task, so you don't have to figure out what to describe.

VSCode Extension

A VS Code extension for working on your QuickStart project locally in the editor of your choice. Download the project as a package from the web console, open the folder in VS Code, and everything that follows — auto-authentication → automatic Laravel / frontend setup → file editing → deploy to other servers → two-way sync between the web and the editor — happens inside a single side panel (QUICKSTART at the bottom). Walk through the steps below once and the rest becomes button clicks.

40-Language Translation

A tool that translates every on-screen phrase (words and menu labels) of one project into many languages at once. It scans your project pages for translatable terms, assembles the AI prompt for you, pulls the AI's JSON response back into the grid automatically, persists the result into the project's translation store (project_translate table), and finally exports a Laravel-ready lang_files.json. The goal — scale to 40 languages in a single cycle — is designed so that even a first-time user can walk through the steps below.

Solution Market

Browse and fork projects, macros, and single files created by other users to start your own.

Fork & Share

Share your projects and fork others' to get a head start.

Domain Management

Manage free domains provided by QuickStart.

Build Your First Website

A step-by-step walkthrough of a small restaurant reservation page from the first click to going live — with exact button locations and the order of events so a complete beginner can follow along. When done, visitors can pick a date, time, and party size and submit a real reservation.

Estimated time: 15–25 min
1
Open Editor
2
Pick Template
3
Edit Content
4
Preview
5
Connect Host
6
Deploy
7
Go Live!
1
Step 1 · Open the Single File editor

After signing in, open the top navigation or dashboard and click Services → Single File. The screen is split into a top toolbar and the body:

  • Top toolbar — left side: History · Guide · Title input · Save (💾). Center: Template dropdown. Right: Share · Run ▶ · Deploy 📦.
  • Center editor — four tabs at the top: prompt · html · scss · vuejs. Click to switch.
  • Right preview panel — renders when you press Run.
TIP The editor may open empty on first visit. Don't worry — the next step picks a template from the dropdown.
2
Step 2 · Pick the Restaurant Booking System template

Open the template dropdown in the center of the toolbar and choose "Restaurant Booking System". The sequence is:

  1. The moment the dropdown value changes, the selected template is automatically applied.
  2. All four tabs (prompt · html · scss · vuejs) are auto-filled with the pre-built code plus the AI prompt used to regenerate it.
  3. The active tab switches to prompt by default — that text is what the AI uses if you ask for a regeneration.
  4. Click Run ▶ in the toolbar and the right preview renders a 3-column reservation screen (calendar / time slots / reservation form).

Note: this template is an operator screen for the shop owner to manage dates, time slots, and table availability — not a simple visitor-facing menu landing page.

TIP Switching templates discards your current code. Press Save (💾) on the toolbar first if you want to keep anything.
3
Step 3 · Customize via Settings modal + code

This template is customized in two tiers: a Settings modal (no code needed) and direct code edits. The entry point is the ⚙ Settings icon next to the theme toggle (☀/🌙) at the top right of the rendered page.

A. Settings modal — data only, no code

  1. Click ⚙ → a full-screen overlay opens with a centered modal (4 tabs).
  2. Time Ranges — adjust morning / lunch / dinner start and end times with number inputs. A visualization bar at the top reflects color segments live. If start == end, the segment shows "(inactive)".
  3. Time Slots — pick a step (10 / 30 / 60 / 120 min), then toggle individual slots active/inactive in the grid. Active/inactive counts are shown at the top.
  4. Tables — list with inline rename + delete, and an input at the bottom to add tables. This list drives the "Table" select in the reservation form.
  5. Holidays — recurring off-days (Sun–Sat, 7 toggle buttons) + specific holidays (date input + reason text, add/delete list). Reasons only show inside settings, never on the public screen.

B. Code edits — shop name, theme, etc.

  • html tab — replace the header title string "레스토랑 예약" with your shop name. Use Ctrl+F to locate it.
  • vuejs tabmounted() contains mock-data generation (D+1 ~10%, D+2 ~5%, D+3 ~2% random reservations + a Korean names array). For real use, empty that block or replace it with a server API call. Public holidays are fetched from https://date.nager.at/api/v3/PublicHolidays/{year}/KR — swap KR for another country code if needed.
  • scss tab — the theme uses CSS custom properties, not SCSS variables. Defined under .reservation (light) / .reservation.dark (dark): --primary (brand accent), --bg (page background), --card-bg, --text / --text-sub, --border, --holiday (public-holiday red), --closed-bg (shop holiday amber), --occ-bg / --occ-border (slot with seats left). Editing just these shifts the whole look consistently.

After editing: Save (💾)Run ▶ to refresh. Unsaved tabs show a small dot (●).

TIP Values you change in the Settings modal only live in-memory and reset on refresh. To persist, add a mounted() localStorage load + a watcher that saves changes, or graduate to the Project service (PRO) to store in a real database.
4
Step 4 · Run a full reservation scenario

Now try booking one reservation yourself, as if you were a customer. This matches exactly what your staff or visitors will do after going live. Follow this order inside the preview:

  1. Pick a date on the calendar (left side) — click any date from today onward. Red days are public holidays, amber days are specific closures you set, and dimmed days are regular days off — those can't be clicked. Days that already have reservations show a small number like "+2" in the corner so you can see bookings at a glance.
  2. Pick a time (middle) — once you choose a date, the available times appear as rounded buttons. The number on each button, like "2/5", means "2 already booked / 5 tables total". Light shade = plenty of seats, dark = mostly taken, strikethrough = fully booked and not clickable.
  3. See who already booked — clicking a time button opens a list below showing the existing reservations for that time (guest name, table, party size). This prevents you from double-booking.
  4. Fill in the form (right side) — your chosen date and time appear as a summary at the top. Then fill the fields from top to bottom:
    • Guest name
    • Phone: just type digits, it auto-formats to "010-1234-5678"
    • Table: tables already taken at this time are automatically hidden, so you can't accidentally double-book
    • Party size: 1 to 20 people
    • Memo: special requests (birthday, wheelchair access, etc.)
  5. Click the [Reserve] button — if you left the name empty, a warning appears. Otherwise a "Reservation complete" confirmation pops up, and the "+N" number on the calendar and the "N/M" number on the time button both go up by 1 instantly. The form clears itself and is ready for the next booking.
  6. Try both the light and dark theme — click the ☀/🌙 icon at the top right. Your shop might be used in bright daylight or a dim evening, so check that everything reads well in both.

To check phone and tablet views, just drag the browser window narrower with your mouse. As the screen gets narrower, the 3 columns automatically rearrange into 2 columns and finally stack as a single column. Since staff often use tablets and customers use phones, make sure text and buttons stay large enough to tap on narrow screens.

TIP Reservations you enter during this test disappear when you refresh the browser (the sample data gets regenerated). To actually keep real reservations saved, move up to the PRO plan's Project or Database service — covered in the next chapter of this guide.
5
Step 5 · Connect your Railway hosting account

Deployment uses Railway, a hosting provider. The first time you click the Deploy button, a "Connect Railway account" modal appears. The sequence is:

  1. Click Log in with Railway → Railway's login page opens in a new tab.
  2. No Railway account yet? Sign up free on that page (email or GitHub).
  3. On the "QuickStart requests permission to deploy" screen, click Authorize.
  4. You're redirected back to QuickStart and a "Connected" toast appears.

You only do this once — subsequent deploys skip this step.

TIP Railway has a free tier and does not require a credit card to start.
6
Step 6 · Run the deployment (watch the progress modal)

With the account connected, click Deploy again. A progress modal opens and walks through 8 stages — each turns green when complete.

  1. Pack — bundle your code into a package.
  2. Upload — send the package to Railway.
  3. Install — install required libraries.
  4. Build — compile SCSS and bundle Vue.
  5. Migrate — place static files in their web-server location.
  6. Start — boot the container.
  7. Health — verify the site actually responds.
  8. Complete — finalize and assign the URL.

Total time is usually 1–3 minutes. Expand Show logs at the bottom of the modal to watch in real time.

TIP If it fails, look for red lines in the logs panel. Most failures are typos or missing brackets.
7
Step 7 · Go live on your free domain

When the deploy finishes, an Open domain button appears at the bottom of the modal. Click it and the auto-assigned free domain (e.g. happycat.apidealder.net) opens in a new tab. Share that URL with anyone.

Later, to attach your own domain (e.g. myname.com), go to Settings → Domain Management in the dashboard, register the custom domain, and add the DNS records shown there to your DNS provider.

TIP The free domain works instantly; custom domains take 5–30 minutes for DNS to propagate.

Build an API Server

Turn data from your own database into a public API anyone can call. Share a single URL like GET https://happycat.apidealder.net/endpoint/menu_list and mobile apps, other websites, or spreadsheets can pull data from it directly. This walkthrough mirrors the real buttons and modal order you'll see on screen.

Estimated time: 10–20 min
1
Open Service
2
Connect DB
3
Pick Table
4
Inspect Data
5
Generate API
6
Call from Outside
1
Step 1 · Open the Database service

From the top nav or dashboard, click Services → Database to open the database page. The screen splits into a left sidebar and a center body.

  • Left sidebar — a blue [+ New Dataset] button at the top, followed by "Recent", "Public datasets", "My datasets", and "Team" sections.
  • Center body — top toolbar has a search box (name / table / URI), a grid⇄list view toggle, and a rows-per-page selector (20/50/100). Below that your existing datasets appear as cards.
  • Four icons on each card▶ (play) opens the Database Editor · table icon opens the Cell Editor · API settings button (plug icon) opens API Settings · plus copy/delete. Double-click the card name for inline rename.
TIP It's fine if you have no datasets yet. The next step creates one with a wizard.
2
Step 2 · Register a new dataset (3-step wizard)

Click the [+ New Dataset] button in the left sidebar and a 3-step wizard modal opens in the center. The flow:

  1. Step 0 — Overview: explainer cards about datasets and capabilities. Click Next to continue.
  2. Step 1 — Connection method: choose one of three large options.
    • Deploy new DB — provisions a fresh DB container on Railway.
    • Connect existing DB (most common) — connect to a DB you already have.
    • Local file — upload a JSON / CSV / Excel as a dataset.
  3. For "Connect existing DB":
    • DB type dropdown — MySQL (default port 3306) · MariaDB (3306) · PostgreSQL (5432) · MongoDB (27017). Selecting one auto-fills the default port.
    • Host · Port · Database name · User · Password
  4. Click [Test connection] at the bottom — on success the wizard auto-advances to Step 2; on failure a red error shows below.
TIP If the connection test fails, it's usually a firewall — the DB server must allow external IP connections. For cloud DBs, add the QuickStart server IP to the "allowed IPs" list.
3
Step 3 · Pick a table & register the dataset

Once connected, the wizard walks you through two more steps automatically.

Step 2 — Table selection

  • Tables in the DB appear as rows (name · icon · row count · comment).
  • Click a table and the right panel expands to show its field list.

Step 3 — Register the dataset (this is where the "dataset" metadata is finalized)

  • Left — registration form:
    • Dataset name (required) — e.g. "Menu list"
    • Dataset description
    • Target table dropdown (required)
    • Primary Key field — auto-selects id if present.
    • Included columns — * (all) or comma-separated like id,name,price
    • WHERE clause — e.g. stock_flag = 1
    • LIMIT — e.g. 0,100 (offset 0, 100 rows)
    • ORDER BY — e.g. created_at DESC
    • Shared checkbox — expose read-only to other users.
  • Right — query tester: clicking [Test query] runs the actual SQL with your current settings and shows result row count, column count, and a live preview. Tune the left-side conditions until you see what you want.
  • Click [Save] → wizard closes → a new dataset card appears on the main screen.
TIP If you filter with WHERE at dataset time, downstream APIs inherit that filter. Enforce access rules at the dataset layer — e.g. "only in-stock products" — rather than relying on the caller.
4
Step 4 · Inspect data in the Database Editor

Click the ▶ (play) icon on a dataset card to open the Database Editor as a full-screen overlay. It has three panels.

  • Left — object browser: tabs at top (Tables / Views / Procedures / Functions). Click any table to see columns · types · comments in the inspector below. The command strip above the list covers Copy CREATE script, Drop, Update, Insert, Delete, Join, Reverse, Refresh.
  • Center — SQL editor: manage multiple queries as tabs. Double-click a tab to rename. The toolbar has a ▶ Run button plus F5 / F9 shortcuts. Results can be exported as TSV / CSV / JSON / SQL, or sent straight to a Macro with "Send to Macro".
  • Right — result grid: rows from the last query, with cell-level editing.

Use this step to confirm that the data you're about to expose actually looks the way you want. Fix it here first if it doesn't.

TIP You can edit cells in the result grid directly, but for real production data, writing UPDATE ... WHERE id=... explicitly in the SQL tab is safer and leaves a clearer trail.
5
Step 5 · Auto-generate the API (Namespace → Endpoint)

Now expose this dataset as a REST API. Click the API settings button (plug icon) on the dataset card to open the API Settings modal.

  1. Basics
    • Namespace (required) — this becomes the URL tail. menu_list produces /endpoint/menu_list.
    • Table — target table (auto-filled from the dataset)
    • JOIN Table — optional second table if you want to join
    • Page var — pagination query param name (default page)
    • Per page — default 50
    • Cache time — 0–1440 minutes
  2. Auto-generate response: clicking [Auto generate] builds the JSON shape as main_container → main_fields → item_container → item_fields → (optional) detail. Each field is a "JSON key → SQL variable" pair (e.g. name → $customer_name). You can add or remove fields manually.
  3. Access control (ACL) — detailed below.
  4. Click [Save] to store the API definition.
  5. Click [Deploy] to run the deploy pipeline — a progress bar appears, and the endpoint goes live when it finishes.
TIP The "Auto layout" button generates a Layout Builder block template that consumes this API immediately. You can turn the API into a rendered page without writing a custom frontend.
6
Step 6 · Call from outside & lock down security

Once deployed, the endpoint is public under (with a custom domain):

  • GET https://happycat.apidealder.net/endpoint/menu_list
  • GET https://happycat.apidealder.net/endpoint/menu_list?page=2
  • GET https://happycat.apidealder.net/endpoint/menu_list/csv — CSV download

API Key auth (ACL section inside the API modal):

  • API Key — click [Auto-generate] for a UUID-style random key.
  • Deliveryheader or param.
  • Header name e.g. X-API-KEY / Param name e.g. api_key.

Call examples

Via header:

curl -H "X-API-KEY: your-secret-key" https://happycat.apidealder.net/endpoint/menu_list

Via query param:

curl "https://happycat.apidealder.net/endpoint/menu_list?api_key=your-secret-key"

Browser fetch:

const res = await fetch('https://happycat.apidealder.net/endpoint/menu_list', { headers: { 'X-API-KEY': 'your-secret-key' } });
const data = await res.json();

Extra guards (all in the ACL section):

  • IP whitelist — wildcards (192.168.1.*) and CIDR (10.0.0.0/24).
  • Referer restriction — list of allowed domains.
  • Rate limit — max requests per minute.
TIP An API key in browser JS is visible from the page source — perfectly fine when the endpoint is meant to be public, but not when you want the request and response kept private. On public pages, pair the key with Referer restriction and Rate limit to scope usage to the domains and rates you want. When you want the key kept private, call the API from server-side code (a PHP program in your Project) and keep the key only there — the simplest setup.

Automate Data Collection

Build a pipeline that scrapes an external website on a schedule and piles the data into your DB (shopping sites, news, price comparison, etc.). Set it once and fresh data arrives every night — ready to be consumed by the API you built in the previous chapter, or by the Layout Builder.

Estimated time: 15–30 min
1
Open Parser
2
New Rule
3
Extract Setup
4
AI Prompt
5
Item Test
6
Save to DB
7
Schedule
1
Step 1 · Open the parser rules page

From the top nav or dashboard, click Services → Data Collection to open the parser rules list screen. The layout mirrors the Database page.

  • Left sidebar — a blue [+ New Parser Rule] button at the top, then "Recent", "Public rules", and "My rules" (with a user filter).
  • Center body — toolbar with search, grid/list toggle, pagination. Below, your existing rules show as cards (or table rows).
  • Icons on each card⚗️ (test tube) Item Test · ⏱ (clock) Schedule (shows a "Max" ribbon if your plan doesn't include it) · edit · duplicate · delete. Cards display rule name, test page, description, and creation date.
TIP For a first try, forking a rule from the "Public rules" list is fastest — selectors are already tuned and you only swap the target URL.
2
Step 2 · Create a new rule (3-step wizard)

Click [+ New Parser Rule] in the left sidebar → a 3-step wizard opens.

  1. Step 1 — Overview: four info cards (Extract / Crawl / Field Mapping / Reuse) and a pipeline diagram (Parser Rule → Database / Macro / Scheduler / API). No input, just context.
  2. Step 2 — Database connection: pick a dataset from a card list where the scraped data will land. Each card shows dataset name, DB type, table, and domain. After selecting, press [Next] — a 3-phase auto flow runs ("Agent connect → Parser engine deploy → Deploy complete") that installs the parser engine onto the selected docker agent.
  3. Step 3 — Rule registration:
    • Rule name (required) — e.g. "Naver News IT section"
    • Description — one line about what it collects
    • Click [Create Rule] and the wizard closes, landing you directly in the parser settings screen.
TIP If you don't have a dataset yet at Step 2, close the wizard and create one on the Database page first. An empty table is fine — the parser auto-creates columns based on what it extracts.
3
Step 3 · Target URL & extraction setup

The rule editor opens with a Target URL field at the top. Enter the page you want to scrape (e.g. https://news.example.com/it), then configure extraction. The parser combines three approaches.

  • Loop Splitter (3 inputs — primary + 2 secondary) — a string pattern that chops the HTML into repeated units. Example: use part of <li class="article"> as the splitter so each article becomes one item.
  • XPath selectors (up to 3 levels) — pick title / URL / image from inside each repeated unit with XPath. The selector should point at a node set (array), so if the value sits at //h3/a/text(), enter just //h3/a.
  • JSON selectors (3 levels) — if the page returns JSON, use dot/bracket syntax to point at the array path. For data shaped like data.items[0].title, enter data.items so the item array is produced.
  • Function post-processing — the "function" column applies to each extracted value:
    • trim(@p) — strip whitespace (@p is the current value)
    • replace(old,new) / regex(pattern,replacement)
    • Direct PHP calls like strtoupper(@p)
    • Built-in helpers: get_data() · slice() · remove() · map()

The fastest path isn't hand-typing selectors — it's feeding a slice of the source (via the Loop Splitter) into the AI Prompt and letting the AI response auto-register the rule. That's exactly what Step 4 below covers.

TIP For sites that render via JavaScript (React SPAs, etc.), a plain HTTP fetch gets HTML without the data. Open the Network tab in devtools and find the internal JSON API the site calls, then target that URL directly with a JSON selector — much more stable.
4
Step 4 · Let AI generate the rule for you

Instead of hand-typing dozens of selectors, you can hand the sample to an AI and apply the completed rule it returns. This is the recommended path for beginners.

Prerequisite — you must have entered a Target URL in Step 3 and run the extract test from the editor's "Test" tab at least once so a response body exists. That body auto-joins the prompt.

A. Build & copy the prompt

  1. In the test result panel, click the highlighted 🪄 "AI Prompt" button (wand icon) at the top.
  2. The document type (HTML / JSON / XML) is auto-detected and the body is extracted and assembled into a prompt.
  3. The code editor panel just below the button fills with a markdown-formatted prompt. It includes:
    • A task intro paragraph
    • The HTML/JSON source sample
    • Target definitions — the repeat delimiter, the detail-URL field, the unique key, and each column's label, variable name, type, split rules, and post-processing function
    • A sample JSON and an explicit "Do not output any text other than JSON" instruction
  4. The prompt is multilingual-aware (8 languages: Korean · English · Japanese · Chinese · Russian · German · French · Spanish) — a Korean document produces Korean labels, a Chinese one produces Chinese labels, and so on.
  5. Click inside the panel → Ctrl+ACtrl+C to copy everything.

B. Paste into your AI of choice and run it

  1. Paste into an AI such as ChatGPT / Claude / Gemini and send.
  2. The AI responds with a rule JSON.
  3. Copy the response (or just the JSON portion).

C. Paste the response to auto-fill rule fields

  1. Back in the same panel, click the 📥 "Import Pattern" button (import icon) — a paste-in textarea opens (the expected format is hinted inside).
  2. Paste your JSON, then click [Apply Pattern].
  3. The repeat delimiter, selectors, unique key, and detail-URL field are mapped into the top of the rule automatically, and every column (label, variable name, type, split rules, post-processing function) is filled into the field list in one shot. Duplicate variable names get a different name automatically to prevent collisions.
  4. The editor auto-switches to the "fields" tab so you can verify immediately, and a summary toast like "Pattern applied: N fields" appears at the bottom.
TIP If the AI response isn't valid JSON or the field list is empty, you'll see an "Invalid JSON" toast and your existing values stay untouched. Add "Output JSON only, no other text" to your AI conversation, or paste just the JSON portion. Also — AI-generated rules are rarely perfect on the first try. Always verify with Step 5 (Item Test) and hand-tune the handful of fields that need it.
5
Step 5 · Item test preview

With the selectors roughly in place, verify they extract what you want. Two entry points:

  • The ⚗️ icon on a rule card
  • Or the "Test" tab at the top of the rule editor

The Item Test modal opens with:

  1. Top status bar — "N items / M columns" summary. If N is 0, the Loop Splitter is wrong — fix it first.
  2. Export buttons — CSV · XLSX · JSON · HTML, handy for sharing a sample with the team.
  3. Result grid — Row# + column headers auto-derived from the first item, one row per extracted item.
  4. Cell hover — a "Copy" button appears on hover to grab the value to clipboard.

If results look wrong, close the modal, adjust selectors/functions, and test again — this loop is ~70% of parser work.

TIP Common signals: "columns look right but only 1 row" → Loop Splitter is too broad. "rows look right but columns are empty" → your XPath/JSON selectors are wrong.
6
Step 6 · Save to the dataset

Once the test looks clean, confirm the save settings in the editor's "Save" section.

  • Save type dropdown — set to "Database" (auto-set already if you picked a dataset in the wizard).
  • Target table / collection name — where rows land. If it doesn't exist, the agent creates it on the first run, using columns detected in your test.
  • DB modeDataset (linked) / Custom. Custom lets you type host · user · password · database directly (useful when writing into a different DB than the one in the wizard).

What happens on run

  1. You run the rule (the "Persist" button in the test, or the next step's schedule) and the docker agent hits the target URL.
  2. Items are extracted: Loop Splitter → XPath/JSON selectors → function processing.
  3. Extracted items are inserted into the target table. Duplicates (by URL hash or the key you pick) are skipped or updated automatically.
  4. Because this table lives in the same DB as the dataset card from Step 5, the API endpoint /endpoint/... you built before now serves the freshest data.
TIP Custom DB mode is useful for landing data in an internal DB that you don't want to expose as a shared dataset. Credentials are stored in QuickStart's DB, so create a dedicated read/write account for the parser instead of using your admin login.
7
Step 7 · Schedule & auto-run (MAX)

The last step makes it run by itself. Click the ⏱ (clock) icon on a rule card to open the schedule modal. This feature is MAX-only — on other plans the icon shows a "Max" ribbon.

  1. Schedule fields:
    • Start time — hour (0–23) + minute (0–59). e.g. 03:30 AM.
    • Interval (minutes) — 60 = hourly, 1440 = once a day.
    • Active — toggle. Off keeps the config but pauses runs.
    • Run modeSingle URL mode (one target URL) or Batch mode (loop through a URL list, one per line).
  2. Click [Save] — the schedule is recorded in QuickStart and auto-synced to the selected docker agent, which is what actually runs it.
  3. From then on the agent fires the rule on your interval and pipes rows into the dataset. QuickStart only signals — it never sits in the traffic path, so there's no bandwidth overhead on it.

Chaining with a macro (optional) — in the editor's flow diagram, use the "Select macro" dropdown to pick a macro. Right after a scrape finishes, that macro runs. Example: compare newly scraped product prices to yesterday's; if dropped by N%, send a Slack alert.

TIP Always check the site's robots.txt and terms of service. Very short intervals (e.g. every minute) both harm the target site and invite bans. For news or shopping prices, 60–1440 minute intervals are the realistic sweet spot between politeness and freshness.

Database Migration · B → A → C Replication

Build a three-stage replication pipeline that pulls data from an external source DB (B), stages it inside your own dataset (A · Docker), and then pushes it out to another external target DB (C). A single Migration button on the dataset list handles both the inbound and outbound half, while the A layer lets you clean columns, rewrite URLs, and aggregate in between.

Estimated time: 20–30 min
B
B · External source DB
e.g. origin.acme.com · MySQL · sales_db
Import
hard_sync / soft_sync
A
A · Your dataset (Docker)
e.g. my_staging · transform & buffer layer
Export
append / soft_sync
C
C · External target DB
e.g. warehouse.acme.com · PostgreSQL · reporting
1
Understand
2
Prepare A
3
Connect B
4
B→A import
5
Transform in A
6
A→C export
7
Automate & verify
1
Step 1 · Why go through A — understanding the three-stage scenario

Pushing straight from the production DB (B) to the analytics DB (C) looks simplest, but in practice column names differ, personal data is mixed in, and time zones diverge — you always end up needing a place to clean things up in between. That is exactly what a QuickStart dataset (A) is for.

  • B (external source) — the live shop or ERP. Touching it risks the business, so we only read.
  • A (your dataset · Docker) — your own workspace. All transformations happen here: rename columns, rewrite URLs, drop unwanted fields, add aggregates.
  • C (external target) — the BI database, a partner DB, any destination. Only the already-clean data from A flows into C.

Why this shape:

  1. B and C can run different engines (MySQL ↔ PostgreSQL …) — A bridges them.
  2. Everything stays in A, so if C is wiped you simply re-push. Rollback is cheap.
  3. You can iterate and test transformations in A as much as needed, and only flip the switch to C when ready.
TIP It is tempting to think "can I not just send B straight to C?" — but the first time you hit "the column names are different" or "UTC has to become KST" or "strip personal columns" you realise a middle layer was needed all along. Design A in from the start and you will not have to redraw the pipeline later.
2
Step 2 · Prepare A (your dataset)

First create the dataset (A) that will hold the data pulled from B.

  1. Top nav → Data → Database. The list screen opens.
  2. Top-right [+ New Dataset]. Fill in:
    • Name — e.g. replication_staging
    • DB typeMySQL or PostgreSQL. Matching B reduces conversion friction.
    • Host — defaults to the DB bundled with your Docker agent (auto-filled).
    • Database name — e.g. my_staging
  3. Click [Save]. A new row appears with icon buttons alongside: 🔌 connect test · edit · migration · export.
  4. Click 🔌 first and confirm you see "Connection success". You must get this before moving on.

A is now the intermediate buffer where data imported from B and data to be exported to C will briefly live.

TIP You do not need to create tables yet. Step 4's hard_sync will copy B's schema into A automatically. On the other hand, if you want a completely different structure in A, create the tables manually in the SQL editor now and plan to use append in step 5.
3
Step 3 · Open Migration modal & enter B (source) connection

Find the row for A in the list and click the Migration icon. A large three-panel modal opens.

  • Deck A (left) — your dataset (replication_staging) is pre-bound; current tables and fields show immediately.
  • Center toolbar — direction indicator (A → B / B → A), [Flip] button, and the action list (⚡ hard_sync, 🔄 soft_sync, ➕ append …).
  • Deck B (right) — a form for entering the remote DB connection.

The default direction is A → B (push out), but we want to pull from B, so click [Flip] in the center to switch to B → A. Deck B's badge turns to "source", Deck A's badge to "target".

Now enter the external production DB (B) connection on Deck B:

  1. Host — e.g. origin.acme.com or 10.0.1.23
  2. DB typeMYSQL · POSTGRESQL · MONGODB · ELASTICSEARCH
  3. Database name — e.g. sales_db
  4. Account / password — strongly prefer a read-only account with SELECT only. You cannot corrupt B with it.
  5. Click [Test Connection]. "Connection success" appears and the remote table list auto-loads.
TIP If the test fails, the culprit is almost always the firewall or IP whitelist. Ask whoever owns B to allow the QuickStart agent's outbound IP. When the error reads Access denied for user 'xxx'@'1.2.3.4', forward that exact IP — it is what the target server sees.
4
Step 4 · B → A import: select tables & run hard_sync

After a successful connection Deck B shows the remote table list and a [Next] button appears. Clicking it flips Deck B from "connection" to "table selection" view.

  1. Select tables — check the tables to bring over. [All tables] toggles the whole list. Starting small (orders · customers · products) is safer than pulling the entire schema on first run.
  2. Filter (optional) — the WHERE textarea at the bottom of Deck B accepts conditions like created_at > '2026-01-01'. LIMIT 0, 1000 pulls only 1000 rows as a sample. Always cap the first run.
  3. Inspect fields (optional) — the icon next to a table opens the column list; uncheck any field you do not want copied (password_hash, national_id …).
  4. Run ⚡ hard_sync — in the center toolbar, click [hard_sync] (the lightning icon). A "Run hard_sync on {count} tables?" dialog appears; confirm. On the A side the tool does DROP → CREATE → INSERT per table. A progress bar shows current table / total tables plus row-level progress.
  5. When it finishes the bottom log reads "Success" and Deck A's table list refreshes, now showing the newly created tables.

Other options instead of hard_sync:

  • 🔄 soft_sync — keyed UPDATE/INSERT/DELETE only; keeps rows already in A that were not in the source set. Good for periodic sync.
  • ➕ append — insert rows whose id does not yet exist in A. Useful for incremental ingest.
  • 🔀 merge — insert only rows whose id does not clash with A.
TIP A full hard_sync over millions of rows takes several to tens of minutes. On the first try, slice off 10k–100k rows with WHERE + LIMIT, verify the schema and flow, then drop the cap on the second run. Leave the browser tab open in the background while you do other work — slow migrations are fine as long as the window stays loaded.
5
Step 5 · Clean up in A — use the in-modal replacement tool

The raw data is now in A, but sending it straight to C usually breaks something. There are two ways to clean it up.

① Replacement inside the Migration modal — the center toolbar has a "Replacement setup" area that performs bulk string substitution. If B uses https://cdn-old.acme.com/ for images and C expects https://cdn.acme.com/:

  1. Pick [Text] mode (or [Regex] for patterns).
  2. Left textarea: https://cdn-old.acme.com/
  3. Right textarea: https://cdn.acme.com/
  4. On the next hard_sync / soft_sync the value is rewritten on the fly as rows move. The source never changes.

② Work directly in the SQL editor — back on the dataset list, click the editor icon for A and run SQL.

  • ALTER TABLE orders DROP COLUMN password_hash; — strip sensitive columns
  • UPDATE orders SET created_kst = CONVERT_TZ(created_at, 'UTC', 'Asia/Seoul'); — time-zone conversion
  • CREATE TABLE orders_summary AS SELECT product_id, COUNT(*) cnt, SUM(amount) total FROM orders GROUP BY product_id; — build an aggregate table

Verify with SELECT * FROM orders_summary LIMIT 20; in the editor before moving on to step 6.

TIP Keep the two layers separate by role so they do not stomp on each other. Simple string substitutions (URLs, domain prefixes) belong in the Migration modal; structural changes (add/drop columns, type changes, aggregation) belong in the SQL editor. Mixing both haphazardly makes it painful to answer "where did this value get changed?".
6
Step 6 · A → C export: flip, connect the target, incremental push

Now push the cleaned data from A out to the external target (C). Open the Migration modal from A again.

  1. Check direction — the center toolbar must read A → B, where B in the UI is now our C. If step 3 left it on B → A, click [Flip] to reverse it: Deck A is now source, Deck B is target.
  2. Enter target connection on Deck B (= C) — host warehouse.acme.com, DB type POSTGRESQL, name reporting, and a writable account with INSERT/UPDATE. [Test Connection] → success.
  3. Pick tables on Deck A — check orders_summary · products · customers_clean — whichever tables you already prepared.
  4. Choose the action.
    • If C is brand new, use ⚡ hard_sync; missing tables are auto-created.
    • If C already has data and this is periodic sync, use 🔄 soft_sync; keyed UPDATE/INSERT/DELETE against C.
    • If C just accumulates history, use ➕ append; only new ids from A are inserted.
  5. Run — confirm and watch the progress bar. If the network hiccups, rows are chunked; re-running continues from where it stopped.
TIP Always back up C before the first export. hard_sync DROPs the target table before re-creating it, so picking the wrong table wipes existing data. For production, make soft_sync or append the default and reserve hard_sync for first-time setup.
7
Step 7 · Automate & verify — wrap it in a macro

Once you have run the pipeline manually, wrap it in a macro for periodic execution. Service → Macro, create a new macro, and have the code invoke the migration.

  • The macro body looks roughly like fetch('/dataset/api/mig_run', { method: 'POST', body: JSON.stringify({ dataset_id: 123, action: 'soft_sync', deck_b: {host, db_name, user, password}, sel_tables: ['orders'] }) }). The exact parameter set is whatever the real button fires — inspect the network tab once to copy the request verbatim.
  • In the macro's Schedule tab, pick a cron. e.g. every day 3am 0 3 * * *.
  • Keep B → A and A → C as two separate macros so one side's failure does not freeze the other. Chain them by triggering the second one from the first one's success result.

Verification checklist:

  1. Run SELECT COUNT(*) FROM orders on C and compare with A and B.
  2. Pick a random recent id and compare column values across B · A · C.
  3. Deliberately insert one row into B and trace it reaching A then C within 5–10 minutes. If it does not, read the macro log and the migration result log.
TIP Always walk a small payload through the pipeline by hand before handing it to the macro scheduler. Errors in a cron that runs nightly can silently pile up for days before anyone notices. Even after automation, spend the first week skimming the result log every morning until you trust it.

Cell Editor · Paste-to-Insert from Excel into your dataset

A hands-on walkthrough of inserting hundreds or thousands of rows into a dataset table by simply copy-pasting from Excel / Google Sheets. One click on the Cell Editor button in the dataset list gives you a browser-side grid and lets you load rows without touching FTP or writing SQL.

Estimated time: 10–15 min
Excel · Sheets
organised columns / rows
Ctrl + C
Cell Editor
in-browser grid
Ctrl + V
Dataset table
INSERT runs automatically
1
Scenario
2
Open editor
3
Prepare schema
4
Paste
5
Verify & fix
6
Save
1
Step 1 · When paste-to-insert beats everything else

Any of these is a clear win for paste-to-insert over hand-written SQL.

  • A marketer hands you an Excel with 500 coupon codes that need to land in the service DB.
  • A designer sends a Google Sheet of product names · prices · categories to be loaded in one go.
  • A partner drops a CSV of members that needs to be imported as-is.
  • You want to feed the AI wizard a table of 100 worked-out examples for later runs.

Cell Editor behaves exactly like Excel: a row × column grid where a Ctrl+C from Excel and a Ctrl+V in any cell auto-detects tab or comma delimiters and drops rows in place. No field-mapping dialog — columns fill left-to-right from the cell you started in.

TIP If you are loading tens of thousands of rows at once, plain CSV import ( icon on the dataset list) or the Migration flow is more robust. Paste-to-insert shines when you want eyes-on review of a few hundred to a couple thousand rows as they go in.
2
Step 2 · Open the Cell Editor

Top nav → Data → Database. Your dataset list appears as cards or rows.

  1. Find the row of a dataset you own (your user_id). Shared datasets are read-only, editing is blocked.
  2. Click the Cell Editor icon in the row's action cluster. A full-screen modal opens.
  3. The layout: Options panel on the left (table selector · page step · sort · search · replace); the grid in the centre; the toolbar on the right (save · add/remove row · undo/redo · copy · CSV/SQL export · ✨ AI wizard).
  4. Pick the target table in the left dropdown. Its existing rows load into the grid. Empty table → empty grid.
TIP Opening plus loading takes a second or two. When the table is big, drop the Page Step (10 · 20 · 50 · 100) so fewer rows render at once. Default 50 is fine for most cases.
3
Step 3 · Check the schema — primary key & column order

Before pasting, confirm that the column order in Excel matches the table. A mismatch puts values into the wrong fields.

  • Column headers — the first row of the grid shows column names and types. Your Excel columns, left to right, must line up with that order.
  • Primary key — headers marked 🔑 are the PK. When id is auto-increment, leave the id column out of your Excel selection; the DB assigns it on INSERT.
  • NOT NULL columns — red-marked headers cannot be empty. Make sure that column has a value in every row you paste.
  • Too many / too few columns — extra columns on the right of your paste are ignored; missing columns on the right end up blank.

If the schema does not match, either regenerate the grid via Create Grid (X × Y) in the left options, or reorder your Excel columns before copying.

TIP If the table has no PK the save step halts with "No primary key field defined". Go back to the SQL editor and run ALTER TABLE ... ADD COLUMN id INT AUTO_INCREMENT PRIMARY KEY; first.
4
Step 4 · Paste — Excel Ctrl+C → Grid Ctrl+V

The heart of the workflow. In Excel / Sheets, select the range you want (excluding the id column) and Ctrl+C. Then in Cell Editor:

  1. Click the starting cell. Usually the left-most column, one row below your last existing row, so new rows land after the current data.
  2. Ctrl+V. Cell Editor auto-detects tab (default Excel copy) or comma (CSV) and splits rows/columns accordingly.
  3. The grid expands and the new rows render with a lightly tinted background — marking them as "new, not yet saved".
  4. Paste again from a different start cell if you want to add more ranges.

Manual delimiter override — the Delimiter dropdown in the left options panel offers tab · comma · safe comma. Pick safe comma when your CSV has commas inside quoted strings — quoted segments stay in one cell.

TIP The safest habit is never select the id column in Excel. Accidentally pasted 1, 2, 3 values will collide with existing ids or confuse the auto-increment counter.
5
Step 5 · Verify & fix — what each colour means

Before saving, scan the grid. Cell Editor colour-codes three states.

  • Tinted row — a just-pasted "new" row. Becomes an INSERT on save.
  • Yellow corner dot on a cell — a modified cell in an existing row. Becomes an UPDATE on save.
  • Greyed-out row — queued for deletion. The status bar shows "🗑 X records will be deleted on save" and a [Restore] button.

Common editing moves:

  • Double-click a cell to type directly into it.
  • Right-toolbar / — add an empty row at cursor / delete current row.
  • Ctrl+Z · Ctrl+Y — undo/redo (up to 50 snapshots).
  • Find & Replace — in the left options panel; text or regex mode, replaces across the whole grid.

The status bar shows ✏ X row(s), Y cell(s) edited. If that number is unexpected, fix it before saving.

TIP Closing the window or refreshing the browser with unsaved changes triggers a confirm dialog. Cancel it and Ctrl+S first.
6
Step 6 · Save — 💾 fires INSERT/UPDATE in one shot

Once it looks right, save either via the Save button in the right toolbar or Ctrl+S. Cell Editor assembles and runs:

  • New rowsINSERT INTO table (col1, col2, ...) VALUES (...). Auto-increment PKs get assigned by the DB.
  • Rows with modified cellsUPDATE table SET col=val WHERE id=.... Only the changed columns are included.
  • Rows queued for deletionDELETE FROM table WHERE id=....

Success shows a "X rows saved" toast. The tinted background on new rows goes back to neutral and empty id cells fill with the numbers the DB assigned. Those rows are now indistinguishable from pre-existing data.

If it fails the memo panel shows the error — usually a NOT NULL breach, a type mismatch, or a unique-key collision. Fix the flagged row and save again.

TIP Saving many thousands of rows in one shot can hit a network timeout. Break the paste into 500–1000 row chunks or switch to CSV import.

AI Wizard · Bulk tasks with the "desired value / current value" pattern

Use Cell Editor's "desired value / current value" markers with the ✨ wizard button to run hundreds of AI tasks — translation, summarisation, classification, extraction, normalisation, outlier detection — from a single prompt. A few marked examples let the AI infer the pattern and apply it to the rest. This approach drops "repeated instruction typing" to almost zero in real work.

Estimated time: 15–25 min
1
Desired
Current
Mark examples
2
✨ Generate prompt
3
AI analyses
4
📥 Apply results

Most successful use cases

1
Concept
2
Preparation
3
Desired cells
4
Current cells
5
Generate prompt
6
AI processing
7
Apply
1
Step 1 · "as if to be" — why a few examples can solve hundreds of cases

as if to be is a pattern-learning form of instruction: "If a correctly transformed result (Desired) looks like this, then transform the raw version (Current) the same way." Instead of writing the rule out in words, you show the AI a few of the rule's outputs and let it generalise to the rest.

Cell Editor ships two markers (colour 1 · colour 2) for exactly this.

  • Marker 1 (Desired · teal) — example cells that show what the finished result should look like.
  • Marker 2 (Current · coral) — raw cells the AI should fill in.

Why this is powerful:

  1. No need to write the rule in natural language. Examples teach the AI.
  2. It works for rules that are too subtle to articulate — tone, nuance, consistent voice.
  3. One prompt handles hundreds of cells. The copy-paste-per-cell grind disappears.
  4. Adding or editing examples lifts quality immediately. The tuning loop is seconds.
TIP First time, "just a few examples is enough?" sounds unbelievable. Step through the simplest translation case in under five minutes — once you feel it, you start seeing this pattern in every repetitive task.
2
Step 2 · Preparation — input column, output column, 2–5 seed examples

With the dataset open in Cell Editor, lay out this structure in advance.

  1. Input column — the raw text the AI will read. e.g. ko_text, product_desc, address_raw.
  2. Output column — empty column the AI will fill. e.g. en_text, summary, city. Add one via SQL editor if missing: ALTER TABLE ... ADD COLUMN en_text TEXT;.
  3. 2–5 example rows — fill the output column by hand. Three good examples decide the quality of 500 rows.

How to pick good examples:

  • Diverse — include short, long, and edge cases. Similar examples leave the AI lost on outliers.
  • Mix difficulties — one easy, one middle, one tricky.
  • Make the style explicit — line breaks, capitalisation, formal/informal register should all be visible in the examples.
TIP The hand-written seed rows feel like a waste of time but never skip them. Five minutes on 2–5 examples usually lets the AI finish 500 rows in thirty seconds. Zero examples = AI guesses the wrong direction and the whole run is thrown away.
3
Step 3 · Mark example cells as "Desired Value"

In the right-panel marker palette click the first swatch (teal · Desired Value) so it becomes the active marker. The selected swatch has an emphasised border.

  1. Click each of the hand-filled example cells in the output column. Each cell you click turns teal, meaning it is now marked as "Desired".
  2. Markers toggle, so clicking a marked cell again clears it.
  3. Drag to select a range, then click the swatch to mark the whole range at once.

Rename the label to match the task — click the pencil next to the label ("Desired Value" by default). Use something descriptive: "English translation" for translation, "One-line summary" for summarisation, "Category" for classification. The label is inserted into the prompt in step 5, which helps the AI understand the task more precisely.

TIP You do not need many Desired cells. 2–5 is plenty. More than 15 eats up prompt tokens and leaves less budget for the actual cells to transform.
4
Step 4 · Mark cells to transform as "Current Value"

Now activate the second swatch (coral · Current Value) in the marker palette.

  1. Drag-select the still-empty (or raw) output cells on the grid — e.g. rows 4 to last in en_text.
  2. Click the coral swatch once; every selected cell turns coral. These are the cells the AI will fill.
  3. The input column (ko_text) does not need marking. The AI reads the input column of each marked row automatically.
  4. Rename this marker too if useful: "To English", "Shorten", "Assign category" — a one-word instruction you want the AI to follow.

When done, the grid shows teal cells (example answers) + coral cells (empty targets) side by side. That is the "as if to be" pattern in its canonical shape.

TIP More than roughly 200 cells in one batch risks hitting the AI's response token limit. Drop Page Step to 50–100 and mark only the visible cells, processing batch by batch. 3–5 passes finish everything.
5
Step 5 · ✨ Wizard → prompt copied to clipboard automatically

Click the AI Wizard button in the right toolbar. Cell Editor reads the markers, assembles a structured prompt, and automatically copies it to your clipboard. A toast "AI prompt copied to clipboard" appears.

The prompt roughly looks like this (actual wording depends on your labels and examples):

  1. System line — "You are a data transformation assistant"
  2. Task statement — built from your labels. e.g. "Transform each 'Current Value' cell according to the pattern shown in 'Desired Value' examples."
  3. Example cells list — the (row, column, value) of each teal-marked cell. The AI learns the pattern here.
  4. Target cells list — the (row, column, raw input value) of each coral-marked cell.
  5. Output format contract — requires a JSON array only, in the shape [{"pos":"row,col","return_txt":"value"}, ...].

Halting condition — with zero teal and zero coral markers a warning pops up. Go back to steps 3 and 4 and mark some cells.

TIP Paste the prompt into Notepad or Notion first at least once before sending it to the AI. Seeing the actual structure (examples present, labels sensible) takes ten seconds and prevents wasted AI calls.
6
Step 6 · Paste into the AI → copy JSON result → paste into Memo

Paste the clipboard into Claude · ChatGPT · Gemini and send. The AI replies with a single JSON array.

  1. Select just the JSON part of the reply and Ctrl+C. Explanations around it are fine — just grab the array itself.
  2. Back in Cell Editor, Ctrl+V into the Memo textarea in the lower right panel. Memo is the landing pad for AI output.
  3. Eyeball the text — shape should be [{"pos":"3,5","return_txt":"Translated sentence"},{"pos":"4,5","return_txt":"Another"}, ...].

Stripping AI chit-chat — the assistant often prefaces the JSON with "Here is the JSON you asked for:". Take only the array that starts with [ and ends with ]. The apply button in step 7 parses strict JSON.

TIP If the reply is tens of kilobytes and the browser clipboard feels slow, save the AI output to a file and copy only the JSON portion back into Memo. Order of items does not matter.
7
Step 7 · 📥 Apply → grid updated → save

With JSON in Memo, click 📥 Apply AI Result in the right toolbar. Cell Editor parses the JSON and writes each return_txt into the cell at pos. A toast "X cell(s) applied" confirms success.

  • Applied cells show the modified marker (yellow dot) — they are in the grid but not yet persisted to the DB.
  • Unhappy with a cell? Ctrl+Z undoes, but undo drops the whole AI result. Usually it's faster to hand-correct just the bad cells.
  • Satisfied → Ctrl+S. The same UPDATE path as Section 1 step 6.

Looping & batch strategy:

  1. Before applying the whole batch, eyeball 10 samples. If results drift, tweak examples/labels in steps 3–4 and regenerate the prompt.
  2. When quality is good, page through and mark the next batch, repeat steps 5–7.
  3. Keep a side column (like batch_note) logging which examples produced each slice. It makes re-running a section trivial if the style changes later.
TIP AI output always has a small percentage of typos or odd translations. Before saving, run Find on suspicious strings ("undefined", "N/A", "???") and hand-correct the hits. "80% from AI, fast human fix on the remaining 20%" beats chasing perfection.

Fork → Customise → Publish · the menupan electronic menu story

Take the menupan (electronic menu board) solution from the marketplace, fork it into your own account, swap the logo for your company's, replace the demo menu with your actual products, dial in colours and fonts that match your brand, and ship it to your domain. Instead of building from zero, you branch a working project into your own copy and quickly make it yours — the most common real-world pattern.

Estimated time: 30–45 min
Solution market
pick the menupan card
Fork
My project
domain · DB auto-wired
Customise
My brand
logo · menu · colour · font
Publish
Live domain
menu.mycafe.com

Design iteration loop — inspect → try → ask AI → apply

1
F12 inspect
2
Tweak in browser
3
Ask AI for ideas
4
Save into CSS
1
Scenario
2
Fork
3
Logo swap
4
Edit menu
5
F12 trial
6
AI palette
7
Save · Deploy
1
Step 1 · Scenario — café "Sodam" makes menupan its own

Concrete scenario first. Café "Sodam" needs an electronic menu board on a tablet at the entrance. Building from scratch is slow; grabbing the marketplace's menupan solution and re-skinning it for the café is dramatically faster.

What we will finish in 30–45 min:

  • Logo — replace the default menupan logo with our café "Sodam" logo
  • Menu items — swap demo entries (Americano 4500 KRW, etc.) for our real menu
  • Colour & font — switch the default blue tone to a warm beige + dark brown that matches the café, change body font to a Korean-friendly typeface
  • Go live — publish at our own domain like menu.sodam.kr

Why fork?

  1. Layout, DB schema and admin UI are already done — save 90% of build time.
  2. The fork lives under your account, your domain, your DB; the original solution stays untouched and only your copy is editable.
  3. If menupan upstream gets an update later, your fork is unaffected — your customisations stay yours.
TIP If "fork" sounds abstract, think of it as "taking a copy of an outfit off the rack to alter at home". The shop's outfit stays as is; only the copy you took home gets cut, hemmed, and dyed.
2
Step 2 · Fork menupan from the solution market

Top nav → Community → Solution Market (or /solution). The marketplace shows solutions as cards.

  1. Use the top filter chips (All / Project / Macro / Community / Direct) — pick Project — or type menupan / electronic menu in the search box.
  2. Click the card to open its detail page with previews, feature description, and required resources (domain / DB).
  3. On the detail page click Fork to new project. The fork modal opens.
  4. Fill in:
    • Domain — pick from your active domains, e.g. menu.sodam.kr. Don't have one? Open Settings → Domains in a new tab and add one (a free ~.apidealder.net subdomain works) before continuing.
    • Dataset — the DB where menu data will live. New or existing one of yours.
    • Project name & description — e.g. name sodam_menu, description "Café Sodam in-store menu board".
    • Auto-deploy toggle — turn it on so the first build runs as soon as the fork finishes. Recommended on the first run.
  5. Click [Run fork]. A progress indicator appears, and after 30 sec to 2 min you get a completion toast. The new project shows up at the top of the My Projects sidebar and the workspace opens automatically.
TIP No domain or dataset yet → the modal nudges you with "Add a domain first". Open Settings → Domains in another tab, claim a free subdomain, and come right back to the modal.
3
Step 3 · Swap the logo — upload via Remote, replace URL in the program editor

Two halves: (a) upload the new logo via Remote management, (b) change the logo URL in the program editor.

(a) Upload the logo via Remote

  1. Top nav → Service → Remote. In the left server list, click your forked project's domain (menu.sodam.kr). Make sure the indicator dot is green.
  2. Type /public/assets in the path bar and press Enter to jump there.
  3. Hit [Upload file] in the bottom action bar and pick your café logo (e.g. sodam_logo.png). For a single file you don't need archive upload.
  4. Open https://menu.sodam.kr/assets/sodam_logo.png directly in the browser to confirm a 200 OK and the image showing.

(b) Replace the logo URL in the program editor

  1. Back in the workspace, click the project's Programs. The list of programs appears (typically main, menu_list, etc.).
  2. Double-click the program that renders the logo (usually main) to open the editor.
  3. Open Find & Replace (Ctrl+H). Search for the existing logo path, often /assets/menupan_logo.png.
  4. In Find type menupan_logo.png; in Replace type sodam_logo.png; Replace All. HTML and CSS get updated together.
  5. Ctrl+S to save and verify the new logo in the right-hand preview pane.
TIP Logo previews fine but breaks after deploy? 90% of the time it's an absolute-vs-relative path issue. Always start with a slash: /assets/sodam_logo.png. Relative paths (../assets/...) break with deeper routes.
4
Step 4 · Edit menu content — admin page (recommended) or DB editor

menupan ships an admin page so staff can add/edit/remove menu items themselves. Two paths exist; strongly prefer the admin page.

(Recommended) Admin page

  1. Open https://menu.sodam.kr/admin (or whatever path menupan defines) and sign in. Default admin credentials are listed in the solution's detail page README right after fork.
  2. Click Menu management in the left sidebar. Categories (Coffee · Dessert · Non-coffee) and items (Americano · Latte · …) appear in tables/cards.
  3. Delete the demo entries, then add your real menu line by line:
    • Name (Americano) · Price (4500) · Description (...) · Category (Coffee) · Photo (a URL pointing at the photo you uploaded via Remote).
  4. Day-to-day work — edits, ordering, show/hide toggles — all happens here. This is the screen your café staff can use too.

(Alternative) Direct DB edit

  • For surgical bulk operations the admin doesn't cover (e.g. raise every coffee price by 500 at once), open Data → Database → the dataset you created at fork → Cell Editor.
  • Pick menu_item and edit the rows directly, or use the SQL editor: UPDATE menu_item SET price = price + 500 WHERE category='Coffee';. (See Best Practices → Cell Editor paste-to-insert for grid usage.)
  • Caveat: editing columns the admin doesn't know about, or breaking PK/FK constraints, can break the admin page. That's why everyday edits stay in the admin.
TIP When uploading menu photos, the most stable approach is uploading via Remote first and then pasting the URL into the admin page. Even if the admin has its own uploader, keeping all images at a consistent path (/assets/menu/*.jpg) pays off later for backups and migrations.
5
Step 5 · Design experiments — F12 inspect to live-edit colours and fonts

Before touching code, find the colour you actually want by tweaking it in the browser. Changes are temporary — refresh wipes them — so experiment freely.

  1. Open the deployed menu (https://menu.sodam.kr) in Chrome, press F12 for DevTools (or right-click → Inspect).
  2. Click the arrow-in-square icon at the top-left of DevTools (Element Picker), then click the area you want to recolour (header, menu card background). The right-hand Styles panel shows the CSS rules applied.
  3. Hover over a colour value (background-color: #2563eb;) — you'll see a tiny colour swatch. Click it to open a colour picker and either drag or type a new hex value.
  4. Change font-family: ...; the same way: type a new family ('Pretendard', 'Noto Sans KR', sans-serif).
  5. Once you like the combination, jot down the hex codes and font names. You'll feed them to the AI in step 6 or apply them in step 7.

Useful tricks:

  • Compare elements live — if a header tweak makes the body look off, edit both at once and see how the pair reads together.
  • Computed tab — shows the final value (with inheritance). Helpful when you're wondering "where did this value come from?".
  • Force :hover — the :hov button at the top of Styles toggles :hover·:focus states so you can vet hover colours too.
TIP F12 changes vanish on refresh. Save what you like — screenshot or notes such as "Header #6b4423, card bg #f5ecd9, body #3c2415, accent #c97a4a, font Pretendard 500".
6
Step 6 · Ask the AI for better colour and font ideas

If your hand-picked colours from step 5 still feel off, ask Claude / ChatGPT for tone candidates and you'll get five to ten alternatives instantly. Send a prompt like:

I'm building an in-store electronic menu board for a café called "Sodam".
Vibe: warm and quiet Korean café.
Space: wood-tone interior, warm yellow lighting.

Current palette:
- Header bg: #2563eb (blue)
- Body bg: #ffffff
- Text: #1f2937
- Accent: #2563eb

Suggest 5 palette sets that fit this vibe better.
For each set give hex codes for header / body bg / text / accent
plus a one-line note explaining the feel.

Also recommend 3 Korean-friendly Google Fonts (or free Korean
fonts) that match this mood.

The AI will respond with something like:

  • Set 1 (warm beige · dark brown) — header #6b4423, body bg #f5ecd9, text #3c2415, accent #c97a4a · blends naturally with wood tones and yellow lighting
  • Set 2 (modern minimal) — …

Validating the suggestions:

  1. Back in step-5 F12 inspect, paste each hex into the live page and pick the set you like best.
  2. Mixing across sets is fine — "header from set 1, accent from set 3" often wins. Note that down too.
  3. For fonts, search https://fonts.google.com for the suggested names and check the actual letterforms on your menu.
TIP Avoid asking the AI for "pretty colours" generically. Always provide (1) the venue's vibe / interior, (2) current hex values, (3) the feel you want (warm / quiet / luxurious …) — quality jumps. Asking for ~5 sets to compare nails the pick in one round.
7
Step 7 · Apply CSS → save → deploy (using save-on-deploy)

Now turn the F12 + AI choices into real code. After this step the change survives a refresh and everyone else sees it too.

  1. Workspace → project → Programs → double-click the design program (typically main or theme) to open the editor.
  2. Switch to the SCSS (or CSS) tab. Colour variables are usually grouped at the top of the file ($primary-color, $bg-color, etc.).
  3. Drop your hex values into those variables:
    $header-bg: #6b4423;
    $body-bg: #f5ecd9;
    $text-main: #3c2415;
    $accent: #c97a4a;
  4. For the Korean font, add at the very top of the SCSS: @import url('https://fonts.googleapis.com/css2?family=Pretendard&display=swap'); and set the body's font-family to 'Pretendard', sans-serif.
  5. Ctrl+S to save. The bottom preview should reflect changes immediately.

Two ways to publish

  • Option A — manual deploy (default): click 🚀 Deploy in the workspace toolbar. Build and push run for 1–2 min, then menu.sodam.kr shows the new design. Safe for the first time.
  • Option B — save-on-deploy (great for fast iteration): flip the "Save on deploy" toggle in the workspace toolbar. From now on every Ctrl+S automatically deploys. Perfect when you're sweeping through colour, font and menu tweaks live. Turn it off during business hours so customers don't see flicker mid-edit.

When deploy completes, open https://menu.sodam.kr on a phone and tablet for the final check. The same URL on the in-store tablet is what your customers see — that's your menu board.

TIP With "save-on-deploy" on, a bad save can briefly break the live page. For big changes, turn the toggle off, verify in preview, then deploy once manually. Reserve the toggle for small colour tweaks during quiet hours — that's the safe-operations habit.

Block Builder × Program Builder × Data binding · build a JSON-driven frontend

Design a reusable component (block) in the Block Builder, drop it into a slot in the Program Builder (a.k.a. Coder Builder) list step, then bind real rows from a dataset to that slot's variable. Once the pattern clicks, you can build screens where a single JSON spec becomes the whole frontend page. To keep the first lap simple, this guide narrows the scope to one "product list" page.

Estimated time: 30–40 min

Anatomy at a glance — block library · frame slots · dataset

Think of the frame as a picture frame, the slots as the insert grooves inside it, a block as a designed photograph, and the dataset as the album that supplies the text printed on top — and the rest falls into place. Slide the photo into the frame, pour the album one row at a time into the empty spots on the photo, and that is the entire job for today.

Block library
Header block
Product card list
Review card
Footer block
into the slot
Frame (picture frame)
slot 1Header
slot 2★ Product list
slot 3Footer
bind to "list"
Dataset · products table
🍎 Apple · 1500
🍌 Banana · 2000
🍇 Grape · 3500
… 7 more rows

Where the data flows — 4-stage pipeline

1
Block has sample_data
2
Slot the block in the Program Builder
3
Bind dataset to "list"
4
Live page renders automatically
1
Scenario
2
Dataset
3
Build block
4
Slot mode
5
Slot config
6
Bind data
7
Codegen · deploy
1
Step 1 · Scenario and analogy — build a single "product list" page

Instead of writing fetch() by hand and rolling your own v-for, there is a pattern: take a pre-designed component (block), drop it into a frame slot, wire a dataset, and the page is done. This guide walks the whole loop end to end.

Analogy refresher: an empty picture frame (frame) holds pre-designed photos (blocks); an album (dataset) supplies the text printed on those photos; hanging the frame on the wall is the deploy.

Today's page — "our shop's product list": a header on top, ten product cards in the middle (real rows from the dataset), a footer at the bottom. Plain one-screener.

  • One step beyond: more advanced builds wire 8–10 dataset tables — quotes, news, rankings — into multiple variables at once (list / list3 ... list10) and render an entire page from a single JSON spec. This guide stays at the first stitch of that pattern: one variable (list) + one dataset (products).
  • Why this approach — designers focus on the block's look, the data person owns the dataset, the page owner only matches slots in the Program Builder. Roles split cleanly. Data changes leave the design alone; design changes leave data alone.
TIP Tell yourself "this round is just to walk the basics". If you also try to add categories, search, and pagination at once, you lose the trail when something breaks. Get the minimum case working end-to-end, then bolt on extras on the next screen.
2
Step 2 · Dataset — products table with 5–10 sample rows

Get the real data ready first. Building the screen on top of an empty table makes it impossible to verify anything. Data first, screen second.

  1. Top nav Data → Database. If you have no dataset of your own, click [+ New dataset]. e.g. name shop, MySQL/PostgreSQL.
  2. Open its SQL editor and create the table:
    CREATE TABLE products (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), price INT, image_url TEXT);
  3. Open the dataset's Cell Editor for products and add 5–10 rows. Pasting (Ctrl+V) from Excel is fastest — see Best Practices → Cell Editor paste-to-insert for details.
  4. Quick check: SELECT * FROM products LIMIT 3;. We'll wire this dataset to the list variable in step 6.

Columns to include — only those your block design needs. name · price · image_url is enough. Extras hurt nothing, but starting simple speeds debugging.

TIP By dataset permission policy, write access (and the cell editor) requires the dataset to be your own (user_id = you). Public datasets others created are read-only. Use only datasets without a lock icon in the database list.
3
Step 3 · Block Builder — design the "product card list" block

Now the block we'll plug into the slot. Top nav Design → Block (or /layout/block) opens the block library. Click [+ New block].

  1. Name — something memorable like product_card_list.
  2. HTML pane — paste a card-grid template. The trick: name your variable list:
    <div class="card-grid">
      <div class="card" v-for="item in list" :key="item.id">
        <img :src="item.image_url">
        <div class="name">@{{ item.name }}</div>
        <div class="price">@{{ item.price }}</div>
      </div>
    </div>
  3. CSS/SCSS pane — basic grid:
    .card-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:16px; }
    .card { padding:14px; border:1px solid #eee; border-radius:8px; }
  4. sample_data — dummy preview data as JSON, keyed list:
    { "list": [
      {"id":1,"name":"Sample A","price":1000,"image_url":"/assets/sample.jpg"},
      {"id":2,"name":"Sample B","price":2000,"image_url":"/assets/sample.jpg"}
    ] }
  5. Save. The Block Builder preview should auto-render two cards from sample_data. Getting that preview to render is the make-or-break check. If it doesn't, confirm the variable name in your HTML (list) matches the key in sample_data (list).
TIP Think of sample_data as a placeholder that the dataset will replace later. Designers can finish the block without any dataset, and once the data shows up it slots in naturally. Whether the block's variable name (list) matches the binding name or differs (with mapping) is the key decision in steps 5–6.
4
Step 4 · Open the Program Builder → list step → switch to slot layout

Now build the page. Service → Project → [your project]+ New program, or open an existing program in the Program Builder (Coder Builder) — same tool, two names. Eight tabs.

  1. Eight tabs — db · list · detail · search · hook · style · code · menu. Click the second tab, list.
  2. Layout mode toggle — at the top of the list tab there are two modes: "fields / slots". Default is fields (table-like). We want to plug in a designed block, so flip to slots. The UI changes to a 3-step slot config:
    • 1) Frame select — which frame (with how many slots, how laid out)?
    • 2) Slot config — which block goes into each slot, how data variables map.
    • 3) Code preview — the synthesised result for review.
  3. If "frame / slot" still feels abstract, picture "a 3-row picture frame waiting for three photos". We pick the frame in step 5.
TIP Toggling out of slots back into fields can drop your slot configuration. Don't flip back and forth — commit to slots for this page and finish the loop.
5
Step 5 · Pick a frame, drop the product card block into slot 2

In the slot-mode UI's 1) Frame select, open the dropdown and pick something simple — "3-row (top / middle / bottom)" works well. Click [Apply] and the 2) Slot config auto-creates rows for slot 1, slot 2, slot 3 …

  1. For slot 2 (middle), open the block selector dropdown and pick the product_card_list from step 3. Options usually read id - name - author.
  2. The slot area immediately previews the block with its sample_data — two cards. If you see those, you've seated the block correctly.
  3. Slot 1 (top) and slot 3 (bottom) can take pre-built header/footer blocks the same way, or stay empty for now. For the first run, only slot 2 needs to be filled.
  4. Each slot row also exposes a data_placer (source selector) and data_selector (target selector) field. For now, leave both at list. We unpack their meaning in step 6.
  5. The block is in the slot, but it's still backed by sample data. We connect a real dataset next.
TIP If the slot looks empty after you pick a block, 9 times out of 10 the block's sample_data is empty. Go back to step 3, fill sample_data in the block, save, and refresh the Program Builder.
6
Step 6 · Bind a dataset to the "list" variable — the heart

This is the most important step. We wire the variable list (used inside the block) to actual rows from the products table.

What the two fields mean:

  • data_placer (source selector) — the variable name as written inside the block. Our block has v-for="item in list", so this is list.
  • data_selector (target selector) — the variable name as used at the page level. If you have two card lists on the same page, list would collide; map one to product_list, another to review_list. With a single list, leaving it as list is fine.

For simplicity, we keep both as list and move on.

Wiring the actual dataset — open the data variables / data_vars section at the top of the Program Builder (or its sidebar). If empty, click + Add for one row.

  1. Var name: list (must match the data_selector from step 5).
  2. Dataset: pick shop from step 2.
  3. Table: products.
  4. WHERE (optional): empty = all. e.g. price > 0.
  5. LIMIT (optional): 0, 20 for the first 20 rows.
  6. ORDER BY (optional): id desc for newest-first.
  7. Save.

Internally this becomes a JSON record (you don't write it directly, but conceptually):

{"var_name":"list","dataset":{"id":42,"table_name":"products","str_limit":"0, 20","str_order":"id desc"}}

That JSON is the spec the page renderer follows: at request time it runs SELECT * FROM products ORDER BY id desc LIMIT 20, drops the rows into list, and the block's v-for takes over.

TIP The reason data_placer ≠ data_selector is so powerful: the same block can appear multiple times on a page. "Recommended" and "New arrivals" can both reuse product_card_list with two different data_selectors (recommend_list, new_list) wired to two different WHERE filters on the same products table.
7
Step 7 · Code gen → save → preview → deploy

With everything wired, jump to 3) Code preview in slot mode (or the dedicated code tab) and let the system synthesise the result.

  1. Click Generate code (sync). The system stitches:
    • The frame's HTML skeleton with <[slot-1]>·<[slot-2]>·… filled by each slotted block's HTML.
    • Inside each block, list → step 5's data_selector (still list here).
    • The data_vars definitions are added to the page's init code.
  2. Review the output. If v-for="item in list" still appears intact and there's a top-of-page list = await fetch('/api/...') (or a server-side injection), you're good.
  3. Ctrl+S or Save. The preview should now flow real products rows as cards. You should see 5–10 cards from the dataset, not 2 from sample_data.
  4. Finally, hit 🚀 Deploy in the workspace (or have "Save on deploy" enabled) and verify on the live domain.

Why the JSON spec is the frontend — at this point everything the page does boils down to three JSON records.

  • slot_info — which frame, which slots, which blocks.
  • data_vars — which variable maps to which dataset, table, filter.
  • ui_info — extra UI options (mostly empty here).

You don't hand-write code anymore: tweak these three JSONs and the page redraws. After this it gets magical — making 10 screens approaches the cost of making 1, because each new screen is mostly a new combination of existing blocks and dataset bindings.

TIP Empty preview? Check in this order: ① dataset 🔌 connection test passes, ② variable names match between block and data_vars (both list?), ③ products table actually has rows, ④ WHERE isn't too strict (resulting in zero rows). Almost every blank-preview case hits one of these.

Parser Advanced · Bring a cURL Verbatim and Loop It Over a Dataset

For sites where a plain GET ?q=... URL is not enough — sites that need cookies, CSRF tokens, Authorization headers, and a POST JSON body — this guide walks you end-to-end through reproducing the exact browser request, marking the parts that should change per row, and looping it N times against a dataset to collect responses into a new table.

about 25–35 min

Pipeline at a glance — Browser request → cURL clone → Variable injection → Loop call

1
Capture in browser
(F12)
2
Copy as cURL —
the whole packet
3
Verify once
in Postman
4
Mark variable
slots ${var}
5
Register parser rule
+ loop over dataset

cURL line by line — URL · Cookies · Headers · Body

A single browser request usually packs four things together — URL/method, session cookies, auth/AJAX headers, and a POST body. Only the parts that change per row become ${variables}; everything else stays exactly as captured.

curl -X POST 'https://example.com/api/search'
URL · Method Endpoint and GET/POST. Usually does not change per row.
-H 'Authorization: Bearer eyJhbGc...' -H 'X-Requested-With: XMLHttpRequest'
Auth · AJAX headers Authorization Bearer, X-Requested-With, etc. Drop one and the response often comes back empty.
--data-raw '{"q":"${query}","page":${page},"size":20}'
POST body · variable slots Wherever the value should change per row (search term, page) write ${name}.

The loop in one picture — Dataset rows → Variable substitution → Responses

A row from the left dataset is injected into the ${variable} slots of the cURL template in the middle, and the response lands as a new row in the right dataset. With 100 input rows you get 100 calls — no human button-press loop.

Input dataset (keyword_list)
query="best ramen", page=1
query="coffee shop", page=1
query="coffee shop", page=2
... N rows
${var}
injected
cURL template (variable slots)
POST /api/search
{"q":"${query}",
"page":${page}}
+ cookies · headers verbatim
response
stored
Response dataset (search_results)
query="best ramen" → 20 hits
query="coffee shop" → 20 hits
query="coffee shop" p2 → 20 hits
... total N×20 rows
1
Scenario
2
Capture (F12)
3
Verify in Postman
4
Mark variables
5
Prepare dataset
6
Register rule
7
Run + override
1
Step 1 · Scenario — why bring the whole cURL

For a simple site, a single GET URL like https://site.com/search?q=hello is enough. But more than half of real-world sites are not that simple.

  • Logged-in-only results — without a session cookie you get an empty page or a login screen.
  • POST + JSON body — the search term is not in the URL, it lives inside the body: {"q":"hello","page":1,"size":20}.
  • CSRF / Bearer tokens — every request needs an extra header or it returns blank.
  • X-Requested-With · Referer · User-Agent — when these AJAX-marker headers are missing, the server often deliberately answers with nothing.

Re-typing every header by hand is a non-starter. The fastest path is to copy the actual browser request as a single cURL command, leave everything as captured, and replace only the per-row pieces with variables.

What we will build — a dataset of N keywords (e.g. keyword_list), then call the site's search API N times and stack the responses into a second dataset (e.g. search_results).

TIP Reproducing the call once, exactly, is half of the whole job. If a single call cannot be reproduced, looping 100 times is meaningless. That is why the next several steps are dedicated entirely to "make one call work".
2
Step 2 · F12 → Copy as cURL — capture the entire request

Open the target site in Chrome (or Edge) and search once the way you normally would.

  1. Press F12 to open DevTools, then move to the Network tab.
  2. Run the search. The list fills with requests. The one you want usually contains search, list, query, or api in its name and returns JSON.
  3. Click the request and check the right-hand Response tab — confirm the body really is the data you want.
  4. Right-click the request line → Copy → Copy as cURL (bash). Even on Windows, the bash flavor has the cleanest quoting.

Your clipboard now holds a one-liner like curl 'https://...' -H 'Cookie: ...' -H 'Authorization: ...' --data-raw '{...}'. It looks long, but it contains URL · cookies · all headers · body in one shot.

TIP A single search will produce 10–30 entries in Network. Skip ads, analytics, and image requests; look for the one whose response preview shows your search results. The Preview tab is the fastest filter.
3
Step 3 · Replay it once in Postman — verify the single call

Do not paste the cURL straight into the parser. First confirm in Postman (or Insomnia / Bruno) that one call works exactly. If it fails here, the parser rule will fail too.

  1. Open Postman → top-left ImportRaw text tab.
  2. Ctrl+V the cURL one-liner and click Continue → Import.
  3. A new request tab opens with all headers and body pre-filled. Click Send at the top right.
  4. If the status is 200 and the body matches what you saw in the browser, you are done. Empty body, 401, 403, or 302 means check the items below.
  • Cookie expired — by far the most common cause. Re-confirm you are still logged in, then re-run F12 → Copy as cURL.
  • Header missed during conversion — Postman occasionally drops 1–2 headers. Open the browser Network tab Headers panel and Postman Headers side by side and compare line by line.
  • Referer / Origin — some sites return blank without these two. If the browser sends them, add them.
TIP The moment Postman returns a clean 200 is the real starting line. Save the request to a Postman collection at this point so that later, when you need to inspect variable slots or the response shape, you do not have to capture from scratch again.
4
Step 4 · Mark variable slots — ${var} for what changes per row

Looking at the working Postman request, mark the parts that will change on the next call. Common candidates:

  • Search term in the POST body"q":"hello""q":"${query}"
  • Page / offset"page":1"page":${page} (numbers without quotes)
  • Category / filter"cat":"food""cat":"${category}"
  • Date range"from":"2026-04-01""from":"${date_from}"
  • URL path variable/api/user/12345/api/user/${user_id}

The trick is to name each variable identically to the dataset column you will create. If you are going to name your columns query · page · category, then write ${query} · ${page} · ${category} in the cURL too. Identical names mean automatic mapping in the next step — no manual wiring.

Format — the parser recognises the ${name} pattern. Use only ASCII letters, digits, and underscore (no spaces, no localised characters, no punctuation).

TIP Never variable-ise the parts that should stay fixed (cookies, auth tokens, fixed headers). Mark only the truly per-row pieces. Things that change "occasionally" — like an expiring cookie — are not variables, they are a sign the rule itself needs to be refreshed.
5
Step 5 · Build the input dataset — keyword_list

The parser reads the dataset row by row and feeds each row into the cURL's variable slots. So in this step you prepare the N input combinations as a dataset.

  1. Side menu Data > Datasets → top-right + New dataset.
  2. Name it something obvious like keyword_list. Add columns whose names match the variables from Step 4 exactly — e.g. query (varchar) · page (int) · category (varchar).
  3. Add rows in either of two ways — (a) type them in the UI one by one, or (b) prep them in Excel/Sheets and use the Cell Editor paste-to-insert flow.
  4. Resist the urge to start big. Add 3–5 rows only for now. Starting with 100 rows means one mistake produces 100 wrong calls.

It also helps to prepare the output dataset now. e.g. search_results with columns query, rank, title, url, snippet. You will point the parser at it in Step 6.

TIP If a dataset column name differs from the cURL ${variable} by even one character, automatic mapping breaks and you have to wire it manually. Copy the variable name from Step 4 and paste it as the column name verbatim — it is the safest habit.
6
Step 6 · Register the parser rule — Test page · cURL · variables

Now build the parser rule and connect the cURL to the dataset.

  1. Side menu Data > Parser → top-right + New rule.
  2. Test-page (base URL) field — paste the endpoint from the start of the cURL, e.g. https://example.com/api/search. If the URL itself contains a variable, write it the same way: ${user_id}.
  3. cURL fieldCtrl+V the variable-marked one-liner from Step 4. The parser auto-splits method, headers, cookies, body, and finds ${...} patterns to register them as variable candidates.
  4. Pick the input dataset — choose keyword_list from Step 5. Matching names auto-map; mismatches surface a mapping dropdown next to each.
  5. Pick the response-storage dataset — choose search_results. Tell the parser which JSON path of the response (e.g. data.items[*]) becomes one row.
  6. Save. The rule is registered — no calls have been made yet.
TIP If the cURL pastes in but the headers do not split cleanly, check whether the outer quotes are single or double. cURL copied from Windows cmd uses double quotes with backslash escapes that the parser may misread. Re-copy with Copy as cURL (bash) and it pastes cleanly.
7
Step 7 · Run + override — single test, then full loop

Two run modes are available.

  • ① One-shot direct override — on the rule page, beside the ▶ Run button, the variable input panel lets you type query="best ramen", page=1 and fire a single call. The response preview and the extracted rows appear side by side. Stay in this mode until the response shape is fully understood.
  • ② Loop over dataset — switch the variable panel to "From dataset", pick keyword_list from Step 5, hit Run. A progress bar climbs from 0/N to N/N as responses are appended row by row to search_results.

While it runs, watch error count (empty/401/5xx), response sample, and rows stored. One or two failed rows is normal; if more than 50% fail, stop and re-check the cURL.

Schedule — under the rule's Schedule tab you can run it daily, hourly, or at any cron-style time. Drop a keyword list in the input dataset and a daily-fresh result table comes out the other end.

TIP For the very first real run, cap the input dataset at 5 rows or fewer. Five calls do not look like suspicious traffic to the target site, and the cost/blocking risk stays low. Once 5 rows hit 100% success, scale to 50, then 500.

Remote Management · Basics

End-to-end walkthrough of taking a design asset bundle (images, logos, fonts, CSS) from the designer, uploading it to the deployed server, and referencing it from a single-file project so the assets actually render in the browser. No FTP client required — everything happens inside the browser.

Estimated time: 10–15 min
1
Zip assets
2
Pick server
3
Navigate path
4
Upload archive
5
Reference in single-file
6
Preview & deploy
1
Step 1 · Bundle the assets into a single zip

Before uploading, pack everything the designer gave you into one zip archive. The way you zip it decides how the paths look on the server, so follow these rules.

  • Wrap everything in a top-level folder — e.g. put images and css inside a design_assets/ folder and zip that folder itself. After extraction you will see /upload-path/design_assets/logo.png, keeping the folder name as one level.
  • Use only letters, digits, hyphens (-) and underscores (_) in names — spaces or non-ASCII characters tend to break URL references. Example: main banner.png ❌ → main-banner.png
  • Supported formats — .zip · .tar · .tar.gz · .tgz. Most of the time .zip is enough. On Windows, right-click the folder → "Compress to ZIP file"; on macOS, right-click in Finder → "Compress".
  • Example layout
    design_assets/
     ├─ images/logo.png
     ├─ images/hero.jpg
     ├─ fonts/pretendard.woff2
     └─ css/theme.css
TIP If you want to reference assets as images/logo.png directly, build the zip without the outer wrapper and pack the sub-folders (images, fonts, css) at the top level. Pick one convention and stay consistent throughout the project.
2
Step 2 · Open Remote Management and pick the target server

From the top navigation or dashboard, go to Services → Remote Management. You should see a server list sidebar on the left, a four-column file explorer in the middle, and an action bar at the bottom.

  1. In the server list on the left, click the domain you want to upload to (e.g. myshop.apidealder.net). The small circle next to each domain name shows its current state.
    • Green dot — ready; the file list opens immediately.
    • Gray dot — offline. The container is stopped, or the server has not been deployed yet.
    • White dot — checking status.
  2. If the list is empty, you will see a "Deploy a server first" prompt. In that case, deploy a single-file or project first and come back.
  3. Once selected, the middle area expands the root (/) folder and reveals the real file tree.
TIP If the gray/white dot stays for long, wait one to two minutes and click again. Containers that have been idle for a while take a moment to wake up.
3
Step 3 · Navigate to the upload location (a public folder)

Assets will be loaded by the browser through a URL, so they must live in a publicly accessible folder. On single-file-based servers the usual choice is public/assets.

  • Path bar — the house icon at the top of the middle area jumps to root, and each slash-separated segment is clickable to jump there instantly.
  • Path input — next to it, type /public/assets directly and press Enter to jump in one shot instead of clicking folder-by-folder.
  • If assets folder does not exist — use the bottom action bar's [New folder] button to create assets and enter it. Only letters, digits, dot (.), hyphen (-) and underscore (_) are allowed in the name.
  • After moving, confirm the path bar reads /public/assets. This is the folder the archive will be extracted into, so a wrong location means you will have to delete and re-upload.
TIP The root (/) and system folders (/etc, /var/log) are not served over HTTP. Always mentally draw the mapping — is https://your-domain/assets/your-file reachable from this location? — before uploading.
4
Step 4 · Upload & auto-extract through the archive modal

With the path set to /public/assets (or any public folder you prefer), click [Upload archive] (cloud-up icon) in the bottom action bar. The upload modal opens with a three-phase flow.

  1. Dropzone — drag the zip file into the dashed box or click it to open a file picker. .zip · .tar · .tar.gz · .tgz are supported.
  2. Preview — the modal draws the folder/file tree inside the archive and shows the file name, size, and the extraction target (/public/assets) at the top. Use this to verify the outer wrapper is correct and that no stray hidden files (macOS .DS_Store, for example) slipped in. The [x] on the upper right swaps the file if needed.
  3. Send — click [Send]. The file is sent in 1 MB chunks with a live progress bar, so flaky networks resume cleanly and large files (hundreds of MB) upload reliably.
  4. When the transfer finishes, the server auto-extracts the archive, the current folder refreshes, and the newly uploaded design_assets folder (or images/fonts/css folders) appears. A completion toast also shows up.

Need to upload a handful of loose files instead? Use the neighboring [Upload files] button to multi-select files — they will be copied into the current folder as-is with no extraction.

TIP Closing the modal or switching browser tabs during upload cancels the transfer. For large files, leave the window open and work in another tab until the completion toast appears.
5
Step 5 · Reference the uploaded assets from a single-file project

Uploaded files are served directly from the deployed domain. For example, if you uploaded to /public/assets/design_assets/images/logo.png on myshop.apidealder.net, the browser URL is https://myshop.apidealder.net/assets/design_assets/images/logo.png. (public is the web root, so it drops out of the URL.)

Now open the single-file editor (Services → Single File) and reference the assets you just uploaded.

  • Insert images in the HTML tab
    <img src="/assets/design_assets/images/logo.png" alt="logo">
    <img src="/assets/design_assets/images/hero.jpg">
  • Reference backgrounds and fonts in the SCSS tab
    .hero { background: url("/assets/design_assets/images/hero.jpg") center/cover; }
    @font-face { font-family: 'Pretendard'; src: url("/assets/design_assets/fonts/pretendard.woff2") format('woff2'); }
  • Key rule — always use an absolute path starting with /. Relative paths (../assets/...) can behave differently between preview and production and are discouraged.
  • To include an external CSS file wholesale, add @import url("/assets/design_assets/css/theme.css"); at the very top of the SCSS tab.
TIP One wrong character and the preview shows a broken-image icon (📷✗). Open DevTools (F12) → Network tab and check if the request returns 404. File names must match exactly, including case — your local machine (Windows/macOS) is forgiving, but Linux servers are strict.
6
Step 6 · Run preview and verify on the deployed domain

After wiring the references, click [Run ▶] at the top right of the single-file editor to preview first. If the preview is fine, press [Deploy 📦] to push it to the live domain.

  1. Run preview — the right-hand pane renders the result in real time. Confirm images appear, fonts load, and the CSS is not broken.
  2. Deploy — the deploy button starts a step-by-step deployment and usually finishes in one to two minutes. A domain link shows up in the result box when it is done.
  3. Verify on the live domain — open the link in a new tab, or visit https://your-domain/ directly. Do a hard reload (Ctrl+F5 or Cmd+Shift+R) to skip cached content.
  4. If an image does not appear, jump back to Remote Management and double-check the path. When the extracted folder structure does not match what you expected, deleting that folder and re-uploading from Step 4 is usually faster than hand-patching paths.
TIP When you need to swap an asset later, just overwrite the file through Remote Management — no redeploy needed for the single-file project. Keep the same file name so the browser picks up the change; if you suspect caching, rename the file (logo.pnglogo_v2.png) and update the reference accordingly.

Remote Management · Advanced

A practical debugging walkthrough for when something on the deployed server is not behaving. You will use the terminal panel — right inside the browser — to run CLI tools like grep, cat, and tail against the log files under storage/logs. No SSH client, no desktop tools — just the remote tool.

Estimated time: 10–20 min
1
Recognize the case
2
Open terminal
3
Go to logs
4
Browse files
5
Narrow with grep
6
Fix & re-verify
1
Step 1 · Recognize the case — when to read the logs

On the surface symptoms look similar, but the root cause varies. If any of these apply, reading the server-side logs is the shortest path.

  • 500 / 502 / 504 server errors — the browser only shows "An error occurred"; the real cause lives in the server log.
  • Blank white page — usually a PHP fatal error silenced the output. The log will almost certainly contain a Fatal Error or Parse Error line.
  • API returning 400/422 with unclear cause — the exact validation rule that tripped is recorded in the controller log.
  • Background work (queue, schedule, macro) "seems to run but produces no result" — silent failures leave traces only in the logs.

Key log files to look for:

  • storage/logs/laravel.log — the main PHP/Laravel log. Your most-visited file.
  • storage/logs/laravel-YYYY-MM-DD.log — if daily log rotation is enabled.
  • storage/logs/worker.log and feature-specific logs (macros, parsers) when those subsystems keep their own files.
TIP Before diving in, write down a rough time window (e.g. "around 3:40 PM when I clicked Order"). Narrowing the log to that window first saves a surprising amount of time.
2
Step 2 · Open Remote Management, select the server, pop open the terminal

Head to Services → Remote Management in the browser.

  1. In the server list on the left, click the domain that has the issue. A green dot means the container is reachable. A gray/white dot means the container is asleep — wait a minute and click again.
  2. Click the terminal icon (▷_) in the toolbar at the top of the middle area. A terminal panel slides up from the bottom. Clicking the same icon again collapses it.
  3. The panel header shows the current working directory (e.g. /var/www/html) and the cursor starts blinking in the input. This cursor is wired to the selected server's shell, so commands run on that server directly.
  4. Before doing anything, sanity-check where you are:
    pwd
    ls
    You usually land at the project root (/var/www/html).
TIP The container runs lightweight Alpine Linux, so the default shell is /bin/sh, not bash. Bash-only syntax (such as [[ ... ]] or arrays) may not work. Simple commands — cd · ls · cat · grep · tail · head — are all fine.
3
Step 3 · Move into storage/logs

In a Laravel project, logs live under storage/logs. Jump there from the terminal.

  • cd storage/logs — relative to the current folder; one line is enough if you are already in /var/www/html.
  • cd /var/www/html/storage/logs — absolute path; works no matter where you started.
  • pwd — confirm you ended up in /var/www/html/storage/logs.

The terminal remembers the working directory, so every subsequent command runs relative to this folder without retyping the path.

Alternative: navigate to /storage/logs in the file explorer first, then open the terminal — the path follows you automatically. Handy when you dislike typing paths.

TIP If the folder is missing or you see "No such file or directory", the server may not be Laravel-based. Step up (cd ..) and ls around to find the real log location (log/, logs/, /var/log/nginx/, etc.).
4
Step 4 · Browse the log files (ls · cat · tail · head)

Once inside the folder, first check which files exist and which were touched most recently, then peek at the contents.

  • ls -lhrt — file listing sorted by modification time ascending; the most recent file sits at the bottom. -h prints human-readable sizes (KB/MB).
  • cat laravel.log — dump the whole file. Only safe for small files; multi-MB files will flood the terminal.
  • tail -n 100 laravel.loglast 100 lines. The fastest way to see the most recent error. Tune the number as needed.
  • tail -f laravel.loglive follow. New log lines appear as they are written; reproduce the bug in the browser and watch entries stream in. Ctrl+C to stop.
  • head -n 50 laravel.logfirst 50 lines; useful for boot-time entries that sit at the top.
  • wc -l laravel.log — total line count. If a file is hundreds of thousands of lines, skip to grep right away.
TIP If a log has grown past hundreds of MB, rotate it away with mv laravel.log laravel.log.old and let a fresh file be created. Reproducing the bug against an empty file gives you a clean signal without losing the old log.
5
Step 5 · Narrow down with grep

When the file is long, tail alone is not enough. grep prints only the lines that contain a given pattern — the workhorse of log debugging.

  • grep -i error laravel.log — all lines containing "error"; -i makes it case-insensitive so "Error", "ERROR", and "error" all match.
  • grep -in "fatal\|exception" laravel.log — lines with "fatal" or "exception", with line numbers (-n). Multiple patterns are OR-combined with \|.
  • grep -A 5 -B 2 "SQLSTATE" laravel.log — find lines containing SQLSTATE and print 2 lines of context before (-B 2) and 5 after (-A 5). Ideal when you want the stack trace next to the exception.
  • grep "2026-04-25 15:4" laravel.log — scope to a specific time window (3:40 PM range). Combined with the window you noted in Step 1, this narrows things down fast.
  • grep -c "production.ERROR" laravel.log — prints only the count of matches. Good for "how often does this happen".
  • tail -f laravel.log | grep -i errorlive follow with filter. Only error lines make it to the screen.

Typical search flowgrep -i error to see the shape → pick a conspicuous message and re-run grep -A 10 "that message" for surrounding context → note the file paths and line numbers that fall out.

TIP If the output is still too much, pipe to less (grep ... | less) for paged navigation, or write to a file (grep ... > /tmp/out.txt) and open it in the remote code editor. less is available on Alpine out of the box.
6
Step 6 · Fix the code and re-verify with logs

Error lines caught by grep usually carry a file path and line number (e.g. /var/www/html/app/Services/Order.php:127). Use that to jump straight to the fix.

  1. Collapse the terminal, paste /var/www/html/app/Services into the file explorer's path input, and hit Enter.
  2. Double-click the target file to open it in the syntax-highlighted code editor. Fix the line and press [Save] — changes apply instantly, no redeploy needed.
  3. Re-open the terminal, start a live follow with tail -f /var/www/html/storage/logs/laravel.log, then reproduce the bug in the browser.
  4. If the same error does not appear, press Ctrl+C and you are done. If a different error shows up, loop back to Step 5 and narrow it down again.

When you need temporary debug logging — drop a single line into the suspect code: \Log::info('[debug] ' . json_encode($variable));, save, reproduce, and run grep "[debug]" laravel.log to read back the value. Remove the line once the issue is understood.

TIP Always remove or comment out debugging calls like Log::info, dd(), and var_dump() when you are finished. Leaving them in bloats the log with every real user request, and a stray dd() turns the affected feature into a blank white page.

Final Challenge · Work via VS Code + AI (Claude/Codex via MCP), Deploy Local → Stage → Production

The capstone guide where every feature you have learned so far comes together. Ask Claude or Codex (connected via MCP) for changes in plain language inside VS Code, see them on your local test server first. Once happy, one button push syncs code and DB to a stage server for verification on a near-production environment, and finally deploys to production — the industry-standard workflow, walked end to end.

about 30–45 min

One work cycle — VS Code editor ⇄ Claude/Codex (MCP) ⇄ Local preview

In an era where AI writes the code, the human role becomes "ask precisely, verify carefully". Type your request in the VS Code chat panel, Claude/Codex reads and edits project files directly through MCP, and the change shows up instantly in the browser via the already-running vite dev / php artisan serve. You only need to confirm intent and queue the next request.

VS Code (you)
Editor Chat Panel

You ask in plain language (e.g. "add a phone column to the users table and a row to the signup form"). You verify the result in the browser and chain the next request.

request
(natural language)
code change
applied
Claude / Codex (AI agent)
MCP Read · Edit · Run

Reads and edits project files directly via MCP — SQL migrations, blade/vue/scss changes, build commands, all in one shot. You watch the result, not the keystrokes.

3-stage deploy pipeline — Local → Stage → Production

You do not throw a local change straight at production. A stage environment in the middle — same domain/DB/traffic shape as prod — catches the regressions that "worked on my machine". A single click of [SRC → DST] in the QS DEPLOY tab moves one stage forward, and it carries code + assets + DB together.

Local Test L
  • vite dev + php artisan serve running on your PC
  • Save → browser refresh in seconds
  • Fastest place to verify what AI just changed
[SRC → DST] code + assets + DB
Stage Server stage
  • Same domain/DB shape as prod (different host)
  • Regression-test against real-shaped data
  • Share the link for review
[SRC → DST] code + assets + DB
Production main
  • The main server real users hit
  • Save on Deploy guards against unsaved files
  • Watch logs after deploy → SWITCH lets you roll back fast
1
Scenario
2
VS Code prep
3
Ask the AI
4
Local test
5
Sync to Stage
6
Verify Stage
7
Deploy to Prod
1
Step 1 · Scenario — why split into Local / Stage / Prod

Almost every working dev team follows this flow. Small changes, verified at every stage. Throwing a change straight at production breaks production all at once.

  • Local is fast — save and refresh in 1 second. The first place you confirm the change matches your intent.
  • Stage mirrors prod's domain, DB, and traffic shape. The last net for "worked on my machine, not on the server" surprises.
  • Prod is what real users see. A problem first found here arrives as a customer complaint.

Today we walk all three stages end to end. The actual work happens by asking Claude or Codex inside VS Code in plain language. Your job is no longer to type code line by line — it is to state intent clearly, verify the result, and decide whether it is safe to send forward.

TIP Do not bundle too many changes into one stage→prod push. Many small pushes are always safer than one big push. Ten 1-line changes are far easier to debug than one 100-line change.
2
Step 2 · VS Code prep — package download → .env auto-auth → Smart Setup

Five minutes once, and the rest of the day is faster.

  1. From QuickStart web, open Download package for your project, unzip, then File > Open Folder in VS Code.
  2. The bottom QUICKSTART panel appears automatically. Auth is silent — the .env's fingerprint connects to the server with no login form.
  3. UTIL tab → bottom-row [🚀 SMART SETUP]. Runs composer dump-autoload → npm install → vite build in one go. When it finishes, vite dev and the PHP built-in server are both up.

Open http://localhost:<port> — your project is live. This is the starting line.

TIP Smart Setup is a one-time-per-folder thing. Re-opening the same folder later only needs vite dev running; press Smart Setup again only when dependencies change.
3
Step 3 · Ask the AI — Claude/Codex (MCP) in plain language

Two paths, usually used together.

  • ① VS Code chat panel + MCP — point Claude (or Cursor / Copilot Chat / Codex CLI) at an MCP server for the project. Then in chat: "add a phone column to the users table and a row in the signup form". The AI writes the SQL, edits blade/vue/scss, and runs the build — all of it.
  • ② UTIL tab AI buttons — select code and click UTIL → AI group → [CODE REVIEW] · [REFACTOR] · [EXPLAIN] · [i18n TS]. Each one builds a project-context-rich prompt you paste into Claude/Codex for a sharper answer.

Writing a good request — be specific about what, where, in what form. Example: "On /admin/users, show the phone column right after email; render \"-\" when empty." That kind of phrasing keeps the AI on track.

TIP Do not ask for huge changes at once. Break work into 3–5 minute units you can verify; ship one, ask for the next. Especially DB-schema changes — one at a time, please.
4
Step 4 · Local test — save → refresh, 1-second loop

The moment AI saves a file, vite dev hot-reloads the browser. Almost any .blade.php · .scss · .vue · .js file refreshes on save; PHP backend changes are picked up by php artisan serve.

  1. Look at the actual screen — right place, right behaviour, right shape?
  2. Quick scan of the F12 console — no red errors before sending forward.
  3. UTIL → SYSTEM → [CLEAN CACHE] clears Laravel's view/route cache so config or template tweaks land cleanly.

If the result is off, just ask the AI again briefly — "move that phone column above the postcode" — refresh. One round of this should fit in under a minute when you are in the groove.

TIP If anything looks even slightly off on local, do not push to stage. A problem you missed locally almost never gets caught on stage, and certainly not on prod.
5
Step 5 · Sync to stage — one [SRC → DST] click

Local passed → push to stage.

  1. Switch to the QS DEPLOY tab in the bottom panel.
  2. In the left sidebar set Source = L (Local), check Destination = stage.
  3. Click each node's [CONNECT] and [TEST CONFIG] once — confirm a real connection. Red dots → check that node's .env (host, port, DB account).
  4. Click [SRC → DST]. Glance at the right-side [Save on Deploy] toggle — when ON, every open editor is saved before deploy starts.
  5. The log viewer streams the move in real time — code + assets (images / build outputs) + DB schema & data flow to stage in one pass.

Once it finishes, open the stage domain in a browser and verify both the code change and the new phone column landed in the stage DB.

TIP You only need [TEST CONFIG] to pass once on first push. After that, [SRC → DST] is one click. If a node card goes red, fix the .env on that node first (host/port/DB credentials).
6
Step 6 · Stage verification — DIFF · BROWSER · regression

Stage is a mirror of production. Only the domain is different — code and DB are exactly what is about to ship.

  • Visit the real stage domain and use the change yourself. Caching, CDN, and session issues that hide on localhost surface here.
  • Share the link with someone else. They see what you cannot see because you wrote it.
  • QS DEPLOY → [DIFF] compares stage ↔ local. Differences mean someone touched stage manually — clean those up before prod.
  • [BROWSER] opens the stage server's real file tree to inspect anything suspicious.

Regression caught? Back to local, ask the AI again → step 4 → step 5. One extra loop here is dramatically cheaper than one production incident.

TIP Do not treat stage as "just a hoop to jump through". Anything you miss here, real users find for you. The cost difference is 100×.
7
Step 7 · Deploy to production — Save on Deploy ON, [SRC → DST]

Stage passed → final push. Same buttons as step 5; the difference is real users see it immediately.

  1. QS DEPLOY → Source = stage (or L, same code), Destination = main (the production node).
  2. Confirm [Save on Deploy] is ON. Habitual ON is the safer default.
  3. Click [SRC → DST]. Stay on the log viewer until it finishes — any 5xx or red line, abort.
  4. Open the production domain. Use the new feature, then walk through the core flows you did not change (login, checkout, etc.) — make sure they still work.
  5. If something is wrong, [SWITCH] source/destination and ship the previous stage state back to prod — your fast-rollback path.

One full lap done — VS Code → Claude/Codex(MCP) → Local → Stage → Prod. From here, every future change rides the same rail, just faster.

TIP After production deploy, spend 10–30 min watching. Error logs, traffic graph, response times on the critical pages — this is the highest-risk and highest-visibility window. Do not jump to the next task right away.