0%
balqalam Logo
balqalam
FeaturesCommunityPricingDocumentation
Login
  • Introduction
  • Pitch
  • Hogwarts
  • Live Demo
  • MVP
  • Roadmap
  • Launch Sprint
  • PRD
  • 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
  • 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
  • Playwright
  • Prettier
  • Block Rebound
Sales & GTM
  • Marketing Brief
  • Sales
  • Go-to-market
  • Marketing
  • Admission — Feature Spotlight
  • Pilot Program
  • Leads
  • Proposal
  • Outreach Templates
  • Case Study
  • Competitors
  • Landing-page teardown
  • Competitor FAQ
  • Business model
  • Shared economy
  • Traction
Fundraising & Ecosystem
  • Get Support
  • Investor Deck
  • Data Room
  • Investors
  • Accelerators
  • Incubators
  • Grants
  • Sponsors
  • Partners
  • Competitions & Hackathons
  • Universities & Training Centers

Entry Points

PreviousNext

Four distinct surfaces — SaaS marketing, operator dashboard, school sites, and school platform.

The platform has four entry points, each serving a different audience with its own access controls. Understanding the surfaces is critical for routing, RBAC, and user-experience design.

Overview

#EntryURLAudienceAuth
1SaaS marketinged.databayt.orgVisitors, school owners, principalsNone for browsing
2Operator dashboarded.databayt.org/en/dashboardPlatform operatorsDEVELOPER only
3School site{school}.databayt.orgSchool visitors, applicantsNone
4School platform{school}.databayt.org/en/dashboardAuthenticated school usersRole-based

1. SaaS marketing

Public landing for everyone — visitors, school owners, principals, teachers, students, parents, guests, investors, contributors.

ComponentLocationPurpose
SiteHeadercomponents/template/marketing-header/Nav with login
Herocomponents/marketing/hero/"Get Started" CTA
UserButtoncomponents/auth/user-button.tsxLogin/avatar (variant="marketing")
CommandMenucomponents/template/marketing-header/Quick search
CTADestinationAuth
Login/loginNo
Get Started/onboardingYes (redirect through login)
Join/joinNo

Login redirect:

// src/components/auth/login/action.ts
if (existingUser.role === "DEVELOPER") {
  finalRedirectUrl = `/${locale}/dashboard`
} else {
  finalRedirectUrl = `/${locale}` // Homepage
}

2. Operator dashboard

DEVELOPER only — platform-wide controls.

src/app/[lang]/(saas-dashboard)/
├── layout.tsx              # SaaS auth guard (DEVELOPER only)
├── dashboard/page.tsx      # Operator home
├── analytics/page.tsx
├── billing/page.tsx
├── domains/page.tsx
├── tenants/page.tsx        # School / tenant management
├── product/page.tsx
├── sales/page.tsx
├── profile/page.tsx
├── kanban/page.tsx
├── observability/page.tsx
└── (catalog)/              # Catalog management

Access guard:

const session = await auth()
if (!session) redirect(`/${lang}/login?callbackUrl=/${lang}/dashboard`)
if (session.user?.role !== "DEVELOPER") redirect(`/${lang}/access-denied`)

3. School site

Public school-branded site. The edge proxy detects the subdomain and rewrites:

