A minimal, secure CCTV viewing dashboard built with Next.js 15, React 19 and Tailwind CSS v4. It authenticates with credentials from .env, protects private routes via middleware, autodiscovers videos from public/, and supports English, Uzbek, and Russian.
- Auth: Username/password from
.env, httpOnly session cookie, middleware-protected routes - CCTV Watch: Grid of autoplaying, looping, muted videos from
public/(recursively) - i18n: EN / UZ / RU with on-page language switcher persisted via cookie
- Clean UI: Tailwind v4, responsive grid, logout control
- Next.js 15 (App Router)
- React 19
- Tailwind CSS v4 (
@tailwindcss/postcss) - ESLint 9 (Next core web vitals)
npm iCreate a .env file at the project root (you can copy .env.example).
ADMIN_USERNAME=admin
ADMIN_PASSWORD=changemeUse strong values in production.
npm run dev
# open http://localhost:3000npm run build
npm start- Visit
/:- Not logged in → redirected to
/login - Logged in → redirected to
/watch
- Not logged in → redirected to
- Sign in at
/loginusing the credentials from.env - Watch grid at
/watch - Logout via the header control (links to
/api/logout)
- Toggle EN / UZ / RU from the header (or login page).
- Selected locale is stored in a
langcookie and applied to the page.
POST /api/login: validates credentials from.env, setssessionhttpOnly cookie containing a SHA-256 digest ofusername|password.GET /api/logout: clears the session cookie and redirects to/login.middleware.js: protects/watchand/admin/*, redirects/based on login state.
- Language files in
src/i18n:en.json,uz.json,ru.json. langcookie controls the UI language; switcher writes the cookie client-side and triggers a soft refresh.
- Server components (
/watch) readpublic/recursively, normalize Windows paths, and render a responsive grid.
npm run dev– start dev server (Turbopack)npm run build– production buildnpm start– start production servernpm run lint– run ESLint
src/
app/
api/
login/route.js
logout/route.js
lang/route.js
login/page.js
watch/page.js
layout.js
components/
LanguageSwitcher.js
i18n/
en.json
uz.json
ru.json
config.js
public/
demo.gif
- Set strong
ADMIN_USERNAMEandADMIN_PASSWORDvalues - Serve over HTTPS so cookies can be marked
secure - Keep videos in a storage bucket/CDN if
public/becomes large
