A site for building community around your high school alumni.
I built it for me and mine but feel free to use it for you and yours.
Directories
/src
- source code from frontend app/functions
- source code for the backend serverless functions/locales
- contains language files for i18n support/design
- UI/UX design attributes; not directly used by site/public
- public assets for site, primarily images
During the build process the following directories are created:
/server
- ironically this is for the serverless functions/.presite
- the prerendered content for the frontend app
The Build Process
This repo is designed to be used on Netlify and therefore the netlify.toml
file in the root provides useful instruction to Netlify's build system. Use this as a guide if you are planning on moving away from Netlify.
It is important to note that the build process is three steps:
- Using Vite's build to generate an optimized set of VueJS components (and deps)
- Using esno -- which wraps esbuild to build HTML prerendered site
- Using Rollup to build/bundle serverless functions written in TS to JS
Note: may consider using esno in the future for serverless functions but I'm not familiar enough with it to say for sure
Functional Overview
This site has the following high-level features/characteristics:
-
Features
- Secure but easy registration of alumni
- Centralized mailing list for all alumni events (aka, not dependent on users being a certain social network like Facebook)
- Create simple votes for decisions like venue or timing
- Provide pages for reunions/meetups that give all relevant meta
- Allow alumni to create music suggestions for events
- Links to photo sharing features
- Provides dark and light modes
- Provides foundation and some illustration of internationalization
-
Performance
- While it certainly could be argued that performance always matters; it could be equally argued that a small "reunion site" doesn't really need that much performance
- I disagree with the latter sentiment ... everything needs performance. Plus, I kinda want to try out a few ideas, so ...
- Site is a PWA, and service worker caches JS/CSS assets and ensures it can operate offline as well as be installed as an app
- All data is cached/synced into the browser's IndexedDB
- Reactive state leverages Vue 3's proxy objects but no global state like Vuex; this is not needed when all state can be cached locally and retrieved without need for network access/latency
-
Security:
- The goal is to keep the community's personal info safe while ensuring the app is really simple to use
- With this in mind, a user registers with their email and can re-register on as many devices as they like
- Each device which is registered will remain logged in forever unless the user chooses to log out
- A registered device has permission to:
- read all data (outside of device registration table itself)
- write and update their profile
- write and update their own vote record (only one vote per
topic
) - add new songs to Music, like other's suggestions
- While the Firebase database does provide cool client rules for Auth, it's usefulness is hindered if you want high performance (starting with the requirement to load their ungodly SDK)
- For this reason we will leverage a backend via Netlify Functions to act on our behalf for data access
- All API requests to our own backend will include the user's unique id which was provided to the client at registration
-
Client API:
- The browser uses our own API implemented in the
functions
directory to interact with the Alumni data - The API is exposed as a strongly typed VueJS composable service which exposes the following surface area:
register(email)
- sends an email to the user with a "magic link" to authorize themsync()
- sync data between Firebase and local IndexedDb; this is to ensure that the local IndexedDB is always an accurate enough reflection of Firebase's data. Each call to sync updates a client cookie timestamp so that only relevant data is being sent back to the client. The promise will return from this call as soon as all entities have been synced.updateProfile(profile)
- two phase commit of registrants profile; writes locally to IndexedDB and then to Firebasevote(topic, voteInfo)
- vote for a given voting topicsuggestSong(songInfo)
- add a new song suggestionlike(songid)
- like someone else's suggested song
-
Data
- Firebase's Firestore DB is primary store for data
- The frontend app, however, will synchronize this data to a local representation in IndexedDB so that offline access is preserved
- All data found in either database is typed in Typescript and can be found in
src/models
-
Main data entities are:
Registry
- the unique ids for the email/device pairingsMember
- registered members of the class (meta on members)Music
- songs which members associate to the graduating yearVote
- members votes on preferences for location/venue as well as timingLocation
- possible venue locations and associated meta data
-
Photos Sharing
- photo sharing is a cool feature for reunions but it's non-trivial feature so instead of building it we instead leverage Flickr!
Credits
As much as I'd love to take credit for everything here ... let's not pretend it's not awesome folks (note the lack of modesty ... its tongue in cheek in case you don't know me) but as is true with all great things ... it rests on the shoulders of giants:
- Anthony Fu
- Wow! This dude is just killing it with amazing tools!
- This project just started as a quick trial of his new Vite starter theme Vitesse.
- So so much out of the box and so much of it based on other amazing tooling he's built. Big thank you!
- I'm still amazed at some of the magic in
Icon
leveraging Iconfiy
- VueJS Core Team
- Switching from Ember to VueJS was scary three years ago but you guys have made that decision worth it every day and it keeps getting better
- Adam Wathan and TailwindCSS
- I'm no UI/UX guy and TailwindCSS along with Adam's super clear thinking and design have made me much more able to build a site someone would want to visit