Skip to content

feat: design-first magic_example (full-set app + DESIGN.md + /preview catalog + agent infra) - #1

Merged
anilcancakir merged 13 commits into
mainfrom
feat/design-first-component-system
Jul 25, 2026
Merged

anilcancakir merged 13 commits into
mainfrom
feat/design-first-component-system

Conversation

@anilcancakir

Copy link
Copy Markdown
Member

Brings up the design-first magic_example reference app: the full fluttersdk set (magic, magic_starter, dusk, telescope, magic_deeplink, magic_notifications, magic_social_auth) on fluttersdk_artisan, a Laravel api/v1 backend under backend/, a DESIGN.md-driven wind theme (design:sync -> lib/config/wind_theme.g.dart), a dev-only /preview component catalog (foundations + component library + feature-screen previews via a backend-free mock harness, tree-shaken from release), and the design-first agent infra (CLAUDE.md + AGENTS.md + .claude/rules + skills + component-visual-reviewer + docs/design-culture + component-registry).

Verified locally end to end: flutter analyze 0; the app boots and renders login/dashboard/profile + the catalog in light and dark (real-browser e2e); the real backend api/v1/auth/login returns a Sanctum token; release builds strip the catalog.

Cross-repo: consumes the sibling feat/design-first-component-system PRs (wind #120, magic #102, magic_devtools #7, magic_starter #78) via local path overrides; land those first.

… catalog + agent infra)

Ready-to-start reference app for the fluttersdk ecosystem:
- Full set installed: magic, magic_starter, dusk, telescope, magic_deeplink,
  magic_notifications, magic_social_auth, on fluttersdk_artisan; a Laravel
  api/v1 backend (magic-starter-laravel) under backend/.
- DESIGN.md is the single source of truth; design:sync generates the wind
  theme (lib/config/wind_theme.g.dart), consumed in main.dart.
- Dev-only /preview catalog (magic_devtools) listing foundations, the
  component library, and feature-screen previews driven by a backend-free
  mock harness; stripped from release builds.
- Design-first agent infra: CLAUDE.md + AGENTS.md + .claude/rules + 3 skills
  + a component-visual-reviewer agent + docs/design-culture + component-registry.

Verified locally end to end: flutter analyze 0, the app boots and renders
(login/dashboard/profile + the catalog) in light and dark, the real backend
api/v1/auth/login returns a Sanctum token, and release builds tree-shake the
catalog.
Copilot AI review requested due to automatic review settings June 25, 2026 22:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Brings up a design-first magic_example reference application, including Flutter multi-platform runner scaffolding, a dev-only /preview component catalog with mock harness, DESIGN.md-driven Wind theme generation, and a Laravel backend/ skeleton intended to support api/v1 and Magic Starter features.

Changes:

  • Adds platform runner scaffolding for Android/iOS/macOS/Linux/Windows/Web, plus basic smoke tests.
  • Introduces Magic app bootstrapping/config (providers, routes, middleware) and a debug-only preview catalog with generated registry.
  • Adds a Laravel backend skeleton with Magic Starter-oriented models, policies, and migrations, plus frontend build tooling (Vite/Tailwind).

Reviewed changes

