Monorepo for Aesthetic.Computer aesthetic.computer
core system netlify functions SOTCE-NET-AGENTS.md
13 kB

🍪 Sotce Net — Agent Context #

A paid diary network by Sotce & Aesthetic Computer — live at sotce.net.


🧠 What Is This? #

A subscription diary platform. The writer (@amelia / Sotce) publishes pages; subscribers read, touch, and chat. Private digital magazine with real-time social features and a warm, paper-like, cookie-themed aesthetic.


🏗️ Architecture #

One giant Netlify function — sotce-net.mjs (~10,270 lines). No framework, no build step. Server-rendered HTML via tagged template literals. Handles GET routes (full HTML pages) and POST/DELETE routes (REST API).

⚙️ Stack #

Layer Tech
🖥️ Runtime Netlify Functions (Node.js serverless)
🎨 Frontend Vanilla JS, Canvas API (page rendering), Monaco Editor (chat input)
🔐 Auth Auth0 SPA SDK — tenant sotce at sotce.us.auth0.com
💳 Payments Stripe subscriptions via Checkout Sessions
🗄️ Database MongoDB — sotce-pages, sotce-asks, sotce-touches, chat-sotce, @handles
⚡ Cache Redis (subscription status via kv.mjs)
💬 Real-time WebSocket chat via session server (room: chat-sotce)
🔤 Fonts Helvetica (custom woff/ttf), Carlito (Google), Wingdings 2

📁 Key Files #

File What
system/netlify/functions/sotce-net.mjs 🍪 The entire app
system/backend/sotce-net-constants.mjs 💳 Stripe keys, price/product IDs, SMTP creds
system/backend/authorization.mjs 🔐 authorize(), hasAdmin(), handleFor(), deleteUser()
system/backend/database.mjs 🗄️ MongoDB connect() → { db, disconnect }
system/backend/kv.mjs ⚡ Redis connect/get/set/del/disconnect
system/backend/http.mjs 📡 respond(status, body, headers)
system/backend/shell.mjs 📝 shell.log() / .warn() / .error()
system/public/aesthetic.computer/lib/chat.mjs 💬 Client Chat class (WebSocket wrapper)

🖼️ Assets #

Served from https://assets.aesthetic.computer/sotce-net/ (prod) or /assets/sotce-net/ (dev). Key: cookie.png, cookie-open.png, thumbnail.png, helvetica.woff, helvetica-bold.woff, Wingdings 2.ttf.


🛣️ Routes #

🌐 GET (HTML Pages) #

Route What
/ 🏠 Gate (login/subscribe) or Garden (page feed)
/chat 💬 Real-time chat
/gate 🚪 Login/subscribe screen
/write ✍️ Page editor (admin)
/ask ❓ Question submission (subscribers)
/respond 📝 Question response editor (admin)
/page/:n 📄 Deep link to diary page
/q/:n ❓ Deep link to Q&A
/privacy-policy 📜 Privacy policy

📡 API Endpoints #

Method Path Auth What
GET /subscribers — Subscriber count
POST /subscribe — Stripe Checkout session
POST /subscribed Bearer Check sub + fetch pages/questions
POST /cancel Bearer Cancel subscription
POST /write-a-page 👑 Admin Draft CRUD + publish
POST /touch-a-page 🔑 Sub Record page touch
POST /delete-account Bearer Full account nuke
POST /ask 🔑 Sub Submit question
GET /asks Bearer User's own questions
GET /asks/pending 👑 Admin Unanswered questions
POST /ask/:id/respond 👑 Admin Answer question
POST /ask/:id/save-draft 👑 Admin Save draft response
POST /ask/:id/reject 👑 Admin Reject question
DELETE /ask/:id Owner Delete own pending question
DELETE /asks/clear-all 👑 Admin Clear all (dev tool)

👤 User Roles #

Role Access
🔒 Logged out Gate, subscriber count, privacy policy
📧 Unverified Email verification prompt (polls Auth0)
✅ Verified (no sub) Subscribe button, read-only chat
🔑 Subscribed Garden, chat, touch pages, ask questions
👑 Admin Write pages, respond to Qs, pending Qs. Emails: me@jas.life, sotce.net@gmail.com (bypass Stripe via ADMIN_EMAILS)

