You are writing down the hardest moments of a child's life. That information deserves more care than a notes app gives it. Here is what we do, in everyday language first. The full technical version is at the bottom.
Last updated October 5, 2026
Only you can see it
Your kids' records are tied to your login and nobody else's. There is no shared library, no agency portal, and no way for another parent to stumble into your files. If you want a social worker to see something, you export it and send it. We never do that for you.
Files are private, not just hidden
Photos, videos, and documents are stored in a locked vault that has no public web address. Every time one is shown to you, our server checks that you are signed in and that the record is yours, then hands over the file. A link copied from your screen does not work for anyone else.
The time comes from us, not your phone
When you save an entry or upload a file, we record the moment it arrived at our server. Changing the clock on a phone or laptop does not change that time. You still tell us when something happened; we separately record when you wrote it down.
Every entry and file gets a fingerprint
A fingerprint is a long code computed from the exact contents. Change one word in an entry or one pixel in a photo and the fingerprint no longer matches. We store it alongside the record so anyone can check later that nothing was altered.
Entries are chained together
Each entry's fingerprint includes the fingerprint of the entry before it. Removing or changing something from last month would break the chain for everything after it. A Verify button on every record checks the whole chain and tells you if anything is off.
Nothing is edited in place
Made a mistake? You add a correction. The original stays on record, marked as superseded, with your reason and its own timestamp. Photos and videos are kept exactly as uploaded, never compressed or converted, so nothing inside them is lost.
Every look is logged
Viewing a file, downloading it, adding a correction, or printing a report leaves a line in that child's History tab with the date and time. If anyone ever asks who saw what and when, you have the answer.
Leaving takes it all with you
Export a printable report whenever you want. If you delete your account, every child record, file, and history line goes with it. We do not keep a copy.
What we will not do
· We will not sell, share, or use your kids' records for advertising, research, or anything else. Ever.
· We will not send your kids' records to any artificial intelligence service. The AI tools on Counted Doors work from what you type into them, not from your records.
· We will not browse your records. Counted Doors is run by one foster parent. Access to the systems behind it is limited to keeping them running, and any file that is opened is logged in your History.
· We will not hand your records to an agency, attorney, or court that asks us directly. Requests go through you. If we ever receive a court order we are legally required to obey, we will tell you before we respond unless the order itself forbids it, and we will release only what it requires.
Honest limits
These records support your own account of what happened. They do not replace your testimony, and they do not replace reporting to your agency when a report is required. Whether a court or agency accepts them depends on local rules, so ask the child's attorney or your social worker what format they need. Your records are only as private as your own login, so use a strong password, keep your phone locked, and sign out on shared computers.
If you are ever asked on the stand how this works, you can say: “Each entry was timestamped by the service when I saved it, sealed with a fingerprint, and chained to the entry before it. I can add corrections but I cannot edit or delete what I wrote. Every time I or anyone else opened a file, it was logged.” That is all true, and it is all you need to say.
For the technically curious
The technical version
Everything above, stated precisely. This section is for attorneys, IT reviewers, and anyone who wants to check our claims.
Architecture and providers
Counted Doors is a Next.js application hosted on Vercel, with a PostgreSQL database on Neon and private object storage on Vercel Blob. Authentication is handled by Clerk; payments by Stripe; transactional email by Resend. All providers host this data in United States data centers and encrypt data at rest. All traffic is served over HTTPS with TLS 1.2 or higher.
Child records are stored in six tables: CD_children, CD_child_contacts, CD_child_contact_links, CD_child_log_entries, CD_child_attachments, and CD_child_audit_events. Every row carries the owning user's identifier, and every API route verifies both the session and that ownership before reading or writing.
Access control
Sessions are issued by Clerk. Every child record API route calls the server-side session check and rejects unauthenticated requests with 401.
Every nested route resolves the child record by both its id and the session's user id. A record that exists but belongs to someone else returns 404, not 403, so the existence of other users' records is not disclosed.
Files are stored with access: private. They have no public URL. The only read path is an authenticated route handler that verifies ownership, writes an audit event, and streams the bytes with Cache-Control: private, no-store.
Upload tokens are generated server-side per request, scoped to the path prefix children/{userId}/{childId}/, restricted to an allow-list of image, video, audio, PDF, and document types, capped at 500 MB, and expire after one hour.
Browser-visible routes expose the application's own file endpoint, never the storage provider's URL.
Integrity model
Property
Mechanism
Server timestamps
recordedAt on entries and uploadedAt on files are set by the server at write time. The client-supplied occurredAt is stored separately and labeled as the user's statement of when the event happened.
Content hash
SHA-256 over a canonical JSON serialization (sorted keys) of child id, entry type, title, body, structured details, occurredAt, recordedAt, the id of any entry being corrected, and the sorted SHA-256 hashes of attached files.
Hash chain
chainHash = SHA-256(previousChainHash + ":" + contentHash), per child, in a strictly increasing sequence that is enforced by a unique constraint. The first entry uses the literal GENESIS as its predecessor.
File hash
After a browser upload completes, the server re-reads the stored object and computes SHA-256 over the stored bytes. That value is authoritative. Files up to 50 MB are also hashed in the browser with WebCrypto before upload, and the two values are compared and both recorded.
Append-only
The entries table has no update endpoint for content. Corrections insert a new row with previousVersionId and a reason. Voiding sets voidedAt and a reason; content and hashes are untouched. Attachments are never modified after creation.
Originals preserved
Uploaded bytes are stored as received. No transcoding, resizing, metadata stripping, or re-encoding is performed on the stored object.
Verification
GET /api/children/{id}/verify recomputes every content hash and chain hash from stored data in sequence order and reports the first sequence number, if any, where the stored values disagree.
Audit trail
Append-only events for record creation and updates, entry creation, correction, and void, file upload, view, and download, contact changes, and report generation. Each event stores the action, related ids, structured details, the request IP address, and user agent.
Data handling
Child records are never sent to the Claude API or any other AI provider. The AI tools on the site operate only on text the user enters into those tools.
Child records are excluded from analytics, logging pipelines, and email. Server logs record route names and error messages, not record content.
Deleting a Counted Doors account removes the user row, which cascades to all child records, entries, contacts, audit events, and attachment rows, and deletes the corresponding stored files. Provider-side backups and point-in-time history expire on their own schedules, within 90 days.
Archiving a child keeps every record and file intact and only hides it from the default list.
Legal process
Requests for a user's records from third parties, including agencies, attorneys, and courts, are directed to the user. Counted Doors does not voluntarily disclose records. If served with legally binding process, Counted Doors will notify the affected user before responding unless legally prohibited from doing so, will seek to narrow overbroad requests, and will produce only what the process requires.
Reporting a security issue
If you believe you have found a vulnerability, email security@counteddoors.com. Please do not access or modify records that are not your own while testing. We will acknowledge reports within three business days.