Copilot reviewed 230 out of 277 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
windows/runner/win32_window.h Adds Win32 window abstraction header
windows/runner/utils.h Declares Windows runner utilities
windows/runner/utils.cpp Implements console + argv UTF conversion
windows/runner/Runner.rc Adds Windows resources/version/icon
windows/runner/runner.exe.manifest Enables PerMonitorV2 DPI awareness
windows/runner/resource.h Defines Windows resource IDs
windows/runner/main.cpp Windows runner entrypoint wiring
windows/runner/flutter_window.h Declares Flutter-hosting Win32 window
windows/runner/flutter_window.cpp Implements Flutter window lifecycle
windows/runner/CMakeLists.txt Windows runner build target setup
windows/flutter/generated_plugins.cmake Generated Windows plugin wiring
windows/flutter/generated_plugin_registrant.h Generated Windows plugin registrant header
windows/flutter/generated_plugin_registrant.cc Generated Windows plugin registrant impl
windows/flutter/CMakeLists.txt Flutter Windows build integration
windows/CMakeLists.txt Windows top-level CMake wiring/install
windows/.gitignore Ignores Windows ephemeral/build artifacts
web/manifest.json Web app manifest for Flutter web
web/index.html Web host page for Flutter web
test/widget_test.dart Adds Flutter widget smoke test
macos/RunnerTests/RunnerTests.swift Adds macOS test target stub
macos/Runner/Release.entitlements macOS release entitlements
macos/Runner/MainFlutterWindow.swift macOS window bootstrapping
macos/Runner/Info.plist macOS app plist metadata
macos/Runner/DebugProfile.entitlements macOS debug entitlements
macos/Runner/Configs/Warnings.xcconfig macOS warning flags config
macos/Runner/Configs/Release.xcconfig macOS release xcconfig includes
macos/Runner/Configs/Debug.xcconfig macOS debug xcconfig includes
macos/Runner/Configs/AppInfo.xcconfig macOS app name/bundle id config
macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json macOS app icon asset catalog
macos/Runner/AppDelegate.swift macOS app delegate behaviors
macos/Runner.xcworkspace/xcshareddata/swiftpm/Package.resolved macOS SPM lockfile
macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist macOS workspace checks
macos/Runner.xcworkspace/contents.xcworkspacedata macOS workspace definition
macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme macOS scheme configuration
macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved macOS project workspace SPM lockfile
macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist macOS project workspace checks
macos/Flutter/GeneratedPluginRegistrant.swift Generated macOS plugin registrant
macos/Flutter/Flutter-Release.xcconfig macOS Flutter release include
macos/Flutter/Flutter-Debug.xcconfig macOS Flutter debug include
macos/.gitignore Ignores macOS ephemeral/Pods/user data
linux/runner/my_application.h Linux GTK runner application header
linux/runner/main.cc Linux runner main entrypoint
linux/runner/CMakeLists.txt Linux runner build wiring
linux/flutter/generated_plugins.cmake Generated Linux plugin wiring
linux/flutter/generated_plugin_registrant.h Generated Linux plugin registrant header
linux/flutter/generated_plugin_registrant.cc Generated Linux plugin registrant impl
linux/flutter/CMakeLists.txt Flutter Linux build integration
linux/.gitignore Ignores Linux ephemeral artifacts
lib/routes/app.dart Registers app routes (dashboard)
lib/preview/teams_screen.preview.dart Adds teams screen preview wrapper
lib/preview/settings_screen.preview.dart Adds settings screen preview wrapper
lib/preview/screen_preview_scaffold.dart Adds shared preview scaffold/harness mounting
lib/preview/register_screen.preview.dart Adds register screen preview wrapper
lib/preview/profile_screen.preview.dart Adds profile screen preview wrapper
lib/preview/login_screen.preview.dart Adds login screen preview wrapper
lib/preview/dashboard_screen.preview.dart Adds dashboard screen preview wrapper
lib/preview/_previews.g.dart Generated preview registry list
lib/main.dart Boots Magic app + devtool integrations + theme
lib/config/wind_theme.g.dart Generated Wind theme + aliases from DESIGN.md
lib/config/view.dart UI config for dialogs/confirms
lib/config/routing.dart Routing/url strategy config
lib/config/network.dart HTTP/network driver config
lib/config/magic_starter.dart Magic Starter feature/routes toggles
lib/config/logging.dart Logging channel configuration
lib/config/deeplink.dart Deeplink configuration
lib/config/database.dart Database connection configuration
lib/config/cache.dart Cache driver/ttl configuration
lib/config/broadcasting.dart Broadcasting connections configuration
lib/config/auth.dart Auth guard/token/endpoint config
lib/config/app.dart App providers + plugin service providers
lib/app/providers/route_service_provider.dart Boots kernel/routes + debug preview routes
lib/app/providers/app_service_provider.dart Boots Magic Starter user/nav/logout/team hooks
lib/app/middleware/redirect_if_authenticated.dart Guest-only redirect middleware
lib/app/middleware/ensure_authenticated.dart Auth-only redirect middleware
lib/app/kernel.dart Registers middleware aliases
lib/app/commands/_index.g.dart Generated artisan consumer command barrel
lib/app/_plugins.g.dart Generated artisan plugin provider registry
ios/RunnerTests/RunnerTests.swift Adds iOS test target stub
ios/Runner/SceneDelegate.swift iOS scene delegate scaffold
ios/Runner/Runner-Bridging-Header.h iOS bridging header
ios/Runner/Info.plist iOS app plist metadata
ios/Runner/Base.lproj/Main.storyboard iOS main storyboard
ios/Runner/Base.lproj/LaunchScreen.storyboard iOS launch screen storyboard
ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md iOS launch assets readme
ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json iOS launch image assets manifest
ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json iOS app icon asset catalog
ios/Runner/AppDelegate.swift iOS app delegate + implicit engine plugins
ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings iOS workspace settings
ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist iOS workspace checks
ios/Runner.xcworkspace/contents.xcworkspacedata iOS workspace definition
ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme iOS scheme configuration
ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings iOS project workspace settings
ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist iOS project workspace checks
ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata iOS project workspace definition
ios/Flutter/Release.xcconfig iOS Flutter release include
ios/Flutter/Debug.xcconfig iOS Flutter debug include
ios/Flutter/AppFrameworkInfo.plist iOS Flutter framework plist
ios/.gitignore Ignores iOS derived/Pods/ephemeral assets
CLAUDE.md Repo agent/dev workflow + design-first rules
bin/fsa Fast CLI wrapper/build cache for dispatcher
bin/dispatcher.dart Artisan dispatcher wiring for plugins/commands
backend/vite.config.js Vite config with Laravel + Tailwind
backend/tests/Unit/ExampleTest.php Laravel unit test stub
backend/tests/TestCase.php Laravel base test case
backend/tests/Feature/ExampleTest.php Laravel feature test stub
backend/storage/logs/.gitignore Storage ignore rules
backend/storage/framework/views/.gitignore Storage ignore rules
backend/storage/framework/testing/.gitignore Storage ignore rules
backend/storage/framework/sessions/.gitignore Storage ignore rules
backend/storage/framework/cache/data/.gitignore Storage ignore rules
backend/storage/framework/cache/.gitignore Storage ignore rules
backend/storage/framework/.gitignore Storage ignore rules
backend/storage/app/public/.gitignore Storage ignore rules
backend/storage/app/private/.gitignore Storage ignore rules
backend/storage/app/.gitignore Storage ignore rules
backend/routes/web.php Laravel web route (welcome)
backend/routes/console.php Laravel console route stub
backend/resources/js/app.js Laravel frontend JS entry stub
backend/resources/css/app.css Tailwind CSS entry + theme font
backend/README.md Laravel skeleton README
backend/public/robots.txt Robots policy
backend/public/index.php Laravel front controller
backend/public/favicon.ico Backend favicon asset
backend/public/.htaccess Apache rewrite rules
backend/phpunit.xml PHPUnit config for backend
backend/package.json Backend JS deps/scripts
backend/lang/vendor/magic-starter/tr/teams.php TR translation strings for teams
backend/lang/vendor/magic-starter/en/teams.php EN translation strings for teams
backend/database/seeders/DatabaseSeeder.php Seeds a test user
backend/database/migrations/2026_06_24_200110_drop_language_column_from_users_table.php Drops users.language if present
backend/database/migrations/2026_06_24_200100_add_two_factor_columns_to_users_table.php Adds 2FA columns to user model table
backend/database/migrations/2026_06_24_200090_add_timezone_to_users_table.php Adds users.timezone if missing
backend/database/migrations/2026_06_24_200080_add_profile_photo_path_to_users_table.php Adds users.profile_photo_path
backend/database/migrations/2026_06_24_200070_add_profile_photo_path_to_teams_table.php Adds teams.profile_photo_path
backend/database/migrations/2026_06_24_200060_add_profile_fields_to_users_table.php Adds users.phone
backend/database/migrations/2026_06_24_200050_add_localization_fields_to_users_table.php Adds users.locale/timezone
backend/database/migrations/2026_06_24_200040_add_guest_and_phone_fields_to_users_table.php Adds guest/phone fields + alters columns
backend/database/migrations/2026_06_24_200030_add_expires_at_to_team_invitations_table.php Adds team_invitations.expires_at
backend/database/migrations/2026_06_24_200020_add_device_info_to_personal_access_tokens_table.php Adds token ip/user_agent columns
backend/database/migrations/2026_06_24_200010_add_current_team_id_to_users_table.php Adds users.current_team_id FK
backend/database/migrations/2026_06_24_100070_create_newsletter_subscribers_table.php Creates newsletter_subscribers table
backend/database/migrations/2026_06_24_100060_create_notification_settings_table.php Creates notification_settings table
backend/database/migrations/2026_06_24_100050_create_notifications_table.php Creates notifications table
backend/database/migrations/2026_06_24_100040_create_personal_access_tokens_table.php Creates personal_access_tokens table
backend/database/migrations/2026_06_24_100030_create_team_invitations_table.php Creates team_invitations table
backend/database/migrations/2026_06_24_100020_create_team_user_table.php Creates team_user pivot table
backend/database/migrations/2026_06_24_100010_create_teams_table.php Creates teams table
backend/database/migrations/0001_01_01_000002_create_jobs_table.php Creates jobs/batches/failed_jobs
backend/database/migrations/0001_01_01_000001_create_cache_table.php Creates cache/cache_locks tables
backend/database/migrations/0001_01_01_000000_create_users_table.php Creates users/sessions/password_reset tables
backend/database/factories/UserFactory.php User factory definition
backend/database/.gitignore Ignores sqlite db files
backend/config/services.php Third-party service placeholders
backend/config/queue.php Queue connection configuration
backend/config/mail.php Mailers configuration
backend/config/logging.php Backend logging channels config
backend/config/filesystems.php Storage disks and links
backend/config/cache.php Cache stores configuration
backend/config/auth.php Auth providers/guards configuration
backend/config/app.php Backend app core config
backend/composer.json Backend PHP deps (Laravel + magic starter)
backend/bootstrap/providers.php Bootstrap provider list
backend/bootstrap/cache/.gitignore Bootstrap cache ignore rules
backend/bootstrap/app.php Laravel app bootstrap configuration
backend/artisan Laravel artisan entrypoint
backend/app/Providers/AppServiceProvider.php Backend service provider scaffold
backend/app/Policies/TeamPolicy.php Team authorization policy stub
backend/app/Models/User.php User model with Magic Starter traits
backend/app/Models/TeamUser.php TeamUser model passthrough
backend/app/Models/TeamInvitation.php TeamInvitation model passthrough
backend/app/Models/Team.php Team model passthrough + fillable
backend/app/Http/Controllers/Controller.php Backend controller base class
backend/app/Actions/MagicStarter/UpdateUserProfile.php Stub action for profile updates
backend/app/Actions/MagicStarter/UpdateUserPassword.php Stub action for password updates
backend/app/Actions/MagicStarter/UpdateTeamMemberRole.php Stub action for team role updates
backend/app/Actions/MagicStarter/UpdateTeam.php Stub action for team updates
backend/app/Actions/MagicStarter/RemoveTeamMember.php Stub action for removing members
backend/app/Actions/MagicStarter/InviteTeamMember.php Stub action for invitations
backend/app/Actions/MagicStarter/DeleteUser.php Stub action for deleting users
backend/app/Actions/MagicStarter/DeleteTeam.php Stub action for deleting teams
backend/app/Actions/MagicStarter/CreateUser.php Stub action for creating users
backend/app/Actions/MagicStarter/CreateTeam.php Stub action for creating teams
backend/app/Actions/MagicStarter/AddTeamMember.php Stub action for adding members
backend/.npmrc Backend npm safety defaults
backend/.gitignore Backend ignore rules
backend/.gitattributes Backend attributes (diff drivers/export-ignore)
backend/.env.example Backend environment example
backend/.editorconfig Backend editor config
android/settings.gradle.kts Android Gradle settings/plugin management
android/gradle/wrapper/gradle-wrapper.properties Gradle wrapper version pin
android/gradle.properties Android/Gradle flags
android/build.gradle.kts Android root build logic
android/app/src/profile/AndroidManifest.xml Profile manifest permissions
android/app/src/main/res/values/styles.xml Android light launch theme
android/app/src/main/res/values-night/styles.xml Android dark launch theme
android/app/src/main/res/drawable/launch_background.xml Android splash background
android/app/src/main/res/drawable-v21/launch_background.xml Android v21 splash background
android/app/src/main/kotlin/com/fluttersdk/magic_example/MainActivity.kt Android MainActivity
android/app/src/main/AndroidManifest.xml Android app manifest
android/app/src/debug/AndroidManifest.xml Debug manifest permissions
android/app/build.gradle.kts Android app module build config
android/.gitignore Android ignore rules
analysis_options.yaml Dart analyzer/lints configuration
AGENTS.md Agent workflow + design-first rules
.metadata Flutter project metadata
.env.example App env example (API_URL etc.)
Files not reviewed (3)
  • ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: Generated file
  • ios/Runner.xcworkspace/contents.xcworkspacedata: Generated file
  • macos/Runner.xcworkspace/contents.xcworkspacedata: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread windows/runner/utils.cpp
