Moving from 1x to 2 0
title: Moving from 1.x to 2.0 description: What 2.0.0 changed for 1.x installations: table prefixes, one collation, merged forum tables, removed classes and the upgrade steps.
2.0.0 (16 September 2026) is a major release because it renames tables and removes classes: a third-party module that names either stops working until it is updated.
The schema migration is not reversible. It renames 31 tables, folds four into two and converts every table's collation; undoing the merges would mean inventing votes nobody cast. Rolling back means restoring the backup.
The upgrade runs the migration for you. It took about 1.5 seconds against a 2,100-row database; a site with a large forum should expect the collation pass to take proportionally longer.
One prefix, everywhere
Nine core tables predated the cp_ convention (users, nodes, assets, menus, menu_items, node_field_index, url_aliases, node_category, node_tag) and modules used whatever prefix their author picked. The rule is now: core tables are cp_<noun>, module tables are cp_<module>_<noun>. So users is cp_users and forum_posts is cp_forum_posts. doctrine_migration_versions and messenger_messages keep their names because Doctrine and Symfony Messenger hardcode them.
One collation
The database carried three collations; joining a varchar across them raises Illegal mix of collations. Everything is now utf8mb4_unicode_ci, already used by 56 of the 66 tables and accepted by MySQL 8 and MariaDB 11.
Likes and dislikes are one table
forum_post_likes and forum_post_dislikes become cp_forum_post_votes, with the verdict stored as +1 or -1. UNIQUE(post_id, user_id) makes it impossible for a member to hold both a like and a dislike on one post, which two concurrent requests could previously produce. Existing votes are carried over; a member who held both keeps the last one cast.
Thread read state and watches are one row
forum_topic_views and forum_topic_watches become cp_forum_topic_user_state, with last_seen_at and watching_since as two nullable columns. Unwatching clears a column instead of deleting a row, so it no longer loses where you had read up to.
Removed classes
Modules\Forum\Entity\ForumPostLikeandForumPostDislike: useForumPostVotewithForumPostVote::LIKE/::DISLIKE.Modules\Forum\Entity\ForumTopicViewandForumTopicWatch: useForumTopicUserState.ForumPostLikeRepository,ForumPostDislikeRepository,ForumTopicViewRepository,ForumTopicWatchRepository: useForumPostVoteRepositoryandForumTopicUserStateRepository.
The domain events ForumPostLikedEvent and ForumPostDislikedEvent are unchanged.
Upgrade steps
- Take a database backup.
- Apply the update from AACP → Updates. Migrations run first, then update hooks, then the cache rebuild.
- If you apply by FTP on shared hosting, empty
cp-core/var/cache/prod/afterwards and clear the Doctrine cache pools. From the update that lands this release onwards, the updater does it itself. - Check any module you did not get from us for the removed classes.
Fixes that came with it
Doctrine's query cache is cleared after an update; module schema files are back in the repository (Whitepaper's tables could not be created from a clean clone); the forum presence table no longer breaks a fresh module install; a post-auth SSRF in the performance probe is closed by pinning the scheme to HTTP and HTTPS; and a path sanitiser that could manufacture the traversal it removed was fixed.
Known limit
doctrine:schema:validate still reports 81 lines of drift on an upgraded database, none introduced here: MariaDB representing JSON columns as longtext, hand-named indexes, and three tables driven by raw SQL with no entity.