A lightweight Go-powered static server and vanilla JavaScript single-page app that reproduces the Zone01 student profile. The back end simply serves the assets, while the front-end handles authentication, routing, and data visualisation against the official https://learn.zone01oujda.ma GraphQL API.
- Go
net/httpserver that serves the compiled assets fromweb/and redirects unknown/assets/*requests back to/. - Client-side router (
web/assets/js/index.js) with basic route guards driven bylocalStorageto protect the profile route. - Authentication view that exchanges username/password credentials for a JWT and stores it in the browser.
- Profile dashboard showing general student info plus XP progression, audit ratio, top skills, and the latest graded projects rendered with inline SVG graphs.
- Utility helpers for logout, global error rendering, and keeping multiple tabs in sync through the
storageevent.
- Go 1.22 for the minimal HTTP server (
main.go). - Plain HTML/CSS served from
web/. - Modern ES modules for the SPA logic (no bundler needed).
- Native
fetch+ GraphQL queries against the Zone01 API.
.
├── go.mod
├── main.go # Static file server + template handler
└── web
├── index.html # Root page that loads the SPA entry script
└── assets
├── css # global.css plus per-view styles (profile, sign-in)
├── js
│ ├── index.js # Router + entry point
│ ├── utils # Session helpers, shared UI helpers
│ └── views # View base class + Profile & SignIn screens
└── holder.webp # Placeholder avatar
-
Install Go 1.22+.
-
From the repo root run:
go run . -
Open
http://localhost:8080in a modern browser. -
Authenticate with valid Zone01 credentials inside the Sign-In form to receive a JWT that unlocks the profile view.
The app talks directly to the public Zone01 API, so no additional environment variables or local databases are required. Ensure your network allows outbound HTTPS calls to
learn.zone01oujda.ma.
-
Entry point (
web/assets/js/index.js)
Declares the available routes, performs history-based navigation, loads the relevant view class, and swaps stylesheets per view. It keeps tabs synchronised by listening forstorageevents involving thejwtkey. -
Base view (
web/assets/js/views/View.js)
Provides shared behaviour for setting titles, injecting/removing stylesheets, and defining thegetHtml/initlifecycle that concrete views implement. -
Sign-in view (
web/assets/js/views/SignIn.js)
Renders the login form, validates inputs, performs a Basic Auth request to/api/auth/signin, stores the returned JWT inlocalStorage, and navigates back to/. Errors are surfaced inline without reloading the page. -
Profile view (
web/assets/js/views/Profile.js)
Executes a single GraphQL query that aggregates user info, XP history, and project grades for event41. It hydrates the DOM with user metadata, derives a human readable "role" label from the latest level, and produces four inline SVG graphs (skills, XP progression, audit ratio, recent projects). Failed fetches trigger a graceful fallback panel. -
Utilities (
web/assets/js/utils/utils.js)
Encapsulates session helpers (isLoggedIn,LogOut) and error rendering so the router and views do not repeat the same DOM logic.
- Adding a route means creating a new view class (extending
View), styling it via a matching CSS file, and adding a{ path, view, style }entry to thepagesarray inindex.js. main.gocurrently serves everything on port8080. Adjust the port or asset root there if you deploy behind a different setup.- The profile graphs rely on data shape from the GraphQL query declared at the top of
Profile.js. If Zone01 evolves the schema, update the query and any dependent DOM helpers together. - The SPA assumes a JWT stored under the
jwtkey. If you integrate with a different auth mechanism, update both the Sign-In view and the router guards (utils.isLoggedIn).
- Start the Go server and navigate to
/sign-in. - Submit valid credentials; verify a
jwtentry appears inlocalStorage. - Confirm you are redirected to
/and the profile dashboard populates or shows a graceful error if the GraphQL call fails. - Click the logout button or run
localStorage.removeItem("jwt")in the devtools console and verify the router returns you to/sign-in.
This README should give you, or any collaborator, enough context to understand how the project is wired, how to run it, and where to make changes.