hogwarts.databayt.org
  → middleware extracts "hogwarts"
  → rewrite to /[lang]/s/hogwarts/(site)/*
  → SchoolProvider loads school context
EnvironmentURL patternInternal route
Productionschool.databayt.org/[lang]/s/school/(site)/*
Previewschool---branch.vercel.app/[lang]/s/school/(site)/*
Developmentschool.localhost:3000/[lang]/s/school/(site)/*
src/app/[lang]/s/[subdomain]/(site)/
├── page.tsx              # School homepage
├── layout.tsx            # SchoolProvider wrapper
├── about/page.tsx
├── academic/page.tsx
├── admissions/page.tsx
├── apply/page.tsx
├── tour/page.tsx
├── contact/page.tsx
└── events/page.tsx
CTADestinationAuth
Apply Now/{subdomain}/applicationYes (to save)
Schedule Tour/{subdomain}/tourNo
Contact Us/{subdomain}/contactNo
Go to Platform/{subdomain}/dashboardYes

All (site) routes are public (publicRoutes in src/routes.ts).

4. School platform

Authenticated school dashboard with role-based routing.

src/app/[lang]/s/[subdomain]/(school-dashboard)/
├── layout.tsx              # PlatformLayout with sidebar
├── dashboard/page.tsx      # Role-specific dashboard
├── admission/
├── attendance/             # ADMIN, TEACHER, STAFF
├── billing/
├── exams/                  # ADMIN, TEACHER
├── finance/                # All authenticated (role-specific views)
├── library/                # All authenticated
├── messages/
├── notifications/
├── profile/
├── settings/               # ADMIN, DEVELOPER
├── timetable/              # ADMIN, TEACHER
└── (listings)/
    ├── announcements/      # ADMIN, TEACHER, STAFF
    ├── assignments/        # ADMIN, TEACHER
    ├── classes/            # ADMIN, TEACHER
    ├── events/             # All authenticated
    ├── grades/             # ADMIN, TEACHER
    ├── lessons/            # ADMIN, TEACHER
    ├── parents/            # ADMIN, TEACHER, STAFF
    ├── students/           # ADMIN, TEACHER, STAFF
    ├── subjects/           # ADMIN, TEACHER
    └── teachers/           # ADMIN only

roleRoutes matrix

export const roleRoutes: Record<string, Role[]> = {
  "/admin": ["ADMIN", "DEVELOPER"],
  "/admin/*": ["ADMIN", "DEVELOPER"],
  "/settings/*": ["ADMIN", "DEVELOPER"],
 
  "/teachers": ["ADMIN", "DEVELOPER"],
  "/subjects/*": ["ADMIN", "TEACHER", "DEVELOPER"],
  "/grades/*": ["ADMIN", "TEACHER", "DEVELOPER"],
 
  "/students/*": ["ADMIN", "TEACHER", "STAFF", "DEVELOPER"],
  "/parents/*": ["ADMIN", "TEACHER", "STAFF", "DEVELOPER"],
  "/attendance/*": ["ADMIN", "TEACHER", "STAFF", "DEVELOPER"],
 
  "/finance/*": [
    "ADMIN",
    "TEACHER",
    "STUDENT",
    "GUARDIAN",
    "ACCOUNTANT",
    "STAFF",
    "DEVELOPER",
  ],
 
  "/my-grades": ["STUDENT", "GUARDIAN", "DEVELOPER"],
  "/my-attendance": ["STUDENT", "GUARDIAN", "DEVELOPER"],
  "/my-fees": ["STUDENT", "GUARDIAN", "DEVELOPER"],
}
export function isRouteAllowedForRole(pathname: string, role: Role): boolean {
  if (role === "DEVELOPER") return true
  if (roleRoutes[pathname]) return roleRoutes[pathname].includes(role)
  for (const [pattern, allowedRoles] of Object.entries(roleRoutes)) {
    if (pattern.endsWith("/*")) {
      const base = pattern.slice(0, -2)
      if (pathname.startsWith(base + "/")) return allowedRoles.includes(role)
    }
  }
  return true // default: allow routes not in matrix
}

Module status

ModuleStatus
DashboardWorking — role-specific widgets
Students CRUDWorking — full DataTable + forms
Teachers CRUDWorking — full DataTable + forms
Parents CRUDWorking — guardian linking partial
AttendanceWorking — daily/weekly views
GradesPartial — needs grade calculation
FinancePartial — basic CRUD, needs Stripe
TimetablePartial — display works, editor needed
AnnouncementsWorking — CRUD with targeting
EventsWorking — calendar integration

Cross-entry navigation

FromActionAuth stateDestination
SaaS marketingGet StartedGuestLogin → onboarding
SaaS marketingGet StartedHas schoolSchool dashboard
SaaS marketingGet StartedNo schoolOnboarding wizard
SaaS marketingLive DemoAnydemo.databayt.org (new tab)
SaaS marketingLoginGuestLogin page
SaaS marketingLoginDEVELOPEROperator dashboard
School sitePlatformGuestLogin → dashboard
School sitePlatformCorrect userRole-based dashboard
School sitePlatformWrong schoolAccess denied
School siteApplyAnyApplication form
Operator dashboardView SchoolDEVELOPERSchool dashboard (impersonate)

UserButton variants

VariantEntryMenu items
marketingSaaS marketingDashboard, Schools (operators), Settings
saasOperator dashboardProfile, Billing, Schools, Settings
siteSchool siteGo to Platform, Profile
platformSchool platformProfile, My Account, School Settings, Help

Edge proxy

// src/proxy.ts (simplified)
export async function middleware(request: NextRequest) {
  const hostname = request.headers.get("host")
  const subdomain = extractSubdomain(hostname)
 
  if (subdomain && subdomain !== "ed") {
    return NextResponse.rewrite(
      new URL(`/${locale}/s/${subdomain}${pathname}`, request.url)
    )
  }
 
  if (isProtectedRoute(pathname)) {
    const session = await auth()
    if (!session) return NextResponse.redirect(new URL("/login", request.url))
  }
 
  return NextResponse.next()
}

Session

session.user = {
  id: string
  email: string
  role: UserRole
  schoolId: string | null   // null for new users / DEVELOPER
  isPlatformAdmin: boolean
}

SchoolProvider

// src/components/school/school-provider.tsx
export function SchoolProvider({ subdomain, children }) {
  const [school, setSchool] = useState(null)
  useEffect(() => {
    getSchoolBySubdomain(subdomain).then(setSchool)
  }, [subdomain])
  return (
    <SchoolContext.Provider value={school}>{children}</SchoolContext.Provider>
  )
}

E2E coverage

// e2e/entry-points.spec.ts
test("SaaS marketing loads without auth", async ({ page }) => {
  await page.goto("https://ed.databayt.org/en")
  await expect(page.locator("h1")).toContainText("School Automation")
})
 
test("Operator dashboard requires DEVELOPER", async ({ page }) => {
  await page.goto("https://ed.databayt.org/en/dashboard")
  await expect(page).toHaveURL(/\/login/)
})
 
test("School site loads with subdomain", async ({ page }) => {
  await page.goto("https://hogwarts.databayt.org/en")
  await expect(page.locator("h1")).toContainText("Hogwarts")
})
 
test("School platform requires auth", async ({ page }) => {
  await page.goto("https://hogwarts.databayt.org/en/dashboard")
  await expect(page).toHaveURL(/\/login/)
})

See also

  • Authentication
  • Architecture
  • Multi-tenancy
CDN AssetsDashboard

On This Page

Overview1. SaaS marketing2. Operator dashboard3. School site4. School platformroleRoutes matrixModule statusCross-entry navigationUserButton variantsEdge proxySessionSchoolProviderE2E coverageSee also

Built by Databayt ·

Welcome to balqalam.

A great journey is about to begin.