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.