Skip to content

Data Architecture and Privacy

This document records the privacy-relevant decisions made about the Master Schedule database structure, the reasoning behind them, and the roadmap for handling student data if that capability is ever added. It is intended for DocGuy Training developers and compliance review.


Current PII inventory

The following personal data is stored in Firestore today. No student PII is collected.

Collection Field(s) Data subject Basis
users/{uid} email, displayName School staff Contract — needed for authentication and access control
schools/{schoolId}/teachers/{teacherId} name, email, teacherId School teachers Contract — needed to build and validate the schedule
schools/{schoolId}/auditLog/{entryId} email, uid School staff Legitimate interest — accountability and security
schools/{schoolId}/supportAccessRequests requestedByEmail, support engineer uid/email Staff + DocGuy Training personnel Legitimate interest — access accountability
Platform auditLog/{entryId} email, uid DocGuy Training superadmins Legitimate interest — platform-level audit trail

Known issues and remediation

1. Teacher IDs derived from email (priority: high)

Problem: Teacher document IDs have historically been generated in first.last format, derived from the teacher's email address. A Firestore document ID is immutable — it cannot be updated or anonymized without migrating all documents that reference it (schedules, placements, audit log entries). This makes it impossible to fulfill a GDPR right-to-erasure request for a teacher without a full data migration.

Decision: Effective immediately, new teacher records use an opaque internal ID (t_ followed by a random eight-character alphanumeric string). The school-assigned staff identifier (previously used as the doc ID) is stored as a staffId field within the document, where it can be updated or cleared independently.

Existing records: Teachers created before this change retain their legacy IDs. A migration script is documented below for schools that need to rename a legacy teacher record.

Migration path for a legacy teacher record:

Because Firestore document IDs are immutable, renaming a teacher record requires:

  1. Create a new document with the new opaque ID and the same field data.
  2. Update all placement and schedule documents that reference the old ID.
  3. Pseudonymize the old audit log entries (replace teacherId in detail with the new opaque ID).
  4. Delete the old document.

This migration is not automated. Contact DocGuy Training support to request it.

2. Email addresses in audit log entries (priority: medium)

Problem: Every audit log entry stores the actor's email address. Audit entries are retained for 13 months. If a user exercises the GDPR right to erasure, their email cannot simply be deleted without destroying the accountability record.

Decision: Erasure requests are handled by pseudonymization, not deletion. The erasure procedure replaces the email field in all affected entries with deleted-user-{uid-hash}, where uid-hash is a one-way hash of the original Firebase UID. The accountability record (action, timestamp, affected record) is preserved. The personal identifier is removed.

Procedure: See User Erasure Procedure below.

3. User record retention after removal (priority: medium)

Problem: removeUser() removes a user's school association but the users/{uid} Firestore document is not deleted. If the user has no remaining active school associations, their document persists indefinitely.

Decision: The erasure procedure (triggered on request) deletes the users/{uid} document and pseudonymizes the audit log as described above. School admins cannot trigger this — it is a superadmin operation performed through the Admin Console.


User erasure procedure

This procedure is executed by a DocGuy Training superadmin via the Admin Console in response to a verified erasure request.

  1. Verify the requester's identity and confirm the request is valid under applicable law.
  2. Locate the user's Firebase UID via the Admin Console Users panel.
  3. Compute uid-hash = SHA-256(uid).slice(0, 12) (the Admin Console will do this automatically).
  4. In every school the user was ever associated with, update all auditLog entries where uid == targetUid:
  5. Set email to deleted-user-{uid-hash}
  6. Delete the users/{uid} Firestore document.
  7. Do not revoke Firebase Authentication — if the user signs in again, they will be treated as a new user with no school access. (Revoking the Auth account is the user's responsibility via their Google account settings.)
  8. Record the erasure in the platform audit log.

Future student data: architectural requirements

If individual student data (names, enrollment, schedules, grades) is ever added to the app, the following architectural constraints apply before any such data may be stored.

Separate collection with strict isolation

Student records must live in a dedicated subcollection (schools/{schoolId}/students/{studentId}) governed by Firestore security rules that are entirely independent of the scheduling data rules. Staff access to student records must be explicitly granted and must not be implied by the scheduling staff role.

Opaque student identifiers only

Student IDs used in scheduling data (placements, schedule documents, validator sessions) must be opaque tokens — a school-assigned student number or a UUID — never a name, email, or other directly identifying value. Schedule exports must not contain student PII.

Audit log handling for student data

Audit log entries that reference student actions must log only the opaque student ID, never the student's name. The audit log must not become a vector for reconstructing student PII.

Age-gating and COPPA

If the app ever accepts data for students under 13, COPPA consent mechanisms must be in place before any such data is collected. This is a product decision that requires legal review before implementation.

Separate retention and deletion policies

Student records require shorter retention periods than staff audit logs and must be deletable independently. The 13-month audit log TTL does not apply to student records. A dedicated deletion mechanism must exist.

Support access exclusion

The Support Access feature must explicitly exclude student record collections. A support engineer's session must not be able to read or write students/ subcollections, regardless of what other access the school admin granted.


Backup anonymization

Production backups

Firebase-managed Firestore exports (to a private GCS bucket) are encrypted at rest. Access is governed by GCS IAM roles. These backups are not anonymized but are acceptable for disaster recovery purposes provided:

  • The GCS bucket is not publicly accessible.
  • Bucket access is logged via GCS audit logs.
  • Access is restricted to named service accounts and DocGuy Training engineers by role.

Staging and development environments

Production data must never be used directly in staging or development. A sanitization function must be run to produce anonymized fixtures:

  • Teacher names → Teacher A, Teacher B, etc.
  • Teacher emails → teacher-a@test.invalid
  • Staff emails → staff-N@test.invalid
  • UIDs → sequential integers
  • Audit log actor emails → actor-N@test.invalid
  • School names → Test School N

All other scheduling data (course codes, block structures, placements) may be used as-is since it contains no PII.

This sanitization function has not yet been built. Until it is, staging must be seeded with manually created test data only.


Audit log TTL policy setup

Audit log entries include an expireAt field set 13 months in the future. Firestore does not enforce TTL automatically — the TTL policy must be activated once in the Firebase Console.

One-time setup required:

  1. Open the Firebase Console and select the Master Schedule project.
  2. Go to Firestore Database → Indexes → TTL policies.
  3. Click Add TTL policy.
  4. Set the Collection group to auditLog.
  5. Set the Field path to expireAt.
  6. Save. Firestore begins honoring the TTL within 24–72 hours.

Until this policy is activated, expireAt is written to every audit entry but has no effect — entries accumulate indefinitely. The Admin Console Action Required panel will surface this as a pending task until a superadmin marks it complete.

One-time action — cannot be automated

Firestore TTL policies can only be created through the Firebase Console or the Firebase Admin SDK with elevated project permissions. The app cannot create them on its own behalf.