Design-Based Research Capstone

OCS Communication Systems

Students are extending the OCS communication system with chat, announcements, assignment discussions, direct messaging, calendar integration, and reusable presentation components. The work includes maintaining the real-time WebSocket service and connecting these features to the existing course site, backend APIs, security, and data model. Students will also develop the OCS SASS grammarβ€”a small, purpose-built styling system for consistent, responsive, reusable components across the OCS GitHub Pages ecosystem.

Class-wide announcement chat pinned to the top of the CSA course page
View Screenshot

Main announcements page: one class-wide thread per course, pinned above the course timeline. Captured signed out, so it runs in local preview with sample messages. Skeleton UI, not the final version β€” layout, styling, and copy will all change as the feature gets polished.

Shipped
Project Leads Akhil, Skandan, Sathwik

Class Announcements

One class-wide thread per course, pinned above the course timeline

βœ“ `announcement_chat.html` renders one class-wide thread per course, pinned at the top of the page
βœ“ Shipped in PR #24, with the build and verification writeup in issue #25
βœ“ No backend changes needed β€” it talks to the group chat already in Open-Coding-Society/spring
βœ“ Groups create themselves on first use, so a new course works without anyone seeding a Groups row
βœ“ Signed-out visitors get the whole UI through a localStorage preview mode, which is what the screenshot shows
βœ“ Checked against a real local Spring instance rather than a mock: JWT login, group auto-creation, live send and receive over the actual WebSocket
REST at /api/groups STOMP over SockJS at /ws-chat Broadcast on /topic/group/{groupId} JWT session against the Spring backend localStorage preview mode Jekyll include (announcement_chat.html)

About

One announcement thread per course, keyed on a group name like csa-announcements and pinned above the course timeline. It reuses the group chat that already ships in Open-Coding-Society/spring, so nothing new had to be built on the backend to get it live. The group is created on first use, which means adding a course never means seeding a database row by hand.

Impact

Class-wide messages live next to the coursework instead of in a separate app
The site already knows who you are through its JWT session β€” no second login
Create-on-first-use means a new course needs no manual database setup
Verified end to end against a real Spring instance, not a mock
View Full Screenshot
Week 0 card with its per-week chat expanded below the assignment list
View Screenshot

Sub-task chat system/UI: every week card carries its own thread, collapsed by default and scoped to that week. Skeleton UI, not the final version β€” layout, styling, and copy will all change as the feature gets polished.

Shipped
Project Leads Akhil, Skandan, Sathwik

Per-Week Chat

Every week card carries its own thread, collapsed by default

βœ“ `week_chat.html` renders one thread per week card (W0, W1, and so on), separate from every other week
βœ“ Collapsed by default, so a week card stays readable until someone opens the chat
βœ“ Same create-on-first-use behavior as announcements, one group per (course, week)
βœ“ Currently backed by localStorage only while the Spring backend waits on a deploy
βœ“ The STOMP/SockJS wiring gets switched back on once the backend is running on real infrastructure
βœ“ Shipped alongside announcements in PR #24
One group per (course, week) localStorage message store (current) REST at /api/groups (pending deploy) STOMP over SockJS at /ws-chat (pending deploy) Jekyll include (week_chat.html) Rendered from sprint-week-card.html

About

Every week card on the course timeline carries its own collapsible chat, scoped to that week alone. It is included from sprint-week-card.html, which already has the week number and sprint key in scope, so a new week gets a thread for free. While the backend waits on deployment, messages are kept in localStorage in the viewer's own browser.

Impact

Questions land on the week they are about instead of scrolling away in a general channel
One thread per week keeps Unit 3 questions findable in one place
Adding a week to a course adds its chat automatically
Works today with no backend, so the UI can be reviewed and polished in parallel with the deploy
View Full Screenshot
Next Up
Planned
Project Leads Samarth, Akshajh, Tarun

Assignment Threads

A thread on every assignment, not just every week