🎨 UI Concepts #

  • 🚪 Gate — Cookie login screen. Click cookie → enter garden. Status-specific buttons per role.
  • 🌻 Garden — Canvas-rendered page feed. 4:5 cards, one at a time, swipe/drag/arrow to navigate. Card flip (ear tap) reveals who "touched" it.
  • 💬 Chat — WebSocket real-time. Monaco Editor input with @handle autocomplete, syntax highlighting for -5- (diary links) and *3* (Q&A links), URL auto-linking, unread badge.
  • ✍️ Page Editor — Admin. 19-line max, justified+hyphenated, draft/keep/crumple/publish.
  • ❓ Ask Editor — Subscriber. 5-line max, localStorage draft, "my questions" list view.
  • 📝 Respond Editor — Admin. Prev/next Qs, auto-draft to server, dynamic response line count.

🗄️ Database Schemas #

sotce-pages #

{ _id, user: "auth0|sub", words: "...", when: Date,
  state: "draft"|"published"|"crumpled",
  questionId?: "...", isQA?: true, updatedAt?: Date }

sotce-asks #

{ _id, user, handle?, question, when: Date,
  state: "pending"|"answered"|"rejected",
  answer?, answeredBy?, answeredAt?: ISO,
  draftAnswer?, draftStartedAt?: ISO, draftLastEditedAt?: ISO,
  rejectedBy?, rejectedAt?: ISO }

sotce-touches #

{ _id, user, page: ObjectId, when: Date }
// Unique index on (user, page)

chat-sotce #

{ text, user, from: "@handle", when: Date, count: N }

@handles #

{ _id: "sotce-{sub}", handle: "amelia" }
// Shared across AC + sotce tenants

🎭 Theme System #

CSS custom properties in :root (light) and @media (prefers-color-scheme: dark). Canvas reads them via getThemeColors() → getComputedStyle().

Key vars: --card-background, --card-text, --card-border, --card-ear, --question-card-background, --garden-background, --chat-background, --line-height: 1.76em, --page-font: "Helvetica", --max-lines: 19

Light: Pink/cream paper. Dark: Warm brown/sepia.


⚡ Redis Cache #

Key sotce-subscribed → hash field {user.sub} → JSON {status, current_period_end}. Set after Stripe lookup, auto-invalidates on expiry or cancellation.


🧑‍💻 Dev Mode #

