Skip to content

49 — The Portal System — one fractal, clean anatomy at every altitude (envisioning)

Envisioning / redesign doc. Governed by 00-ROADMAP.mddefer to it on conflict. Created 2026-06-29 (owner-raised: "in Project I saw Portals so complex and so messy it looks like it requires a re-design… and I don't see it in Workspace/Roster, Artist, Track, Configure"). The two observations are one root cause: there is no Portal system — each portal is a bespoke, hand-stacked file, and the fractal principle locked in [doc-47 §6] ("one Portal grammar at every altitude") was never built.

2 decisions locked with the owner (2026-06-29):

  1. Envision the Portal System first (this doc), then build.
  2. Full ladder incl. the Workspace root — Workspace ("cloud root space") → Artist → Project → Track → File all share one clean Portal shell.

Reconciled by [doc-50] (2026-06-29): the app's center of gravity is now action-first — Portals are the substrate you land on when you act, not the daily entry. This redesign stays valuable (a calm, fractal substrate) but sequences after the action-first Home leads (doc-50 §6).

Needs confirmation (§9 open questions).


1. The problem — audit of today's portals (verified)

  • Portal is just a container. DesignSystem/Components/Portal.swift = a .sheet (medium/large detents, Liquid-Glass) wrapping a ScrollView { VStack(spacing: lg) { content } }. It imposes no anatomy — whatever sections the caller stacks, in whatever order, is the portal.
  • The Project Portal flat-stacks ~11 heterogeneous sections (ProjectPortalContent.swift): header · release-readiness headline · workflow pipeline · metadata · album art · tracklist · team · share · team-share · notes · my-tag · delete. No grouping, no hierarchy, no progressive disclosure → the "messy, complex" feel. Every feature we shipped bolted another section on.
  • Sections are hand-duplicated across entities. ArtistPortalContent and ProjectPortalContent each re-implement image / notes / team / team-share / share / my-tag / delete. Shared bits (PortalTeamSection, PortalShareSection, PortalNotesSection, PortalTeamShareSection) exist but the composition is copy-pasted per file.
  • Coverage is partial. Track has no Portal (correction 2026-06-30: Track does have a Portal — Features/Review/TrackPortalContent.swift, reached from the player; the audit missed it by surveying only Browse/. It was the same flat wall and is now zoned, slice 3.) Workspace and Roster have none.
  • The fractal is on paper only. [doc-47 §6] decided "one grammar at every altitude"; the codebase has bespoke per-entity portals instead. This doc makes the principle real.

2. Diagnosis

Two symptoms, one cause: there is no designed Portal anatomy and no shared composition. Fixing it once — a clean, ordered set of zones that every Portal renders (filling in only what applies), built from shared zone components instead of bespoke files — fixes the mess and the missing-altitudes gap together.

3. The Portal anatomy (the fix)

Every Portal, at every altitude, is the same ordered set of zones. A zone renders only if the node has content for it. Calm by default (doc-47 §7): each zone is a summary that expands; rarely-used actions go to an overflow menu.

#ZoneWhat it isProgressive disclosure
1Identityname · type · key art · status/health pill · provenance breadcrumb (doc-36)always shown, compact
2Healththe at-a-glance: release-readiness / lifecycle / countssummary chip → expand for the breakdown
3Contentthe node's reason for being (varies by altitude — §4)the primary, always-expanded zone
4Workflow / Configthe doc-48 process for this node: pipeline · inherited-vs-custom · level-appropriate config (incl. doc-43 attributes later)summary line → expand pipeline
5Relationshipsteam · sharing · cross-links / variants (doc-28) · membershipcollapsed groups
6Notesnode-anchored annotations (doc-33)summary count → expand
7Personalmy-tag, my view prefscollapsed
8Manageedit · lifecycle · danger/deletetucked at the bottom / overflow

This turns the Project Portal's 11 flat sections into ~8 predictable zones, most collapsed — the same mental model on every screen.

4. The fractal — what each altitude's Content zone holds

Zones 1–2 and 4–8 are constant; only Content (zone 3) changes by altitude. That's what makes it a fractal and not eight different screens.

