- Get Started
- Localhost
- Architecture
- Structure
- Pattern
- Page
- Layout
- Content
- Types
- Config
- Actions
- Queries
- Authorization
- Validation
- Form
- Table
- Detail
- Card
- Util
- Hooks
- List Params
- Views
- README.md
- ISSUE.md
- Technology Stack
- Database
- File
- CDN Assets
- Entry Points
- Dashboard
- Authentication
- Credentials
- OAuth
- Flow Diagrams
- Multi-Tenancy
- Offline
- Onboarding
- Onboarding Videos
- Add Values
- Admission
- Application
- Attendance
- Compliance
- Profile
- Exams
- Exam Wizard
- Timetable
- Classrooms
- Notifications
- Conference
- LMS (Lumos)
- Finance
- Fee Management
- Invoice
- Wallet
- Salary
- Payroll
- Timesheet
- Expenses
- Budget
- Receipt
- Accounts
- Banking
- Reports
- Dashboard
- Permissions
- Messages
- Integration Flow
- Provision
- AI Document Processing
- Document Intelligence
- Internationalization
- Translation
- Translation Guide
- Icons
- Docs Factory
- Inspiration
- Listings
- Teachers
- Students
- Catalog
- Library
- Contributing
- Code of conduct
- GitHub Workflow
- Database Seeds
- Database Safety
- Test Accounts
- Bulk import
- Playwright
- Prettier
- Block Rebound
- Transportation
Every curated hogwarts asset lives under the hogwarts/ namespace of cdn.databayt.org (hogwarts is the internal name; balqalam is only the public brand). There are two tiers:
- Product media — the stills and videos
/shootand/recordproduce. The folder mirrors the app's routes, the keys are content-hashed, and pages read them by id fromsrc/components/docs/media-manifest.json, never by URL. - App chrome — icons, illustrations, animations and photos, through
asset()(flat, unhashed).
Both are cached immutable for one year. One origin helper, src/lib/cdn.ts (CDN_ORIGIN, cdn(key)), builds every URL; nothing else hard-codes the domain.
Infrastructure
| Component | Value |
|---|---|
| S3 bucket | databayt-cdn (us-east-1; user uploads stay in hogwarts-databayt) |
| CloudFront CNAME | cdn.databayt.org (preferred) |
| CloudFront raw | d1dlwtcfl0db67.cloudfront.net (still works — additive alias) |
| Cache | public, max-age=31536000, immutable |
| Env var | NEXT_PUBLIC_CDN_DOMAIN (build-time; read only by src/lib/cdn.ts) |
Product media — the CDN mirrors the routes
cdn.databayt.org/hogwarts/<route>/<flow>-<step>-<locale>-<width>.<hash>.avif stills (+ .webp)
cdn.databayt.org/hogwarts/<route>/<flow>[-<clip>]-<locale>.<hash>.mp4 videos (+ .av1, poster, .vtt)
| Route the flow films | CDN folder | Example |
|---|---|---|
/students | hogwarts/students/ | add-student-created-ar-1600.<hash>.avif, add-student-ar.<hash>.mp4 |
/teachers | hogwarts/teachers/ | add-teacher-created-ar-1600.<hash>.avif |
/school/bulk | hogwarts/school/bulk/ | bulk-student-review-ar-1600.<hash>.avif |
/ (homepage) | hogwarts/ | story.<hash>.mp4, hero-3d.<hash>.mp4, modern-02.<hash>.avif |
Render them by manifest id:
<FlowMedia flow="add-student" />
<Shot id="add-student/created-ar" />
<TutorialVideo id="add-student/video-ar" />FlowMedia lists stills by their order (the step number they were shot in). The sources stay outside the repo in ~/media/hogwarts/<flow>/; see the kun shoot docs for the full grammar.
App chrome — asset()
import { asset } from "@/lib/asset-url"
<Image src={asset("/icons/logo.png")} />
<Image src={asset("/illustrations/attendance.png")} />
<img src={asset("/icons/visa.svg")} />
<source src={asset("/media/story.mp4")} />asset("/icons/logo.png") → https://cdn.databayt.org/hogwarts/logo.png — only the file name is kept.
Chrome groups
The chrome objects sit flat at hogwarts/<file>; the groups below are how they are catalogued, not folders.
| Group | Purpose | Count |
|---|---|---|
icons/ | Small functional SVGs, logos, small PNGs | 42 |
illustrations/ | Art, decorative, complex | 88 |
animations/ | Lottie JSON | 3 |
photos/ | Real photographs | 22 |
media/ | Video and audio | 1 |
| Total | 155 |
Naming conventions
| Rule | Example | Anti-pattern |
|---|---|---|
| kebab-case | data-science.png | dataScience.png |
| Lowercase | visa.svg | Visa.svg |
| No spaces | hands-build.svg | Hands Build.svg |
| No prefixes by default | visa.svg | payment-visa.svg |
| Rename only on collision | site-ball.png | Prefix everything |
icons/ (42)
| Group | Keys |
|---|---|
| Brand | logo.png, master-card.png, z.png |
| Anthropic UI | graduation-cap.svg, star-outline.svg, book-open.svg, anthropic-user.svg, users.svg, check-circle.svg, document.svg, news.svg |
| Payment | visa.svg, mastercard.svg, amex.svg, apple-pay.svg, google-pay.svg, paypal.svg, mada.svg, stcpay.svg, fawry.svg |
| Exam types | multiple-choice.svg, true-false.svg, short-answer.svg, essay.svg, fill-in-blank.svg, matching.svg, ordering.svg, multi-select.svg |
| Form attachments | degree.png, transcript.png, id.png, resume.png, files.png, image.png |
| Mission | hands-build.svg, hands-stack.svg, objects-puzzle.svg |
| Sponsors | faisal.png, mtdt.png, zain.png, khartoum.png, dal.png, 249.png, uok.png |
illustrations/ (88)
| Group | Highlights |
|---|---|
| Anthropic art | hands-build.svg, hands-stack.svg, objects-puzzle.svg, category-01.svg … category-14.svg, claude-code-best-practices.svg, think-tool.svg, eng-long-running-agents.svg, anthropic-abstract.svg |
| Feature (32) | student.png, teacher.png, fees.png, exam.png, assigment.png, attendance.png, gradebook.png, timetable.png, library.png, events.png, video.png, payroll.png, invoicing.png, wallet-3.png, credit-card.png, app-store.png, email.png, offer.png, canteen.png, parent.png, transport.png, headphone.png, notifications.png, calendar-2.png, id-cards.png, phone.png, messaging.png, graduate.png, blackboard.png, download.png, role-based.png, cover-letter.png, admission.png |
| Site art | site-ball.png, hat.png, glass.png, tent.png, teleport.png, community.png, champion.png, world.png, light-bulb.png, ball.png, robot.png, ai-fluency-hero.webp |
| Lumos | teach.jpg, inspire.jpg, reward.jpg, generative-ai.png, it-certifications.png, data-science.png |
| Onboarding | private.png, onboarding-public.png, international.png, techincal.png, espical.png, onboarding-step2.svg |
| GitHub achievements | starstruck-detail.png, galaxy-brain-detail.png, pull-shark-detail.png, yolo-detail.png, pair-extraordinaire-detail.png, quickdraw-detail.png, public-sponsor-detail.png |
Feature illustrations are used by feature-tabs.tsx and dream-section.tsx.
animations/ (3)
| Key | Used by |
|---|---|
confetti.json | success modal, completion modal |
anthropic-hero.json | hero illustration |
education.json | education animation |
photos/ (22)
| Group | Keys |
|---|---|
| Contributors | contributors-h.jpeg, contributors-d.jpeg, contributor-1.jpg … contributor-6.jpg, mazin.jpg |
| Site | harry-potter.png, site-h.jpeg, trian.jpeg, site-a.jpeg, site-b.jpeg, map.jpeg |
| Faculty | dumbledore.jpeg, snape.jpeg, mcgonagall.jpeg, hagrid.jpeg |
| Houses | gryffindor.jpeg, ravenclaw.jpeg, hupplepuff.jpeg, slytherin.jpg |
media/ (1)
| Key | Used by |
|---|---|
story.mp4 | legacy flat copy, served application/octet-stream; nothing reads it any more |
The story video and the school hero loop are product media now: hogwarts/story.<hash>.mp4 and
hogwarts/hero-3d.<hash>.mp4 (route /), listed with their codecs and posters in
media-manifest.json. The lumos lesson-player fallback plays the story's H.264 source.
Pre-existing CDN systems (do not touch)
| System | S3 prefix | Helper |
|---|---|---|
| Catalog images | catalog/subjects/{id}/thumbnail-{size}.webp | getCatalogImageUrl() |
| Video uploads | lumos/{schoolId}/video/{timestamp}_{name} | getCloudFrontUrl() |
| Subject fallbacks | public/subjects/ (local) | image-map.ts |
What stays in public/
| Item | Reason |
|---|---|
service-worker.js | Browser same-origin requirement |
leaflet/ (3 files) | Leaflet CSS hardcodes relative paths |
logo.png | PWA manifest fallback |
exams-main/ (666 PDFs) | Arabic exam papers, local access |
us-curriculum/ (1,023 images) | Deferred |
courses/ (57 PNGs) | Deferred |
books/ (20 images) | Deferred |
subjects/ (17 PNGs) | Catalog pipeline fallback |
Adding new assets
Product media (screens, flows, videos): shoot or record it, then publish.mjs --flow <flow> — never upload by hand.
App chrome:
- Upload to
hogwarts/<file>. - kebab-case, lowercase filenames.
- Set
Content-TypeandCacheControl: "public, max-age=31536000, immutable". - Reference with
asset("/category/filename.ext").
Or use the migration script.
pnpm tsx scripts/migrate-assets-to-s3.ts # dry run
pnpm tsx scripts/migrate-assets-to-s3.ts --upload # upload
pnpm tsx scripts/migrate-assets-to-s3.ts --manifest # output JSON manifestFuture
- Move
us-curriculum/,courses/,books/to acontent/prefix in S3. - Multi-tenant branding at
schools/{schoolId}/brand/.