School Bus Home — Data Storage & Data Flow

Last updated: 8 September 2026.

This page documents where School Bus Home (operated by Erbacci LLC, a company registered in Wyoming, United States) stores data and how data moves through the system. It exists to answer the Ring privacy review's data-flow questions and is referenced from the certification questionnaire. Contact: info@erbacciltd.com.

School Bus Home performs snapshot classification and keeps no image in its data stores apart from the single still that confirms a school bus. On a motion or doorbell event inside one of the customer's windows it makes one vision attempt, which retrieves up to 3 still image snapshots (2 seconds apart, stopping early once the check can answer) from the Ring device via the Ring Partner API, sends each one to a single-stage computer-vision check to decide whether a US yellow school bus is visible, and discards its copy of every image immediately after classification (the one image that confirms a bus is kept on the terms set out below).

There are two windows, and they share this one pipeline:

Snapshot volume is budgeted per day and per window, and the budget is expressed in vision attempts, which is not the same as still images: 12 vision attempts for the after-school window (unchanged) and 4 for the morning window, and each window stops as soon as a bus is confirmed. One attempt re-samples up to 3 still images taken 2 seconds apart at the event moment — Ring's upload of the event can lag and a bus can be mid-turn or out of frame in the first frame — and it stops early as soon as it can answer. The worst case per customer per school day is therefore about 12 × 3 = 36 still images with the morning window off, and about 16 attempts = 48 still images with it on.

These are per-window spend bounds, not exact admission control, and we state them that way deliberately. The attempt counter is advanced when an attempt completes, while the decision to start one reads that counter beforehand, so a burst of near-simultaneous events can start a few attempts against a count that has not caught up yet and push a window slightly past its budget before it closes. The overshoot is bounded by how many attempts are in flight (the worker runs at a fixed reserved concurrency), it is small, and it does not change anything about retention. The single-notification guarantees are a different mechanism — conditional single-claim writes, not counters — and those are exact.

Every one of those images is classified in memory. The ones that show no school bus are discarded immediately; only the single image that confirms a bus is kept, on the terms set out above. The retention commitments below are unaffected by the count. Events outside every window fetch nothing at all: the after-school window is evaluated first and wins, and the morning window is consulted only for events outside it.

The pipeline is one stage. There is no vehicle gate, screen, or pre-filter in front of the classifier: every frame the worker fetches goes straight to the school-bus check, and no AWS vision service is shown the frame — the only AWS component that ever sees one is Amazon Bedrock, and only when it answers as the fallback below. Configuration: LOCAL_INFERENCE=off (no gate), BUS_ENGINE=local, LOCAL_CLASSIFY_TIMEOUT_MS=60000.

No video, clips, live view, audio, or biometric data ever enter the system, and no image is ever written to any database or log. Every frame that does not confirm a school bus is discarded in memory. The single frame that confirms one — at most one per window per day — is written to a private, encrypted S3 bucket (see section A), where it expires automatically after 31 days and is served only to the account owner through a short-lived pre-signed URL; alongside it the derived result (a boolean "school bus present", a confidence value, and timestamps) is persisted. No person, face, age, or licence-plate recognition is performed; the question is vehicle type only. The classifier runs its model only to answer that one question about the single frame in front of it: the model on our own GPU servers and the Claude Haiku 4.5 model on Amazon Bedrock that answers in its place are both used for inference only, and Erbacci LLC uses no customer image to train, fine-tune, or improve any model — not the model on the GPU servers we own in the United Arab Emirates, and not through the AWS inference service we call, which under its terms does not train on customer content.

A. Data storage locations and systems

All persistent storage is in Amazon Web Services, region us-east-1, encrypted at rest with AWS-managed keys. DynamoDB tables use on-demand capacity; point-in-time recovery is enabled on the durable state tables (users, days, devices, push-tokens), while the short-lived TTL tables (one-time codes, link codes, webhook dedupe) and the voluntary waitlist do not use it.

The only component outside AWS is the school-bus classifier (see section B): a reverse proxy on a rented Contabo GmbH virtual server in Germany in front of GPU servers Erbacci LLC owns and operates in the United Arab Emirates. It is a processing step, not one of the application's storage systems: it receives the frame in order to answer the school-bus question and returns that decision and a confidence value, and no School Bus Home table, bucket, or log is hosted there — no account, credential, schedule or detection record ever leaves us-east-1. The frame is processed transiently at both hops for that single check and is not retained, under the same no-media-retention commitment as our AWS systems.

