Venue Age Rules Schema โ
Overview โ
Lantern enforces age restrictions at the venue level to ensure:
- Legal compliance (21+ for bars serving alcohol)
- Time-based restrictions (some venues change age requirements by time of day)
- User safety and appropriate venue matching
All age verification happens server-side using encrypted birth dates. Users never see ages displayed publicly.
Venue Configuration Schema โ
Basic Structure โ
{
"venue_id": "unique-venue-id",
"name": "Venue Name",
"type": "bar|cafe|restaurant|club|activities",
"min_age": 18,
"time_restricted": false,
"restrictions": []
}Fields โ
venue_id (string, required) โ
Unique identifier for the venue.
name (string, required) โ
Display name of the venue.
type (string, required) โ
Venue category. One of: bar, cafe, restaurant, club, activities, shop, public-space
min_age (integer, required) โ
Minimum age to light a lantern at this venue (default: 18)
- Most venues:
18 - Bars/clubs:
21 - Can be higher for special venues
time_restricted (boolean, required) โ
Whether venue has different age rules at different times.
false: Same age rule all daytrue: Age requirements change by time (seerestrictionsarray)
restrictions (array, optional) โ
Array of time-based age restrictions. Only used if time_restricted: true.
Each restriction object:
{
"start_time": "HH:MM",
"end_time": "HH:MM",
"min_age": 18
}Examples โ
Example 1: Simple Cafe (18+, All Day) โ
{
"venue_id": "cafe-midnight-bean",
"name": "The Midnight Bean",
"type": "cafe",
"min_age": 18,
"time_restricted": false,
"restrictions": []
}Behavior: All users 18+ can light lanterns anytime.
Example 2: Bar/Restaurant (Age Changes by Time) โ
{
"venue_id": "bar-rusty-anchor",
"name": "Rusty Anchor Pub",
"type": "bar",
"min_age": 18,
"time_restricted": true,
"restrictions": [
{
"start_time": "06:00",
"end_time": "22:00",
"min_age": 18,
"description": "Restaurant hours: 18+"
},
{
"start_time": "22:00",
"end_time": "06:00",
"min_age": 21,
"description": "Bar hours: 21+"
}
]
}Behavior:
- 6am-10pm: 18+ can enter (restaurant/dining)
- 10pm-6am: 21+ only (bar mode)
Example 3: Nightclub (21+ Always) โ
{
"venue_id": "club-electric-avenue",
"name": "Electric Avenue",
"type": "club",
"min_age": 21,
"time_restricted": false,
"restrictions": []
}Behavior: Only 21+ users can light lanterns.
Example 4: Public Space (18+) โ
{
"venue_id": "library-city-main",
"name": "City Library",
"type": "public-space",
"min_age": 18,
"time_restricted": false,
"restrictions": []
}Behavior: All 18+ users can light lanterns.
Server-Side Age Verification Logic โ
Pseudocode โ
function canUserLightLanternAtVenue(user, venue, currentTime) {
// 1. Decrypt user's birth date (server-side only)
const userAge = calculateAge(decryptBirthDate(user.encrypted_birth_date))
// 2. Get applicable age requirement
let requiredAge = venue.min_age
if (venue.time_restricted) {
// Find matching time restriction
const restriction = venue.restrictions.find(r =>
isTimeBetween(currentTime, r.start_time, r.end_time)
)
if (restriction) {
requiredAge = restriction.min_age
}
}
// 3. Check if user meets requirement
return userAge >= requiredAge
}Response to User โ
If eligible:
{
"can_light": true,
"venue_id": "bar-rusty-anchor",
"venue_name": "Rusty Anchor Pub"
}If NOT eligible:
{
"can_light": false,
"venue_id": "bar-rusty-anchor",
"venue_name": "Rusty Anchor Pub",
"reason": "This venue requires users to be 21+ after 10pm"
}Frontend Behavior โ
Venue Selection โ
When user selects a venue to light their lantern:
Frontend sends request to backend with:
user_idvenue_idcurrent_time
Backend validates age and responds
Frontend shows:
- Success: Open LightLanternForm
- Failure: Display error message with reason
Error Message Examples โ
โ This venue is 21+ after 10pm
โ This venue requires users to be 21+
โ You must be 18+ to use LanternPrivacy Guarantees โ
What's Encrypted โ
- User's birth date (encrypted with user-specific key)
- Only decrypted server-side for age verification
- Never transmitted or displayed to other users
What's Logged โ
โ "User X requested access to Venue Y at Time Z" โ "Age verification passed/failed" โ User's actual age โ User's birth date โ Calculation details
Data Retention โ
- Birth dates: Deleted 30 days after account deletion
- Verification logs: 90 days (no PII, just pass/fail)
- Location check-ins: 48 hours max
Integration with Merchant Offers โ
Merchants can only create offers for age-appropriate users.
Example: Bar Offer โ
{
"offer_id": "bogo-pints",
"venue_id": "bar-rusty-anchor",
"min_age_override": 21,
"headline": "BOGO pints after 8pm"
}Backend filters:
- Only shows offer to users who pass age check for venue
- If
min_age_overrideis set, use that instead of venue's min_age - Prevents accidental marketing of alcohol to underage users
Backend Implementation TODO โ
Firestore Schema
venues/{venue_id} - min_age: number - time_restricted: boolean - restrictions: array users/{user_id} - encrypted_birth_date: string - created_at: timestampCloud Function:
verifyVenueAge- Input: userId, venueId, timestamp
- Output:
Security Rules
javascript// Users can't read other users' birth dates match /users/{userId} { allow read: if request.auth.uid == userId; allow write: if false; // Only backend can write }Logging
- Log age verification attempts (no PII)
- Alert on repeated failures (potential abuse)
Questions to Answer โ
Grace period for birthdays?
- Should we verify age daily or cache verification status?
- Recommendation: Cache for 24 hours, reverify daily
Venue-specific overrides?
- Can merchants request custom age rules?
- Recommendation: Yes, but requires manual approval
Emergency access?
- What if user is locked out due to age miscalculation?
- Recommendation: Support ticket with ID verification
International users?
- Drinking age varies by country
- Recommendation: Use venue's local age rules