Educational portal with whimsical frog and mushroom theme. Built with Go and Vue 3.
- 📚 Course management (lectures, labs, grade sheets, exam questions)
- 🔐 JWT authentication with role-based access (Owner/Admin/Student)
- 👥 User management system (owner-only)
- 🎫 Exam ticket generation with random question selection
- 🎨 Beautiful UI with mushroom and frog theme with animations
- 📱 Responsive design
- 🔬 GitHub integration for lab assignments
- 📝 Markdown support with syntax highlighting
- 🌙 Dark mode support
- 🐸 Frog animation on page load
Backend: Go 1.25 + Gin + MariaDB
Frontend: Vue 3 + TypeScript + PrimeVue + Tailwind CSS
Install these first:
- Go 1.23+: https://go.dev/dl/
- Node.js 20+: https://nodejs.org/
- MariaDB 11: https://mariadb.org/download/ (or use Docker)
- mkcert: for local HTTPS certificates
# Install mkcert
brew install mkcert # macOS
choco install mkcert # Windows
sudo apt install mkcert # Linux
# Create trusted certificates
mkcert -install# Clone repository
git clone https://github.com/your-username/laritmo.git
cd laritmo
# Option A: Using Docker (easiest)
docker compose -f docker-compose.local.yml up -d mariadb
# Option B: Using local MariaDB
mysql -u root -pCREATE DATABASE edu_portal CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'eduuser'@'localhost' IDENTIFIED BY 'edupass';
GRANT ALL PRIVILEGES ON edu_portal.* TO 'eduuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;# Create certs directory in backend
mkdir -p src/back/certs
cd src/back/certs
# Generate local HTTPS certificates
mkcert -key-file localhost-key.pem -cert-file localhost.pem localhost 127.0.0.1 ::1
cd ../../..cd src/back
# Config file already exists: configs/config.local.yaml
# Edit if needed (default values work out of the box)
nano configs/config.local.yamlconfigs/config.local.yaml (default):
server:
host: localhost
mode: debug
port: 8443
use_tls: true
tls_cert_file: "./certs/localhost.pem"
tls_key_file: "./certs/localhost-key.pem"
database:
host: localhost
port: 3306
user: eduuser
password: edupass
name: edu_portal
auth:
jwt_secret: "super-secret-key-change-in-production-abc123"
jwt_expiration_hours: 168# Install goose (if not installed)
go install github.com/pressly/goose/v3/cmd/goose@latest
# Run migrations
cd src/back
goose -dir migrations mysql "eduuser:edupass@tcp(localhost:3306)/edu_portal" up
# Verify
goose -dir migrations mysql "eduuser:edupass@tcp(localhost:3306)/edu_portal" statuscd src/back
# Run admin creation tool (creates user with 'admin' role)
go run cmd/createadmin/main.go
# Enter credentials when prompted:
# Username: admin
# Email: admin@example.com
# Password: admin123Note: The first user should be manually promoted to 'owner' role in the database:
UPDATE users SET role = 'owner' WHERE username = 'admin';Only owner can manage other users through the web interface.
cd src/front
# Install dependencies
npm install
# Build for production (goes to src/back/web/)
npm run buildcd src/back
# Install Go dependencies
go mod download
# Run server
go run cmd/server/main.goYou should see:
{"level":"INFO","msg":"Config loaded successfully"}
{"level":"INFO","msg":"HTTPS server started","url":"https://localhost:8443"}
{"level":"INFO","msg":"Swagger UI available","url":"https://localhost:8443/swagger/index.html"}
Open in browser:
- App: https://localhost:8443
- Login Page: https://localhost:8443/auth
- API Docs: https://localhost:8443/swagger/index.html
- Health Check: https://localhost:8443/health
Login:
- Navigate to
/authto access the login page - Username:
admin(or whatever you created withcreateadmin) - Password:
admin123(or whatever you set)
⚠️ Browser will show security warning for self-signed certificate - click "Advanced" → "Proceed to localhost"
⚠️ Important: Create admin user first usinggo run cmd/createadmin/main.gobefore logging in!
For frontend development with hot reload:
# Terminal 1: Backend
cd src/back
go run cmd/server/main.go
# Terminal 2: Frontend dev server
cd src/front
npm run devFrontend will run on http://localhost:5173 with API proxy to backend.
laritmo/
├── src/
│ ├── back/ # Go backend
│ │ ├── cmd/server/ # Main application
│ │ ├── internal/ # Business logic
│ │ │ ├── handlers/ # HTTP handlers
│ │ │ ├── repository/ # Database layer
│ │ │ ├── middleware/ # Auth middleware
│ │ │ ├── models/ # Data models
│ │ │ └── auth/ # JWT manager
│ │ ├── configs/ # Configuration files
│ │ ├── migrations/ # Database migrations
│ │ ├── certs/ # SSL certificates (local)
│ │ └── web/ # Built frontend (generated)
│ └── front/ # Vue 3 frontend
│ ├── src/
│ │ ├── views/ # Page components
│ │ ├── components/ # Reusable components
│ │ ├── stores/ # Pinia stores
│ │ ├── router/ # Vue Router
│ │ └── api/ # API client
│ └── public/ # Static assets
├── docker-compose.local.yml # Docker setup for local development
└── README.md
# Start database with Docker
docker compose -f docker-compose.local.yml up -d mariadb
# View logs
docker compose -f docker-compose.local.yml logs -f mariadb
# Stop
docker compose -f docker-compose.local.yml down
# Stop and remove volumes (clean slate)
docker compose -f docker-compose.local.yml down -vSwagger UI available at: https://localhost:8443/swagger/index.html (debug mode only)
Public:
POST /api/auth/login- LoginGET /api/courses- List coursesGET /api/lectures/:id- Get lectureGET /api/labs/:id- Get labGET /api/courses/:id/tickets/random- Generate random ticket
Admin (requires JWT + admin/owner role):
POST /api/admin/courses- Create coursePUT /api/admin/lectures/:id- Update lectureDELETE /api/admin/labs/:id- Delete labPOST /api/admin/courses/:id/tickets/generate- Generate tickets document
Owner only (requires JWT + owner role):
GET /api/admin/users- List all adminsPOST /api/admin/users- Create userPUT /api/admin/users/:id- Update userDELETE /api/admin/users/:id- Delete userPUT /api/admin/users/:id/activate- Activate userPUT /api/admin/users/:id/deactivate- Deactivate userPUT /api/admin/users/:id/password- Reset user password
Authenticated (any logged-in user):
PUT /api/auth/me/password- Change own password
Authentication is handled via a dedicated login page at /auth:
- Navigate to
/authto access the login form - Enter credentials → Receive JWT token
- Token stored in localStorage → Automatically attached to requests
- Redirected to home page after successful login
| Role | Description | Permissions |
|---|---|---|
| Owner | System owner | Full access + user management |
| Admin | Administrator | Create/Edit/Delete courses, lectures, labs, questions |
| Student | Regular user | View content, generate tickets |
Access via header button "👥 Users" (visible only to owner):
- Create/edit/delete admin accounts
- Activate/deactivate users
- Reset passwords for other users
- View all administrators
Note: Owner account cannot be modified or deleted for security.
Whimsical forest theme with:
- 🍄 Mushroom icons and decorations
- 🐸 Frog mascot with entrance animation
- 🌿 Nature-inspired color palette
- Playful yet educational design
- Smooth animations and transitions
MIT License - feel free to use for your own educational projects!
This is a learning project, but suggestions and improvements are welcome!
"Connection refused" when accessing app:
- Check backend is running:
curl https://localhost:8443/health - Check certificates exist:
ls src/back/certs/
"Database connection failed":
- Verify MariaDB is running:
docker compose -f docker-compose.local.yml psormysql -u root -p - Check credentials in
configs/config.local.yaml - If using Docker, ensure container is up:
docker compose -f docker-compose.local.yml up -d mariadb
"Swagger returns 500":
- Regenerate docs:
cd src/back && swag init -g cmd/server/main.go
Browser security warning:
- This is normal for self-signed certificates
- Click "Advanced" → "Proceed to localhost (unsafe)"
- Or use mkcert for trusted certificates
Questions? Open an issue on GitHub!