CN331 Software Engineering · Project Presentation
BoardWipe
แพลตฟอร์มชุมชนคนเล่นบอร์ดเกม — หาเพื่อน หาเวลา แล้วเปิดกล่องเล่นกัน
Phetphong Kanmud
6710615169
Phudinan Jenjobketr
6710545028
Tortawan Luangaramchai
6710615128
Live: boardwipe.onrender.com Release v1.0.0 CI: passing Coverage 97%
Problem & Value Proposition
ปัญหาของคนอยากเล่นบอร์ดเกม
ปัญหา
ไม่รู้ว่าใครเล่นเกมไหนเป็น หรือใครมีเกมนั้นอยู่
นัดเวลาว่างตรงกันยาก
ข้อมูลกระจายอยู่หลายแชต หลายแอป
BoardWipe ช่วยอย่างไร
คลังเกม — เลือกจาก Catalog (Wikidata) ระบุว่า “เล่นเป็น” / “มีเกม”
เพื่อน — ค้นหาผู้เล่นและส่งคำขอเป็นเพื่อน
เวลาว่าง — ปฏิทินเวลาว่างบนโปรไฟล์
แชต — ข้อความส่วนตัว พร้อมแจ้งเตือนทางอีเมล
ผู้ใช้หลัก: นักศึกษาและคนทั่วไปที่อยากหาเพื่อนเล่นบอร์ดเกม
Live Software Demonstration · boardwipe.onrender.com
เส้นทางการสาธิต (Core User Journey)
เข้าสู่ระบบ → หน้าโปรไฟล์
เพิ่มเกมจาก Catalog เข้าคลัง (เล่นเป็น / มีเกม)
ค้นหาผู้เล่น → ส่งคำขอเป็นเพื่อน
สลับบัญชี → ยอมรับคำขอ
เพิ่มเวลาว่างในปฏิทิน
ส่งแชต → แจ้งเตือนทางอีเมล
กรอกข้อมูลผิด → ระบบแจ้งเตือน (Boundary case)
บัญชีที่ใช้สาธิต
ผู้ใช้ A — ส่งคำขอ / ส่งแชต
ผู้ใช้ B — ยอมรับ / รับแชต
รันบน Production จริง · DEBUG=False · HTTPS
Architecture · C4 Model
สถาปัตยกรรมระบบ
Browser → Render (HTTPS) → Gunicorn → Django [accounts · chat] → PostgreSQL | ภายนอก: Wikidata · Cloudinary · Gmail SMTP
Architecture · Modular Monolith
แบ่งขอบเขตเป็น Django Apps
accounts ผู้ใช้ · โปรไฟล์ · เพื่อน · Catalog เกม · คลังเกม · เวลาว่าง
chat ข้อความส่วนตัว · แจ้งเตือนทางอีเมล (จำกัด 1 ฉบับ / 15 นาที)
config Settings · URL หลัก · WSGI · ตั้งค่า Production บน Render
chat ใช้ User จาก accounts ทางเดียว — accounts ไม่ import chat จึงไม่มี Circular Import
ทำไมเลือก Modular Monolith แทน Microservices?
ทีม 5 คน ระบบขนาดนี้ — Deploy เดียว ฐานข้อมูลเดียว ดูแลง่าย ไม่ต้องจัดการ Network ระหว่าง Service
ข้อมูลผูกกันแน่น (เพื่อน ↔ แชต ↔ คลังเกม) — Query ข้าม App ได้ใน Transaction เดียว
แบ่ง App ตามขอบเขตไว้แล้ว ถ้าโตขึ้นค่อยแยกเป็น Service ได้ภายหลัง
Database · ERD
โครงสร้างฐานข้อมูล (7 Models)
1 : N ×2
1 : N
0..1 : N สร้าง
1 : N
0..1 : N
1 : N ×2
1 : N ×2
M : N เพื่อน
User
id · username email (unique) display_name · bio
favorite_genre favorite_boardgame profile_picture email_notifications
FriendRequest
from_user → User to_user → User created_at
FreeTime
user → User date start_time end_time (> start)
Boardgame (Catalog)
external_id (Wikidata) name cover · cover_url
min / max_players genres rating created_by → User
ProfileBoardgame
user → User boardgame → Boardgame name · picture
is_known is_owned
Message
sender → User recipient → User body created_at
ConversationNotification
recipient → User sender → User last_notified_at
Clean Code · Transactions & ORM Queries
ตัวอย่างโค้ดจากโปรเจกต์จริง
@transaction.atomic — สร้างเกม + เพิ่มเข้าคลัง
@transaction.atomic
def save (self):
"""Create the catalog game and add it
to the user's profile as known."""
game = super().save(commit=False )
game.genres = Boardgame.format_genres(
self.cleaned_data["genre_choices" ])
game.created_by = self.user
game.save()
ProfileBoardgame.objects.create(
user=self.user, name=game.name,
boardgame=game, is_known=True )
return game
accounts/forms.py — สองตารางสำเร็จพร้อมกัน หรือไม่บันทึกเลย
ป้องกัน N+1 Query
# โปรไฟล์: ดึงเกมพร้อม Catalog ใน query เดียว
"profile_boardgames" :
user.profile_boardgames
.select_related ("boardgame" ),
# ค้นหาผู้เล่น: โหลดคลังเกมของทุกคนครั้งเดียว
users = users.distinct().order_by("username" )
.prefetch_related ("profile_boardgames" )
# หน้าเพื่อน: คำขอพร้อมข้อมูลผู้ส่ง
user.received_friend_requests
.select_related ("from_user" )
accounts/views.py · chat/views.py
Quality Evidence · Testing & CI/CD
หลักฐานคุณภาพซอฟต์แวร์
202
Test cases — ผ่านทั้งหมด
97%
Statement coverage (เกณฑ์ ≥ 80%)
4
ด่านตรวจใน GitHub Actions
GitHub Actions — ทุก Push / PR เข้า main
Black — Format Flake8 — Lint Bandit — Security scan Tests + Coverage (fail < 80%)
Security Hardening บน Render
DEBUG=False · SECRET_KEY จาก Environment HTTPS redirect · HSTS 1 ปี Secure / HttpOnly cookies · CSRF trusted origins
Agile Governance
กระบวนการทำงานของทีม
GitHub Projects ติดตาม User Story บน Board · ประเมินงานด้วย Story Point ในแต่ละ Issue
Branch ต่อ Feature feat/… fix/… chore/… → Pull Request → Review → Merge
PR Template Related Issue · Summary · Test Evidence · Reviewer Checklist
21
Pull Requests ที่ Merge
Burn-down Chart · Story Points จาก GitHub Issues
Story Points คงเหลือ (Aug 31 – Nov 8)
ช่วงว่างระหว่าง Sprint
Sprint 1 Sprint 2 Sprint 3
0 10 20 30 40 50 60 70
Aug 31 Sep 14 Sep 29 Oct 12 Oct 26 Nov 8
Story Points คงเหลือ
61
53
33
+18 SP (Nov 6)
9
0
คงเหลือจริง
เส้นอุดมคติ
เพิ่มขอบเขตงาน
Sprint Velocity (SP)
Sprint 1 8
Auth (3) · Profile (5)
Sprint 2 21
Own / Known Game · Friend · Search (5 ×4) · Fix 1
Sprint 3 52
Free Time (20) · Chat (13) · Email (8) · Visual (8) · Fix ×3
เฉลี่ย 27 SP / Sprint
+18 SP (Nov 6): เพิ่ม US-09 Email (8) · US-10 Visual Design (8) · Fix 2 รายการ (1+1)
รวม 81 SP · Issue ที่ไม่มี SP (fix/chore) นับ 1 SP
Sprint Retrospectives
บทเรียนของทีม
Sprint 1
Start
ตกลงขอบเขต User Story ให้ชัดก่อนเขียนโค้ด เขียน Unit Test ควบคู่การพัฒนา ใช้ GitHub Milestone ผูกทุก Issue
Stop
เลิกทำงานใกล้เดดไลน์ — กระจายงานตลอด Sprint
Continue
Sprint 2
Start
ใช้ CI/CD Pipeline ตรวจโค้ดอัตโนมัติทุก PR ตรวจด้วย Black · Flake8 · Bandit · Coverage Merge main เข้า branch ก่อนเปิด PR
Stop
Merge ช้า — ยิ่งมี PR อื่นเข้าก่อนมาก ยิ่งเกิด Conflict ง่าย วางแผนไม่ละเอียด จนงานไปกองใกล้กำหนดส่ง
Continue
1 Branch ต่อ 1 Feature / Fix เข้าประชุมตรงเวลา
Capstone Deliverables
สรุปสิ่งที่ส่งมอบ
รายการ หลักฐาน
Live Cloud App boardwipe.onrender.com · DEBUG=False · HTTPS ✓
Clean Architecture Modular Monolith (accounts · chat) · Transactions · select/prefetch_related ✓
Automated Quality GitHub Actions · 202 tests · Coverage 97% · Black / Flake8 / Bandit ✓
Documentation README (Setup · C4 · ERD · Tests) · Tag v1.0.0 ✓
ขอบคุณครับ