AltitudeContent zoneNotes
Workspace (root / "cloud space")studio identity · studio defaults (workflow — doc-48; attributes later) · roster overview (the lens) · asset cloud (doc-45) · membersNEW — top of the ladder; the "cloud root space" the owner sensed. Entry from Configure / a Workspace affordance
Artistthe artist's projects · roster tag · (future) artist-level workflow default override (doc-48 rung 2)exists; re-home onto the shell
Projecttracklist · release-readiness + workflow pipeline (inherited/custom) · album artexists — the redesign reference (worst offender)
Trackversions / player · per-track readiness steps · variants & cross-links (doc-28) · attachmentsNEW as a Portal (today it's the PlayerView)
Filethe asset · review status (doc-29) · metadatalater phase

Roster vs Workspace (resolves the owner's conflation, per doc-48): Roster is a tag/lens, not a container — it has no Portal of its own; it appears as a grouping inside the Workspace Portal and as a Browse lens. Workspace is the tenant rootthat gets the root Portal ("cloud space").

5. Composition — how this kills the mess structurally

One shared PortalScaffold renders zones 1–8 in order; each entity supplies a small content builder per zone (most reused verbatim — team, share, notes, my-tag, danger are already shared components). No more bespoke per-entity portal files duplicating sections. Adding a new altitude = supply its Content zone; everything else is inherited. This is the doc-47 §6 "one grammar" made literal in code, and it's what stops the next feature from "bolting on another section."

6. The Project Portal redesign (reference implementation)

Map today → the anatomy (grouping + disclosure, nothing lost):

Today (flat)New zone
headerIdentity
release-readiness headlineHealth (summary)
tracklist · album artContent
workflow pipeline · readiness itemsWorkflow/Config (summary → expand)
team · share · team-shareRelationships (collapsed groups)
notesNotes
my-tagPersonal
metadata · edit · deleteManage (tucked)

Eleven stacked sections → eight predictable zones, most collapsed. Same data, calm surface.

7. Open questions (confirm before building)

  1. Sheet vs full-screen. Today Portal is a .sheet (medium/large). A Workspace/root portal with an asset cloud may want full-screen / its own tab. Mixed? (Lean: keep node portals as sheets; Workspace root is a destination in Configure or its own surface.)
  2. Where does the Workspace Portal live? A Configure entry ("Workspace")? A dedicated affordance? (ties to doc-47 account-corner vs Configure split.)
  3. Track: Portal vs keep PlayerView. Add a Track Portal alongside the player, or fold the player into the Track Portal's Content zone? (Lean: Track Portal whose Content embeds the player.)
  4. How aggressive is progressive disclosure — default-collapsed everything but Content, or keep Health+Workflow expanded? (Owner taste.)

    Resolved by doc-54 (2026-07-04) — start almost empty (doc-47 §7 principle 7): Identity + Content expanded; Health + Workflow collapse to one-line summary chips; everything else collapsed; and a zone with no content doesn't render at all (mirror of doc-37 §2.1) — a single "+" affordance at the Portal foot offers the unfilled zones instead.

  5. File-level Portal — in this pass or deferred?

8. Sequencing (after confirmation)

  1. Confirm the anatomy + §7 forks (this doc).
  2. Build the zone primitivePortalZone BUILT 2026-06-30 (xcodebuild green) — collapsible, progressive-disclosure zone (DesignSystem/Components/PortalZone.swift).
  3. Re-group the Project Portalslice 1 done 2026-06-30 — primary zones (Identity · Health · Content · Workflow) visible, secondary (Team & sharing · Notes · My tag · Manage) collapsed. The 11-section wall → ~5 visible + tidy collapsed groups. (Full zone-header normalization of the remaining self-headed sections + extracting the shared zone components = follow-up.)
  4. Roll the shell to Artist + TrackArtist (slice 2) + Track (slice 3) done 2026-06-30 — both re-grouped onto PortalZone; the Track Portal already existed (in Review/, not Browse/ — audit miss, §1 corrected). Slice 3 also surfaced doc-28 variant chips (variantType + cross-links + appearances) — the long-standing iOS gap. Project · Artist · Track now share the anatomy.
  5. Build the Workspace root Portalslice 4 done 2026-06-30 (xcodebuild green) — WorkspacePortalView (Configure ▸ Workspace, Soon→live): Identity · Portfolio KPIs · Studio defaults (doc-48) · Roster overview. Composes existing reads (overview/workspace/templates/matrix). THE FRACTAL IS COMPLETE — Workspace → Artist → Project → Track all share the zone anatomy. (Asset cloud / doc-45 deferred.)
  6. File Portalslice 5 done 2026-06-30 (xcodebuild green) — FilePortalContent (leaf altitude): Identity · Asset (image preview + metadata) · Review (doc-29, read-only) · Notes (.file). Entry = long-press a version in the player's version switcher. ALL FIVE ALTITUDES NOW SHARE THE ANATOMY (Workspace → Artist → Project → Track → File). Remaining: full zone-header normalization + extract shared zone components · more discoverable File-Portal entry · doc-28 variant authoring · asset cloud (doc-45).

This is UI-layer work over mostly existing endpoints (workspace, project, track, workflow, comments, collaboration); net-new backend is small (Workspace asset cloud ties to doc-45, deferred). It directly "achieves success": the messy Project Portal becomes calm, and the fractal finally exists end-to-end.

9. Cross-references

Ctrl-Audio Platform Documentation