Skip to content

Latest commit

 

History

History
328 lines (271 loc) · 18.7 KB

File metadata and controls

328 lines (271 loc) · 18.7 KB

ClassProject — Group Formation Web App: Specification

Version: 0.3 · Date: 2026-07-02 · Owner: John Yao

A web app for a class of ~45 undergraduate students to post project ideas, form groups of teammates, and submit end-of-project reports with confidential peer reviews for the instructor.


1. Tech stack

Layer Choice Why
Language / framework Python 3.13 + Django 5.2 LTS Batteries included: auth, forms, ORM, admin site — minimal code for an app this size. LTS is supported into 2028; 3.13 is the newest Python on Azure App Service
Database (production) Azure Database for PostgreSQL — Flexible Server (Burstable B1ms) Django's first-class database; no driver friction on Azure
Database (local dev) SQLite (Django default) Zero setup on your PC; switching to PostgreSQL in production is a one-line settings/env change
Hosting Azure App Service (Linux, Python 3.13), Basic B1 plan Managed, HTTPS out of the box, native Python support
Web server Gunicorn (App Service's default for Django) Standard
Static files WhiteNoise Serves CSS/JS directly from the app — no separate storage account needed at this scale
Email SendGrid via django-anymail Same SendGrid account/API key you use from ASP.NET Core; Anymail plugs it into Django's standard send_mail
Frontend Django server-rendered templates + Bootstrap 5 (CDN) No JavaScript framework needed; fastest to build and maintain
CI/CD GitHub Actions → App Service deploy Auto-generated by Azure when you connect the repo

Django concepts you'll meet (mapped to your ASP.NET Core experience): models ≈ EF Core entities, migrations ≈ EF migrations, views ≈ controller actions, templates ≈ Razor views, forms ≈ model binding + validation attributes, Django admin ≈ a free auto-generated CRUD back office (no ASP.NET equivalent — this is a big time-saver here).


2. Roles

Role Who Capabilities
Anonymous visitor Anyone Register, verify email, sign in. Nothing else — all content requires sign-in.
Student Any verified, signed-in account Everything in §4
Instructor You, via a Django superuser account Django admin site: view/edit all data, and the only role that can see peer-review scores/comments. Can export reviews to CSV for grading.

The instructor works through the built-in Django admin at /admin — no custom dashboard is built for v1 (can be added later if the admin feels clunky).


3. Functional specification

3.1 Accounts & profiles

  • Registration collects: email (used as the login username), password, full name, year of birth, department, major, study year, gender, height (cm), languages spoken, interests, skills.
  • Email verification (SendGrid): on registration the account is created inactive and a verification link (signed token, 3-day expiry) is emailed. The user cannot sign in until they click it. A "resend verification email" link exists on the sign-in page.
  • Sign in / sign out with email + password. Django's standard session auth.
  • Profile page (/users/<id>/): visible to signed-in users only — never to the open internet — and shows only the publicly relevant fields (see table below). The personal fields (year of birth, gender, height, study year) are collected for later in-class data-analysis examples, not for display: they appear only to the student themselves (edit page) and to the instructor (admin).
  • Edit own profile: users can update every profile field (not email) at any time.

Field details:

Field Type / validation On public profile?
Email Unique, valid format; login identifier No — login only
Full name Required, ≤100 chars Yes
Year of birth Integer, 1950–2015 No — private
Department Required, ≤100 chars, free text Yes
Major Required, ≤100 chars, free text Yes
Study year Choice: 1, 2, 3, 4, 5+ No — private
Gender Choice: Male / Female / Prefer not to say No — private
Height (cm) Integer, 100–250 No — private
Languages spoken Free text, comma-separated (e.g. "Chinese, English") Yes
Interests Free text, multi-line Yes
Skills Free text, multi-line Yes

"Private" = visible only to the student themselves and the instructor.

3.2 Projects

  • Any signed-in student can create a project with: title (≤220 chars), description, keywords (comma-separated), group size (integer 2–5 — total members including the owner), talents needed, and the owner's contact info (free text — email / phone / WeChat, etc.). A student who already owns an open/fulfilled project, or is a member of someone else's project, cannot create one.
  • Owner can edit any field, with one guard: group size cannot be set below 1 + currently confirmed members.
  • Project status: openfulfilled, and either can become cancelled.
    • Fulfilled — automatic when owner + confirmed members = group size; reverts to open if the owner removes a member.
    • Cancelled — set by the owner at any time (typically to free themselves to apply to another project, see §3.3). Cancelling releases all members and declines pending applications. The project is not hidden: it stays on the list, sorted to the bottom, with a grayed-out background and a "Cancelled" status pill.
    • Un-cancel — the owner can reactivate their cancelled project (status returns to open; former members are not automatically restored — they re-apply if still interested) provided the owner is still free: not admitted into any other group, and no pending application of their own (they must withdraw it first).
  • Owner can also delete the project outright (confirmation page; removes it and its applications/memberships entirely). Cancel keeps the record for history; delete does not.
  • Project list (/, the home page): all projects. Open and fulfilled ones first (newest first), each showing title, owner, keywords, members joined / group size, and a status pill; cancelled projects sort to the bottom, grayed out, with a "Cancelled" pill. Simple keyword search box (filters title/keywords/description).
  • Project detail page: all fields, owner's contact info, current member list (linking to their profiles), and — prominently — the meet-first notice (§3.3) above the Apply button.

3.3 Applications & membership

Tone: the app finalizes teams, it does not match strangers. Students are expected to meet and agree offline first — applying is the confirmation step. The UI wording reinforces this everywhere:

  • Banner on the project list: “Found a project you like? Talk to its owner first — apply once you've agreed to team up.”
  • Project detail, above the Apply button: “Discuss with the owner (contact above) before applying. Your application should confirm what you've already agreed.”
  • The apply form has a required checkbox: “I have discussed this project with the owner.”
  • The owner's accept action is labelled Confirm member, not "accept".

Mechanics:

  • A student may apply to an open project with an optional short message, if eligible (below). At most one pending application at a time, app-wide — to apply elsewhere, withdraw the pending one first.
  • The owner sees applicants (linked to their profiles) on their project page and can Confirm or Decline each. Confirming creates a membership; when the team is complete (owner + members = group size), the project flips to fulfilled and any remaining pending applications are auto-declined.
  • The owner can remove a confirmed member at any time; the project reopens if it was full.
  • Eligibility — a student can apply only if all of these hold (re-checked when the owner confirms, since things can change while an application waits):
    1. They don't own an open or fulfilled project. An owner who wants to join someone else's project must first cancel their own (§3.2).
    2. They aren't already a member of any project (one group per student).
    3. They have no other pending application.
    4. The target project is open and isn't their own.
  • Notification emails keep everyone in the loop (full list in §6): the owner is emailed when someone applies; the applicant is emailed when their application is confirmed or declined (including auto-declines when the team fills up or the project is cancelled); team members are emailed when their project is fulfilled or cancelled. Notifications are best-effort (fail_silently) — an email outage never blocks the action itself, and the site remains the source of truth.

3.4 Stats card & bonus score

A card at the top of the project list shows:

  • Total projects submitted — count of open + fulfilled projects (cancelled and deleted don't count, since they no longer contribute to team supply).

  • Current bonus score — the extra points a student would earn by posting and fulfilling a project right now. Non-linear (logistic S-curve), designed around how many projects the class actually needs: 45 students in groups of 2–5 ≈ 12–14 projects. Encouragement stays near-maximal while supply is short, drops fastest right around the target, and levels off at the floor:

    score = round( 3 + 17 / (1 + e^((N − 12) / 2.5)) ) where N = open + fulfilled projects

    N (projects) 0 4 8 10 12 14 16 18 22+
    score 20 19 17 15 12 8 6 4 3

    Why not linear: 20 − N would punish the 6th poster heavily even though the class still needs ~7 more projects. The S-curve rewards every early poster close to the maximum, concentrates the drop where additional projects stop being needed, and never goes below 3.

  • The four constants (max 20, min 3, midpoint 12, steepness 2.5) live in settings so you can tune the curve without code changes.

  • This number is display-only / informational: the app does not record it per project or per student — you award actual points manually.

3.5 Reports & peer reviews

  • Available to every student who is the owner or a confirmed member of an open or fulfilled project (nav link "My report" appears once they're in a group).
  • The report form collects, about the project the student belongs to:
    1. Link to the project work (URL, required) — where the finished work lives. Form hint: “e.g. a GitHub repository, a project website, or a shared Google Drive / Baidu Pan link.” Teammates may all paste the same team link.
    2. My contribution to the project (text, required)
    3. What I did well (text, required)
    4. What can be improved (text, required)
    5. For each teammate (everyone in the group except the report author, owner included): a score 0–10 (required) and comments (optional).
  • The form displays clearly: “Teammate reviews are visible only to the instructor — your teammates will never see your scores or comments.”
  • One report per student per project. The student may edit and resubmit any time (latest version is kept, with a last-modified timestamp) — you decide the real deadline outside the app, or we can add a hard cutoff date later.
  • Visibility: the report sections (1–4) and all peer reviews are visible only to the instructor via the admin site. Students can see/edit only their own submission.
  • Admin includes a CSV export of all peer reviews (reviewer, reviewee, project, score, comments) for grading in Excel.

4. Data model

User (custom, email = username)
  email, password, is_active (false until verified), is_staff/superuser (instructor)
  full_name, birth_year, department, major, study_year, gender, height_cm,
  languages, interests, skills
  # birth_year, study_year, gender, height_cm are private: self + instructor only

Project
  owner → User            # a user may own at most one open/fulfilled project
  title, description, keywords, group_size (2–5, total incl. owner), talents_needed,
  contact_info, status (open|fulfilled|cancelled), created_at, updated_at

Application
  project → Project, applicant → User, message, discussed_with_owner (bool),
  status (pending|confirmed|declined|withdrawn), created_at, decided_at
  rule: at most one *pending* application per student, app-wide

Membership
  project → Project, member → User, joined_at
  unique(member) — one group per student (owner's "membership" is implied by ownership)

Report
  author → User, project → Project, work_url, contribution, did_well, to_improve,
  created_at, updated_at ; unique(author, project)

PeerReview
  report → Report, reviewee → User, score (0–10), comments
  unique(report, reviewee)

Notes: the custom User model must exist before the first migration (a well-known Django rule) — it's step 1 of the build. Free-text fields (languages, skills, keywords) stay free text for v1; structured tags are unnecessary at 45 users.

5. URL map

URL Page Access
/accounts/register/, /login/, /logout/, /verify/<token>/ Auth flows Anonymous
/ Project list + stats card + search Signed-in
/projects/new/, /projects/<id>/, /projects/<id>/edit/, /projects/<id>/cancel/, /projects/<id>/uncancel/, /projects/<id>/delete/ Project CRUD + cancel/un-cancel Signed-in; edit/cancel/un-cancel/delete owner-only
/projects/<id>/apply/ Apply form (with "discussed with owner" checkbox) Signed-in, eligible
`/projects//applications//confirm decline/, /projects//members//remove/` Owner actions (POST)
/users/<id>/ Public profile Signed-in
/profile/edit/ Edit own profile Signed-in
/report/ My report + peer reviews Signed-in, in a group
/admin/ Instructor back office Superuser

6. Email (SendGrid)

  • django-anymail with the SendGrid backend; the SENDGRID_API_KEY goes in an App Service application setting (never in code/git). Sender identity: reuse the verified sender from your ASP.NET app.
  • Emails sent by the app:
    • Verification link at registration (§3.1) — required for sign-in, so it is not fail-silent; everything below is best-effort (fail_silently=True).
    • Password reset (confirmed in review): Django's built-in flow, enabled since email is already configured. Without it you'd be resetting forgotten passwords by hand in the admin for 45 students.
    • Student notifications (§3.3): owner ← new application; applicant ← application confirmed / declined (incl. auto-declines on fulfillment or cancellation); team members (owner excluded — they took the action) ← project fulfilled / cancelled.
    • Admin notifications to every active staff account (the instructor — accounts.emails.notify_staff()): new user registered, project posted, project fulfilled. Recipients come from the database (is_staff), so there is no admin-email setting; seeding the instructor via createsuperuser turns them on.
  • Links inside notification emails are built from the SITE_URL setting (the service layer has no request to derive the host from).

7. Azure architecture & deployment

GitHub repo ──GitHub Actions──▶ App Service (Linux, Python 3.13, B1, gunicorn)
                                   │  app settings: SECRET_KEY, DATABASE_URL,
                                   │  SENDGRID_API_KEY, ALLOWED_HOSTS
                                   ▼
                    Azure Database for PostgreSQL Flexible Server (B1ms)
  • One resource group; App Service connects to PostgreSQL over the Azure backbone (firewall: allow Azure services; SSL required).
  • Config via environment variables (django-environ): local .env file (git-ignored) vs. App Service settings in production — same code both places.
  • Migrations run on deploy via the App Service startup command (python manage.py migrate && gunicorn config.wsgi).
  • DEBUG=False, HTTPS-only, secure cookies, HSTS in production settings.
  • Estimated cost: ≈ $13/mo (B1 App Service) + ≈ $13–15/mo (B1ms PostgreSQL); both have free-tier options if your subscription qualifies.

8. Non-functional

  • Scale: ~45 users, bursty around deadlines — B1 tiers are ample.
  • Security: Django defaults give CSRF, XSS-escaping, hashed passwords, SQL-injection-safe ORM. All pages except auth pages require sign-in. Peer-review data queryable only via admin.
  • Timezone: site-wide setting (confirm yours; assumed UTC+8 for now). English UI.
  • Backups: PostgreSQL Flexible Server automated backups (7-day default).

9. Remaining assumptions to confirm

Resolved in review (2026-07-02): group size = total members incl. owner (2–5); one group per student; one pending application at a time; an owner must cancel their project before applying elsewhere; password reset included; bonus score is display-only with a non-linear curve.

Still open:

  1. Reports remain editable indefinitely in v1 — deadlines are enforced by you outside the app. (A hard cutoff date is easy to add later if wanted.)
  2. Instructor tools = Django admin + CSV export, no custom dashboard in v1.
  3. Cancel semantics: cancelling releases all members and declines pending applications — even if the project was already fulfilled (the formed team dissolves and those students are free again). Cancelled projects stay visible at the bottom of the list (grayed, "Cancelled" pill) but don't count toward the stats-card N. Un-cancel restores the project to open without its former members, and is allowed only while the owner is not in another group and has no pending application.
  4. Bonus curve calibration: S-curve midpoint at 12 projects, sized for 45 students in groups of ~3–4. All four constants are settings, so tuning later needs no code change.

10. Build plan

# Milestone Contents Est.
1 Skeleton + accounts Django project, custom email-login User with all profile fields, register/sign-in/sign-out, profile view/edit, Bootstrap base layout, admin day 1
2 Projects CRUD, list + search, stats card with bonus score day 2
3 Groups Apply / confirm / decline / remove, one-pending-application + eligibility rules, cancel flow, auto-fulfill day 3
4 Reports Report + per-teammate review forms, instructor admin views, CSV export day 4
5 Email Anymail + SendGrid, verification flow, password reset day 5
6 Azure Provision resources, production settings, GitHub Actions, smoke test, seed instructor account day 6

Each milestone ends runnable locally (python manage.py runserver) so you can review as we go.