Comment on lines +13 to +18
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
_dup2(_fileno(stdout), 1);
}
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
_dup2(_fileno(stdout), 2);
}
Comment on lines +64 to +68
switch (message) {
case WM_FONTCHANGE:
flutter_controller_->engine()->ReloadSystemFonts();
break;
}
Comment thread lib/main.dart Outdated
Comment on lines +53 to +54
// Theme generated from DESIGN.md via `design:sync`. Regenerate with:
// dart run magic_example:artisan design:sync
Comment thread lib/config/view.dart
Comment on lines +8 to +10
'dialog': {
'class': 'bg-white dark:bg-gray-800 rounded-xl p-6 shadow-2xl max-w-lg',
},
Comment thread lib/config/view.dart
Comment on lines +11 to +19
'confirm': {
'container_class':
'bg-white dark:bg-gray-800 rounded-xl p-6 shadow-2xl w-80',
'title_class': 'text-lg font-bold text-gray-900 dark:text-white',
'message_class': 'text-gray-600 dark:text-gray-400 mt-2',
'button_cancel_class': 'px-4 py-2 text-gray-600 dark:text-gray-300',
'button_confirm_class': 'px-4 py-2 bg-primary text-white rounded-lg',
'button_danger_class': 'px-4 py-2 bg-red-500 text-white rounded-lg',
},
Comment on lines +1 to +4
// GENERATED: do not edit by hand.
// Regenerate via: dart run magic:artisan design:sync
//
// Source of truth: DESIGN.md
Comment on lines +15 to +18
Schema::table('users', function (Blueprint $table) {
$table->string('email')->nullable()->change();
$table->string('password')->nullable()->change();

…flow

ComponentsPreview is now stateful so the switch, tabs, and select are
live (toggle/select to see real behavior). Variant rows use Wind's
`wrap` utility instead of the no-op `flex-wrap` so they reflow rather
than overflow. The feature-screen scaffold drops its phone-frame
MediaQuery override so screens render at their real size in the
single-pane catalog.
The app shell picks sidebar-vs-bottom-nav off the window width
(wScreenIs reads MediaQuery.size), so the two layouts never show at the
same time and the bottom nav was invisible at the catalog's desktop
width. Add two dedicated previews that pin each layout by overriding the
ambient MediaQuery width: SidebarMenu (desktop rail + user menu, full
width) and BottomMenu (mobile header + bottom bar, in a phone frame).
ScreenPreviewScaffold gains appDesktop/appMobile chrome modes; feature
screens stay bare content. Also flex-1 the dashboard card title so it
fits/wraps instead of overflowing (yellow stripe) in the narrow shell.
…ign parity)

Match the idea-design catalog's one-component-per-preview model: split the
lumped components.preview.dart into dedicated Badge/Button/Card/Input/
Select/Switch/Tabs preview files, each its own auto-discovered section.
With the catalog now a single scrolling page, bare screen previews
(chrome: none) no longer wrap their own SingleChildScrollView (a nested
vertical scroll broke the outer scroll geometry and sidebar
scroll-to-section); the catalog page provides the scroll.
SidebarMenu/BottomMenu previews showcase the navigation shell, so their
body is now an empty placeholder card instead of the full DashboardView.
The dashboard's 3-column cards crammed into the narrow content area beside
the sidebar and broke titles mid-word ("Docum entatio n"); a neutral
"Page content" card keeps the focus on the nav chrome.
…talog

Register magic_starter's 30 component previews via its dev-only
previews.dart barrel (User Profile Dropdown, Team Selector, Notification
Dropdown, Accordion, Checkbox, Radio, Dialog, Toast, etc.), merged with
the app-owned previews (foundations, screens, nav shells) and sorted by
label. The 7 hand-written component preview duplicates are removed; the
catalog now mirrors the whole library with no duplication. Registration
stays kDebugMode-gated so the starter preview set tree-shakes from
release.
Without registerMagicStarterNotificationRoutes() the /settings notification
preferences route was never registered, so the hub's Notification Preferences
row navigated nowhere.
Introduce lib/ui/components/ as the app-owned component library (folder-per-component: component + recipe + preview + index, discovered by /preview scanning *.preview.dart, no barrel, no re-export aliases). Ship three example components magic_starter does not provide, demonstrating the recipe patterns: Tag (multi-axis WindRecipe intent x size), Callout (single-axis WindRecipe intent), StatCard (static slot classNames). Add pure recipe unit tests.
previews:refresh regenerates lib/_previews.g.dart, but the route provider still imported the stale lib/preview/_previews.g.dart, so newly scaffolded components never reached the catalog. Repoint the import and remove the stale file.
Replace the separate DuskPlugin / TelescopePlugin installs with MagicDevtools.installPre/installPost, add MagicStarter.useWindTheme(windTheme), and fix the stale design:sync command comment.
magic_starter renamed its flat components to MS-prefixed classes; update Card -> MSCard and Typography -> MSTypography (variant enums CardVariant/TypographyVariant unchanged) so the views and foundations preview compile again.
Update the design rule, three skills, the visual-reviewer agent, CLAUDE.md, DESIGN.md, and the component registry from the old magic_starter/lib/src/ui/components target to the app-local lib/ui/components/; add the no-re-export-alias discipline and the hand-authored status-token supplement pattern (generic example).
@anilcancakir
anilcancakir merged commit 334e3a2 into main Jul 25, 2026
@anilcancakir
anilcancakir deleted the feat/design-first-component-system branch July 25, 2026 19:19
anilcancakir added a commit that referenced this pull request Sep 13, 2026
…e command (#13)

* Bump the magic ecosystem past the constraint that silently capped it

magic_starter alpha.26 needs magic_notifications ^0.2.0, and this app pinned
^0.0.2, which means >=0.0.2 <0.1.0. The two do not intersect, so pub quietly
walked the starter back to alpha.24 instead of failing: a fork got a build that
resolved, ran, and was two releases stale. The two constraints move together or
not at all.

alpha.24 also introduced 20 magic_starter.titles.* keys that en.json never
gained, and route_service_provider.dart:29 registers the notification routes
ungated, so those titles have been rendering as raw keys.

The two generated files come along because they are functions of the resolved
graph rather than edits: flutter pub get performs a one-time SDK migration on
analysis_options.yaml, and the macOS registrant gains purchases_flutter now that
magic_payments arrives through the starter. The registrant records the LOCAL
graph, which is what keeps the working tree clean. Unlike pubspec.lock, no fork
ever consumes this file: any build regenerates it from whatever that fork
resolves, so the committed value is transient for them and permanent dirt here
would be the only lasting cost.

* Wire the two plugins that were registered but never configured

config/app.dart registers LocalizationServiceProvider and
NotificationServiceProvider, but neither had a config file and neither appeared
in main.dart's factory list, so both fell through to package defaults. The
notifications feature flag was off besides, which meant a dependency this app
pays for shipped undemonstrated.

supported_locales already claimed en and tr while assets/lang held only en.json.
That claim is now true. The parity between the two files is exact rather than
best effort because magic's Translator replaces its sentence map on load instead
of merging it with the fallback: a key missing from tr.json renders the raw key
path on screen, not the English string. locale_parity_test.dart is what keeps
that from drifting back.

auto_detect_locale stays off. A device set to a locale this boilerplate does not
ship has no tested path here, and the replace-not-merge behaviour above is
exactly what turns that into raw keys on every screen. A fork flips it once its
supported_locales covers the locales its users actually have.

* Close the guardrail gaps a fork would inherit

Four independent things, all of which were wrong or missing today.

CI gains a published job. Resolving is not the check: pub exits 0 on a
downgrade as long as SOME version in range resolves, which is exactly how the
alpha.24 walk-back stayed green. The job reads the resolved version out of the
lock and asserts it, verified against a synthetic alpha.24 lock to confirm it
fails on the input it exists to catch.

The component-visual-reviewer agent pointed at /Users/anilcan/Code/fluttersdk/
lib/ui/components, missing this repo's own directory segment. That path does not
exist, so every find and grep in its procedure returned nothing and reported a
clean review. It was also the only absolute path in a repository whose whole
purpose is to be cloned somewhere else.

design.md described components as living in the magic_starter generic library on
one line and scoped the WindRecipe import rule to magic_starter files on another.
Both meant this app's own lib/ui/components/. The import rule itself was right
and is unchanged.

design-tokens rescanned raw on one trigger, an unterminated block comment at end
of file. That catches the OPEN case, which flutter analyze already makes
impossible in real Dart. The CLOSED case is the live one: a /* inside a
triple-quoted string that some later ordinary */ closes leaves the scanner
balanced at EOF, so nothing fires and the region between them is dropped in
silence. Measured against the pre-edit script, a raw literal placed that way
passed clean.

* Track the lock a fork should build from, and gate what gets committed

The lock was gitignored because one generated with pubspec_overrides.yaml
active encodes sibling paths that exist on one machine. That diagnosis was
right and the conclusion was not: the fix for a lock generated the wrong way is
to generate it the right way. Untracked, a fork's first build resolves whatever
the caret ranges happen to solve to on the day it clones, which is not what CI
proved green.

run_lockfile is what makes tracking safe. It reads the STAGED lock, not the
working tree, and fails on a source: path entry. That split is deliberate and
permanent: a local pub get puts sibling paths back in the lock every time, so
the working copy stays dirty and unstaged while the index holds the hosted
resolution. require_local_siblings reads the opposite state (the overrides file
must be PRESENT), and the two cannot wedge because regenerating hosted-only
moves that file aside and back rather than removing it.

Verified by staging the real local-path lock, 11 path entries, and confirming
the job fails with every other job green. An earlier probe that appended a
malformed line proved nothing: pub refused to parse it and the run aborted
before the gate executed.

* Reduce the fork checklist to one command, and demonstrate the patterns

app:rename rewrites 24 sites plus the Kotlin package directory: the Dart
package name and its import sites, the Android namespace and applicationId, the
iOS and macOS bundle identifiers, the three desktop build systems, the web
manifest and title, .env, lib/main.dart, DESIGN.md and dependabot.yml. It
derives the CURRENT identity from the tree rather than hardcoding it, which is
what makes a second run a no-op. --dry-run is proven inert by hashing every file
in scope before and after, not by reading git status, which cannot tell a
sibling's staged file from a write.

Rewrite rules scan for their anchor instead of visiting recorded line numbers.
That is why the command handles the sixth PRODUCT_BUNDLE_IDENTIFIER line in the
iOS project file, which the research inventory had missed.

Two things the repo documented and never demonstrated now have exactly one
instance each: a controller implementing SessionScopedController, so the
SessionScopeSync.attach() call that has always run finally has something to
reset, and a status token family in the supplement shape DESIGN.md describes.

The tracked macOS plugin registrant switches to the hosted variant. A fork
clones it, runs pub get against the published graph, and gets no diff, so
app:rename does not refuse on its first run. The local variant is what made it
refuse. The tracked lock already follows this rule for the same reason: what is
committed is the graph a fork resolves, not the one this machine does.

* Act on the review: four false accessibility claims, two silent data paths

The status tokens asserted WCAG AA in their comments and missed it on four
of six pairs, measured: white on #16A34A is 3.30, near-black on #B45309 is
3.53, white on #0EA5E9 is 2.77, white on #0284C7 is 4.10. The cause was
assuming one foreground per role works in both modes, but the generated fills
do not hold lightness across modes and they move in opposite directions:
bg-success goes darker to lighter, bg-warning lighter to darker. So each
foreground flips by mode now, no generated fill changed, and every pair is
recomputed in the docblock: 5.93, 6.40, 5.02, 5.38, 5.57, 5.02.

Two paths could act without the operator seeing it. The identity read back out
of the tree was never validated, only the flags were, so a pubspec.yaml
carrying a traversal in its name reached a directory move; it is now held to
the same patterns. And the Kotlin package move skipped every non-File entity
and then deleted the source recursively, which would take a fork's subpackages
with it, silently, in a case this repo has no fixture for.

--display now rejects # and tab. They break nothing syntactically, they get
eaten: flutter_dotenv strips a trailing #comment, so --display='Acme #1' left
the app reading 'Acme' while the command's own re-read saw the whole string,
which quietly breaks idempotency.

TEST_HOST on macOS is rewritten after all. The constraint was to touch the
Xcode project only through anchored matches, and this rule anchors on the
setting name and the current value exactly like the bundle-id rule beside it,
so it is an instance of that constraint rather than an exception to it. Left
alone it pointed a renamed fork's RunnerTests target at a bundle that is no
longer produced.

The lockfile gate did not run in CI at all, because CI never invokes bin/check;
it now checks the committed lock directly, before pub get rewrites the
evidence. The dashboard card was duplicated between its loading and loaded
branches, differing only in indentation, and its two strings were hardcoded
English on the one screen the rules name as the pattern to copy.

* Let magic decide file_picker, instead of pinning it twice

Nothing in this app imports file_picker. It arrives through magic's Pick
facade, which makes the pin here a second opinion on a version this app has no
stake in, and second opinions on a transitive dependency only matter when they
disagree with the first one.

They did. magic's master moved to ^12.2.0 ahead of a release while this app
pinned ^11.0.2 to match published magic 0.0.9. Those ranges do not intersect,
so version solving failed outright against local sibling checkouts and
bin/check could not run at all, which is the state this repository was already
in before any of this work started.

Removing the pin resolves file_picker from whichever magic is in play:
transitive 12.2.0 against the path-bound local checkout, transitive 11.0.3
against published magic 0.0.9, which is the same version a fork was getting
before. Both graphs verified green with the full suite, and the day magic
publishes its file_picker 12 port nothing here needs editing.

The comment the pin carried argued a fork has no dependency_overrides safety
net so the constraint should be repeated here. That was true and still
insufficient: magic 0.0.9 already caps file_picker below 12.0.0-0, so the pin
never protected anything the framework was not already protecting.

* Merge rewrites by path, so two generators cannot cancel each other

_buildPlan spread the identity rewrites and the Dart-import scan into one list
without merging by path, and the loop re-reads each path from disk. So a file
claimed by both generators produced two planned writes from the same original
source, and _apply performed them in order: the second discarded the first
while the report counted the file as changed twice, with plausible line counts.

lib/main.dart is the only path both can claim. It carries the MagicApplication
title AND is scanned for a `package:` self-import. This repository never
reaches the collision because its own main.dart imports relatively, which is
exactly why the fix has to be structural rather than left to a fixture that
mirrors this tree: a fork that self-imports loses its display name silently.
The test introduces the self-import to reach the case, and fails on the old
code with "the display-name rewrite was discarded by the import rewrite".

The published job now reads the expected version floor out of pubspec.yaml
instead of carrying a literal. A hard-coded alpha.26 would turn the job red on
the next routine bump, in a file the bumping author has no reason to open, and
name a version nobody typed. The comparison is a floor rather than an equality
so a legitimately newer release still passes, verified against alpha.24
(rejected), alpha.26, alpha.27 and 0.0.2.

* chore(deps): pin every fluttersdk dependency at the release that exists

The nine constraints were written against what was published when this branch
opened, and five releases have gone out since: magic 0.0.11, magic_deeplink
0.1.0, magic_notifications 0.3.1, magic_starter 0.0.27 and fluttersdk_artisan
0.0.15.

Two of them were not lagging but EXCLUDING. A caret raises the minor whenever
the major is zero, so magic_deeplink ^0.0.3 ends at 0.1.0 and
magic_notifications ^0.2.0 ends at 0.3.0: the two releases that carry the
cold-start push fix this app is the demonstration of could not be resolved
here at all. Pub does not report that as a conflict, it walks another package
backwards and exits zero, which is the failure this branch exists to close.

The macOS plugin registrant moves with them: magic 0.0.10 took file_picker to
12, which splits the plugin into federated platform packages, so the generated
import is file_picker_darwin rather than file_picker. It is a tracked
generated file and has to match the graph the lock describes.

Resolved hosted with no overrides, which is what the published CI job asserts.
dart analyze clean, 27 tests green.

* fix(rename,config): close four defects this branch introduces

app:rename refused a target whose Kotlin package would sit INSIDE the current
one only by accident: the guard compared the two paths for equality, and
--org=com.fluttersdk.magic_example --name=app names a real identity whose move
is the package into a child of itself. The apply step creates the destination
first and then lists the source, so the rename landed on the directory it had
just made and threw EINVAL after the identity rewrites were already on disk,
leaving a half-renamed tree with git as the only undo. It is refused at
validation time now, and the message names the two-run route that reaches the
same identity without nesting. Equality is excluded, because a display-only
rename leaves the Kotlin path untouched.

appleId camel-cased only the package, so an org carrying an underscore
(com.acme_inc, the ordinary Java encoding of acme-inc.com) produced
com.acme_inc.acmeApp in both pbxproj files, and CFBundleIdentifier takes
alphanumerics, hyphen and period alone. Every segment is camel-cased now. The
report prints androidId and appleId beside the three inputs, because the two
ids no longer match character for character and a dry run that hid them made
the difference a surprise at code-signing time.

lib/config/notifications.dart declared no service worker keys. The web driver
drops an absent key from the config it hands the SDK, which then registers
OneSignalSDKWorker.js at the root scope that a Flutter web build already owns,
so whichever registration lands second wins and push silently never arrives.
The two literals match what notifications:install writes into web/, and a fork
cannot recover them by re-running that command because it refuses to overwrite
an existing config file.

database.enabled stays and gains a comment rather than being removed: nothing
at runtime gates on it, but notifications:configure prints and rewrites it, and
the package's own install stub declares it.

Also fixes the floor gate in ci.yml, which compared with sort -V. GNU
filevercmp orders an empty suffix below -alpha.1, so a walk-back from 0.0.27 to
0.0.27-alpha.1 sorted the floor first and PASSED the assertion that exists to
catch exactly that, and an alpha floor against a stable resolution failed the
opposite way. The comparison is semver now, verified against both directions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants