TutorLoom
The learning platform for companies, colleges and training institutes. Free and open source, with an Enterprise edition.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證View basic information about CUET Students
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗An independent index of Chittagong University of Engineering & Technology students: search by name or ID, browse every batch and department, or use the public JSON API.
Site https://cuet.sayed.app · API docs https://cuet.sayed.app/api
@astrojs/cloudflareCUET_students): the single source of truth for student data; no data files live in this reposrc/middleware.ts), API rate limit via the Workers rate-limiting bindingsrc/
lib/departments.ts department table, keyed by the ID's department digits
lib/db.ts all D1 queries
lib/api.ts JSON helpers, rate limiting, API response shapes
pages/ routes (pages + /api endpoints)
components/, layouts/
migrations/ D1 schema and data fixes (data imports are gitignored)
scripts/csv-to-sql.mjs CSV → D1 migration for importing a new batch
scripts/refresh-derived.sql rebuilds class_counts / name_words (see below)
D1 bills every row a query reads, and students has ~17K rows, so no request
path may scan it. Counts come from class_counts (one row per class) and name
search goes through the indexed name_words table. After changing students
by hand, run npm run db:refresh (imports made with csv-to-sql do it already).
IDs are YY DD RRR: batch, department code, class roll. The site and API take the department from DD, not from the
department text column. Code 12 shows as MSE for batches ≤ 22 and MME after that.
| Page | URL |
|---|---|
| Home | / |
| Search | /search?q=…&batch=25&dept=cse (a full ID redirects to the profile) |
| Batches | /batch, /batch/25, /batch/25/cse |
| Departments | /department, /department/cse |
| Student | /2504001 |
| API docs | /api |
Old URLs (/batch?department=…&batch=…, /search?name=…, sitemap_N.xml) redirect.
Read-only, no key, CORS *, 60 requests/minute per IP, responses cached up to 24 h.
| Endpoint | Returns |
|---|---|
GET /api/v1/students/{id} | one student |
GET /api/v1/search?q=&batch=&dept=&limit= | name search, or ID prefix if q is digits |
GET /api/v1/batches | batches with per-department counts |
GET /api/v1/batches/{batch}/{dept} | full class list |
GET /api/v1/departments | departments with their batches |
The legacy /api/student/{id} and /api/student/search?query= endpoints still answer in the old flat format. Full
reference with a live console: /api.
Node 22.12+ (.nvmrc pins 24).
npm install
npm run dev # http://localhost:4321 with a local D1
npm run check # wrangler types + astro check
npm run preview # build and run the real Worker locally
The local D1 starts empty. Copy production into it:
npx wrangler d1 export CUET_students --remote --output prod.sql
npx wrangler d1 execute CUET_students --local --file prod.sql
Cloudflare Workers Builds watches this repo:
main → npm run build → npx wrangler deploy (production)redirect) → preview version onlynpm run deploy deploys manually. Every deploy also clears the edge cache.
/sitemap.xml is a sitemap index: /sitemap-pages.xml (home, listings, batch/class/department pages) plus one
/sitemap-batch-YY.xml per batch with every profile. All entries carry <lastmod> from D1's updated_at.robots.txt allows everything except /search?… (search result pages are also noindex).WebSite + search action, Person, BreadcrumbList).cuet.sayed.app).node scripts/indexnow.mjs pushes every sitemap URL via IndexNow;
--since YYYY-MM-DD sends only changed pages. Key file: public/1144afef155385c08e4aca5b16ec8642.txt.studentid,name,admission_roll,admission_merit.node scripts/csv-to-sql.mjs batch26.csv migrations/0006_import_batch_26.sql
(use the next free migration number; the script appends scripts/refresh-derived.sql,
so class_counts and name_words update in the same migration)npm run db:migrate (applies new migrations to production D1)npx wrangler d1 execute CUET_students --remote --command "SELECT (SELECT COUNT(*) FROM students), (SELECT SUM(count) FROM class_counts), (SELECT COUNT(DISTINCT studentid) FROM name_words)"
If they differ, run npm run db:refresh.main so the edge cache and the in-memory overview refresh, then
node scripts/indexnow.mjs --since <today>.Import migrations contain personal data and are gitignored; keep the CSV outside the repo.
Any hand-made change to students (a fix migration, d1 execute, the dashboard) must be
followed by npm run db:refresh, or counts and search go stale:
db:refresh is enough.DELETE FROM name_words WHERE studentid = '2504001'; then db:refresh.DELETE FROM name_words WHERE studentid = ... (stale rows are
harmless for results, but waste reads).Don't rebuild name_words from scratch (DELETE FROM name_words + refresh): that is
~50K row writes, half the free daily limit.
D1 bills every row a query reads: 5M/day, then all queries fail until 00:00 UTC. A
query without an index on its WHERE reads all ~8.6K students (plus index rows). Before
adding a query, check its plan in wrangler d1 execute --local with EXPLAIN QUERY PLAN:
it must say SEARCH ... USING INDEX, never SCAN students. Usage per database:
dashboard → D1 → CUET_students → Metrics.
Avoid node scripts/indexnow.mjs without --since: it makes crawlers fetch every
profile at once (that, plus full-table scans, caused the Nov 2026 outage).
D1 keeps 30 days of point-in-time history (Time Travel). For an offline copy:
npx wrangler d1 export CUET_students --remote --output cuet-backup.sql
main: this siteredirect: the cuet.pages.dev Pages project, which redirects to cuet.sayed.apparchive/* tags: the old Next.js versionsData was compiled from publicly available sources and may contain errors. Personal use is free; commercial use or integration into another system requires acknowledgment. See privacy and terms. Contact: [email protected].
Built by Sayed.