Achievement ideas
Every achievement JAM could offer with the data it keeps today, what is still missing before any of them can be earned, and a first batch of one-off badges drawn as 16px pixel art, so the ideas can be judged as badges and not as words. Pick the ones worth keeping; each can come back as its own item for an icon and the build.
- Two kinds of achievement. Trees count something up through Stone to Diamond and wear a fruit (on a shield from platinum). Badges are earned once and sit on a round coin, so a badge never reads as a tier.
- A badge's rim says its kind: red for firsts, blue for time of day, green for the calendar, purple for hidden ones.
- A hidden badge shows one shared "?" coin until it is earned; after that it looks like any other badge.
- Every idea is grounded in what jam-core stores today: running and cycling JAMs, joining as an RSVP only, no check-in, weather, chat or ratings. Times are read in Europe/Brussels.
- Only the trees go next to a name. Badges live on the profile.
- The tree thresholds stay the placeholders from Avatars and achievements.
Two trees are drawn, each with six tiers and a locked silhouette, plus the states a tree can be in. That is the whole of it: so far achievements are drawings only.
Every state is drawn in full on Avatars and achievements.
What has to exist before anyone earns the first Stone. These are the jam-core and jam-web items; none of it is in this sheet's scope.
- A stored unlock: who, which achievement, when. jam-core
Leaving a JAM, unstarring and removing a connection all delete rows, so an achievement worked out live from those rows would vanish again. Unlocks are kept once earned, never recomputed. - Unlock evaluation when a person joins or creates a JAM, connects, or joins a group, and when a JAM's start time passes (the time-of-day and calendar badges), plus a one-off backfill so existing members start with what they already earned. jam-core
- An API to read a person's achievements: earned with the date, progress to the next tier, and the hidden ones only as a count until earned. jam-core
- Profile UI: earned, in progress, locked and hidden, and the tree icon next to a name. jam-web
- Sharing settings respected: an achievement says something about your sessions, history or connections, so it follows that subject's per-person sharing setting before anyone else sees it. jam-core jam-web
- An honesty caveat: joining a JAM is only an RSVP; there is no check-in. Every "joined" count trusts the RSVP until a check-in exists. Counting a JAM only once its start time has passed with you still on it is the cheapest guard.
One card per idea: the badge (or a dashed placeholder), the rule, and the jam-core data it would be worked out from. Twelve badges are drawn as a first batch; the rest wait for a pick.
One set: badges next to the trees, at 64px
The same drawing at 16, 32 and 64px
Milestone trees
Counted up through Stone to Diamond, one fruit per tree. The two drawn trees, and candidates for more; each would need its own fruit.
JAMs joined
How many JAMs you joined, 1 to 100.
Count of attendance rows, the JAM's session.starts_at past.
Trusts the RSVP: there is no check-in.
buildable today drawnJAMs created
How many JAMs you organised, 1 to 50.
Count of session where organiser_id is you.
Connections made
How many people you are connected with.
connection with status = 'accepted', either side.
Groups joined
How many groups you are a member of.
group_member with status = 'member'.
Friends invited
How many people signed up with your invite link.
profile.invited_by_code pointing at your invite_code (owner_profile_id).
Kilometres covered
Distance of every JAM you joined, added up: 10 km to 1,000 km.
Sum of session.distance_m over joined JAMs.
distance_m is optional; a JAM without one adds nothing.
Weeks in a row
Consecutive weeks with at least one JAM: 2 to 52.
Joined JAMs grouped by week of session.starts_at, Brussels time.
Crowd puller
People who joined the JAMs you organised, added up.
attendance on session where organiser_id is you, yourself not counted.
One-time firsts
Earned once, the first time you do something. Red rim. Most of the app's first steps are already rows with a date on them.
First connection
Your first accepted connection. Two cherries, one stem.
connection.accepted_at
First group joined
You became a member of a group. A bunch of grapes.
group_member.joined_at, status = 'member'
First group created
You started a group.
group.owner_id, group.created_at
Friend joined with your invite
Someone signed up with your invite link. A letter with a strawberry seal.
profile.invited_by_code → invite_code.owner_profile_id
First starred JAM
You starred a JAM to keep an eye on it.
star.created_at
Unstarring deletes the row; the unlock has to be kept.
buildable todaySecond city
You joined a JAM in a city other than your first one.
Two distinct session.city_id over joined JAMs.
Both sports
You joined a running JAM and a cycling JAM.
session.sport is running and cycling over joined JAMs.
Onboarding done
You finished setting up your profile.
profile.onboarded_at
Everyone from before onboarding was backfilled to their sign-up date, so they get it too.
buildable todayFirst group JAM
You joined a JAM posted in one of your groups.
session.group_id set, on a joined JAM.
Time of day
When the JAM starts, in Brussels time. Blue rim. Earned once the start time has passed with you still on the JAM.
Early bird
A JAM that starts before 07:00. An orange coming up over the hill.
session.starts_at, Brussels time
Night owl
A JAM that starts at 21:00 or later. A banana moon.
session.starts_at, Brussels time
Lunch break
A weekday JAM that starts between 12:00 and 13:59.
session.starts_at, Brussels time and weekday
Calendar and seasonal
A JAM on a day that means something. Green rim. Worth a badge each because they come round once a year: miss it and it is a year's wait.
New Year's Day
A JAM on 1 January. A firework in jam colours.
session.starts_at date, Brussels time
Longest day
A JAM on 21 June. A lemon for a sun.
session.starts_at date
Halloween
A JAM on 31 October. A pumpkin, which is a fruit.
session.starts_at date
Shortest day
A JAM on 21 December. Holly, the fruit that is out then.
session.starts_at date
JAMiversary
A JAM on the anniversary of the day you signed up.
profile.created_at against session.starts_at
Gentse Feesten
A Ghent JAM during the Gentse Feesten. One of a family of local ones.
session.city_id and starts_at
Needs the festival's dates for each year, as a small table.
needs a small additionCar-free Sunday
A cycling JAM in Brussels on its car-free Sunday.
session.sport, city_id, starts_at
The date moves each year: the same small table of dates.
needs a small additionRain or shine
A JAM that went ahead in the rain.
Nothing: JAM keeps no weather.
Would need the weather at the meeting point and time.
needs new dataA profile's achievements, mixing tree tiers, firsts, a calendar badge and a hidden one, and the same person in a list. Only the trees go next to a name: that slot belongs to them.
Sofia 
Ghent · running · 58 JAMs, 12 created
A badge says what happened once; a tier says how far you have come, which is what someone glancing at a list wants to know. A coin next to a name would also be a second, competing icon there.
Locked badges show their silhouette with how to earn them; hidden ones show only the "?" coin and never say how.