Design-Based Research Capstone

Communication System

Class discussion is moving out of Slack and into the course site, next to the work it is about. Class-wide announcements, per-week chat, and a rich-text composer with emoji already ship; still to build are a thread on every assignment, 1:1 direct messages, GIFs in the composer, and Slack-style emoji reactions.

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 Samarth, Akshajh, Tarun

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 Samarth, Akshajh, Tarun

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
Design Settled
Designed — Not Built
Project Leads Perry, Syown, Leon

Direct Messages

1:1 conversations with a real security boundary

Design settled in issue #27, nothing built yet
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 backend domain rather than being squeezed into two-person Groups. Group chat ships with membership checks commented out — the right call for a class feed where everyone reads everything, and the wrong one for a private conversation. DMs are stored in the database through JPA rather than the S3 JSONL files group chat uses, so "only these two people" is enforced in the query, and sender identity comes off the STOMP Principal instead of whatever the client claims.

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.