- bcrypt: 5.1.1 → 6.0.0 (убрана уязвимая зависимость glob@7.2.3) - jsdom: 22.1.0 → 28.1.0 (исправлены 3 low severity уязвимости) - @types/jsdom: 21.1.3 → 28.0.0 - autoprefixer перемещён в dependencies для корректной установки - Добавлен resolve.alias в webpack конфиг для path alias @
Schedule for College of Communication Volga State Goverment University of ICT (КС ПГУТИ)
Reskin of https://lk.ks.psuti.ru/ since it lacks mobile support.
Tech stack & features
- React 19.2.0 with Next.js 16.1.6 (pages router)
- Tailwind CSS
- @shadcn/ui components (built with Radix UI)
- JSDOM for parsing scraped pages, rehydration strategy for cache
- TypeScript 5.9.3 with types for each package
- SQLite database (better-sqlite3) for storing groups and settings
- bcrypt for secure password hashing
- Telegram Bot API (native
fetch) for parsing failure notifications - Custom js parser for teachers' photos
- Accessibility & tab navigation support
- Dark theme with automatic switching based on system settings
- Admin panel for managing groups and settings
- Optimized code structure with reusable utilities and components
- Optional auto-sync of groups from
lk.ks.psuti.rucontrolled by env
Architecture & Code Organization
The project follows a feature-sliced design pattern with clear separation of concerns:
Code Structure:
- Shared utilities (
src/shared/utils/):auth.ts- Authentication and session managementapi-wrapper.ts- Reusable API route wrappers with auth and error handlingvalidation.ts- Centralized validation functions
- Data layer (
src/shared/data/):- SQLite database for persistent storage
- Data loaders with caching (1-minute TTL)
- Automatic cache invalidation on updates
- API routes (
src/pages/api/admin/):- Unified authentication via
withAuthwrapper - Consistent error handling
- Method validation
- Unified authentication via
- Components:
- Reusable UI components in
src/shared/ui/ - Feature-specific components in
src/features/ - Complex widgets in
src/widgets/
- Reusable UI components in
Optimizations:
- Toggle switch component reused across admin panel
- Unified data loading functions
- Centralized validation logic
- Consistent API error handling
- Optimized cache management
Known issues
- Previous week cannot be accessed if you enter from main "/"
Workaround: Locate to next week, then enter previous twice.
Schedule modes
The behaviour of group management and data source is controlled by the SCHED_MODE environment variable:
hobby(default):- Groups are managed manually via the admin panel (add/edit/delete).
- The app uses whatever is stored in the local SQLite
groupstable.
kspsuti:- On the server, the app periodically fetches
https://lk.ks.psuti.ru/?mn=2, parses the group list (day + distance), and synchronises it into the local database. - The admin panel shows the current groups but disables manual editing/removal — groups are treated as read‑only and must be changed on the college site.
- All pages that call
loadGroups()automatically work with the synced list.
- On the server, the app periodically fetches
Set SCHED_MODE=kspsuti during deployment to enable automatic group syncing; omit it or set SCHED_MODE=hobby to keep the previous manual workflow.
Project structure
kspguti-schedule/
├── src/ # Source code
│ ├── app/ # App-level code
│ │ ├── agregator/ # Schedule fetching logic
│ │ ├── parser/ # HTML parsing for schedule
│ │ └── utils/ # App-level utilities
│ ├── pages/ # Pages router (Next.js)
│ │ ├── api/ # API routes
│ │ │ └── admin/ # Admin panel API endpoints
│ │ │ ├── groups.ts # Groups CRUD operations
│ │ │ ├── settings.ts # Settings management
│ │ │ ├── login.ts # Authentication
│ │ │ ├── check-auth.ts # Auth verification
│ │ │ ├── change-password.ts # Password change
│ │ │ └── logs.ts # Error logs viewer
│ │ ├── [group].tsx # Dynamic group schedule page
│ │ ├── admin.tsx # Admin panel page
│ │ └── index.tsx # Home page
│ ├── entities/ # Business entities
│ ├── features/ # Feature modules
│ │ ├── add-group/ # Add group feature
│ │ └── theme-switch/ # Theme switcher
│ ├── shared/ # Shared code
│ │ ├── constants/ # App constants
│ │ ├── context/ # React contexts
│ │ ├── data/ # Data layer
│ │ │ ├── database.ts # SQLite database operations
│ │ │ ├── groups-loader.ts # Groups data loader
│ │ │ └── settings-loader.ts # Settings data loader
│ │ ├── model/ # Data models
│ │ ├── providers/ # React providers
│ │ ├── ui/ # Shared UI components
│ │ └── utils/ # Utility functions
│ │ ├── auth.ts # Authentication utilities
│ │ ├── api-wrapper.ts # API route wrappers
│ │ └── validation.ts # Validation utilities
│ ├── shadcn/ # shadcn/ui components
│ └── widgets/ # Complex UI widgets
│ ├── navbar/ # Navigation bar
│ └── schedule/ # Schedule display components
├── public/ # Static assets
│ └── teachers/ # Teacher photos
├── old/ # Deprecated/archived files
│ ├── data/ # Old data files (groups.ts, groups.json)
│ └── README.md # Documentation for old files
├── scripts/ # Deployment scripts
├── systemd/ # Systemd service file
├── db/ # SQLite database files
├── components.json # shadcn/ui config
├── docker-compose.yml # Docker Compose config
├── Dockerfile # Docker image definition
├── next.config.js # Next.js configuration
├── tailwind.config.js # Tailwind CSS config
└── tsconfig.json # TypeScript config
Development
Prerequisites
- Node.js 20+ (see
.nvmrc) - npm 10+ or pnpm
Local development
# Install dependencies
npm install
# Run development server
npm run dev
Admin Panel
The application includes an admin panel for managing groups and application settings. Access it at /admin route.
Features:
- Manage groups (add, edit, delete)
- Configure application settings (e.g., week navigation)
- Password-protected access with session management (24-hour sessions)
- Change admin password from the admin panel
- View error logs
- Debug options (development mode only)
Security:
- Passwords are hashed using bcrypt
- Session-based authentication with secure cookies
- Rate limiting on login attempts (5 attempts per 15 minutes)
- Default password warning if not changed
Default password:
- On first launch, the default password is
ksadmin - ⚠️ Important: Change the default password immediately after first login for security!
- The admin panel will show a warning if the default password is still in use
Password recovery:
- If you forgot your admin password, you can reset it using the provided scripts
- See
scripts/RESET_PASSWORD.mdfor detailed instructions - Quick reset:
node scripts/reset-admin-password.js "new_password"
Environment variables for admin panel:
ADMIN_SESSION_SECRET- Secret key for session tokens (optional, defaults to 'change-me-in-production')ADMIN_PASSWORD- Initial admin password (optional, defaults to 'ksadmin')
⚠️ Important: Always set a strong ADMIN_SESSION_SECRET in production!
API Endpoints:
GET /api/admin/groups- Get all groupsPOST /api/admin/groups- Create new groupPUT /api/admin/groups/[id]- Update groupDELETE /api/admin/groups/[id]- Delete groupGET /api/admin/settings- Get settingsPUT /api/admin/settings- Update settingsPOST /api/admin/login- AuthenticateGET /api/admin/check-auth- Check authentication statusPOST /api/admin/logout- LogoutPOST /api/admin/change-password- Change passwordGET /api/admin/logs- Get error logs
Docker deployment
Build and run with Docker
# Build the image
docker build -t kspguti-schedule .
# Run the container
docker run -p 3000:3000 kspguti-schedule
Using Docker Compose
# Build and start
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down
Environment variables: Edit docker-compose.yml to add your environment variables:
PROXY_URL- URL for schedule parsing (optional)PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_BOTAPI_TOKEN- Telegram bot token (optional)PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_CHAT_ID- Telegram chat ID (optional)ADMIN_SESSION_SECRET- Secret key for session tokens (optional, but recommended in production)NEXT_PUBLIC_SITE_URL- Site URL for canonical links and sitemap (optional)
Database:
- The application uses SQLite database (
db/schedule-app.db) for storing:- Groups configuration
- Application settings
- Admin password (hashed with bcrypt)
- Database is automatically created on first run in the
db/directory at the project root - Database directory is excluded from deployment scripts to preserve data
- No additional database setup required
Note: Admin password is stored in SQLite database. Default password is ksadmin - change it after first login!
Production deployment
Netlify
The project includes netlify.toml for automatic deployment configuration.
Docker
The Dockerfile uses Next.js standalone output for optimized production builds. The image includes:
- Multi-stage build for smaller image size
- Non-root user for security
- Health checks
- Production optimizations
System installation (Linux systemd)
Install the application directly on a Linux system as a systemd service:
Prerequisites:
- Linux system with systemd
- Node.js 20+ installed
- Root/sudo access
- ICU library (for Node.js):
- Arch Linux:
sudo pacman -S icu - Ubuntu/Debian:
sudo apt-get install libicu-dev - Fedora/RHEL/CentOS:
sudo dnf install libicuorsudo yum install libicu
- Arch Linux:
Installation:
# Clone the repository
git clone <repository-url>
cd kspguti-schedule
# Copy example and edit .env
cp .env.production.example .env
nano .env
# Run the installation script
sudo ./scripts/install.sh
The installation script will:
- Check Node.js and npm versions
- Copy files to
/opt/kspguti-schedule - Install dependencies
- Build the production version
- Install and enable systemd service
Configuration:
- Edit environment variables:
sudo nano /opt/kspguti-schedule/.env
The installation script will:
- Copy
.envfile from source directory if it exists - Preserve existing
.envin installation directory if it already exists - Create
.envfrom.env.production.exampleif no.envfile is found
- Update systemd service if needed:
sudo nano /etc/systemd/system/kspguti-schedule.service
Managing the service:
Use the management script for easy service control:
# Start the service
sudo ./scripts/manage.sh start
# Stop the service
sudo ./scripts/manage.sh stop
# Restart the service
sudo ./scripts/manage.sh restart
# Check status
./scripts/manage.sh status
# View logs
./scripts/manage.sh logs
./scripts/manage.sh logs -f # Follow logs
# Update application
sudo ./scripts/manage.sh update
# Enable/disable autostart
sudo ./scripts/manage.sh enable
sudo ./scripts/manage.sh disable
Service configuration:
- Installation directory:
/opt/kspguti-schedule - Service user:
www-data - Port:
3000(configurable via environment variables) - Logs:
journalctl -u kspguti-schedule
Environment variables:
See .env.production.example for available options. The application uses .env file in production:
Schedule parsing:
PROXY_URL- URL for schedule parsing (optional, defaults to https://lk.ks.psuti.ru)PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_BOTAPI_TOKEN- Telegram bot token for parsing failure notifications (optional)PARSING_FAILURE_NOTIFICATIONS_TELEGRAM_CHAT_ID- Telegram chat ID for receiving notifications (optional)
Admin panel:
ADMIN_PASSWORD- Initial password for admin panel access (optional, defaults to 'ksadmin')ADMIN_SESSION_SECRET- Secret key for session tokens (optional, defaults to 'change-me-in-production', but should be changed in production)
Note: The admin password is stored in SQLite database and can be changed from the admin panel. The ADMIN_PASSWORD environment variable is only used for initial setup.
Site configuration:
NEXT_PUBLIC_SITE_URL- Site URL for canonical links and sitemap (optional, defaults to https://schedule.itlxrd.space)
Other platforms
The project can be deployed to any platform supporting Node.js 20+:
- Vercel
- Railway
- DigitalOcean App Platform
- AWS App Runner
- Any Docker-compatible platform