When NETLIFY_DEV is truthy:

  • 💳 Test Stripe keys
  • 📂 Local asset path /assets/sotce-net/
  • 🔄 WebSocket live reload (wss://localhost:8889)
  • 🛣️ URL prefix /sotce-net (e.g., /sotce-net/chat)
  • 💾 Session preserved via ?session-sotce=retrieve

Run: npm run aesthetic (full stack) or npm run site (client only).


🔧 Common Dev Tasks #

➕ New route: Add path to the if condition ~line 270, update title assignment, add client routing in updatePath().

➕ New API endpoint: Add else if clause after ~line 9238. Use authorize(event.headers, "sotce") for auth, respond(status, body) to return.

🎨 Canvas changes: Start at ~line 6367 (USE_CANVAS_GARDEN). Key fns: renderPage(), renderCardBack(), wrapText(), getThemeColors(). Animation in loop().

💳 Subscription logic: subscribed(user) checks Redis cache → Stripe. Admin emails bypass. Cache TTL from current_period_end.

💬 Chat: Connects to sotce room via new Chat(dev, undefined, disconnectCallback). Messages via session server WebSocket. History on connected event.


🗺️ Source Map — sotce-net.mjs #

📦 Server-Side Preamble (1–265) #

Lines What
1–62 📋 TODO list
63–98 ♻️ Env, imports (Stripe, DB, auth, KV)
106 🚀 export const handler
129–226 💳 subscribed(user) — Stripe + Redis cache check
230–264 📊 getActiveSubscriptionCount()

🎨 CSS (319–3209) #

Lines What
319–510 🌗 Theme variables (light :root + dark @media)
511–860 🌑 Dark mode DOM overrides
860–1010 📐 Base layout (html, body, scroll, print)
1010–1280 📄 Page/card rendering (font size, 4:5 ratio)
1280–1620 ❓ Ask editor styles
1620–1870 📝 Respond editor styles
1870–2100 🌻 Garden layout (binding, FYP scroll-snap)
2100–2500 🐕 Ear fold, backpage, hover states
2500–2770 🔘 Buttons, nav, cookie menu
2770–3100 🚪 Gate, spinner, chat, veil, tooltips

💬 Client JS — Chat (3227–4140) #

Lines What
3227–3280 🗺️ Env, updatePath(), platform detection
3280–3310 💬 Chat init, connect("sotce")
3312–3420 🖱️ Chat DOM, click/hover handlers, page previews
3420–3550 🔧 chatScrollToBottom(), linkifyText(), chatAddMessage(), fading
3555–3740 ⌨️ Chat input bar, autocomplete system
3740–3950 🎹 Monaco Editor — language, themes, keybindings, mobile
3951–4000 📤 chatSend()
4011–4140 📥 chat.system.receiver — event handlers

🚪 Gate & 🌻 Garden (4141–5040) #

Lines What
4141–4245 🏷️ URL param flags, auth UI setup
4246–4810 🚪 gate(status, user, subscription) — full gate builder
4810–4920 🌻 garden() — top bar, chat button, ask/respond buttons
4920–5040 🔘 Ask + Respond button handlers

✍️ Editors (5045–6290) #

Lines What
5045–5405 ❓ openAskEditor() — 5-line question form, "my questions"
5403–5775 📝 openRespondEditor() — admin Q&A, prev/next, draft save
5831–6290 ✍️ compose() / Write a Page — 19-line editor, keep/crumple/publish

📦 Feed & Cache (6295–6365) #

Lines What
6295–6365 🔀 Feed construction (pages + questions → sorted feed), IndexedDB cache

🎨 Canvas Garden Renderer (6367–7470) #

Lines What
6367 🚩 USE_CANVAS_GARDEN = true
6370–6455 📊 State: page index, transitions, drag, flip, card dims
6457–6485 🎭 getThemeColors() — CSS vars → canvas colors
6487–6520 📐 resizeCanvas() — card sizing (4:5, centered)
6525–6555 📥 fetchPage(idx) — IndexedDB → server fallback
6560–6590 📏 wrapText() — canvas word wrap
6590–6810 📄 renderPage() — diary card OR Q&A card
6813–6928 🔙 renderCardBack() — touch info, @handle hit boxes
6928–7090 🖼️ render() — main frame (flip, transition, drag)
7090–7095 🔄 loop() — requestAnimationFrame loop
7112–7170 👆 Pointer events (drag navigation)
7171–7230 ⌨️🖱️ Keyboard + wheel navigation
7233–7470 🖱️👆 Click, mousemove, touch (ear flip, links, handles)

📜 DOM Fallback Garden (7517–8530) #

Lines What
7517–8530 📜 DOM-based rendering (fallback when canvas off): scroll-snap FYP, renderPageContent(), drag, ear/backpage DOM

🔐 Auth Flow & Session (8532–9230) #

Lines What
8534–8600 🔐 Auth0 client init
8600–8650 💾 Session restore (localStorage / URL params)
8650–9160 🔀 Main auth flow → gate/garden routing
8820–8905 🔧 veil(), unveil(), flash(), login(), signup(), subscribe()
8905–9015 💾 IndexedDB cache fns (getCachedPage, setCachedPage, getCacheMeta, clearPageCache)
9017–9090 💳 Client subscribed(), cancel()
9092–9170 🚪 logout(), resend(), aesthetic()
9171–9228 📡 userRequest(method, endpoint, body) — authenticated API caller

📡 REST API Endpoints (9238–10125) #

Lines What
9238 📊 GET /subscribers
9246 💳 POST /subscribe (Stripe checkout + dup guard)
9321 🔑 POST /subscribed (sub check + pages/Qs fetch)
9476 ❌ POST /cancel
9482 ✍️ POST /write-a-page (draft CRUD + publish)
9627 👆 POST /touch-a-page
9698 🗑️ POST /delete-account
9785 ❓ POST /ask
9823 📋 GET /asks
9839 📋 GET /asks/pending
9863 📝 POST /ask/:id/respond
9926 💾 POST /ask/:id/save-draft
9964 🚫 POST /ask/:id/reject
10003 🧹 DELETE /asks/clear-all
10017 🗑️ DELETE /ask/:id
10047 📜 GET /privacy-policy

🧩 Module-Level (10127–10271) #

Lines What
10127 💳 cancelSubscription() — Stripe cancel + Redis clear
10195 📊 analyticsScript — GA tag
10214 🔄 reloadScript — dev WebSocket live reload

📅 Date Convention #

Comment timestamps: YY.MM.DD.HH.MM (e.g., 24.06.13.06.38 = Jun 13 2024 6:38 AM).


📋 Open TODOs #

🔊 Sound (sine clicks/beeps) · 📸 Pictures in pages · 🔔 Chat notifications · 📧 Email blasts for new pages · 🧘 Meditation timer · 📟 Multi-user page feed · ♿ Accessibility (tab index, zoom, relational scroll) · 📰 Snippet endpoint (latest page on login)