Fixes#1949
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is
generating a summary for commit
46ac310c762fd4044c35bc59264122234ed19bbf. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!-- This is an auto-generated description by cubic. -->
---
## Summary by cubic
Make app ports dynamic instead of hardcoded 32100 to prevent conflicts
and keep local runs, Docker, and env URLs in sync. Ports now derive from
appId using a base of 32100.
- **Bug Fixes**
- Added getAppPort(appId) = 32100 + (appId % 10_000).
- Used the dynamic port in NEXT_PUBLIC_SERVER_URL, start commands,
Docker -p mapping, and cleanUpPort.
- Updated getCommand to accept appId and generate a per-app default
start command.
<sup>Written for commit 46ac310c762fd4044c35bc59264122234ed19bbf.
Summary will update automatically on new commits.</sup>
<!-- End of auto-generated description by cubic. -->