| | | 1 | | using ArturRios.Data.Relational.Core.Entities; |
| | | 2 | | |
| | | 3 | | namespace ArturRios.Heimdall.Domain.Entities; |
| | | 4 | | |
| | | 5 | | /// <summary> |
| | | 6 | | /// A tombstone: the public id of a person or Google User that was hard-deleted, kept only until |
| | | 7 | | /// the audit trail no longer names it (NFR-21, #195). |
| | | 8 | | /// </summary> |
| | | 9 | | /// <remarks> |
| | | 10 | | /// <para> |
| | | 11 | | /// <b>Why it exists.</b> An audit entry's <see cref="AuditLog.TargetId" /> is a bare |
| | | 12 | | /// <c>PublicId</c>, not a foreign key, so it outlives the row it named. The database clears a |
| | | 13 | | /// target only once it can tell the target was a person, and after a hard delete nothing is |
| | | 14 | | /// left to tell it so: the entries about that person, and the hard delete's own entry, kept |
| | | 15 | | /// an id that a backup, an export or a log line could still join back to them. This row is |
| | | 16 | | /// that evidence, written before the delete, so the retention pass may clear those targets |
| | | 17 | | /// and the trigger installed by <c>AllowClearingErasedSubjectTarget</c> may accept it. |
| | | 18 | | /// </para> |
| | | 19 | | /// <para> |
| | | 20 | | /// <b>What it holds.</b> The id, which table it came from, and when — nothing else about the |
| | | 21 | | /// person. It is the processing record of a deletion, and it is short-lived: the pass removes |
| | | 22 | | /// it once it is a day old and no audit entry names it any more. |
| | | 23 | | /// </para> |
| | | 24 | | /// <para> |
| | | 25 | | /// <b>Only for somebody who exists.</b> A database trigger accepts a row only while a |
| | | 26 | | /// <c>person</c> or <c>google_user</c> row has its id (#195, R1). A tombstone is what makes a |
| | | 27 | | /// target with no row clearable, so one planted for a scope's id would otherwise let that |
| | | 28 | | /// scope's targets be cleared too. |
| | | 29 | | /// </para> |
| | | 30 | | /// <para> |
| | | 31 | | /// <b>The key is the public id.</b> <c>Id</c> holds the removed identity's <c>PublicId</c>, |
| | | 32 | | /// stored as <c>public_id</c>; there is no surrogate key. The table is looked up by the id |
| | | 33 | | /// the trail carries and holds each id at most once, so a hard delete that is retried writes |
| | | 34 | | /// no second row. |
| | | 35 | | /// </para> |
| | | 36 | | /// </remarks> |
| | | 37 | | public class ErasedSubject : Entity<Guid> |
| | | 38 | | { |
| | | 39 | | /// <summary> |
| | | 40 | | /// Which table the id was taken from (see <c>ErasedSubjectKinds</c>). |
| | | 41 | | /// </summary> |
| | 114 | 42 | | public int Kind { get; set; } |
| | | 43 | | |
| | | 44 | | /// <summary> |
| | | 45 | | /// When the tombstone was written, just before the delete. The pass keeps it for a day at |
| | | 46 | | /// least, whether or not anything names it yet. |
| | | 47 | | /// </summary> |
| | 132 | 48 | | public DateTime CreatedAt { get; set; } |
| | | 49 | | } |