A competition where teachers build lessons in the builder, publish them to Explore, and get ranked. The submission pipeline already exists in production; this document specifies the front door, the entry marker and the scoring layer that turn it into a contest.
Turn the community shelf on Explore into content teachers compete to fillpartner-web and admin-web codebases, so the “what already exists” claims are verifiable. Everything from section 5 onward is a design proposal. Unresolved items are listed in Open questions rather than assumed.FLYER wants to run a “best content” competition so that teachers publish their own material to the Explore shelf on Teado.ai. Three requirements were given: a landing page teachers can read, functions for teachers to submit content to Explore, and a ranking report that produces ten prize winners.
The starting point is better than it looks. A teacher can already build a lesson in the builder, publish it to the community, have it reviewed by an admin, and see it appear on Explore with their name printed on the card. That path is live in production today and is used rarely, because nothing points at it.
So the problem is not “teachers cannot publish”. The problem is that publishing is invisible, unrewarded and unmeasured. A contest is a good instrument against all three, provided it is built on the existing pipeline instead of beside it.
| Metric | Definition | Type |
|---|---|---|
| Approved entries | Community items approved inside the contest window | Primary |
| Participating teachers | Distinct teachers with at least one approved entry | Primary |
| Adoption depth | Share of entries used by at least 5 teachers outside the author's school | Primary — measures quality, not volume |
| Builder activation | Entrants who had never created content before the contest | Secondary |
| Review turnaround | p50 and p90 hours from submit to decision | Guardrail |
| Rejection rate | Share of entries rejected at first review | Guardrail — a high rate means the brief or the checklist failed |
| Retention after the contest | Teachers who publish again in the 30 days after the awards | The real test of whether this was worth running |
Read from the current source, not assumed. Every row below is live in production.
| Capability | Where it lives | State |
|---|---|---|
| Content builder — 12 question types (multiple choice, gap fill, matching, drag and drop, word ordering, reorder, flashcard, passage, open ended, dropdown, audio response, interactive video), an AI question generator and themes | /creator/[id], components/creator | Live |
| Publish to community — a modal with three visibility choices, of which one is “Public to the community — anyone can find and take this test” | /exams, my-exams/components/publish-modal, mutation partnerPracticeCheckPointsPublish(community: true) | Live |
| Content policy consent — a one-time gate a teacher must accept before publishing publicly | providers/flyer/content-policy | Live |
| Moderation queue — Pending / Approved / Rejected with a bilingual rejection reason | table check_point_review_requests; admin screen admin-web /users/check-point-request | Live |
| Community shelf on Explore — a “Community” source filter, with author credit printed on the card | /explore, views/exam-library | Live |
| Reuse signals — attempt counter per item, clone-to-my-library, assignment to classes, playlists | checkPoint.testCount, partnerPracticeCheckPointClone, assign_tests, featured playlists | Live |
| # | Gap | Why it blocks a contest |
|---|---|---|
| 1 | No campaign concept | Nothing marks an item as an entry. There is no window, no category, and no way to answer “how many entries do we have” without a hand-written query. |
| 2 | No landing page | Teachers have nowhere to read the rules, see the prizes or find the button, and marketing has nothing to link to from Zalo or email. |
| 3 | Submission is buried | The builder has no publish exit. A teacher who has just finished a lesson must leave the builder, open the test library, tick a checkbox and find a toolbar. Drop-off will be heavy at exactly the moment of highest motivation. |
| 4 | Review is a black box | Status is one table column and the rejection reason is a tooltip. Against a deadline, a teacher rejected on day 12 needs to see why and resubmit. |
| 5 | Authors get no feedback | Nothing tells a teacher that 40 other teachers used their lesson. That number is the real prize and it is currently shown nowhere. |
| 6 | No ranking of any kind | Review is binary approve or reject. There is no rubric score, no leaderboard and no report that could defend a choice of ten winners. |
One pipeline, three actors. Steps 3 and 6 already exist; the rest is the work.
/contest landing page: rules, categories, prizes, rubric, live counters.Usage-based scoring punishes late entries: a lesson published on the last day has no time to be used. The fix belongs in the calendar, not in the formula.
| Phase | Length | What happens |
|---|---|---|
| Announce | 1 week before | Landing page live in countdown state, notify-me capture, Zalo push. |
| Submission window | 4 weeks | Teachers submit. Review runs continuously against a 48-hour service level. |
| Usage window | 2 weeks after submissions close | Nothing new is accepted, so every approved entry gets at least 14 days live before metrics freeze. This is what makes the ranking fair. |
| Judging | 1 week | The jury scores the shortlist. The leaderboard freezes and is labelled provisional. |
| Awards | 1 day | Winners published on the same landing page, which then becomes the evergreen proof for the next round. |
Route /contest inside partner-web, localised vi and en like the rest of the app, and readable when logged out so that it can be shared outside the product.
The counters and the leaderboard read live data. A static poster goes stale on day two and stops being worth revisiting, which removes the main reason a teacher would return to the page mid-contest.
| State | Hero | Primary action |
|---|---|---|
| Countdown | Dates and “opens in N days” | Notify me — captures teachers before day one |
| Running | Days left and live counters | Join / Submit an entry |
| Judging | “Submissions closed — results on 20/10” | Browse the entries, which drives Explore traffic while judging runs |
| Ended | Winners, with their lessons embedded | Browse winning content · Register interest for the next round |
The mutation exists. The design work is putting it where the teacher already is, and making the aftermath legible.
| Entry point | Placement | Why there |
|---|---|---|
| Builder exit | After Save in the editor header: a success sheet whose primary action is “Submit to the contest” | The highest-intent moment. The builder has no publish exit at all today, which makes this the single highest-leverage change in the proposal. |
| Test library row | A row action and a bulk-toolbar action in /exams, beside the existing publish action | Covers the teacher who wants to enter a lesson built last month. |
| Contest page | “Submit an entry” opens a picker of eligible items from the teacher's library | Covers the teacher who arrives from the campaign rather than from inside the product. |
The eligibility checklist is the quality lever. It rejects thin entries before a reviewer spends time on them, and it teaches the standard while the teacher is still in a position to fix it.
A tab on the contest page, mirrored as a filter in /exams. One card per entry.
Three deliberate choices. The rejection reason is shown in full rather than as a tooltip. “Rejected” is renamed “Needs a fix” and carries a resubmit button, because inside a contest a rejection should read as a rally rather than a verdict. And a live entry shows the two numbers that make an author feel paid: teachers using it and learners reached.
Two surfaces, deliberately different. Teachers need motivation and a sense of fairness; the awards committee needs an auditable table.
| Column group | Fields |
|---|---|
| Identity | Teacher, school, domain, date of first submission, number of entries |
| Quality | Jury score per criterion, reviewer names, divergence flag, shortlist yes or no |
| Adoption | Distinct outside teachers who assigned or cloned the entry, playlist adds |
| Usage | Distinct outside learners with a completed attempt, completion rate, average score |
| Integrity | Self-traffic share, near-duplicate flag, bulk-submission flag, policy strikes |
| Outcome | Computed score, rank, manual override with a mandatory note, final lock |
Two functions matter beyond display. CSV export, because the awards conversation will happen in a meeting and a spreadsheet. And lock the ranking, which freezes the metric snapshot with a timestamp so that the winners list cannot silently drift after it is announced.
Three components. Human judgement dominates, because the goal is good content rather than viral content, but adoption and usage keep the jury honest and give teachers something they can influence daily.
A teacher's total is the sum of their best three entries. One outstanding lesson can win; a teacher who uploads thirty thin lessons cannot buy a rank with volume.
| Risk | Rule |
|---|---|
| The author assigns the entry to their own 200 students | Attempts by learners in the author's own school or domain are excluded from the usage component entirely. |
| Colleagues at the same centre boost each other | Adoption counts distinct teachers outside the author's school and domain. |
| Bulk AI dumps | An eligibility floor of at least 10 questions with complete answer keys and a description, near-duplicate detection on titles and question hashes, and only the best three entries counting. |
| Recycled or copied material | The existing content policy consent plus a reviewer check. One policy strike disqualifies the entry, a second disqualifies the teacher. |
| Late entries disadvantaged | Solved in the calendar: submissions close two weeks before metrics freeze. |
An entry set can be derived with no backend change at all: community-published, approved, inside the date window. That is enough to launch and not enough to run the awards, because it cannot hold a category, a jury score, a frozen metric snapshot or a manual override, and every ranking question becomes a hand-written query.
Recommendation: one campaign table and one entry table, added in the first sprint.
campaigns
id, slug, name_vi, name_en, status,
submit_open_at, submit_close_at, metrics_freeze_at, announce_at,
categories[], rules_url, prize_config
campaign_entries
id, campaign_id, check_point_id, teacher_profile_id, category,
submitted_at, review_request_id, -- reuses the existing queue
jury_scores[], jury_avg,
adoption_count, learner_count, -- snapshotted at freeze
computed_score, rank, is_disqualified, override_note
Two properties to preserve. campaign_entries points at the existing review request rather than duplicating moderation, so a contest entry travels the same approval path as any other community item. And the metric columns are snapshots taken at freeze time rather than live counts, so a published ranking stays reproducible.
| Metric | Source | Exclusions |
|---|---|---|
| Adoption | Distinct teacher profiles that created an assignment from the entry, cloned it, or added it to a playlist | The author; any teacher in the author's school or custom domain; sample or auto-generated assignments |
| Learner usage | Distinct learner profiles with a completed attempt on the entry | Learners belonging to the author's school or domain |
| Quality | Rubric scores captured on the review request | — |
GET /campaign/:slug — campaign config, live counters, leaderboard page. Public, cacheable for a few minutes.POST /campaign/:slug/entries — submit; validates eligibility server-side, then calls the existing publish mutation. Client-side validation is a courtesy, not the gate.GET /campaign/:slug/my-entries — status, reviewer note and live statistics for the signed-in teacher.POST /admin/campaign/:slug/score — jury score on one entry.POST /admin/campaign/:slug/freeze — snapshot metrics and lock the ranking.This is the operational risk that decides whether the contest feels good or embarrassing. A campaign that lands 500 entries against a 48-hour promise needs roughly 60 to 80 reviewer-hours across four weeks. The queue today is one admin screen with an approve button and a reject button.
| Phase | Ships | Rough size |
|---|---|---|
| 1 — Launch before the announcement | Landing page with all four states · campaign and entry tables · submit modal with eligibility checks · builder exit call to action · entry list with status and reasons · contest filter and rubric field in the admin queue | ~2 sprints, 1 FE and 1 BE, design in parallel |
| 2 — During week 1 of the window | Daily leaderboard · author statistics on entry cards · weekly progress notification · integrity flags in the admin report | ~1 sprint |
| 3 — Awards before judging | Jury scoring screen · internal ranking report with CSV export and ranking lock · winners state on the landing page | ~1 sprint |
Cut in this order: the leaderboard becomes a weekly manual publish; the jury screen becomes a shared spreadsheet fed by the CSV export; the integrity flags become a manual check on the shortlist only. Do not cut the landing page, the submit modal or the entry status list — those three are what teachers actually touch.
| Question | Why it changes the design | Owner |
|---|---|---|
| Which content types are eligible — builder tests only, or also worksheets, playlists and Topic Talk? | Each extra type is a different publish path, a different eligibility rule and a different usage metric. The recommendation is builder tests only for round one. | Product |
| Who sits on the jury, and how many hours can they give? | Sets the shortlist size and therefore the whole scoring model. | Academic |
| Prize structure — ten equal prizes or a tiered top three? | Tiers require tie-breaking rules and a defensible margin between ranks; equal prizes do not. | Marketing |
| Are contest entries permanently public? | Affects the consent copy. A teacher who can withdraw a lesson after winning weakens the library; a teacher who cannot must be told clearly before submitting. | Product + Legal |
| What is today's baseline of community items and community authors? | Sets the target and the review-capacity plan. Requires a query against the analytics replica. | Product |
| Which channel carries the campaign — Zalo, email, or in-app only? | Determines the notification build in phase 2. | Marketing |
partner-web (views/exam-library, views/my-exams, components/creator, the generated GraphQL schema) and admin-web (pages/users/check-point-request). Everything from section 5 onward is a design proposal awaiting approval.Cuộc thi để giáo viên tự soạn bài trên builder, đăng lên Explore và được xếp hạng. Luồng đăng bài đã chạy trên production; tài liệu này đặc tả phần cửa vào, phần đánh dấu bài dự thi và phần chấm điểm để biến luồng đó thành một cuộc thi.
Biến kệ nội dung cộng đồng trên Explore thành nơi giáo viên tranh nhau đóng góppartner-web và admin-web, nên các khẳng định “đã có sẵn” đều kiểm chứng được. Từ mục 5 trở đi là đề xuất thiết kế. Những điểm chưa có dữ liệu đều được nêu ở mục Câu hỏi mở thay vì tự suy diễn.FLYER muốn tổ chức cuộc thi “Soạn nội dung hay nhất” để giáo viên tự đăng nội dung của mình lên kệ Explore của Teado.ai. Có ba yêu cầu chính: một trang giới thiệu để giáo viên hiểu về cuộc thi, các chức năng để giáo viên tự nộp nội dung lên Explore, và một báo cáo xếp hạng để chọn ra mười giáo viên trao giải.
Điểm xuất phát tốt hơn nhiều so với hình dung ban đầu. Giáo viên hiện đã có thể soạn bài trên builder, đăng công khai cho cộng đồng, chờ admin duyệt, và thấy bài của mình xuất hiện trên Explore kèm tên tác giả. Luồng này đang chạy thật trên production và rất ít người dùng, vì không có gì dẫn tới nó.
Vấn đề vì vậy không phải là “giáo viên không đăng được nội dung”. Vấn đề là việc đăng nội dung đang vô hình, không được ghi nhận và không được đo. Cuộc thi là công cụ tốt cho cả ba điều đó, với điều kiện được dựng trên luồng sẵn có chứ không dựng song song bên cạnh.
| Chỉ số | Định nghĩa | Loại |
|---|---|---|
| Số bài được duyệt | Nội dung cộng đồng được duyệt trong thời gian diễn ra cuộc thi | Chính |
| Số giáo viên tham gia | Số giáo viên khác nhau có ít nhất một bài được duyệt | Chính |
| Độ lan toả | Tỉ lệ bài được ít nhất 5 giáo viên ngoài trường của tác giả sử dụng | Chính — đo chất lượng, không đo số lượng |
| Kích hoạt builder | Số người dự thi chưa từng tạo nội dung trước cuộc thi | Phụ |
| Thời gian duyệt | p50 và p90 số giờ từ lúc nộp tới lúc có kết quả duyệt | Kiểm soát |
| Tỉ lệ bị từ chối | Tỉ lệ bài bị từ chối ngay vòng duyệt đầu | Kiểm soát — tỉ lệ cao nghĩa là đề bài hoặc danh sách điều kiện chưa đạt |
| Duy trì sau cuộc thi | Số giáo viên tiếp tục đăng bài trong 30 ngày sau lễ trao giải | Thước đo thật sự cho việc cuộc thi có đáng tổ chức không |
Các mục dưới đây đọc từ mã nguồn hiện tại, không phải phỏng đoán. Tất cả đang chạy trên production.
| Năng lực | Nằm ở đâu | Trạng thái |
|---|---|---|
| Builder soạn nội dung — 12 dạng câu hỏi (trắc nghiệm, điền từ, nối, kéo thả, sắp xếp từ, sắp xếp câu, flashcard, bài đọc, câu hỏi mở, dropdown, trả lời bằng giọng nói, video tương tác), công cụ sinh câu hỏi bằng AI và bộ theme | /creator/[id], components/creator | Đã có |
| Đăng công khai cho cộng đồng — modal ba lựa chọn phạm vi, trong đó có “Công khai cho cộng đồng — ai cũng tìm và làm được bài này” | /exams, my-exams/components/publish-modal, mutation partnerPracticeCheckPointsPublish(community: true) | Đã có |
| Xác nhận chính sách nội dung — cổng bắt buộc đồng ý một lần trước khi đăng công khai | providers/flyer/content-policy | Đã có |
| Hàng đợi kiểm duyệt — Chờ duyệt / Đã duyệt / Từ chối kèm lý do từ chối song ngữ | bảng check_point_review_requests; màn admin admin-web /users/check-point-request | Đã có |
| Kệ nội dung cộng đồng trên Explore — bộ lọc nguồn “Community”, thẻ bài có in tên tác giả | /explore, views/exam-library | Đã có |
| Tín hiệu tái sử dụng — số lượt làm bài, sao chép về thư viện riêng, giao bài cho lớp, playlist | checkPoint.testCount, partnerPracticeCheckPointClone, assign_tests, featured playlists | Đã có |
| # | Điểm thiếu | Vì sao chặn cuộc thi |
|---|---|---|
| 1 | Chưa có khái niệm chiến dịch | Không có gì đánh dấu một bài là bài dự thi. Không có thời gian diễn ra, không có hạng mục, và không trả lời được câu “đang có bao nhiêu bài dự thi” nếu không viết truy vấn tay. |
| 2 | Chưa có trang giới thiệu | Giáo viên không có nơi đọc thể lệ, xem giải thưởng hay tìm nút tham gia, còn marketing không có đường link để đẩy qua Zalo hoặc email. |
| 3 | Đường nộp bài bị chôn sâu | Builder không có lối ra để đăng bài. Giáo viên vừa soạn xong phải thoát builder, mở kho đề, tích chọn rồi tìm thanh công cụ. Tỉ lệ rơi rớt sẽ cao đúng vào lúc động lực lớn nhất. |
| 4 | Việc duyệt là hộp đen | Trạng thái chỉ là một cột trong bảng, lý do từ chối nằm trong tooltip. Trong một cuộc thi có hạn nộp, giáo viên bị từ chối ở ngày thứ 12 cần thấy rõ lý do và nộp lại được. |
| 5 | Tác giả không nhận được phản hồi | Không có gì cho giáo viên biết bài của họ đã được 40 giáo viên khác sử dụng. Con số đó mới là phần thưởng thật, và hiện không hiển thị ở đâu cả. |
| 6 | Chưa có xếp hạng | Việc duyệt chỉ có duyệt hoặc từ chối. Không có thang điểm, không có bảng xếp hạng, không có báo cáo nào đủ cơ sở để bảo vệ việc chọn ra mười người thắng giải. |
Một luồng duy nhất, ba nhóm người tham gia. Bước 3 và bước 6 đã có sẵn; phần còn lại là khối lượng công việc.
/contest: thể lệ, hạng mục, giải thưởng, thang điểm, số liệu trực tiếp.Chấm điểm theo mức sử dụng sẽ thiệt cho bài nộp muộn: bài đăng ngày cuối không có thời gian để ai dùng. Cách xử lý nằm ở lịch tổ chức, không nằm ở công thức.
| Giai đoạn | Thời lượng | Diễn ra điều gì |
|---|---|---|
| Công bố | 1 tuần trước | Trang giới thiệu ở trạng thái đếm ngược, thu thập đăng ký nhận thông báo, đẩy Zalo. |
| Nhận bài | 4 tuần | Giáo viên nộp bài. Duyệt liên tục với cam kết 48 giờ. |
| Thời gian tính sử dụng | 2 tuần sau khi đóng nhận bài | Không nhận thêm bài mới, nên mọi bài được duyệt đều có ít nhất 14 ngày trên kệ trước khi chốt số. Đây chính là điều làm cho bảng xếp hạng công bằng. |
| Chấm giải | 1 tuần | Hội đồng chấm danh sách rút gọn. Bảng xếp hạng đóng băng và ghi rõ là kết quả tạm. |
| Trao giải | 1 ngày | Công bố người thắng ngay trên trang giới thiệu, trang này sau đó trở thành bằng chứng cho mùa sau. |
Đường dẫn /contest nằm trong partner-web, có tiếng Việt và tiếng Anh như phần còn lại của sản phẩm, và xem được khi chưa đăng nhập để có thể chia sẻ ra ngoài.
Các con số và bảng xếp hạng lấy dữ liệu trực tiếp. Một trang tĩnh sẽ cũ ngay từ ngày thứ hai và mất lý do để giáo viên quay lại giữa kỳ thi.
| Trạng thái | Phần đầu trang | Hành động chính |
|---|---|---|
| Đếm ngược | Thời gian và “mở sau N ngày” | Nhận thông báo — giữ chân giáo viên trước ngày mở |
| Đang diễn ra | Số ngày còn lại và số liệu trực tiếp | Tham gia / Nộp bài |
| Đang chấm | “Đã đóng nhận bài — công bố ngày 20/10” | Xem các bài dự thi, qua đó kéo lượt truy cập vào Explore trong lúc chấm |
| Kết thúc | Người đoạt giải kèm bài dự thi của họ | Xem nội dung đoạt giải · Đăng ký quan tâm mùa sau |
Phần mutation đã có. Việc thiết kế là đặt nó vào đúng nơi giáo viên đang đứng, và làm cho những gì diễn ra sau đó trở nên rõ ràng.
| Cửa vào | Vị trí | Vì sao đặt ở đó |
|---|---|---|
| Lối ra của builder | Sau khi Lưu ở thanh tiêu đề trình soạn: một bảng thành công với hành động chính là “Nộp bài dự thi” | Thời điểm động lực cao nhất. Hiện builder hoàn toàn không có lối ra để đăng bài, nên đây là thay đổi có sức bật lớn nhất trong toàn bộ đề xuất. |
| Dòng trong kho đề | Hành động trên từng dòng và trên thanh công cụ chọn hàng loạt ở /exams, cạnh nút đăng bài hiện có | Dành cho giáo viên muốn dự thi bằng bài đã soạn từ tháng trước. |
| Trang cuộc thi | Nút “Nộp bài dự thi” mở danh sách các bài đủ điều kiện trong thư viện của giáo viên | Dành cho giáo viên đi vào từ chiến dịch truyền thông chứ không từ trong sản phẩm. |
Danh sách điều kiện là đòn bẩy chất lượng. Nó loại bài sơ sài trước khi người duyệt mất thời gian, đồng thời dạy tiêu chuẩn ngay lúc giáo viên còn đang ở vị trí sửa được.
Một tab trên trang cuộc thi, đồng thời là một bộ lọc trong /exams. Mỗi bài một thẻ.
Ba lựa chọn có chủ đích ở đây. Lý do từ chối hiển thị đầy đủ thay vì nằm trong tooltip. Trạng thái “Từ chối” đổi tên thành “Cần chỉnh lại” kèm nút nộp lại, vì trong một cuộc thi thì lời từ chối nên đọc như một lời mời sửa chứ không phải một phán quyết. Và bài đang hiển thị nêu đúng hai con số khiến tác giả thấy công sức được đền đáp: bao nhiêu giáo viên đang dùng và bao nhiêu học sinh đã làm.
Hai bề mặt khác nhau một cách có chủ đích. Giáo viên cần động lực và cảm giác công bằng; hội đồng trao giải cần một bảng số liệu kiểm chứng được.
| Nhóm cột | Trường dữ liệu |
|---|---|
| Định danh | Giáo viên, trường, domain, ngày nộp bài đầu tiên, số bài dự thi |
| Chất lượng | Điểm hội đồng theo từng tiêu chí, tên người chấm, cờ lệch điểm, có vào danh sách rút gọn hay không |
| Mức tái sử dụng | Số giáo viên ngoài trường đã giao bài hoặc sao chép, số lần thêm vào playlist |
| Mức sử dụng | Số học sinh ngoài trường đã hoàn thành, tỉ lệ hoàn thành, điểm trung bình |
| Tính liêm chính | Tỉ trọng lượt truy cập nội bộ, cờ trùng lặp, cờ nộp hàng loạt, số lần vi phạm chính sách |
| Kết quả | Điểm tổng, thứ hạng, quyền chỉnh tay kèm ghi chú bắt buộc, khoá kết quả |
Ngoài phần hiển thị, hai chức năng quan trọng. Xuất CSV, vì cuộc trao đổi về giải thưởng sẽ diễn ra trong một cuộc họp và một bảng tính. Và khoá kết quả, tức đóng băng bản chụp số liệu kèm dấu thời gian, để danh sách người thắng không âm thầm thay đổi sau khi đã công bố.
Ba thành phần. Đánh giá của con người chiếm phần lớn, vì mục tiêu là nội dung tốt chứ không phải nội dung lan truyền, nhưng mức tái sử dụng và mức sử dụng giữ cho hội đồng không lệch và cho giáo viên thứ họ tác động được hằng ngày.
Điểm của một giáo viên là tổng của ba bài tốt nhất. Một bài xuất sắc vẫn đủ để thắng; nộp ba mươi bài sơ sài không mua được thứ hạng bằng số lượng.
| Rủi ro | Quy tắc |
|---|---|
| Tác giả giao bài cho chính 200 học sinh của mình | Loại hoàn toàn lượt làm bài của học sinh thuộc trường hoặc domain của tác giả khỏi phần điểm mức sử dụng. |
| Đồng nghiệp cùng trung tâm đẩy điểm cho nhau | Mức tái sử dụng chỉ đếm giáo viên ngoài trường và ngoài domain của tác giả. |
| Nộp hàng loạt nội dung sinh bằng AI | Ngưỡng tối thiểu 10 câu hỏi có đủ đáp án và mô tả, cơ chế phát hiện trùng lặp theo tiêu đề và mã băm câu hỏi, và chỉ tính ba bài tốt nhất. |
| Nội dung sao chép hoặc dùng lại của người khác | Xác nhận chính sách nội dung sẵn có cộng với bước kiểm tra của người duyệt. Vi phạm lần đầu loại bài, lần thứ hai loại giáo viên khỏi cuộc thi. |
| Bài nộp muộn bị thiệt | Xử lý bằng lịch tổ chức: đóng nhận bài trước thời điểm chốt số hai tuần. |
Có thể suy ra tập bài dự thi mà không đổi gì ở backend: các bài công khai cho cộng đồng, đã được duyệt, nằm trong khoảng thời gian cuộc thi. Cách đó đủ để mở màn nhưng không đủ để trao giải, vì nó không lưu được hạng mục, điểm hội đồng, bản chụp số liệu đã đóng băng hay quyền chỉnh tay, và mọi câu hỏi về xếp hạng đều biến thành một truy vấn viết tay.
Đề xuất: thêm một bảng chiến dịch và một bảng bài dự thi ngay ở sprint đầu tiên.
campaigns
id, slug, name_vi, name_en, status,
submit_open_at, submit_close_at, metrics_freeze_at, announce_at,
categories[], rules_url, prize_config
campaign_entries
id, campaign_id, check_point_id, teacher_profile_id, category,
submitted_at, review_request_id, -- dùng lại hàng đợi duyệt sẵn có
jury_scores[], jury_avg,
adoption_count, learner_count, -- chụp lại tại thời điểm chốt
computed_score, rank, is_disqualified, override_note
Hai tính chất cần giữ. campaign_entries trỏ tới yêu cầu duyệt sẵn có thay vì dựng lại quy trình kiểm duyệt, nhờ đó bài dự thi đi đúng đường duyệt như mọi nội dung cộng đồng khác. Và các cột số liệu là bản chụp tại thời điểm chốt chứ không phải số đếm trực tiếp, nhờ đó kết quả đã công bố luôn tái lập được.
| Chỉ số | Nguồn | Loại trừ |
|---|---|---|
| Mức tái sử dụng | Số hồ sơ giáo viên khác nhau đã tạo bài giao từ bài dự thi, sao chép nó, hoặc thêm vào playlist | Chính tác giả; mọi giáo viên cùng trường hoặc cùng custom domain; các bài giao mẫu hoặc sinh tự động |
| Mức sử dụng của học sinh | Số hồ sơ học sinh khác nhau đã hoàn thành bài | Học sinh thuộc trường hoặc domain của tác giả |
| Chất lượng | Điểm theo thang chấm, lưu trên yêu cầu duyệt | — |
GET /campaign/:slug — cấu hình cuộc thi, số liệu trực tiếp, một trang bảng xếp hạng. Công khai, cache được vài phút.POST /campaign/:slug/entries — nộp bài; kiểm tra điều kiện ở phía máy chủ rồi gọi mutation đăng bài sẵn có. Kiểm tra ở phía trình duyệt chỉ để hỗ trợ người dùng, không phải là cổng chặn.GET /campaign/:slug/my-entries — trạng thái, ghi chú của người duyệt và số liệu trực tiếp cho giáo viên đang đăng nhập.POST /admin/campaign/:slug/score — chấm điểm một bài dự thi.POST /admin/campaign/:slug/freeze — chụp số liệu và khoá bảng xếp hạng.Đây là rủi ro vận hành quyết định cuộc thi diễn ra suôn sẻ hay mất mặt. Một chiến dịch nhận 500 bài với cam kết 48 giờ cần khoảng 60 đến 80 giờ công duyệt trong bốn tuần. Hàng đợi hiện tại chỉ là một màn admin với nút duyệt và nút từ chối.
| Giai đoạn | Nội dung bàn giao | Khối lượng ước tính |
|---|---|---|
| 1 — Mở màn trước ngày công bố | Trang giới thiệu với đủ bốn trạng thái · bảng chiến dịch và bảng bài dự thi · modal nộp bài kèm kiểm tra điều kiện · lối ra nộp bài trong builder · danh sách bài dự thi kèm trạng thái và lý do · bộ lọc theo cuộc thi và ô chấm điểm trong hàng đợi admin | ~2 sprint, 1 FE và 1 BE, thiết kế chạy song song |
| 2 — Trong cuộc thi tuần đầu của kỳ nhận bài | Bảng xếp hạng cập nhật hằng ngày · thống kê cho tác giả trên thẻ bài · thông báo tiến độ hằng tuần · cờ liêm chính trong báo cáo admin | ~1 sprint |
| 3 — Trao giải trước kỳ chấm | Màn chấm điểm cho hội đồng · báo cáo xếp hạng nội bộ kèm xuất CSV và khoá kết quả · trạng thái công bố người thắng trên trang giới thiệu | ~1 sprint |
Cắt theo thứ tự sau: bảng xếp hạng chuyển thành đăng tay hằng tuần; màn chấm của hội đồng chuyển thành một bảng tính dùng chung lấy từ file CSV; các cờ liêm chính chuyển thành kiểm tra tay trên danh sách rút gọn. Không cắt trang giới thiệu, modal nộp bài và danh sách trạng thái bài dự thi — đó là ba thứ giáo viên thật sự chạm vào.
| Câu hỏi | Vì sao ảnh hưởng tới thiết kế | Người quyết |
|---|---|---|
| Những dạng nội dung nào được dự thi — chỉ bài soạn trên builder, hay cả worksheet, playlist và Topic Talk? | Mỗi dạng thêm vào là một đường đăng bài khác, một bộ điều kiện khác và một chỉ số sử dụng khác. Đề xuất là mùa đầu chỉ nhận bài soạn trên builder. | Product |
| Hội đồng gồm những ai và dành được bao nhiêu thời gian? | Quyết định quy mô danh sách rút gọn, và qua đó quyết định toàn bộ cách tính điểm. | Academic |
| Cơ cấu giải thưởng — mười giải bằng nhau hay có phân hạng ba giải đầu? | Phân hạng đòi hỏi quy tắc xử lý đồng điểm và khoảng cách đủ thuyết phục giữa các thứ hạng; mười giải bằng nhau thì không. | Marketing |
| Bài dự thi có công khai vĩnh viễn không? | Ảnh hưởng tới câu chữ ở phần đồng ý. Nếu giáo viên rút bài được sau khi đoạt giải thì kho nội dung bị yếu đi; nếu không rút được thì phải nói rõ trước khi họ nộp. | Product + Pháp lý |
| Số nền hiện tại là bao nhiêu nội dung cộng đồng và bao nhiêu tác giả? | Quyết định mục tiêu và kế hoạch nhân sự duyệt bài. Cần một truy vấn vào read-replica. | Product |
| Chiến dịch chạy trên kênh nào — Zalo, email hay chỉ trong sản phẩm? | Quyết định khối lượng phần thông báo ở giai đoạn 2. | Marketing |
partner-web (views/exam-library, views/my-exams, components/creator, GraphQL schema đã sinh) và admin-web (pages/users/check-point-request). Từ mục 5 trở đi là đề xuất thiết kế đang chờ duyệt.