What it does
A Moment is a fact of the household's garage worth sharing, found in its records and never invented (social sharing spec §1): a new car (an Ownership Period opens: added, "I bought it", an accepted History Transfer, a dealer's hand-over), a whole-year ownership anniversary, a distance milestone every 10,000 km or mi driven while owned (the account's unit), a sale (a Disposal), a Cinematic Studio picture saved to a car's gallery, and the collection reaching 3, 5, 10, 25, 50 or 100 cars. Only the latest of each counts, so a car added with years of history brings one anniversary, not five.
A Moment is new until someone in the household shares or dismisses it. The launch backlog is not: on a household's first find (the launch, or a garage filled with years of history), a Moment older than 30 days is written as seen, listed under "Earlier" but never counted as new and never pushed (statusOnFind). Sharing is a Share Card: an image made on the phone (story 9:16, post 4:5 or square 1:1) and handed to the system share sheet. Nothing is uploaded, no link is in the image, and plate, VIN and address never appear; the date is on, distance and the car's value are off by default, and a shown value carries its source, date and confidence (RN03).
The flag social.moments gates the job's push and the app's screens. It is off by default (production stays off until QA passes); dev builds of the app show the screens anyway.
Data and isolation
moment belongs to the Organization: kind, key (the period, the Disposal, <period>:<years>, <period>:<unit>:<milestone> or cars:<n> or the Studio picture), value, unit, photo_id (a studio Moment's picture), occurred_on and status (new, seen, shared, dismissed). One row per Organization, kind and key, so finding a Moment again inserts nothing. A collection Moment has no car; row-level security shows it only to owners and admins, and a Member sees the Moments of the cars granted to them (ADR-0009). Tenant traffic inserts Moments and changes status, nothing else. Deleting a car, or a studio Moment's picture, deletes its Moments.
The pure rules are findMoments in moment.rules.ts; recordMoments reads the facts (periods of current and sold cars, the first and highest reading of each open period, disposals, the gallery's Studio pictures) and inserts what is new.
Procedures
| Procedure | Who | Failures |
|---|---|---|
moment.list {} | every Member | none: first finds what is new, then lists every Moment not dismissed, newest first, with its car, a 15-minute cover link and a studio Moment's picture |
moment.setStatus { id, status } | an editor of the car; owners and admins | INPUT_VALIDATION (new is not settable), NOT_FOUND, FORBIDDEN (a viewer) |
Job
The cron tick's moments job (moment.jobs.ts) runs during each data region's morning hour (07 UTC EU, 11 UTC BR, 14 UTC US), with social.moments on. It finds the Moments of every household whose owner's account is in the region (their distance unit) and pushes the ones from the last seven days, once per device, to each Member who allows push and sees that car: one Moment says what it is ("Novo na garagem · Toyota Corolla Cross chegou."), several say how many. The launch backlog is written as seen and never pushed. Sends are never retried; the Moments screen always lists them.
The scan reads 50 households at a time in id order, pushes that page, and keeps its place for the day in job_cursor (platform/jobs/day-cursor.ts): the hour's later ticks go on from there and find nothing left once it is done; the next day starts over. A Moment that appears after its household was scanned is found the next morning (or when the Moments screen is read).
App
- Social-Celebrate (
screen-Social-Celebrate,/celebrate/<vehicleId>): opens after Add vehicle saves a car to the garage. The car's photo under the fade, the "New in the garage" pill, the model and "Your Nth car · the story starts today"; "Share this moment" (celebrar-compartilhar), "Record the purchase" (celebrar-compra, while the car has no purchase) and "Not now" (celebrar-agora-nao). A save from a dev link's example reading (the handoff's F1) still ends on the garage, as F1 asserts. - Social-Card (
screen-Social-Card,/share-card?momentId=…|vehicleId=…&template=…): templates New car, Photo, Milestone and Collection (cartao-modelo), formats (cartao-formato), toggles date, distance, car value and Cover the plate (cartao-date,cartao-distance,cartao-value,cartao-placa; locked on, with no manual cover, for a Studio picture, whose plates the Studio blurred, and the card then says "AI-generated background, original car"), another photo of the gallery (cartao-foto) and Share (cartao-compartilhar). The preview is the image:makeImageFromViewsnapshots it, the JPEG goes to a cache file, the share sheet gets the file (React Native's on iOS,expo-sharingon Android,platform/share/share-file.ts) and the file is deleted after. A shared Moment is marked shared; Android's sheet does not say whether the person shared, so closing it counts. - Social-Moments (
screen-Social-Moments,/moments): "New · N" and "Shared" (momentos-segmento), a row per Moment with its photo, title and kind · date, Share and, until shared, Dismiss, each with its spoken name; New ends with "Earlier", the seen backlog, then My collection (momentos-colecao), which opens the collection's card.
Profile has a Moments row; the garage shows "N new moments" while some wait; My collection's share button opens the collection's card (its "Share as image" choice when social.showcase is on too). autofolio://dev/Social-Celebrate, Social-Card (the seeded M3) and Social-Moments open the boards; the seed's sales are already shared, the current cars' arrivals are the seen backlog, a Studio picture in the M3's gallery brings a studio Moment, and the rest are found on the first read.
shortcut: on an original photo the plate cover is placed by the person (tap the photo where the plate is) until an on-device plate detector exists; a Studio picture needs none.