SuperAPI AI Directory

basercms4-to-5-upgrade

Coding & development

View repository

Updated 10-15 17:24

About this skill

Rules for upgrading/migrating from baserCMS 4 to 5

This file defines the rules and patterns that AI agents must follow when migrating baserCMS 4 (CakePHP 2-based) code to baserCMS 5 (CakePHP 5-based).

Recommended: Before starting the migration, refer once to basercms5-claude-workflow-setup(environment setup) to prepare the environment for how to proceed (permissions organization = permissions-audit / Auto mode on top of that / design = superpowers brainstorming / Markdown preview of spec and plan). This is a suggestion; skip it if everything is already in place.

Basic policy

  1. Framework differences: baserCMS 4 is based on CakePHP 2, and baserCMS 5 is based on CakePHP 5. CakePHP 2 syntax basically does not work. Please completely rewrite it to CakePHP 5 syntax.
  2. Class replacement: Replace deprecated classes with alternative classes or standard PHP classes.
  3. Use of accessors: Avoid direct access to properties, and use getters/setters.
  4. For detailed information about the upgrade, refer to https://baserproject.github.io/5/ver5_migration .
  5. [Most important / cross-cutting principle] Among the defects found while fixing one screen, if the same cause is scattered across the plugin/site as a whole, handle them all at once "cross-cuttingly" on the spot. Do not repeat fixing only one place and then hitting the same error on the next screen. Procedure: ① Once you fix an error, find all instances of the same pattern grep -rn with(e.g.: $this->Form->input(、'multiple' => 'checkbox', singular get('Sample.Sample...')、searches/、Time->format($x) without the second argument, etc.) → ② For mechanically unique conversions, apply them all at once with perl -pi → ③Verify all changed files php -l with → ④ Handle only non-obvious places individually. Representative examples that can be cross-cut in bulk are cataloged in C-0 of the basercms-plugin-4-to-5-upgrade skill (patterns that can be mechanically batch-converted) (add to it as soon as you find one). When you find a new cross-cutting pattern, first add it to C-0 and then execute it in bulk. For concrete rewriting of plugin internal code (Controller/Table/Entity/View/Helper/forms/Vue/JS), refer to the same skill.

Standard migration flow (proceed in this order; source of truth)

Proceed with the entire migration in the order of this checklist. Because there are multiple order-dependent pitfalls (marked with ★), do not change the order of the sections based on assumptions. Details for each step are written in the referenced sections.

  • 0. Confirmation of the execution environment — Confirm with the user whether Docker is used, the container name, the PHP version, and the proxy configuration → "Prerequisite: Confirmation of the execution environment" section
  • 1. Survey the current state of v4 — Identify the plugin list (app/Plugin/)・Theme (theme/), DB name/prefix, whether multisite is used, whether submodules are present (find app/Plugin theme -name .git), and the admin prefix (app/Config/core.php の Routing.prefixes) and lay them out
  • 2. Determine migration targets (inventory) — Classify plugins and themes one by one into (a) use existing v5 version / (b) convert v4 / (c) discontinue, andget the user's agreement in a table → "Plugin Inventory" section
  • 3. Create a migration plan — Create a plan reflecting the inventory results and get user approval (for the environment/approach, see basercms5-claude-workflow-setup )
  • 4. Create a topic branch — Create a branch for the migration work (e.g. git switch -c basercms5-migration). For cautions when bringing v5 artifacts into git, see the "Git / Repository Operations" section (G-1 to G-4)
  • 5. Create a v4 backup — Create it via "Data Maintenance" in the v4 admin screen → zip to v5/tmp/ へ。★In environments involving a PHP switch (7.4→8.1), always take it 【before】 installing v5 = raising PHP(if taken after raising it, v4 admin may stop working properly) → "Database Migration Procedure" section 1.
  • 6. Install v5 /v5/ install to — Obtain the package → composer → .env → bin/cake install → Confirm login in a real browser → "Obtaining the Latest baserCMS" to "Installing baserCMS" sections
  • 7. Install BcDbMigrator → DB conversion — Up to outputting the conversion zip.★Do not restore yet(wait until step 12) → "Database Migration Procedure" section 2.-3.
  • 8. Install BcAddonMigrator — "Theme Conversion" section 2.
  • 9. (a) Install existing v5 versions + (b) convert and deploy themes/plugins — For (b), zip → bc_addon_migrator → v5/plugins/ extract.★Also perform the (a) installations here (before restoration). If deferred to the end, data will not be restored into that plugin's tables → "Theme Conversion" and "Plugin Conversion" sections
  • 10. Enable plugins directly in the DB — plugins Table INSERT (for those with Migrations, also run migrations migrate -p ).★Enabling them makes v4 remnants in the boot path cause fatals, sobin/cake version make minimal fixes until the smoke test passes. Verification only up to CLI + SQL (do not check in a browser yet — it is normal for screens not to appear until the v5 conversion in steps 15-17) → "Enabling Plugins (Direct DB / Standard)" section
  • 11. Apply the theme directly in the DB — sites.theme UPDATE + clear all caches → "Applying a Theme (Direct DB)" section
  • 12. DB restoration — Restore the converted zip in a browser via "Data Maintenance" in the v5 admin screen (no restoration CLI; performed by the user).★Always after steps 10-11 (enablement and application)Immediately beforehand, check only that the admin panel login is alive (do not look at the front end). After restoration, verify table creation and record counts with SQL → "Database Migration Procedure" section 4.
  • 13. Migrating uploaded files — /files → /v5/webroot/files → "Migrating uploaded files" section
  • 14. Creating the migration ledger (file list) — For each target plugin/theme, create a ledger listing the constituent files and their status in docs/superpowers/ (do not place.superpowers/ there since it is an SDD internal scratch). Record all subsequent cross-cutting check and operation verification progress and open issues here.The status vocabulary must always distinguish "not started / fixed / not applicable (with reason)" — Files that were not hit by grep in the cross-cutting check are not "not started" but "not applicable (no known-pattern hit; final verification is the rendering check in step 17)". State clearly in the ledger that "complete" in the summary table means "cross-cutting application of known patterns is complete" and does not mean every file has been individually inspected (there have been actual cases of misunderstanding)
  • 15. Cross-cutting theme check → conversion to the 5.x series (up to preparation) — Use grep to enumerate all TH-series patterns (siteConfig[]removed,fullUrl()removed, etc.) and handle them in bulk → basercms-theme-4-to-5-upgrade skills (TH-series plus template/theme rendering F-series).The completion criterion is that all php -l checks pass. Do not perform rendering checks here(do that with the user at the beginning of step 17). For template view variables, do not perform a full mapping in advance; rewrite only the variables found by grep that are "specific to the 4.x series and not supplied by the 5.x core ($siteConfig , etc.)", and leave core-supplied ones to actual rendering and log detection in step 17
  • 16. Cross-cutting plugin check → conversion to the 5.x series (up to preparation) — Apply C-0 (mechanical bulk conversion catalog) to all plugins first → handle T-/C-series individually. The completion criterion is that all php -l checks pass.Do not make unreasonable improvements (excessive refactoring of working code); note any findings in the ledger and move on → basercms-plugin-4-to-5-upgrade Skill
  • 17. Verify operation one by one, themes first then plugins (in collaboration with the user) — ★Before starting, temporarily disable all migration-target plugins (UPDATE plugins SET status=0 WHERE name IN (...)+ clear cache), and first check front-end rendering with the user in the bare state where "only the theme is enabled"(screen by screen: layout → top → list → detail. Mechanically detect 500 errors with error.logand missing/gapped rendering with grep "Undefined variable" , and fix until there are zero warnings). After that, proceed while enabling the plugins to be verified one at a time. This is because event listeners and the like make them susceptible to the influence of other plugins, and if all remain enabled, faults cannot be isolated. If the target depends on another plugin, enable onlythat dependent pluginas well. For each plugin, in the following order:
    • a. Verify things other than controllers/templates (Table/save/aggregation) with unit tests (heavy dependencies may be skipped; note in the ledger) → basercms-unittest Skill
    • b. Create and run controller integration tests (Failures at this point are acceptableand record in the ledger).★For plugins that have a standalone UT foundation, running b before browser verification is highly cost-effective (proven): The GET rendering test detected "all admin screens 404 caused by snake_case in setting.php" and "mismatch between control() auto ids and inline JS selectors (C-F2)" with zero browser round trips. Whether to introduce the foundation just for b in plugins that don't have it should be judged by the number of screens and amount of logic (small, event-glue-centric ones are fine with browser verification)
    • c. Ask the user to verify browser behavior (present URLs as links) → Resolve errors by getting screenshots/wording
    • d. Resolve (turn green) the controller tests that failed in b.
    • e. Once verification of the target is complete, leave it enabled and move on to the next plugin (ultimately all targets become enabled and fully verified)
  • 18. Decide policy and handle pending plugins — For items marked "needs review" in the inventory and pending notes in the ledger, decide policy with the user (handle/postpone/abolish) and clear them
  • 19. Final integration test — The user verifies the front end, admin, forms, and blog end-to-end in a real browser. Resolve any issues
  • 20. Git import → Complete — Check G-1 to G-4 and commit v5 → "Git / Repository Operations" section

Prerequisite: Check the execution environment (always do this first)

Before starting the concrete migration work (package acquisition, composer,bin/cake install, DB migration, tool conversion), always confirm the execution environment with the user. Do not try to guess or discover it (docker inspect , etc.).

  1. Ask whether Docker is used and what the container name is (most important): The command examples in this skill frequently use docker exec <container-name> ... , but container names differ by environment.First ask, "Are you using Docker? If so, please tell me the container name"thing.docker ps や docker inspect Before trying to guess with , first ask the user (there are many setups where the compose definition is not in the repository but in a separate repository, and discovery causes misjudgments and detours). Also confirm the DB container name, DB user/password,VIRTUAL_HOST , etc.
  2. Check the PHP version of the existing container (baserCMS 5 requires PHP 8.1+): baserCMS 4 often runs on php7.4, etc., butbaserCMS 5 requires PHP 8.1 or higher. If v5 is to coexist in an existing container and that container's PHP is below 8.1 (e.g. baserproject/basercms:php7.4), then The image needs to be upgraded to PHP 8.1 or higher(change the image tag in compose → restart). This image change often involves editing the compose definition side (which may be in a separate repository), socheck the edit location, and if it is outside the repository, ask the user to do it or obtain explicit permission before proceeding。
    • ★Before upgrading the image, always warn about "the possibility that v4 will stop working" and get confirmation: When PHP is upgraded to 8.1, the co-located v4 will also run on 8.1,v4 may stop working normally. Before performing the switch, explicitly confirm "The container will be changed to 8.1, but v4 may stop working. Is that acceptable?" and obtain approval before making the change. The order should be to obtain consent beforehand, not to run a v4 operation check afterward (since v4 is assumed to be abolished eventually,no v4 operation check is needed after the switch)。
  3. v5 is built as a "subdirectory inside the existing container and existing mount" (do not create a separate container or separate vhost): v5 Create the folder directly under the project, and via the existing container's mount, serve it as /var/www/html/v5 in the same container. This is why the login URL becomes https://<既存ホスト>/v5/baser/admin/... . Do not over-engineer by adding a separate service for parallel operation (v4 remains as is, without downtime).

Communication and Language (Important)

All communication and documents you create must be in Japanese.

Specifically, the following items must alwaysJapanesebe written in:

  1. Chat responses: messages to the user, status reports, questions.
  2. Task Artifact (task.md): progress management checklists, task names, summaries.
  3. Implementation Plan Artifact: implementation plan details, goals, changes, verification plans.
  4. Walkthrough Artifact: work retrospectives, verification result reports.

[Important: Present URLs as links] to the userWhen requesting browser operation checks(admin login URL, data maintenance screen, frontend check, etc.), always display the URLas a Markdown link([https://...](https://...)). Do not present it as plain text URL (so the user can click and open it immediately). Example: 👉 [https://<project>.localhost/v5/baser/admin/baser-core/users/login](https://<project>.localhost/v5/baser/admin/baser-core/users/login)。

[Important: Always use AskUserQuestion (selectable dropdown) for questions to the user] Policy confirmation, A/B selection, completion confirmation of work requests, etc.When waiting for the user's response, do not just ask in the body text; always use the AskUserQuestion toolWhen a dropdown appears, a notification is sent to the user's smartphone, but text-only questions are not notified and go unnoticed. Migration is a long process and users are often away from their seats, so the presence or absence of notifications greatly affects the round-trip lead time (established through user requests and actual operation). If an option does not fit, the user can freely enter text under "Other", so when in doubt, use a dropdown.

Obtaining the latest version of baserCMS

The code cloned from GitHub is a development version and is not used in actual projects. Use the following URL to use the packaged code. https://basercms.net/packages/download_exec/basercms-x.x.x.zip

For the obtained code, within the project,v5 create a folder and place it there.

How to obtain (workaround when the host's curl/wget is denied): download_exec The URL is a generated download for browsers, butWebFetch is a tool that "converts pages to Markdown and summarizes them", so it cannot save binaries such as zip files. The host's curl/wget is often denied by permissions. In that case,If you are using Docker, you can obtain it "via the container"(Bash(docker:*) If is permitted,docker exec ... curl は Bash(curl:*) is not subject to the deny). The project is mounted in the container, so if you download it inside the container, the actual files will also appear on the host side. Check the latest stable version on GitHub Releases (baserproject/basercms latest).

# 例: コンテナ内でパッケージを取得(マウント先 /var/www/html にプロジェクトがある想定)
docker exec -w /var/www/html <container> bash -lc \
  'curl -fL -A "Mozilla/5.0" -o basercms-<x.x.x>.zip "https://basercms.net/packages/download_exec/basercms-<x.x.x>.zip"'
# 取得後: file / unzip -l で zip 妥当性を確認 → unzip -q -o basercms-<x.x.x>.zip -d v5/

Only when obtaining via container is difficult, ask the user to download it in the browser and get the path.

Install packages with composer

composer install Execute.

  • The package version's vendor/ is empty (.gitkeep only), so composer install is required. Immediately after extraction, test -d vendor may be true but the contents may be empty (.gitkeep because the directory exists with only that).vendor/autoload.php Determine by the presence or absence of, and if absent, composer install do.

  • Third-party packages used by 4.x plugins must be explicitly added to v5 composer require do: 4.x composer.json libraries derived from (e.g. phpoffice/phpspreadsheet)は v5 の composer.json/vendor and may not be included,Class "PhpOffice\PhpSpreadsheet\Reader\Xlsx" not found etc. 4.x composer.json and install a version compatible with the PHP version (v5 is 8.1+) (e.g. docker exec -w <v5> <container> composer require "phpoffice/phpspreadsheet:^1.29" → 1.30.x is installed). After execution, php -r 'class_exists(...)' confirm resolution with.

  • Template assets such as Excel/PDF (.xlsx, etc.) are migrated to templates/Admin/Excel/... , and 4.x's View/Excel/admin/... has a different path structure: If generation components (SampleExcel, etc.) are assembling Plugin::templatePath('Sample') . 'Excel' . DS . 'admin' . DS . ...(4.x placement), File "..." does not exist。templatePath() はwith trailing slashso . DS . adding results in // . Also note that 5.x's actual placement Plugin::templatePath('Sample') . 'Admin' . DS . 'Excel' . DS . <controller> . DS . <file>.xlsx should be corrected to (check the actual file location with find <plugin> -iname "*.xlsx" ).

Copy .env

v5 Inside the folder, /config/.env.example を /config/.env copy to.

HASH_TYPE を sha1 set to.

★SECURITY_SALT に v4 の Security.salt Always set the same value as(app/Config/core.php の Configure::write('Security.salt', '...') . Copy from.env (the corresponding line in is commented out, so uncomment it). The password for v4 is sha1(salt.password), soif the salt does not match, after DB restoration you will not be able to log in at all as a v4 user(I actually got stuck on this..env It is also clearly stated in the comments in: "Set the security salt used in v4").

Also,nginx-proxy When using the .env の TRUST_PROXY container, set the value of true to

baserCMS installation

Create a new database for v5, andv5 run the installation command in the

# 引数の並び: <設置URL> <管理者メール> <管理者パスワード> <データベース名>
#   ★第4引数がDB名。--database というオプションは存在せず、付けると `Unknown option `database`` で失敗する
#   ★サブディレクトリ設置では --baseurl も付ける
bin/cake install [設置URL(例:https://localhost/v5/)] [管理者メール] [管理者パスワード] [DB名(例 <既存DB>_v5)] \
  --baseurl [/v5/] --host [DBホスト名] --username [DBユーザー名] --password [DBパスワード]
  • The database name is the 4th positional argument(--database option does not exist). Create one by appending _v5 as a suffix to the existing database name, and then pass it.
  • For subdirectory installation, --baseurl /v5/ add。

.htaccess の RewriteBase はIn most cases it works as is(the default for v5 .htaccess is a relative rewrite, so/v5/ it often works without adjustment even in a subdirectory = proven)./v5/v5 Only if duplication (404) or a redirect loop occurs for webroot/.htaccess の RewriteBase adjust (first suspect the SITE_URL below and remaining cache).

The login URL is,https://localhost/v5/baser/admin/baser-core/users/login It will be in a form like this.

  • [Important: When installing in a subdirectory, SITE_URL must include the subdirectory + always clear all cache after changing it] For subdirectory installation with config/.env の SITE_URL はthe full URL including the subdirectory(example https://localhost/v5/)がcorrect. Heredomain root (https://localhost/), you must not change it to— at first glance /v5/v5 it may seem that duplication disappears, but insteadadmin login enters an infinite loop 302ing to itself(because loginUrl and the request path differ, and the login page is mistakenly judged to be "protected").
    • The admin screen becomes /v5/v5 When duplication (404) or a redirect loop occurs, the true cause is often ".env(especially SITE_URL) remaining cache after changing it". baserCMS caches the root/URL, so.env If you change bin/cake cache clear_all always run https://host/v5/ . Return SITE_URL to the correct
    • [Verify with a real browser, not curl inside the container] nginx-proxy Under curl https://localhost/... , even if you hit X-Forwarded-Proto from inside the container, proxy headers such asare not added, and it shows redirect behavior different from a real browser (SSL/normalization redirect judgment is off). Whether the admin redirect is alive or deadmust be a real browser via a proxyCheck with . Do not blindly trust curl 302/duplication inside the container and misdiagnose it as a "subdirectory root bug".

Database migration procedure

For database migration, please recommend and guide a process that uses the dedicated plugin BcDbMigrator rather than directly rewriting SQL. This plugin does not provide a command and must be used in a browser.

  1. Prerequisites:

    • Migration source: Must be baserCMS 4.5.5 or later.
    • Migration destination: baserCMS 5 must be freshly installed.
  2. Migration flow(DB migration is divided into "1. Backup -> 2. Conversion" and "3. Restoration". Up to 2 can be performed early, but 3. Restoration isafter installing the necessary v5 plugins= performed after the plugin inventory/conversion phase):

    1. Backup (v4): Create a backup in the baserCMS 4 admin panel "Data Maintenance", and place the downloaded zip in /v5/tmp/ .\n
      • [Important: Order with PHP version] Creating a v4 backup requires a PHP version on which the v4 admin panel runs . If you raise the container to PHP 8.1 first for v5, the unsupported v4 admin may malfunction.Take the backup before raising PHP, or if you have already raised it,temporarily return to a v4-supported version (e.g., php7.4), take the backup, and return to 8.1 again (v4 and v5 cannot run simultaneously because they require different PHP versions).
      • [Important: Do not assume the v4 admin URL] Admin login may have /admin Sites that return 404 withthe admin prefix changed(app/Config/core.php の Configure::write('Routing.prefixes', ...). For example, cmsadmin → /cmsadmin/users/login, data maintenance is /cmsadmin/tools/maintenance)。Do not easily misdiagnose a 404 as "broken due to PHP switching"—first Routing.prefixes . Check .
    2. Tool preparation (v5): BcDbMigrator Place .It can be obtained via composer or GitHub(The old description "composer unavailable" and "plugins/ required" is incorrect = composer acquisition is possible andbaserCMS recognizes it even under vendor):
      • (a) composer: packagist に baserproject/bc-db-migrator has been released and can be obtained with composer require baserproject/bc-db-migrator:^5.2 . However, this package's composer.json has no autoload definition, so cakephp plugin-installer Unable to get primary namespace で config/plugins.php tofails to register it automatically(= the download itself succeeds). To use it reliably, copy the obtained files to plugins/BcDbMigrator and perform the DB activation below (from composer, composer remove and keep composer.json clean).
      • (b) GitHub: git clone --branch 5.2.0 https://github.com/baserproject/BcDbMigrator.git plugins/BcDbMigrator(after clone .git to avoid submoduling). *In Auto mode, fetching external repositories may be blocked by the classifier, so present the fetch source to the user and obtain approval. There are two ways to enable it:
      • (Recommended, low friction) Enable via DB record: BcDbMigrator はIt has no installation script (migration)therefore,plugins It can be enabled by INSERTing one row into the table (name='BcDbMigrator', title='BcDbMigrator', version='5.2.0', status=1, db_init=1, priority=<末尾+1>, created/modified=NOW()). No browser operation required. After enabling, bin/cake the command appears.
      • (Alternative) Install from the plugin management in the admin panel. *cake plugin load/config/plugins.php Direct editing is not possible (routing inconsistency causes crashes).
    3. Conversion execution (CLI support, 5.2.0 and later): BcDbMigrator 5.2.0 supports CLI execution(older versions are browser-only).docker exec <container> bash -lc 'cd v5 && bin/cake bc_db_migrator tmp/<v4バックアップ>.zip' When you run v5/tmp/baserbackup_<v5version>_<日時>.zip (no need for upload/download round trips. Even on error, the assistant can iterate). Conversion is performed with a temporary connection (bcOldDbMigrator/bcNewDbMigrator, prefixed temporary tables)the live DB is not modified(output is only the zip).
      • [Important: incompatibility patch with baser-core 5.2.5] BcDbMigrator 5.2.0 conversion replaces the old schema PHP with extends \BaserCore\Database\Schema\BcSchema(FQN), but baser-core 5.2.5's BcDatabaseService::isValidSchemaFile() は AST で extends requires the short name BcSchema to be an exact match, so無効なスキーマファイル: BcSchema を継承し、drop/create メソッドをオーバーライドしてはいけません all fail (the Component path common to CLI/browser).Workaround: plugins/BcDbMigrator/src/Controller/Component/BcDbMigratorComponent.php の _createTableBySchema() Withinextends CakeSchema with the short name instead of the FQN and add the use statement:
        $contents = preg_replace('/extends CakeSchema/', 'extends BcSchema', $contents);
        $contents = str_replace('<?php', "<?php\nuse BaserCore\\Database\\Schema\\BcSchema;", $contents);
        
        (Local patch because upstream BcDbMigrator does not support this.The root cause is on the baser-core side=isValidSchemaFile() which only allows exact matches of short names and rejects FQNs. A fix to relax this so that FQNs are also accepted has been submitted to baserproject/basercms as PR #4438 (targeting 5.3.x). Until it is merged and released, this local patch (replacing with short names on the BcDbMigrator side) is required. It is expected that the patch will no longer be needed in 5.3 and later.)
    4. Restore (v5): Restore the converted zip in the baserCMS 5 admin panel "Data Maintenance" (There is no restore CLI; it is browser-only)。This step is performed after the plugin inventory/conversion(see the "Plugins" notes below).
      • Restore works based on the contents of the zip (implementation confirmed): UtilitiesService::_loadBackup() simply drops→creates all *Schema.php in the zip and inserts all CSVs, andplugins does not reference the enabled/disabled state of the tableTherefore, tables whose converted zip contains a schema + CSV will be imported even if the corresponding plugin is disabled (unzip -l で <Table>Schema.php confirm that it is bundled).
      • ★Restoration also plugins replaces the table itself with the contents of the zip (= v4 plugin list, all rows status=0) (measured): Activation records made before restoration (including core BcBlog/BcMail, etc.) areall deleted and disabled。Always re-enable after restoration: The 6 core standard ones UPDATE plugins SET status=1 WHERE name IN ('BcBlog','BcMail','BcUploader','BcSearchIndex','BcThemeConfig','BcWidgetArea') + those among the migration targets that have been confirmed (during the operation check process, the migration targets may remain 0). The rows for BcDbMigrator/BcAddonMigrator are also deleted, so if you will continue using them, re-INSERT. After execution, bin/cake cache clear_all。
      • ★sites the table is similarly overwritten, and the theme application is removed (measured): After restoration, all sites theme='BcThemeSample' return to (the default value for BcDbMigrator conversion. Each multisite row is also restored from v4). When you open the front end, you notice with MissingLayoutException(the custom theme is not in the search path).Re-apply the theme after restoration: UPDATE sites SET theme='<CamelCaseTheme>' WHERE id=<対象サイト>+ cache clear. = Memorize this as **"the 3-point post-restoration reconfiguration set: re-enable plugins, re-apply sites.theme, cache clear_all"**.
      • ★Manually installed tool plugins (BcDbMigrator / BcAddonMigrator, etc.) are also deleted along with the plugins table(because restoration overwrites with the v4-derived plugins. Measured: after restoration, bc_addon_migrator command is Unknown command ). If you will use the tool again, re-INSERT into the plugins table (+ cache clear) before running it.
      • ★For multisite, always verify the consistency of site_id after restoration (measured; inconsistencies exist): In the restored data, the site_id conversion may differ from table to table — contents.site_id is converted to "v4 id +1" (5-series standard, main=1), whilesites.id is repacked to 2~ by AUTO_INCREMENT, and the site_id of plugin-related tables (search_indexes, etc.) remains v4 with no conversion. As a result, the subsite's contents point to a nonexistent site_id, and the subsite URLs (/blog/ , etc.) becomeall 404 . Verification SQL: cross-check SELECT site_id, COUNT(*) FROM contents GROUP BY site_id と SELECT id, alias FROM sites .The fix is to align the others with "5-series standard = contents numbering (v4 +1)": sites.id and UPDATE each table's site_id in descending order (to avoid collisions), andALTER TABLE sites AUTO_INCREMENT=<最大+1>. Tables that have a site_id column are identified with information_schema.COLUMNS .Re-restoring will cause the inconsistency to recur, so keep the unified SQL on hand and re-run it every time you restore.
      • If the admin panel returns 500 before restoration, (b) you may avoid it by disabling the conversion plugin: (b) tends to break the admin panel due to 4.x remnants in the boot/rendering path (Event listener viewVars references, etc.). As noted above, restoration imports the tables even when disabled, soUPDATE plugins SET status=0 WHERE name IN (...)+ cache clear to restore the admin panel, then restore (in any case, during the operation check process, disable everything once).
  3. Notes:

    • ★Reserved word column support (must be set before restoration): config/install.php の Datasources.default に 'quoteIdentifiers' => true must be set before restoration. 4.x sites almost certainly have reserved word columns such as check・message derived from mail form fields, and if not set, restoration will SQLSTATE[42000] 1064 Syntax error ... near 'check' でfail midway. It is not "may be needed" but can be set by default (there is no harm in it being quoted).
    • ★Midway restoration failure leads to "users being empty" (recovery procedure): Restoration performs drop→create of the schema in the zip first, so if it fails midway, users=0 remains and login becomes impossible(MySQL does not roll back DDL). Reinstalling is the reliable recovery method:
      1. mv config/install.php config/install.php.bak + .env の INSTALL_MODE="true"(If install.php remains, it is treated as "already installed" and bootstrap references an empty DB and crashes)
      2. DB を DROP→CREATE し bin/cake install <URL> <メール> <パス> <DB名> --baseurl /v5/ --host <DBホスト> --username <ユーザー> --password <パス>
      3. INSTALL_MODE back to false, and in the regenerated install.php set quoteIdentifiers again, and the plugin's plugins INSERT・migrations migrate -p・sites.theme reapply
      4. Redo the browser restoration.Do not log out during restorationask them to
    • Notes on login immediately before/after restoration: After reinstalling or recreating the DB, old CSRF cookies remain in the browser and cause Missing or invalid CSRF cookie → after reloading the login pageHave them log in. After a successful restore, users will be replaced with the v4 ones, sosubsequent logins will use the same admin ID/password as v4(inform the user of this in advance).
    • Plugins (order relative to restore): In the standard flow,conversion (early) → plugin inventory/installation & activation → restorein that order. Note that in implementation, the restore itself operates based on the contents of the zip, and plugin enable/disable does not affect table import (see "Restore operates based on the contents of the zip" above). The practical benefits of following the order are: "by completing activation before the restore, you can check plugin data in the admin screen immediately after the restore" and "you can create tables that have no schema in the zip (those created only by Migrations) beforehand."
    • Memory: A memory over error may occur when creating a backup. In that case, prompt the user to change memory_limit in php.ini.
    • Decimal: For tables using decimal(8,2) etc., migration will not succeed normally, so you need to define and import them separately via SQL.

Migration of uploaded files

/files Move the directory /v5/webroot/files to .

  • While v4 is running in parallel, use "copy" instead of "move"(so as not to break the display on the v4 side). Since it is several GB, doing cp -a inside the container is fast.
  • ★Nesting trap: v5/webroot/files has already been partially generated at the time of restore or plugin activation(theme_configs/ uploads/ and the blog directory skeleton, etc.). Therefore, if you do cp -a /path/files /v5/webroot/files then it will be files/files/ copied nested into. To merge into an existing directory, use cp -a /path/files/. /v5/webroot/files/(trailing /.) to copy the contents. If nesting has occurred, resolve it with cp -a .../files/files/. .../files/ && find .../files/files -delete .
  • Symptoms when not migrated: For upload-related URLs such as eye-catch images, if the actual file does not exist, the helper's fallback outputs **root-relative /files/...(no subdirectory)**, causing v5 pages to incorrectly reference v4's files (v5's error.log に MissingRouteException: /files/... line up). After files migration, /v5/files/... is generated correctly.Complete this step before "plugin activation → rendering check".
  • Verification after migration: Extract with src を curl | grep -o 'src="[^"]*files[^"]*"' from the rendered HTML and confirm 200 for static delivery. In a local environment, the DB is up to date but files are old(a timing discrepancy from when they were brought from production), and that 404 is not caused by the migration — distinguish it by the fact that the actual file also does not exist at the same path on the v4 side.

Theme conversion

For theme conversion,BcAddonMigrator Use the plugin.

  1. Preparation: ZIP-compress the baserCMS 4 theme folder.
    • Important: When compressing, do not include the parent directory of the theme directory (theme/) and compress so that the theme directory itself becomes the root.
    • Example procedure:
      # 1. テーマ名を特定 (データベースの site_configs テーブルを確認)
      # 例: SELECT value FROM site_configs WHERE name = 'theme';
      # 結果: my-custom-theme
      
      # 2. テーマディレクトリ名をキャメルケースに変更
      # 例: my-custom-theme -> MyCustomTheme
      THEME_NAME="my-custom-theme"  # 実際のテーマ名に置き換える
      THEME_CAMEL="MyCustomTheme"    # キャメルケースに変換
      
      # ★【最重要・データ破壊注意】変換後の名前が「大文字小文字だけの差」になる場合
      # (例: philosophy → Philosophy)、macOS 等のケースインセンシティブFSでは
      # theme/<camel> が元ディレクトリと同一に解決され、一時コピーの削除で
      # **元テーマ本体を削除してしまう**(実害あり。サブモジュールなら
      # `git submodule update --init theme/<name>` で復旧できる)。
      # 同名ケース差になるテーマは theme/ 配下でなく一時ディレクトリへコピーする:
      #   cp -r "theme/${THEME_NAME}" "/tmp/${THEME_CAMEL}" して /tmp 側で zip する
      cp -r "theme/${THEME_NAME}" "theme/${THEME_CAMEL}"
      
      # 3. ZIP圧縮 (node_modules除外)
      mkdir -p v5/tmp/zip
      cd theme
      zip -r "../v5/tmp/zip/${THEME_CAMEL}.zip" "${THEME_CAMEL}/" -x "*/node_modules/*"
      rm -rf "${THEME_CAMEL}"
      cd ..
      
      # 4. 圧縮後の確認(重要)
      unzip -l "v5/tmp/zip/${THEME_CAMEL}.zip" | head -n 20
      # ルートが MyCustomTheme/ であること、theme/ ディレクトリが含まれていないことを確認
      
  2. Tool: baserCMS 5 に BcAddonMigrator Install and enable (obtain from GitHub). * Note: BcAddonMigrator is obtained from GitHub andplugins/BcAddonMigrator placed in. Enabling can be done with plugins direct INSERT into the table(because it does not have an installation migration. Proven. Step 2 in the "Plugin activation (DB direct/standard)" section).cake plugin load/config/plugins.php Direct editing is not possible.
  3. Conversion (command line): bc_addon_migrator Use the command to convert the theme.
    # Docker環境の場合
    THEME_CAMEL="MyCustomTheme"  # 実際のキャメルケーステーマ名に置き換える
    docker exec <container-name> bash -c "cd v5 && bin/cake bc_addon_migrator --type=theme tmp/zip/${THEME_CAMEL}.zip"
    
    # 出力: v5/tmp/${THEME_CAMEL}_5.2.0.zip
    
  4. Deployment: Extract the converted ZIP file to v5/plugins/ .
    THEME_CAMEL="MyCustomTheme"  # 実際のキャメルケーステーマ名に置き換える
    cd v5/tmp && unzip -q -o "${THEME_CAMEL}_5.2.0.zip" -d ../plugins/
    
    • Note: The conversion is not complete. Be sure to visually check the entire code and make manual corrections.
  5. Manual correction:
    • Model data: Change array access ($post['BlogPost']['name']) to entity property ($post->name).
    • URL: Add the 'plugin' key to the array-format link and change the controller name to UpperCamelCase (e.g., 'controller' => 'search_indexes' → 'controller' => 'SearchIndexes')。
    • Form: $this->BcForm->create('Model') を $this->BcForm->create($entity) or null change to.input() を control() change to.
    • Element: Change the path specification to the PluginName.element_name format.

Plugin conversion

For plugin conversion as well, use the BcAddonMigrator plugin. However, a version already compatible with baserCMS 5 may be published in a GitHub repository, etc. In that case, do not perform conversion work and use that instead.

Plugin inventory (always before conversion; decide policy per plugin)

Before applying batch conversion to plugins, take inventory of plugins one by one and confirm with the user whether to "convert the 4-series" or "use the existing 5-series version". Do not suddenly apply BcAddonMigrator to all plugins (this would mean double-maintaining those for which the official/author has already released a 5-series version).

  • Investigation: For each plugin, check ① whether it is included as standard in baserCMS official 5-series (baser-core/bc-* whether it has been integrated into) ② whether a 5-series-compatible version exists on the author/distributor's GitHub or baser Market ③ whether a 5-series version is provided separately for external SaaS integration, etc. Leave those with insufficient information for judgment as "needs confirmation."
  • Classify and present to the user(example):
    • (a) Use the existing 5-series version: Already integrated into the formula / the author has released a version for the 5.x series (e.g., editor-related, OGP-related, and other externally distributed items). → Exclude from conversion targets, and install the 5.x version via composer/the admin panel.
    • (b) Convert the 4.x version and migrate: Custom implementations with no 5.x version (in-house plugins, etc.). → BcAddonMigrator Convert with , then convert the internal code to 5.x.
    • (c) Discontinued/Unnecessary: Features absorbed into standard functionality in 5.x / no longer used. → Do not migrate.
  • Get agreement in a table: Create a list of "Plugin name / Role in 4.x / Availability and source of 5.x version / Policy (a/b/c)", andafter confirming (a)(b)(c) with the user,proceed to the next step. Perform the same inventory for themes as well.
  • Reflect the results of this inventory in the migration plan (plan/spec), and make only the (b) items targets of the conversion phase.
  • ★For (a) items that the agent cannot obtain on its own due to private distribution, purchase requirement, license requirement, etc., clearly distinguish them in the inventory table and record them after agreeing with the user on "who will obtain/install them and when". Simply classifying them as "(a) use the existing 5.x version" leaves the person responsible for obtaining/installing them and the deadline up in the air, and they tend to remain unstarted as the execution phase proceeds (real example: although the introduction of the 5.x version of an editor-related plugin listed in the inventory document required the user to obtain it because of private distribution, it was not carried out in subsequent phases, and surfaced after migration completion as front-end display breakage. The cause was creating the inventory once and then leaving it, without tracking the execution status).
  • ★Do not create the inventory and stop there; before declaring migration complete, cross-check the inventory table against the actual installation status and verify it. For items classified as (a), individually confirm whether they have been installed, and if any remain uninstalled, do not leave them out of scope for the migration plan; reconfirm the timing for handling them (handle this time / continue as a separate task) with the user before considering the migration complete.
  1. Preparation: Compress the baserCMS 4 plugin folder into a ZIP.
    • Important: As with themes, do not include the parent directory (app/Plugin/); the plugin directory itself must be the root when compressing.
    • Example procedure (compress all plugins at once):
      # app/Plugin/ に移動して全プラグインを圧縮(node_modules除外)
      mkdir -p v5/tmp/zip
      cd app/Plugin
      for d in */; do 
          name=${d%/}
          zip -q -r "../../v5/tmp/zip/${name}.zip" "$name" -x "*/node_modules/*"
      done
      cd ../..
      
  2. Conversion (command line): bc_addon_migrator Use the command to convert all plugins at once.
    # Docker環境の場合
    docker exec <container-name> bash -c "cd v5 && for zip in tmp/zip/*.zip; do bin/cake bc_addon_migrator \"\$zip\"; done"
    
    # 出力: v5/tmp/<PluginName>_5.2.0.zip (各プラグインごと)
    
  3. Deployment: Extract the converted ZIP files all at once into v5/plugins/ .
    cd v5/tmp && for zip in *_5.2.0.zip; do unzip -q -o "$zip" -d ../plugins/; done && cd ../..
    
  4. Cleanup: Delete unnecessary ZIP files.
    rm -rf v5/tmp/zip v5/tmp/*_5.2.0.zip
    
    • ★baserbackup_*.zip(DB-converted backup) is not deleted。v5/tmp/ also contains the zip output by BcDbMigrator, so the wildcard [matches] the intermediate conversion zip (<PluginName>_<version>.zip) only. Limit the target accordingly.
    • rm -rf In environments where this is denied by Bash permissions, find <path> -delete use(Example: find v5/tmp/zip -delete. For individual files, find v5/tmp -maxdepth 1 -name '<Name>_*.zip' -delete)。
    • Note: The conversion is not complete. Be sure to visually check the entire code and make manual corrections.
    • What BcAddonMigrator does / does not do (measured):
      • What it does: Controller/Model/View の src/ namespacing,admin_ method Controller/Admin separation,src/<Name>Plugin.php generation (empty class class <Name>Plugin extends BcPlugin {})、config.php/setting.php return array conversion.
      • What it does not do: config/Schema(4.x CakeSchema) → config/Migrations conversion(the 4.x Schema remains as is),config/init.php removal(remains as residue), 5.x conversion of internal code (ClassRegistry・$this->data etc. remain).
      • In other words, immediately after conversion, "placement and php -l pass, but there are no Migrations and 4.x residue remains" is the normal state. For restoration operation, there is no obstacle to enabling (see the "Plugin enabling (direct DB / standard)" section). Migrations generation, residue cleanup, and internal 5.x conversion are performed in the cross-check process (flows 15-17).
  5. Manual correction:
    • Directory structure: The controller's admin_ prefix method has been moved to the Controller/Admin namespace.
    • Configuration file: config/setting.php の BaserCore.nav adjustment of array structures such as. Also,$config instead of variable definition, change to the form of return the array.
      • Important: array() syntax should be changed to [] (short syntax), and indentation should be adjusted.
      • Important: If there are multiple $config['Key'] definitions, merge them into one return array.
      • Important: During automatic conversion, be careful not to create the nested structure return [ $config = [...] ]; .$config = Delete and make it a pure array definition.
      • Important: When referencing your own configuration, define it once in a local variable and then reference it.
      • ★adminNavigation の url should be CamelCase for both plugin/controller(Example 'plugin' => 'PopularBlogPost', 'controller' => 'PopularBlogPostConfigs'). If it remains snake_case as in 4.x,common sidebar URL generation will result in MissingRouteException, and not only that plugin but the entire admin screen will become 404 (an actual case detected in integration tests). The 4.x-only adminNavi block is unused in 5.x and may be deleted.
    • Generating migrations (bake migration_snapshot):
      • Even if you run bake migration_snapshot -p [PluginName] --table [TableName] individually per plugin, the table definitions may not be extracted correctly (resulting in an empty file).
      • In that case, it is more reliable to run bin/cake bake migration_snapshot GlobalInitial all at once to obtain the state of all tables, and then manually (or with a script) distribute the generated code to each plugin's Initial.php .
    • $autoId property:
      • When generating a snapshot, $autoId = false is set so that the existing database structure is accurately reproduced from column names to indexes and comments.
      • By explicitly addColumn all definitions rather than relying on automatic generation, you eliminate discrepancies with the source database.
    • [Important] For database settings, v5/config/app_local.php takes precedence over v5/config/install.php . When checking or changing settings, pay attention to both files.
    • [Important] v5/config/plugins.php Do not edit directly. In baserCMS 5, plugins enabled in the plugin management screen are automatically loaded, and editing this file directly causes inconsistencies in the load order of dependencies and routing (routes.php), which can cause the application to crash.
    • [Important] Do not modify the baserCMS core (such asbaser-core ) or plugins that were included in the package from the start (bc-admin-third and other core plugins whose directory names contain hyphens). These are affected by core updates, so exclude them from the migration work.
    • [Important] BcAddonMigrator は admin_ Methods with the prefix are moved automatically, but the protected methods they call and helper methods such as _setFormViewData remain in the original (front-end) controller. Move these manually to the admin controller (Controller/Admin) and fix the namespace and any necessary use statements.
    • Plugin information: config.php Similarly, confirm that the array is in the return format (BcAddonMigrator converts it automatically, but just to be safe).
    • Initialization process: config/init.php is abolished.src/[PluginName]Plugin.php (class name: [PluginName]Plugin) and inheritBaserCore\BcPlugin .
      • $this->Plugin->initDb() is unnecessary (because migrations run automatically).
      • If there is any other initialization logic, migrate it to the install() や bootstrap() method.
      • Important: install The method signature must be public function install($options = []): bool and must return as its return value the result of parent::install($options) (or true).
    • Schema: Config/Schema is deprecated. Migrate to CakePHP Migrations (config/Migrations).
    • Feed: The feed plugin has been deprecated, so consider alternatives.

Enabling plugins (direct DB, standard)

Enabling the placed migration-target plugins is standardized as a direct INSERT into theplugins table. This allows the agent to run autonomously with zero browser round-trips, and verification is completed with SQL (for enabling via the admin screen, see the note as an alternative). ★Themes are not registered in the plugins table(proven by the absence of a row for the default theme BcFront in plugins immediately after a fresh install). Applying a theme only requires the sites.theme UPDATE in the next section "Applying themes (direct DB)".

  1. Pre-enable checks (per plugin): ls v5/plugins/<Name>/config/Migrations で Check for the presence of Migrations.
    • (a) Existing 5.x plugins usually have Migrations (table creation is required at enable time).
    • (b)BcAddonMigrator Conversion sets usually do not have Migrations (only the 4.x config/Schema remains).Check with unzip -l v5/tmp/baserbackup_*.zip | grep -iE "<table名>" whether the restore zip contains the schema + data, and if it does, the restore supplies the tables so Migrations generation is unnecessary (generate with bake migration_snapshot only when using a clean-install operation).
  2. plugins INSERT into the:
    INSERT INTO plugins (name, title, version, status, db_init, priority, created, modified)
    VALUES ('<Name>', '<Name>', '<version>', 1, 1,
            (SELECT p FROM (SELECT COALESCE(MAX(priority),0)+1 AS p FROM plugins) tmp), NOW(), NOW());
    
    When there are multiple entries, shift priority sequentially.
  3. Plugins with Migrations run migrations alongside(INSERT alone does not create tables):
    docker exec <container> bash -lc 'cd /var/www/html/v5 && bin/cake migrations migrate -p <Name>'
    
  4. Clear all caches: bin/cake cache clear_all(because the plugin load configuration changes).
  5. Verification is up to CLI startup smoke + SQL (do not check in the browser at this stage): SELECT name, status FROM plugins with status=1, for migration-executing sets confirm table creation with SHOW TABLES , and confirm thatbin/cake version returns the version number without fatal errors(= that the bootstrap of all enabled plugins passes).Browser checks of the front/admin screens are not required yet — since the internal code is still 4.x, it is normal for screens not to appear. Browser checks come after the operation verification step (standard flow 17). The admin screen is needed only for restore (flow 12), so just before that it is sufficient to check that admin login is alive.

★4.x remnants in boot paths that surface upon enabling (eliminate them first)

(b) When enabling a conversion set,4.x remnants that become fatal at app startup (bootstrap) before the screen appearsstart working (php -l runtime errors not caught by ). After enabling, bin/cake version they surface one by one in smoke tests, soonly the minimal fix (with TODO markers)and defer to flows 15-16 (full 5.x migration). Measured typical patterns:

Location Symptom Minimal fix
src/Event/*EventListener.php Class "<NS>\Event\ClassRegistry" not found(Because BcEvent instantiates listeners of enabled plugins at bootstrap, 4.x APIs in constructors die immediately) ClassRegistry::isKeySet/getObject Remove the branch and TableRegistry::getTableLocator()->get() unify to
config/setting.php Class "CakeLog" not found / Configure::load cannot get an array CakeLog::config() Remove executable statements such as (log configuration moves to Plugin::bootstrap in Phase 4).$config['X'] = [...] は return ['X' => [...]] へ
config/setting.php 4.x constants in Undefined constant "CACHE_DATA_PATH" etc. Replace with 5.x constants (TMP・CACHE etc.)
config/routes.php Router::connect Static calls,CakeRequest・BcSite::findByUrl で fatal Disable the entire file with return; and keep the old definitions as comments (rewrite to RouteBuilder format in Phase 4)

Smoke tests pass (bin/cake version returns the version) until cleared using this table. ★Note the limits of CLI smoke tests: bin/cake version differs partly from Web requests in the bootstrap path, andmay slip past fatals caused by BcEvent listener generation (e.g., immediate Table retrieval in the constructor → MissingTableClassException)(measured). Passing CLI smoke tests does not mean Web is fine too. Final confirmation on the Web side should be done with the admin screen GET integration test (step 17-b) or a real browser. It is safer to use lazy retrieval instead of immediate Table retrieval in listener constructors.

  • Rationale for why direct INSERT is safe: BcAddonMigrator The Plugin class generated by is empty (class XxxPlugin extends BcPlugin {}) and has no custom install processing, so the only difference from enabling via the admin screen is "whether migrations run automatically." That can be covered in step 3.Only for plugins that override their own install() , check the contentsand enable from the admin screen if necessary.
  • (Alternative) Enabling from the admin screen's plugin management runs migrations automatically. If the user can operate a browser, this is also fine.
  • config/plugins.php Direct editing of is not allowed (a crash cause, as noted earlier).
  • Enabling all targets in this step is "to import tables and data via restore"(premise of flow 12). Once restore is complete, at the start of the operation check step (flow 17),temporarily disable all migration targetsand proceed while enabling only the check target + its dependencies one by one (to isolate event interference). Disabling/re-enabling can be done with UPDATE plugins SET status=0(/1) WHERE name='<Name>'+bin/cake cache clear_all (safe because tables and data remain).

Theme application (direct DB)

In the 5 series, themes are site_configs not sites in the theme column of thetable. Application is also standardized as direct DB update.

-- サイトごとに適用(マルチサイトは site 単位で theme を持つ。全サイト同一テーマなら WHERE 句なし)
UPDATE sites SET theme = '<CamelCaseTheme>' WHERE id = 1;
  • After applying, always bin/cake cache clear_all(because theme resolution is cached).
  • For verification,actual browseropen the front end in and confirm that the theme's templates are being used (that it is not a 500). If an error occurs due to leftover 4-series remnants in the theme-side templates, record it in the ledger at this point and handle it in step 15 (cross-theme check).

Conversion of plugin internal code (separate skill)

BcAddonMigrator after conversion with Specific rewriting of plugin internal code(Controller の $this->Model→fetchTable、Table の initialize() association declarations,find() query builder conversion, Entity/getControlSource, View/Helper, search form/edit form BcAdminForm/control() conversion,Time::format の ICU、Number::format/Text::truncate null handling, Vue/JS $.bcUtil.adminBaseUrl conversion and webpack rebuild, symptom-specific handling of front-end display errors, etc.) are cataloged in the dedicated skill basercms-plugin-4-to-5-upgrade . When moving through the plugin screens one by one, refer to that (C-0 mechanical bulk conversion catalog / T- Table/ORM / C- Controller/screen / F- among front-end display errors, the plugin-context portion).The migration patterns for themes (mainly templates) (TH- series + template/theme rendering F- series) are split into the basercms-theme-4-to-5-upgrade skill. For the authoritative source of the correct 5-series way to write the conversion target, refer to basercms5-plugin-development(plugin) / basercms5-theme-development(theme).

How to proceed with migration (unit tests first → screen integration per domain)

BcAddonMigrator The process of manually converting the plugin internal code after conversion to the 5 series proceeds faster and more safely with the following workflow (proven).The goal is to create a state in which any baserCMS 4-series project can be migrated to the 5 series with minimal effort。

Why this order: In migration, there are many cases where "the screen display works, but the save/aggregation/output logic is quietly broken" (prorated calculations, aggregation return value shapes, filter conditions, columns that do not exist in production, etc., whose correctness cannot be judged visually). On the other hand,the user's biggest effort is repeated reloads during screen testing. Tests can be run autonomously by AI and require no human labor. Therefore, solidify correctness with tests, then do screen integration all at once requires the least effort.

  1. Phase 1: Migrate logic test-driven(Almost no manual work required). Refactor the Table/persistence/aggregation/output logic for the target domain (quotes/invoices/sales/aggregation, etc.) into the 5.x style with TDD while organizing responsibilities. Use a Factory + unit tests to numerically lock in "same values as the 4.x style" (RED→GREEN, with regression automatically guaranteed). → The test foundation is basercms-unittest, and the conversion patterns are basercms-plugin-4-to-5-upgrade(T-/C-/F-)。
  2. Phase 2: Thin glue layer. Keep controllers thin: "receive → call Table/Service → set", and move logic into the tested Table/Service. Minimize the surface area that must be checked on screen (glue that cannot be tested).
  3. Phase 3: One screen integration pass per domain. After all logic is green, verify the integration of templates/JS, Vue/transitions, CSV/Excel, and notifications in a single screen session. Prepare a checklist in advance of "which screen, what operation, what expected result", and have the user go through it one round trip at a time in order (consolidate reloads not "per method" but "per domain").
  4. Phase 4: Feedback into skills. For each paragraph, reflect reusable knowledge into the relevant skill (plugin internal code → basercms-plugin-4-to-5-upgrade, tests → basercms-unittest, site procedures → this skill, 5.x common rules → basercms5-development, 5.x implementation patterns → basercms5-plugin-development / basercms5-theme-development). Leave behind the symptom → cause → fix, code fragments, and cautions.

Integration timing is per domain(finalize quotes → check the quote screen once → next, invoices...). Problems can be found while fresh, and rework is smaller.

Operating long sessions (countermeasures for context bloat, frequent /compact)

The 4→5 migration tends to make a single sessionlonger than a normal task(many steps: environment setup → DB migration → inventory → conversion → 5.x-ification per domain...). If a session drags on,context bloat can cause the assistant's tool calls to start breaking(symptoms: <invoke>/<parameter> missing namespace prefixes, or an unrelated word at the beginning—e.g., "court"—sneaking in and causing command/tool calls to fail. This is not an environment or shell defect, but a breakdown in the assistant's output format).

  • Countermeasure: If this kind of failure continues several times, do not stubbornly retry,promptly /compact compress the context with /compactand then continue (the key points are carried over into the summary, so work can continue). You may also proactively /compact at work boundaries (such as when each phase is completed).
  • Prevention: Do not let large intermediate artifacts (plans, ledgers, investigation logs) accumulate in the conversation; write them out to spec/plan files or a scratchpad so they are easy to reference after compact and bloat is kept down.

Git / repository operations (version control for migration code)

The 4.x plugin BcAddonMigrator after converting with and placing it in v5, this is a classic pitfall when importing into git. G-2 through G-4 apply to any project. G-1 applies only to projects that used git submodules in the 4.x series(most projects do not use submodules, so it does not apply).

G-1. [Only when using submodules] Remove the 4.x submodule .git(gitlink) remaining in the converted plugin

* This item applies only to projects that managed plugins in the 4.x series as git submodules (registered in.gitmodules ). If you are not using submodules, .git will not come along, so it is irrelevant (iffind v5 -name .git is 0 entries, it does not apply).

When you copy a plugin that was a git submodule in the 4.x series (app/Plugin/<X>),.git(the gitlink file) comes along too. This still points to gitdir: ../../../.git/modules/app/Plugin/<X>(= the 4.x main body's submodule storage), causing contradictions such as "two working trees tied to the same git module" and "the converted 5.x code is entirely different from the 4.x HEAD".

  • Remedy: find v5 -name .git -type f -delete delete the gitlink files under v5 with (does not touch the actual code,.gitignore, the 4.x actual submodules/.git/modules/.gitmodules = safe). This makes the converted plugin a "normal directory".

G-2. Ignore baserCMS5 standard .gitignore は /plugins/* → make custom plugins a negation

Ignore the v5-bundled .gitignore は /plugins/* and track only the core/samples (!/plugins/baser-core, !/plugins/bc-*, !/plugins/BcColumn etc.) via negation.As is, the converted custom plugins become untracked.

  • Remedy: add the custom plugin as a negation like !/plugins/Sample (confirm withgit check-ignore v5/plugins/Sample being empty = trackable)./plugins/*/vendor・/plugins/*/node_modules・/plugins/*/composer.lock・schema-dump-default.lock remains ignored.

G-3. Do not include upload entities webroot/files/* in git

Ignore the v5 standard .gitignore は /webroot/files/* (the correct default). If you put uploads migrated from the 4.x series (this project: 1.7GB / over 10,000 files) into git, the repo can bloat, clones can be slow, and pushes may become impossible due to GitHub limits.Keep them excluded, and operate by backing up / recopying the entities separately (preserve empty directories with!/webroot/files/.gitkeep ).git add -n v5 | wc -l It is a good idea to check in advance for huge items with etc.

G-4. v5 nesting/import

git add v5 when nesting, the nested v5/.gitignore still takes effect in the parent repository as well (secret config/.env・app_local.php・vendor・tmp・logs is automatically excluded).git add -nAlways verify the staging plan with (dry-run) before committing. Even if you later want to make the plugin a "reusable independent repository", it is easier to first import it into the parent as normal files, and after it stabilizes, do a phased migration by extracting it with git subtree split .

Notes

  • When proposing code, always CakePHP 5.0 official documentation and baserCMS 5 source code (vendor/baserproject/ and below) for consistency.
  • Do not leave behind CakePHP 2 code that "probably works".
  • [Important] When executing terminal commands, do not run them in the background (& by appending it at the end, or setting the tool's WaitMsBeforeAsync to a short value and leaving it, etc.). Processing may stall and subsequent operations may not be accepted. Always complete them synchronously.