βœ“ The finest grain today is a week, so every assignment inside Week 0 shares one thread
βœ“ One thread per assignment, keyed on its own slug (csa-week-0-home-page-game-feedback) instead of the week
βœ“ Shown on the task row in the week card and on the assignment page
βœ“ Same create-on-first-use behavior, so a new assignment never means a new database row
βœ“ An unread count on the task row, so it is obvious where the conversation is
Per-assignment slug keys Task row + assignment page surfaces Create-on-first-use groups Unread badges

About

Week-level threads are still too coarse: every assignment inside Week 0 currently shares a single conversation. Re-keying the thread on the assignment's own slug gives each piece of work its own discussion, surfaced both on the task row in the week card and on the assignment page itself, with an unread count so nobody has to go hunting for where people are talking.

Impact

Questions attach to the assignment they are about, not just the week
Unread counts point students at live conversations
No new database seeding β€” threads still create themselves on first use
Follow Issue #13
Slack Parity
Planned
Project Leads Samarth, Akshajh, Tarun

GIFs and Slack-Parity Messaging

GIFs in the composer, and the Slack habits people still leave the site for

βœ“ The shared composer already ships bold, italic, underline, strikethrough, lists, font and size controls, and a 90-emoji picker (PR #36)
βœ“ Emoji today are inserted into the message body β€” reacting to somebody else's posted message is the piece that does not exist yet
βœ“ GIFs are not supported at all: the composer accepts text and formatting and nothing else
βœ“ Planned: a GIF picker in the composer toolbar, sitting beside the emoji button it already has
βœ“ Planned: emoji reactions on a posted message, with a per-emoji count and the list of who reacted
βœ“ The chat payload already carries an `image` field that is null on every message sent today, so an attachment has a slot to ride on
βœ“ Slack-style link previews already ship, so the renderer can already draw a card underneath a message
βœ“ Every message renders through the shared sanitiser in rich-text.js, so any new embed gets allow-listed there rather than passed through raw
βœ“ Reaction counts are the one piece that needs real backend work β€” they are per-message state, not another field on the message
assets/js/chat/rich-text.js (shared composer) image field on the group chat payload Shared message sanitiser Link preview renderer GIF search API (not yet chosen) Reaction counts on the Spring side

About

Rich text and emoji insertion landed in PR #36, which covers the writing half of Slack parity. What is left is the part people reach back to Slack for: dropping a GIF into a message, and reacting to somebody else's message instead of replying to it. GIFs can ride the image field the chat payload already carries and render through the same allow-listed sanitiser as everything else, which keeps the message model and the security story unchanged. Reactions are the piece that genuinely needs backend work, since a count of who reacted with what is per-message state rather than another field on the message.

Impact

Closes the gap that still sends people to Slack for anything more expressive than formatted text
Reactions collapse a run of "ok", "got it", "+1" replies into a single tap, which keeps a class thread readable
GIFs reuse the existing image field, so the message model does not have to change to carry them
New embeds go through the sanitiser that already exists, so the security review stays in one place
Follow Issue #13
Direct messages get their own backend domain rather than being squeezed into two-person Groups
View Screenshot

Direct messages get their own private backend domain instead of being squeezed into a two-person group. The conversation is stored in JPA so only the matched participants can read it, and sender identity comes from the authenticated STOMP principal rather than a client-supplied name.

Designed β€” Not Built
Project Leads Perry, Syown, Leon

Direct Messages

1:1 conversations with a real security boundary

βœ“ Design settled in issue #27, built and deployed
βœ“ Its own backend domain at mvc/directmessages/, not two-person Groups
βœ“ GroupsApiController / GroupChatApiController ship with membership checks commented out: right for a class chat where everyone can read everything, wrong for a DM
βœ“ Two entities: DirectMessageConversation (participantA, participantB, unique and canonicalized so A.id < B.id) and DirectMessage (conversation, sender, body, sentAt)
βœ“ Stored in the database through JPA instead of the S3 JSONL files group chat uses, so "only these two people" is enforced in the query
βœ“ REST under /api/dm: list your conversations (identity from SecurityContextHolder, no personId in the path), get-or-create from otherPersonId, and messages with a 403 for non-participants
βœ“ That 403 check is the security boundary, so it does not get commented out
βœ“ Realtime reuses the same broker: clients send to /app/dm.send, the server broadcasts on /topic/dm/{conversationId}
βœ“ Sender identity comes from the STOMP Principal, not a client-supplied name β€” GroupChatWebSocketController.resolveSender() trusts the client today, and a wrong name in a class feed is survivable where a wrong sender on a DM is not
βœ“ Frontend _includes/dm_chat.html reuses the shipped connect/subscribe/send skeleton, plus a conversation list page
βœ“ Still open: read receipts β€” no readAt column yet, which is cheap to add now and a migration later
Spring domain at mvc/directmessages/ JPA entities (DirectMessageConversation, DirectMessage) REST under /api/dm STOMP /app/dm.send β†’ /topic/dm/{conversationId} SecurityContextHolder identity STOMP Principal for sender identity _includes/dm_chat.html

About

Direct messages get their own secure backend domain instead of being squeezed into a shared group chat. Private conversations stay isolated by design: only the two participants can read them, sender identity comes from the authenticated user, and the conversation is stored in the database rather than in the class-wide JSONL feed.

Impact

Private conversation gets a real, enforced security boundary rather than a commented-out one
Canonicalized participant pairs mean one conversation per pair, not two
Reuses the shipped connect/subscribe/send frontend skeleton, so the UI work is small
Read receipts stay cheap to add now and expensive to add later
Read the DM Design (#27)
Blocker
Planned
Project Leads Samarth, Akshajh, Tarun

Teacher Moderation

Delete already works on the backend and nothing calls it

βœ“ The backend answers DELETE /api/groups/chat/{groupId}/messages/{messageId}
βœ“ Nothing in the UI calls it today
βœ“ Teachers need a delete button before this replaces Slack for announcements
DELETE /api/groups/chat/{groupId}/messages/{messageId} Role-gated UI control

About

The moderation endpoint is already implemented on the Spring side β€” it is the frontend that has no way to reach it. Until a teacher can delete a message from the page, the announcement chat cannot responsibly take over from Slack as the class-wide channel.

Impact

Blocks the Slack cutover for announcements until it lands
No backend work required β€” the endpoint already exists
Follow Issue #13

Team

Who owns what, straight off the UGRC-CSA sprint board

Announcements, per-week chat, assignment threads, and teacher moderation β€” Samarth, Akshajh, Tarun
Direct messages, from the #27 design through the conversation list and the Spring side β€” Perry, Syown, Leon
EC2 provisioning, CI/CD, HTTPS on a real domain, and monitoring β€” Sathwik, Akhil, Skandan

Why Not Stay on Slack

The case for moving discussion onto the course site

Questions land in a general channel with nothing tying them to the assignment, then scroll away and get asked again.
It's a second login and a second app. The site already knows who you are through its JWT session against the Spring backend.
Slack messages can't attach to a course, week, assignment, or a person's progress, which is exactly what unread badges, teacher moderation, and "every question about Unit 3" need.
History, search, and deletion become ours instead of a workspace admin's.

What Has to Land First

Straight off the UGRC-CSA sprint board

EC2 and infra (Sathwik, Akhil, Skandan). The Spring backend only runs locally and on the maintainers' deploy, and chat is only as real as the backend behind it. Issues #5–#10 cover provisioning, CI/CD, HTTPS on a real domain, and monitoring.
Issue #26 covers the Groups admin page, where chat-created rows now sit beside roster groups with nothing to tell them apart.
CSA page and chat (Samarth, Akshajh, Tarun). Issue #11 owns the page, #13 polishes and extends the widgets, #15 QAs them across every course and week.
DMs (Perry, Syown, Leon). Issue #17 is the design, answered by #27; #19 is the conversation list and thread UI; #21 is the Spring side.
One gap worth repeating: group chat history lives in S3. Without credentials in the deploy environment, send and receive work but scrollback comes back empty. That's already true of lesson_chat.html, but it does block a real Slack migration.