StoreContentsRetention
school-bus-home-users (DynamoDB)Account (email, Ring account id, encrypted Ring OAuth tokens), embedded arrival schedule (after-school window times, expected-by, school days, timezone; plus the optional morning window's start/end and on/off flag — no expected-by), notification preferencesUntil account deletion
school-bus-home-days (DynamoDB)One record per user per school day: detection status, first school-bus-confirmed timestamp, detection confidence, classifier model name, frozen window snapshot, and — when the morning window is on — a separate morning sub-record (first sighting timestamp, confidence, attempt count) — no image bytes31 days (TTL, automatic expiry)
schoolbushomestack-proofframes… (S3)The single still image that confirmed a school bus — at most one per window per day, per user. Private bucket: all public access blocked, encrypted at rest (SSE-S3), TLS required. Never public; served to the account owner only, through a short-lived pre-signed URL. No frame that failed to confirm a bus is ever written here31 days (S3 lifecycle rule expire-with-day-row, automatic expiry — the same horizon as the day record it belongs to), or immediately on account deletion
school-bus-home-devices (DynamoDB)Device id, user-assigned name, type, online/offline statusUntil device removed or account deleted
school-bus-home-push-tokens (DynamoDB)APNs/FCM push endpoints per installUntil unregistered or account deleted
school-bus-home-otp-codes (DynamoDB)Salted scrypt hashes of sign-in one-time codes10 minutes (TTL)
school-bus-home-oauth-codes (DynamoDB)Unclaimed Ring link tokens + single-use session codesShort TTL (minutes)
school-bus-home-webhook-dedupe (DynamoDB)Webhook request ids for idempotency~24 hours (TTL)
school-bus-home-waitlist (DynamoDB)Email addresses voluntarily left for feature updates (the form is no longer offered)Until removal requested
AWS Secrets ManagerRing client credentials, webhook HMAC secret, JWT signing secret, Resend API keyOperational
Amazon CloudWatchDiagnostic logs (labels, confidence, timing — never image data)30 days
Amazon S3 + CloudFrontStatic web dashboard assets only — no customer dataOperational

Apart from the single confirming frame in the proof-frames bucket listed above, there is no media storage anywhere in the application estate: every other image snapshot is held only in the worker's memory for the duration of the classification and then discarded, and nothing writes an image, base64, or embedding to any other store. The classifier is shown a copy of each frame in order to answer the school-bus question and returns only that decision, a confidence value and a vehicle-present flag; that copy passes through the Contabo-hosted reverse proxy in Germany and is processed transiently on one of the Erbacci-owned GPU servers in the United Arab Emirates for that single check, and is not retained at either hop — the same no-media-retention commitment as our AWS systems.

B. Data flow between systems

Ring Partner API
   │  webhook POST (motion_detected, button_press, device_online/offline,
   │  device_added/removed, app_integration_added/removed — metadata)
   ▼
AWS Lambda (webhook-handler)   ── verifies the HMAC signature on the raw body,
   │                              deduplicates on the request id, returns 200
   ▼
Amazon SQS (events queue)
   ▼
AWS Lambda (event-processor)   ── resolves the account, checks the event against
   │                              the after-school window first, then (only if the
   │                              event falls outside it) the optional morning
   │                              window — deterministic time comparison. If it is
   │                              inside a window and within THAT window's daily
   ▼                              ATTEMPT cap (12 after-school / 4 morning), it
Amazon SQS (vision queue)         enqueues ONE vision job tagged with its window
   ▼
AWS Lambda (vision-worker)     ── ONE attempt = UP TO 3 still image snapshots from
   │                              Ring (image download API, 2s apart, stopping
   │                              early once answerable). There is NO gate and NO
   │                              pre-filter: EVERY frame goes STRAIGHT to the
   │                              classifier. No AWS vision service is shown it.
   │
   │  THE ONE CHECK — "is this a US yellow school bus?" (OUTSIDE AWS)
   ├──► vision.erbacciltd.com     ── TWO HOPS, both OUTSIDE AWS: (1) a reverse proxy
   │      │                          on a virtual server RENTED FROM CONTABO GmbH in
   │      │                          GERMANY, which TERMINATES THE TLS (so Contabo is
   │      │                          an infrastructure sub-processor able to see the
   │      │                          frame in transit; it runs no analysis and keeps
   │      │                          nothing), then (2) the GPU servers ERBACCI LLC
   │      │                          OWNS AND OPERATES in the UNITED ARAB EMIRATES,
   │      │                          which runs the classifier: qwen3.5 (9B, 8-bit),
   │      │                          an open-weights vision-language model.
   │      │                          Called as POST /schoolbushome/classify over
   │      │                          HTTPS/TLS with a bearer token (the endpoint
   │      │                          answers 403 without one). Returns ONLY the
   │      │                          school-bus decision, a confidence value and a
   │      │                          vehicle-present flag.
   │      │                          THIS is where the final answer is produced.
   │      │                          The frame is processed transiently there for
   │      │                          this one check and is not retained.
   │      │  on error / timeout (60s) / unreachable  (circuit breaker
   │      ▼  after 5 consecutive failures)
   │    Amazon Bedrock            ── automatic fallback, inside AWS: Anthropic's
   │                                 Claude Haiku 4.5 answers the SAME question
   │                                 instead. ONE model — no second tier.
   │
   │                              the worker then DISCARDS its copy of every frame
   │                              and writes only boolean + confidence + timestamp.
   │                              A confirmed bus in the MORNING window writes the
   ▼                              morning sighting instead and queues its own alert
Amazon DynamoDB
   ▼
Amazon SQS (notifications queue)
   ▼
AWS Lambda (notification-dispatch)
   ├──► Resend        — email delivery (recipient address + notification text only)
   └──► Amazon SNS    — mobile push via Apple APNs / Google FCM
                        (push token + notification title/body only)

A once-per-minute scheduled check (arrival-sweep) evaluates whether a user's expected-by time has passed with no school bus confirmed and, if so, dispatches the heads-up through the same notification path. That sweep is after-school only — the morning window has no expected-by time and no sweep, so a morning with no detection produces no notification at all, only an attempt counter on the day record. Both single-alert guarantees are enforced by conditional single-claim writes on the day record (one for the after-school arrival, a separate one for the morning sighting), so each can fire at most once per day; a morning sighting whose claim resolves at or after local noon is still recorded on the day but sends nothing, so the copy is never out of date with the clock. A daily job refreshes Ring OAuth tokens.

Every image snapshot exists only transiently in the application: each of the up-to-3 frames in an attempt is fetched, downscaled, classified, and the worker's copy is then discarded. Inside AWS none is ever persisted apart from the single confirming frame described above, and none is ever written to a log line — CloudWatch records labels, confidence and timing only, never image data. Each frame is sent to one destination: the school-bus classifier (POST https://vision.erbacciltd.com/schoolbushome/classify), which is a reverse proxy on a rented Contabo GmbH virtual server in Germany that terminates the TLS, in front of the GPU servers Erbacci LLC owns and operates in the United Arab Emirates. Across both of those hops the frame is processed transiently for that single school-bus question and is not retained, under the same no-media-retention commitment as our AWS systems. The only other service that is ever shown a frame is Amazon Bedrock, running Anthropic's Claude Haiku 4.5 inside AWS, and only when it answers the school-bus question as the automatic fallback; no AWS vision service sees the frame at any point. A Ring device with cloud recording (Ring Protect) active is required for a still image to exist at the event moment; when none exists, the app records "detection unavailable" for that camera and does not report a false result.

Ring API calls made by the system (exhaustive): POST https://oauth.ring.com/oauth/token, GET /v1/users/me, GET /v1/devices (with ?include=status), GET /v1/devices/{id} (single-device metadata refresh when a device name/status needs healing), POST/PATCH /v1/accounts/me/app-integrations, and POST /v1/devices/{id}/media/image/download (retrieves a still image snapshot, called up to 3 times per vision attempt; every frame is classified in-memory and discarded). No live-view, clip, or event-history endpoint is ever called.

Third parties receiving data: AWS (infrastructure — it hosts the application, its databases, queues, the proof-frame bucket and push dispatch; the only AWS component ever shown a frame is the Amazon Bedrock inference service, and only when it answers the school-bus question as the automatic fallback), Anthropic (its Claude Haiku 4.5 model performs that fallback classification within Amazon Bedrock; it receives the transient image for that inference only, does not retain it, and does not train on it), Contabo GmbH (the German hosting provider whose rented virtual server runs the TLS-terminating reverse proxy in front of the classifier; the frame passes through it in transit and it performs no analysis and holds no account data), Resend (email address + notification content), and Apple/Google (push token + notification title/body). None of these third parties retain the image and none use the data for any other purpose.

The classification itself is not an onward disclosure to another company: it runs on GPU servers Erbacci LLC owns and operates. It is listed separately from the third parties above because it is first-party processing — but it takes place in the United Arab Emirates, outside the United States, which is disclosed as such in the privacy policy rather than presented as an in-AWS step.

Deletion: in-app Account → Delete account cascades across all tables immediately; unlinking the integration in the Ring app revokes our access immediately; requests can also be made via info@erbacciltd.com.

C. Contact

Erbacci LLC · info@erbacciltd.com