Skip to content

matthewstraub/surviving-to-thriving

Repository files navigation

Surviving to Thriving — Technical Documentation

Author: Manus AI Last Updated: February 2026 Version: 1.0


1. Introduction

Surviving to Thriving is a real-time classroom check-in tool designed for instructors who want a quick pulse on how their students are feeling. Each student opens a link on their phone or laptop, enters their name, picks an emoji, and slides a 1–10 scale from "barely surviving" to "really thriving." The teacher watches responses stream in live on a password-protected dashboard, complete with group statistics and outlier alerts.

The application was built with the Marymount Manhattan College brand palette in mind, using the official Pantone 286 C blue (#0033A0) as the primary accent color, paired with warm gold highlights and the DM Serif Display typeface for an elegant, institutional feel.


2. Architecture Overview

The application follows a monolithic full-stack architecture where the frontend and backend are bundled into a single deployable unit. In production, the Express server serves the pre-built React SPA alongside the API and WebSocket endpoints.

┌─────────────────────────────────────────────────────┐
│                    Render (Free Tier)               │
│                                                     │
│  ┌──────────────┐   ┌──────────────┐   ┌────────┐   │
│  │  React SPA   │   │  Express +   │   │ Socket │   │
│  │  (Vite build)│◄──│  tRPC API    │──►│  .io   │   │
│  └──────────────┘   └──────┬───────┘   └────────┘   │
│                            │                        │
└────────────────────────────┼────────────────────────┘
                             │ MySQL protocol (SSL)
                    ┌────────▼────────┐
                    │  TiDB Cloud     │
                    │  (Free Starter) │
                    └─────────────────┘

The table below summarizes each layer and its role.

Layer Technology Purpose
Frontend React 19, Tailwind CSS 4, Vite 7 Single-page application served as static files
UI Components shadcn/ui (Radix primitives), Framer Motion Accessible, animated interface components
Emoji Picker emoji-mart v5 Full searchable emoji library with categories
Client Routing Wouter Lightweight client-side routing
API Layer tRPC 11 over Express 4 Type-safe RPC between client and server
Real-time Socket.io v4 WebSocket push for live submission updates
ORM Drizzle ORM 0.44 Type-safe SQL query builder and schema management
Database TiDB Cloud Starter (MySQL-compatible) Persistent storage for sessions and submissions
QR Codes qrcode (npm) Server-side QR code generation as data URIs

3. Application Routes and Pages

The React SPA defines four primary routes, each serving a distinct role in the classroom workflow.

Route Component Access Description
/ Home.tsx Public Landing page with branding, feature overview, and a link to the teacher dashboard
/s/:code StudentSubmit.tsx Public (via unique link) Student submission form — name, emoji picker, 1–10 slider
/teacher/login TeacherLogin.tsx Public Password entry form that gates access to the dashboard
/teacher TeacherDashboard.tsx Password-protected Live dashboard showing all submissions, statistics, QR codes, and session management

The student submission URL includes a unique 8-character code (e.g., /s/Qgy92taA) generated by the nanoid library each time the teacher creates a new session. This ensures that every class check-in has its own isolated link, preventing cross-session contamination.


4. Database Schema

The application uses three custom tables in a MySQL-compatible database (TiDB Cloud). The schema is defined in drizzle/schema.ts and managed through Drizzle Kit migrations.

4.1 survey_sessions Table

This table stores each check-in session that a teacher creates. Each session has a unique code that becomes part of the shareable student URL.

Column Type Description
id int (auto-increment, PK) Surrogate primary key
code varchar(32) (unique) Short alphanumeric code used in the URL path /s/{code}
label varchar(255) Optional human-readable name (e.g., "Monday 9am Section")
isActive int (default 1) Whether the session is currently accepting submissions (1 = active, 0 = closed)
createdAt timestamp When the session was created

4.2 submissions Table

Each student response is stored as a row in this table, linked to its parent session by sessionId.

Column Type Description
id int (auto-increment, PK) Surrogate primary key
sessionId int (FK to survey_sessions.id) Which session this submission belongs to
studentName varchar(255) The name the student entered
emoji varchar(32) The emoji character the student selected
rating int The 1–10 scale value
ipAddress varchar(64) Client IP address captured at submission time
createdAt timestamp When the submission was recorded

4.3 users Table

This table is part of the Manus OAuth scaffold and is not actively used by the core classroom check-in functionality. It exists to support the platform's built-in authentication system. The teacher dashboard uses a simpler password-based authentication mechanism instead.


5. Backend API Reference

All API endpoints are defined as tRPC procedures in server/routers.ts. The tRPC layer provides end-to-end type safety — the same TypeScript types are shared between server and client, eliminating the need for manual API documentation or schema validation on the frontend.

5.1 Teacher Authentication

Teacher access is protected by a simple password comparison. The password is read from the TEACHER_PASSWORD environment variable at server startup. There is no user registration or OAuth flow for the teacher — just a single shared password.

Procedure Type Input Description
teacher.login Mutation { password: string } Validates the password and returns a token if correct
teacher.verify Query { token: string } Checks whether a stored token is still valid

The "token" returned by teacher.login is the password itself, stored in the browser's localStorage. Every subsequent teacher-only request includes this token for verification. This is a deliberately simple scheme appropriate for a single-teacher classroom tool.

5.2 Session Management

These procedures handle creating, listing, activating, deactivating, resetting, and deleting survey sessions. All require the teacher token.

Procedure Type Input Description
session.create Mutation { label?, token } Creates a new session with a random 8-character code
session.list Query { token } Returns all sessions ordered by creation date (newest first)
session.getByCode Query { code } Looks up a session by its URL code (used by the student page)
session.activate Mutation { id, token } Re-opens a session for submissions
session.deactivate Mutation { id, token } Closes a session so no more submissions are accepted
session.reset Mutation { id, code, token } Deletes all submissions for a session and emits a WebSocket reset event
session.delete Mutation { id, token } Permanently deletes a session and all its submissions

5.3 Submissions

Procedure Type Input Description
submission.submit Mutation { sessionCode, studentName, emoji, rating } Records a student submission, emits it via WebSocket, and checks for outliers
submission.listBySession Query { sessionCode, token } Returns all submissions for a session (teacher-only)

5.4 Outlier Detection and Notifications

When a student submits a response, the server performs an outlier check if there are at least 3 submissions in the session. The algorithm calculates the mean and standard deviation of all ratings, then flags the new submission as an outlier if it deviates by more than 2 standard deviations from the mean and the rating is extreme (1–2 or 9–10). When an outlier is detected, the server attempts to send a push notification to the project owner via the notifyOwner helper. This notification channel depends on the Manus platform's built-in notification API and will silently fail if the required environment variables (BUILT_IN_FORGE_API_URL, BUILT_IN_FORGE_API_KEY) are not configured.


6. Real-Time Communication (WebSocket)

The application uses Socket.io to push live updates from the server to the teacher's browser without requiring page refreshes or polling. The WebSocket server is initialized in server/socket.ts and attached to the same HTTP server that runs Express.

The communication flow works as follows. When the teacher opens a session on the dashboard, the browser establishes a Socket.io connection to the server at the /api/ws path. The client then emits a join-session event with the session code, which causes the server to add that socket to a named room (session:{code}). When a student submits a response, the server saves it to the database and then broadcasts a new-submission event to all sockets in that session's room. The teacher's dashboard receives this event and appends the new submission to the displayed list without any manual refresh. Similarly, when the teacher clicks "Reset," the server emits a session-reset event that clears the submission list on any connected client.

The client-side WebSocket logic is encapsulated in a custom React hook at client/src/hooks/useSocket.ts, which manages the connection lifecycle and provides onNewSubmission and onSessionReset callback registrations.

Event Direction Payload Purpose
join-session Client → Server Session code string Subscribe to a session's room
new-submission Server → Client Full submission object Push a new student response to the dashboard
session-reset Server → Client None Notify the dashboard that submissions were cleared

7. External Services and Dependencies

The application relies on two external services for hosting and data persistence.

7.1 Render (Application Hosting)

Render hosts the Node.js application as a Web Service on the free tier. The build process installs pnpm, runs pnpm install to fetch dependencies, then executes pnpm build which uses Vite to bundle the React frontend and esbuild to bundle the Express server. In production, the single node dist/index.js process serves both the API and the static frontend files.

Render's free tier has an important operational characteristic: the service spins down after approximately 15 minutes of inactivity. The next incoming request triggers a cold start that takes 30–60 seconds. For classroom use, the teacher should visit the dashboard a minute or two before class to wake the server. Upgrading to Render's paid tier ($7/month) eliminates cold starts entirely.

The Render dashboard is accessible at dashboard.render.com. The service name is surviving-to-thriving and the public URL is https://surviving-to-thriving.onrender.com.

7.2 TiDB Cloud (Database)

TiDB Cloud Starter provides a free MySQL-compatible database with 25 GiB of storage and 250 million Request Units per month. The application connects via the standard MySQL protocol over SSL. The connection string is stored in the DATABASE_URL environment variable on Render.

The TiDB Cloud console is accessible at tidbcloud.com. The cluster is named "Cluster0" and is located in the US East (N. Virginia) region. The database name is surviving_to_thriving.

7.3 GitHub (Source Code)

The source code is hosted in a GitHub repository at matthewstraub/surviving-to-thriving. Render is configured to auto-deploy from the main branch — any push to main triggers a new build and deployment automatically.


8. Environment Variables

The application requires the following environment variables to be set on Render. These are configured in the Render dashboard under the service's Environment section.

Variable Required Description
DATABASE_URL Yes Full MySQL connection string including SSL parameter, pointing to the TiDB Cloud database
TEACHER_PASSWORD Yes The password used to access the teacher dashboard
JWT_SECRET Yes A random string used for signing session cookies (part of the Manus auth scaffold)
NODE_ENV Yes Must be set to production so the server serves the built static files
NODE_VERSION Recommended Set to 22.13.0 to match the development environment

The following variables are part of the Manus platform scaffold but are not required for the core check-in functionality when hosting on Render.

Variable Effect if Missing
VITE_APP_ID Manus OAuth login button will not work (not needed — teacher uses password auth)
OAUTH_SERVER_URL Same as above
VITE_OAUTH_PORTAL_URL Same as above
BUILT_IN_FORGE_API_URL Outlier push notifications will not send (app still works normally)
BUILT_IN_FORGE_API_KEY Same as above
OWNER_OPEN_ID Admin role auto-assignment will not work (not needed)

9. Key Files Reference

The table below maps each important file to its role in the application, organized by layer.

File Path Purpose
drizzle/schema.ts Database table definitions (users, survey_sessions, submissions)
server/db.ts Database query helpers (CRUD operations for sessions and submissions)
server/routers.ts All tRPC API procedures (teacher auth, session management, submissions)
server/socket.ts WebSocket server initialization and event emission functions
server/_core/index.ts Express server entry point, Vite middleware, and Socket.io registration
server/_core/env.ts Environment variable loading and validation
server/_core/notification.ts Push notification helper for outlier alerts
client/src/App.tsx React router configuration (all four routes)
client/src/pages/Home.tsx Landing page with branding and teacher dashboard link
client/src/pages/StudentSubmit.tsx Student submission form with emoji picker and slider
client/src/pages/TeacherLogin.tsx Password entry form for teacher access
client/src/pages/TeacherDashboard.tsx Live dashboard with stats, submissions list, QR code, and session management
client/src/hooks/useSocket.ts Custom React hook wrapping Socket.io client connection
client/src/index.css Global styles, MMM brand color variables, and emoji picker width overrides
client/index.html HTML shell with Google Fonts (DM Serif Display, Inter)
server/survey.test.ts Vitest test suite for backend procedures (19 tests)
RENDER_DEPLOYMENT_GUIDE.md Step-by-step deployment instructions for Render + TiDB Cloud
package.json Dependencies, scripts, and build configuration

10. Maintenance Guide

10.1 Changing the Teacher Password

To change the teacher password, go to the Render dashboard, navigate to the surviving-to-thriving service, click Environment in the left sidebar, find the TEACHER_PASSWORD variable, update its value, and save. Render will automatically redeploy the service with the new password. The change takes effect in 2–3 minutes.

10.2 Updating the Code

Any changes pushed to the main branch of the GitHub repository will trigger an automatic redeployment on Render. The typical workflow is to edit the code locally (or via GitHub's web editor), commit, and push. Render will detect the new commit, rebuild the application, and swap to the new version with zero downtime.

10.3 Database Maintenance

The TiDB Cloud console provides a SQL Editor for running ad-hoc queries. If you need to manually inspect or clean up data, navigate to tidbcloud.com, select your cluster, and open the SQL Editor. Some useful queries include the following.

To view all sessions and their submission counts:

SELECT s.id, s.code, s.label, s.isActive, s.createdAt,
       COUNT(sub.id) AS submissionCount
FROM survey_sessions s
LEFT JOIN submissions sub ON sub.sessionId = s.id
GROUP BY s.id
ORDER BY s.createdAt DESC;

To manually delete old sessions and their submissions:

DELETE FROM submissions WHERE sessionId IN (
  SELECT id FROM survey_sessions WHERE createdAt < DATE_SUB(NOW(), INTERVAL 90 DAY)
);
DELETE FROM survey_sessions WHERE createdAt < DATE_SUB(NOW(), INTERVAL 90 DAY);

10.4 Monitoring and Logs

Render provides a Logs tab in the service dashboard that shows real-time server output. Look for lines prefixed with [Socket] for WebSocket connection events, [Database] for database connection issues, and [Notification] for outlier alert delivery status.

10.5 Handling Cold Starts

On Render's free tier, the server hibernates after 15 minutes of inactivity. To avoid the 30–60 second cold start delay during class, either visit the app URL a couple of minutes beforehand, or set up a free external monitoring service like UptimeRobot to ping the URL every 14 minutes. Alternatively, upgrading to Render's Starter plan ($7/month) keeps the service running continuously.

10.6 Schema Migrations

If you modify the database schema in drizzle/schema.ts, you need to generate and apply migrations. Run pnpm db:push locally with the DATABASE_URL environment variable pointing to your TiDB Cloud database. This command generates SQL migration files in the drizzle/ directory and applies them to the database. Commit the generated migration files to Git so they are tracked in version control.

10.7 Updating Dependencies

Run pnpm update locally to update packages to their latest compatible versions, test the application, and push to main. Key dependencies to keep an eye on include socket.io and socket.io-client (must be the same major version on both sides), drizzle-orm and drizzle-kit (must be compatible versions), and emoji-mart, @emoji-mart/react, and @emoji-mart/data (must all be from the same major release).


11. Classroom Usage Quick Reference

The following table summarizes the typical workflow for using the app in a classroom setting.

Step Who Action
1 Teacher Visit https://surviving-to-thriving.onrender.com and click "Teacher Dashboard"
2 Teacher Enter the teacher password and sign in
3 Teacher Type a session label (e.g., "Wednesday 2pm") and click "New Session"
4 Teacher Click "Show QR Code" and project it on screen, or click "Copy Link" and share it
5 Students Scan the QR code or open the link on their devices
6 Students Enter their name, pick an emoji, slide the scale, and tap "Submit Check-In"
7 Teacher Watch responses appear in real time on the dashboard
8 Teacher Review the group average, range, standard deviation, and any flagged outliers
9 Teacher Before the next class, click "Reset" to clear submissions (or create a new session)

12. Security Considerations

The teacher dashboard is protected by a shared password stored as an environment variable on the server. This password is never exposed to the client except as a localStorage token after successful login. Student submissions are public endpoints — anyone with the session link can submit. The session codes are random 8-character strings generated by nanoid, making them impractical to guess. IP addresses are captured with each submission for audit purposes but are not displayed on the dashboard. The database connection uses SSL encryption as required by TiDB Cloud. All traffic between the browser and Render is encrypted via HTTPS, which Render provides automatically with managed TLS certificates.


This documentation was generated for the Surviving to Thriving project hosted at https://surviving-to-thriving.onrender.com with source code at github.com/matthewstraub/surviving-to-thriving.

About

A classroom exercise where students rate themselves on a 1-10 scale from surviving to thriving, selecting an emoji and entering their name. The teacher has a protected dashboard showing all responses in real-time, group averages, outlier detection, and a reset button. Students access via QR code or link.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors