Staff submit
Authenticated staff create announcements or request edits and deletions from a dedicated management dashboard.
School-wide web system
I designed and built the production site solo so teachers across SITHS have one place to open the daily morning announcements.
Open Early Bird Hub ↗
Usage
200+ daily visits
Reach
SITHS classrooms
Implementation
Built solo
Publishing
Staff submissions + admin review
The hard part
The public Nuxt app deploys to Netlify, but approved announcements stay live through Supabase-backed API routes. A prebuild step also mirrors uploaded images from the school-hosted storage into the static deploy, so the site is not dependent on every image request reaching the school server.
Self-hosting
Instead of paying for a managed Supabase subscription, the database runs locally on a school computer. That avoids depending on a free hosted project that can pause after inactivity and keeps the recurring cost at zero.
Self-hosting created a second problem: a machine inside the school network is not normally reachable from the public internet. Opening inbound ports or changing the school router was not a realistic option, so the connection had to start from inside the network.

Reverse tunnel
The school computer opens an encrypted SSH connection to a public host. That outbound connection is allowed through the network, and the host maps a public endpoint back through the tunnel to the selected service running inside school.
Requests reach the public host, travel through the already-open tunnel, and arrive at the local server. The school router does not need a new inbound rule, and the database can remain on the school machine while the public app and management tools still reach it.
System model
The public site, publishing tools, video feed, and school-hosted database are separate pieces joined through API routes.
Input
Create, edit, or delete request
Gate
Compare, approve, or reject
Data
Auth, records, and image storage
External feed
Latest morning broadcast
Delivery
Static interface with live API data
Output
200+ visits on school days

First architecture pass
This was the first pass at separating the people publishing, the database storing changes, and the site classrooms actually open. The final build keeps records live and mirrors uploaded media during deployment.
Behind the homepage
Staff submit changes. The AV teacher reviews them. Only approved records reach the public page.
Early Bird
Announcement manager

Edit request
Robotics interest meeting
Before
Proposed

Authenticated staff create announcements or request edits and deletions from a dedicated management dashboard.
The AV teacher sees pending actions, including a before-and-after view for edits, then approves or rejects each change.
Approved records appear through the public API and are grouped into today's announcements and earlier posts.
Moderation
if (action.action_type === "edit" && action.old_id) {
await supabase
.from("daily_links")
.update({
name: action.name,
description: action.description,
url: action.url,
img: action.img
})
.eq("id", action.old_id)
await supabase
.from("daily_links")
.delete()
.eq("id", actionId)
}Build pipeline
try {
execSync("node scripts/copy-local-images.js", {
stdio: "inherit"
})
console.log("Images bundled for deploy")
} catch (error) {
console.log("Storage unavailable")
console.log("Continuing build without copied images")
}Actual use
The repeating traffic spikes line up with school-day announcement use, reaching more than 200 visits per day across SITHS classrooms.

What the project taught me
A static frontend can still serve changing content. The important choice is deciding which parts belong in the deploy and which remain live behind an API.
The admin experience matters as much as the public page. The system only works daily if staff can contribute and the teacher can review changes without developer help.
Cost constraints can lead to real architecture decisions. Self-hosting removed the subscription cost but required a reliable path through the school network.
Deployment is part of the product. Authentication, database access, image storage, API routes, build scripts, tunneling, and hosting all had to work as one system.