StudyCircle is a mobile-friendly web app for Cal Poly students. Verified campus accounts join course/professor groups to organize meetups, chat, message classmates, and share notes. ClassAI uses those notes to answer questions with sources and generate cards for Quizlet import.
| Layer | Technology | Purpose |
|---|---|---|
| App | Next.js 16.3.4 App Router, React 19.2.8, TypeScript 5 | Server-rendered pages, interactive client components, API routes, and Server Actions in one app |
| Styling | Tailwind CSS 4, global CSS, CSS Modules | Responsive layouts and component styles |
| Runtime | Node.js 22.22.2 (.nvmrc), npm, tsx |
Runs Next.js, TypeScript scripts, and the background worker |
| Backend | Supabase Auth, Postgres, Storage | Accounts, relational data, access policies, and private uploaded files |
| AI | OpenAI SDK, Postgres pgvector |
Source extraction, embeddings, retrieval, and grounded answers |
| Supabase Auth email + Resend | Verification through configured SMTP; Resend HTTP API for notification testing | |
| Quality | ESLint 9, TypeScript, Node test runner, PGlite | Linting, type checks, unit tests, and local SQL tests |
Other runtime libraries are @supabase/ssr for cookie-based sessions, @supabase/supabase-js for database/storage calls, file-type for file-signature detection, pdf-lib for PDF inspection and page splitting, mammoth for DOCX text, yauzl for DOCX archive checks, and sharp for image processing. Audio validation requires the system executable ffprobe.
Browser
└─ Next.js pages + React client components
├─ API routes / Server Actions → Supabase Auth + Postgres
└─ Authorized file operations → private Supabase Storage
Postgres job queue
└─ Separate Node worker → Storage + OpenAI → passages / AI replies
└─ Browser polls APIs for messages and processing status
Server Components load the authenticated user and class context. Client components manage interactive forms, selected channels, messages, uploads, and previews with React hooks. API routes handle client requests; Server Actions handle operations such as profile edits, enrollment, and meetups. The active workspace uses HTTP polling for new messages and upload status.
The core data hierarchy is course → professor/term subspace → enrolled sections. A student's section enrollments determine access to the corresponding class group. Postgres also stores profiles, meetups and attendance, chat messages, direct messages, and notification preferences.
The active notes system separates each student's contribution (kb_uploads) from its deduplicated processing asset (kb_assets). Indexed passages and embeddings support retrieval. Shared class chat and private AI conversations use study_messages; human direct messages use class_direct_messages.
Supabase Row Level Security (RLS) and server-side authorization enforce class membership and private-message visibility. The browser uses a publishable key; privileged operations and worker jobs use a server-only secret/service-role key. Mutations validate inputs and origin where applicable, with database-backed quotas for messages, uploads, and AI requests. File downloads recheck access before issuing expiring signed URLs.
- Sign up and verify. A student registers with an
@calpoly.eduaddress, verifies through Supabase Auth email, and signs in with a cookie-based session. Protected pages require a verified account. - Complete onboarding and enroll. The student completes their profile and selects existing course sections from the catalog. Students do not create catalog entries. An account-specific HTTP-only cookie remembers the last selected class on that browser.
- Open a class.
/spacesopens the remembered accessible class, or an enrolled fallback./chatsopens its chat. The class header switches between Meetups, Chat, Classmates, and Files; switching classes preserves the current tab. Students without enrollments go to Profile. - Organize study sessions. Members create and edit meetups, RSVP or leave, and view attendee information subject to privacy rules. Meetup lifecycle changes are implemented through Server Actions and database functions.
- Chat and connect. Shared channels include General, Homework, Exam prep, Projects, Resources, and Off topic. Classmates provides one-to-one messages and a private Circle AI conversation. Mentioning
@Circle AI,@AI, or@ClassAIin shared chat queues a class-visible AI response; messages in private AI chat queue a private response. - Share and study files. Students upload notes in Files, preview or download authorized originals, and track processing. Uploaders can remove their contributions or retry failed processing. AI answers include source references; generated question/answer cards can be copied as tab-separated text for manual Quizlet import. There is no Quizlet API integration or internal quiz player.
- The upload API checks membership, quotas, request size, file signatures, and format limits, then stores originals in the private
class-notesbucket. - SHA-256 deduplication shares extraction work within a class while preserving separate contributions and ownership.
- The worker claims durable jobs and extracts text: plain text and DOCX locally, PDF pages and images through OpenAI vision, and audio through transcription.
- Extracted passages retain page, paragraph, or timestamp references. OpenAI embeddings are stored in Postgres with
pgvector. - For an AI question, the worker retrieves relevant passages using semantic and lexical ranking, includes recent conversation context, and requests structured output. It validates the returned sources and saves the answer/cards for the UI to fetch.
- Jobs use leases, retries, and backoff so worker restarts can recover unfinished work. Upload processing and answer processing run independently. Removing a final contribution removes its indexed passages and queues original-file cleanup; historical chat answers remain.
OpenAI integrations are the Responses API for extraction and answers (default gpt-5.4-mini, configurable), Embeddings API (text-embedding-3-small, 1,536 dimensions), and Audio Transcriptions API (whisper-1). Uploaded content is treated as untrusted reference material. Answers are probabilistic; citations let students check the original sources.
Supported inputs are PDF, images, plain text, DOCX, and audio. Main limits are 1–5 files per submission, 25 MB per file, a 30 MB request ceiling, 60 PDF pages, and one hour of audio. DOCX embedded images require separate uploads. Video, slides, spreadsheets, scheduled summaries, and automatic Quizlet publication are outside the current implementation. See AI setup and limits.
AI reply bodies render Markdown (including tables, lists, and code) with react-markdown and remark-gfm. remark-math, rehype-katex, and KaTeX render inline $…$ / \(…\) and display $$…$$ / \[…\] equations. Code stays literal; raw HTML and remote images are disabled. Human messages and Quizlet exports remain plain text. Run npm run test:markdown for rendering tests, or open /preview/markdown in development for a visual check. Restart the worker after deploying changes to its formatting instructions.
Paths below are relative to the app. Class-scoped study and classmates requests use a class query parameter containing the subspace ID.
| Endpoint | Methods | Responsibility |
|---|---|---|
/api/auth/{signup,login,logout,resend,verify,callback} |
Varies by operation | Supabase account creation, sessions, and verification |
/api/study/messages |
GET, POST, PATCH | Read/send shared or private AI messages; retry failed AI requests |
/api/study/uploads |
GET, POST | List contributions and upload notes for indexing |
/api/study/uploads/[id] |
GET, POST, DELETE | Preview/download, retry processing, or remove an owned contribution |
/api/classmates |
GET, POST, PATCH | Class roster, paginated direct messages, sending, and read receipts |
/api/notifications/test |
POST | Send the signed-in user a test email through Resend |
/api/chat/overview, /api/chat/messages |
GET; GET/POST | Separate chat implementation retained in the repository |
/api/class-files, /api/class-files/[id]/download |
GET/POST; GET | Separate file/attachment implementation retained in the repository |
The active Chat and Files pages use /api/study/*. The separate class_files APIs/components and legacy lecture code are not the active Files view. Old class Lectures URLs redirect to Files. Notification preferences and a test email endpoint exist, but automatic event notification dispatch is not wired up. Supabase handles verification emails; it does not use the placeholder verification helper in src/lib/email.ts.
| Location | Contents |
|---|---|
src/app/ |
Landing/auth pages, protected workspace routes, API handlers, and Server Actions |
src/components/study/ClassWorkspace.tsx |
Active class chat, private AI, and indexed Files UI |
src/components/classmates/ |
Class roster and direct-message UI |
src/features/class-meetups/ |
Meetup UI, validation/access, and actions |
src/lib/knowledge/ |
Upload validation, extraction, retrieval, OpenAI integration, and worker logic |
src/lib/supabase/, src/lib/auth.ts, src/proxy.ts |
Supabase clients, authentication, and session refresh |
scripts/ |
Worker entry point, environment/hosted checks, and catalog validation |
supabase/migrations/ |
Versioned SQL schema, functions, and access policies |
tests/, colocated *.test.* files |
SQL, feature, and validation tests |
docs/ |
Detailed setup, feature contracts, and verification notes |
nvm use
npm ci
cp .env.example .env.local
# Fill in .env.local, then:
npm run devRun the AI worker in a separate terminal:
npm run worker| Environment variable | Purpose |
|---|---|
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY |
Browser-safe Supabase key |
APP_URL |
Canonical app origin; localhost for development, HTTPS in production |
SUPABASE_SECRET_KEY or SUPABASE_SERVICE_ROLE_KEY |
Server/worker privileged Supabase access |
OPENAI_API_KEY |
Server/worker OpenAI access |
OPENAI_RESPONSE_MODEL |
Optional extraction/answer model override |
FFPROBE_PATH |
Optional executable path; defaults to ffprobe |
RESEND_API_KEY, EMAIL_FROM |
Optional notification test configuration with a verified sender |
Configure verification SMTP and Auth redirects in Supabase separately. SMTP_URL appears in the example environment file but is not used by the current mail implementation. Never put privileged keys in NEXT_PUBLIC_ variables or commit secrets. Follow team setup and email setup.
The repository currently contains 18 SQL migration files: 202609050001–202609050016 and 202609060001–202609060002. Version 202609050004 is a historical marker without executable SQL. Compare hosted migration history and apply only missing reviewed versions; do not reset the shared database. The database inventory describes the original 17-table baseline, not the complete current schema.
Production requires a server-capable Next.js deployment (npm run build, then npm start for Node hosting) plus a supervised persistent npm run worker process. Next.js alone does not drain AI jobs. Configure private Storage, Auth redirects/SMTP, server secrets, ffprobe on web and worker hosts, and suitable upload size/time allowances.
npm test
npm run test:auth
npm run test:knowledge
npm run typecheck
npm run lint
npm run buildAdditional scripts cover feed, catalog, profiles, and email notifications. npm run check:supabase checks hosted Auth configuration and anonymous denial for the original 17-table contract; it does not validate all later migrations, Storage, or worker processing. Local tests and fictional preview pages do not establish hosted readiness. See remaining Files acceptance checks and the detailed setup guides before deployment. Some older feature documents describe historical implementations; the active route wiring and SQL migrations are the implementation reference.