Monorepo for Aesthetic.Computer
aesthetic.computer
Profile Scorecard + Paintings Route Split#
Date: 2026-02-27 Owner: platform/frontend
Goal#
Change user profile behavior from "painting portfolio" to "full user activity scorecard" while preserving easy access to a user's paintings in a dedicated paintings.mjs route.
Target behavior:
/@handleshows a live profile scorecard (presence + activity + media summary).paintings~@handleshows the painting portfolio carousel (moved from currentprofile.mjsbehavior).
Current Routing + Data Flow (As Implemented)#
URL routing to profile#
- Netlify catch-all sends app paths to the index function.
system/netlify.tomlroutes/*->/.netlify/functions/index.- Server-side index routing rewrites
@handleto load theprofiledisk source. system/netlify/functions/index.mjsrewrites local disk path toprofilewhen path starts with@.- Client-side loader also rewrites
@handleto theprofilepiece and passes@handleas first param. system/public/aesthetic.computer/lib/disk.mjsrewrites slug@handleto hidden slugprofileand sets params to include@handle.
What profile currently does#
system/public/aesthetic.computer/disks/profile.mjs:- resolves
visiting = params[0] || handle(). - fetches
/api/profile/:handlefor identity + latest mood. - fetches
/media-collection?for=@handle/paintingfor user painting URLs. - loads paintings one-by-one and behaves like a portfolio viewer with prev/next, open in
painting, and download.
Realtime session data currently available#
system/public/aesthetic.computer/lib/disk.mjsalready broadcastslocation:broadcastover WebSocket on piece changes and periodic keep-alives.session-server/session.mjsstores per-clienthandle,user, andlocationfrom those broadcasts.session-server/session.mjsexposes:GET /statusfull presence snapshot.WS /status-streamlive status updates every 2s withclients[], including location and world membership/showing metadata.
Existing HTTP Endpoints Useful for Scorecard#
/api/profile/:handle-> basic identity (sub) and latest mood./media-collection?for=@handle/painting-> painting file URLs only (no rich metadata)./api/painting-metadata?slug=...&handle=...-> per-painting code/slug metadata./api/store-kidlisp?recent=true&handle=@handle&limit=...-> recent KidLisp with timestamps and hits./api/store-clock?recent=true&limit=...-> recent clocks with handle included (client-side filter needed today)./api/mood/all?for=@handle-> mood history./api/piece-hitand/api/piece-fans-> piece-centric analytics (not user-centric timeline yet)./api/metrics-> platform-wide totals (global, not per-user).
Gaps To Close#
- No single endpoint returns "user scorecard" (counts + latest media + timeline).
- No dedicated paintings route piece; portfolio is embedded in
profile.mjs. - Realtime stream currently broadcasts all clients (
/status-stream) instead of a per-handle feed.
Proposed Route Contract#
Keep#
/@handleas canonical public profile URL.profileprompt command and@handlelinks as-is.
Add#
- New disk:
system/public/aesthetic.computer/disks/paintings.mjs. - Canonical portfolio route:
paintings~@handle.
Optional aliases#
@handle/paintingsalias (implemented in client parse/load rewrite) ->paintings~@handle.profile~@handlecontinues working as scorecard alias.
Proposed Data Contract#
Introduce a new Netlify endpoint:
GET /api/profile-scorecard/:handle- Returns:
identity: handle, sub, optional display fields.presence: online, currentPiece, worldPiece, showing, lastSeenAt.counts: paintings, pieces, kidlisp, clocks, tapes, moods.recentMedia: latest N per media type with slug/code/when.activity: unified reverse-chronological list ([{type, when, label, ref}]).topPieces: frompiece-user-hitsfor this user.
Implementation notes:
- Resolve
subfrom@handles. - Aggregate from Mongo collections:
paintings,pieces,kidlisp,clocks,tapes,moods,piece-user-hits. - Cache response briefly (30-60s) with optional
?fresh=true.
Realtime Strategy#
Phase 1 (fast path, minimal backend changes)#
- In
profile.mjs, open WebSocket towss://session-server.aesthetic.computer/status-stream. - Filter incoming
status.data.clientsby target handle. - Update scorecard presence block in real time:
- online/offline
- current piece slug
- world piece + currently showing media
- ping/connection count
Phase 2 (scalable / cleaner)#
- Add targeted session-server stream:
WS /profile-stream?handle=@nameor message-basedprofile:watch.- Server emits only relevant updates for that handle on:
location:broadcastworld:*:join|show|hide|move|slug- connect/disconnect for matching handle.
Activity freshness#
- Begin with timed refresh of
/api/profile-scorecard/:handleevery 15-30s. - Later: push activity events from write endpoints (
track-media,store-kidlisp,store-clock,mood) through Redis -> session-server -> profile watchers.
Frontend Plan#
paintings.mjs#
- Start by moving the current painting-portfolio logic from
profile.mjswith minimal visual changes. - Inputs:
params[0]handle. - Data source initially remains
/media-collection?for=@handle/painting. - Keep existing controls (prev/next, jump to
painting, download).
New profile.mjs#
- Replace painting carousel UI with scorecard blocks:
- header identity (
@handle, mood, quick stats) - live presence card (current piece, online state)
- last activity timeline
- recent media strip (painting/piece/kidlisp/clock/tape)
- CTA/link to
paintings~@handle
Rollout Steps#
- Add
paintings.mjsby extracting current portfolio behavior fromprofile.mjs. - Update
profile.mjsto scorecard UI using mocked data shape. - Add
/api/profile-scorecard/:handleand wire profile data fetch. - Add realtime presence hookup via
/status-streamfilter. - Add optional alias rewrites (
@handle/paintings) and update sitemap/help text. - Optimize with targeted profile stream and push activity events.
Compatibility + Risks#
- Keep
/@handlecanonical; no external link breakage expected. - Keep
painting~@handle/timestampbehavior unchanged. status-streamcurrently reveals global presence payload; acceptable short-term but should move to targeted stream for scale/privacy.media-collectionreturns URLs only; scorecard should not rely on it for activity ordering.
Acceptance Criteria#
- Visiting
/@handleshows live scorecard, not painting carousel. - Visiting
paintings~@handleshows portfolio carousel. - Presence card updates within ~2s when target user switches pieces.
- Activity/media sections show latest data without manual refresh.