Guardar datos y luego borrarlos
La conservación de datos es la regla que dice cuánto tiempo guarda una aplicación cada tipo de dato. Pasado ese tiempo, el dato se borra.
Una aplicación de chat que guarda todas las conversaciones para siempre acumula más riesgo cada año. Aquí haces el barrido, borras a petición y cuentas lo que queda.
Al final de esta lección
Nota
Puedo borrar datos por una regla y por la petición de una persona.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Conservación | cuánto tiempo se guardan los datos | |
| Barrido | una tarea que borra lo que es demasiado antiguo | |
| Petición de borrado | una persona que pide que quiten sus datos | |
| Copia | otro lugar donde se guardan los mismos datos | una caché |
| Copia de seguridad | una copia guardada para recuperarse de un fallo |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Una regla de conservación fija un plazo
Cada dato necesita un tiempo distinto. Un chat puede guardarse 30 días. Una factura puede guardarse más tiempo. Aquí usamos 365 días para practicar; en la vida real la ley fija un plazo más largo para las facturas.
Cada registro tiene el día en que se hizo. Un barrido calcula su edad: hoy menos ese día. Si la edad supera el plazo, el registro se va. Un registro justo en el límite se queda.
Ejemplo resuelto: un barrido el día 100
| Registro | Tipo | Hecho el día | Edad | Plazo | Resultado |
|---|---|---|---|---|---|
| c1 | chat | 10 | 90 | 30 | Borrado |
| c2 | chat | 80 | 20 | 30 | Conservado |
| b1 | factura | 20 | 80 | 365 | Conservado |
| c3 | chat | 70 | 30 | 30 | Conservado, justo en el límite |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un borrado debe llegar a cada copia
Una persona puede pedirte que borres sus datos. Sus mensajes pueden estar en el almacén principal, en una caché que acelera las cosas y en una copia de seguridad.
Un borrado que llega solo al almacén principal deja el resto. Haz primero la lista de todos los lugares. En el RGPD esto es el derecho de supresión, que tiene límites, así que consulta a una persona experta. No es asesoramiento legal.
Un error frecuente
Advertencia
Mucha gente cree que borrar del almacén principal borra los datos de la persona. No es así. Las cachés, los registros y las copias de seguridad guardan copias. Una copia de seguridad no se puede editar, así que se limpia cuando caduca. Díselo a la persona, con la fecha.
Escribe el ayudante del modelo, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// Los tokens de una respuesta, o null si no trae ninguno.' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el ayudante del modelo, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"estado \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, inTokens: count(d, \"prompt_tokens\"), outTokens: count(d, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"Muestra grabada: ningún modelo respondió (\" + error.message + \").\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el barrido de conservación, parte 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const rules = { chat: 30, factura: 365 };' 'const today = 100;' 'const records = [' ' { id: \"c1\", user: \"u1\", day: 10, kind: \"chat\" },' ' { id: \"c2\", user: \"u2\", day: 80, kind: \"chat\" },' ' { id: \"b1\", user: \"u1\", day: 20, kind: \"factura\" },' ' { id: \"c3\", user: \"u1\", day: 70, kind: \"chat\" },' '];' > retain.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el barrido de conservación, parte 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function expired(r) {' ' return typeof rules[r.kind] === \"number\" && today - r.day > rules[r.kind];' '}' 'function ids(list) {' ' return list.map(function (r) { return r.id; });' '}' 'const stores = {' ' principal: records.filter(function (r) { return expired(r) === false; }),' ' cache: [records[3]],' ' copia: [records[0], records[2], records[3]],' '};' >> retain.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el barrido de conservación, parte 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function remaining(user, reached) {' ' const left = {};' ' Object.keys(stores).forEach(function (name) {' ' const mine = stores[name].filter(function (r) { return r.user === user; });' ' if (reached.indexOf(name) < 0 && mine.length > 0) left[name] = ids(mine);' ' });' ' return left;' '}' >> retain.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Escribe el barrido de conservación, parte 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' console.log(\"caducados hoy: \" + JSON.stringify(ids(records.filter(expired))));' ' console.log(\"conserva el barrido: \" + JSON.stringify(ids(stores.principal)));' ' console.log(\"borrar u1 de principal y cache, queda: \" + JSON.stringify(remaining(\"u1\", [\"principal\", \"cache\"])));' ' console.log(\"borrar u1 de las tres, queda: \" + JSON.stringify(remaining(\"u1\", [\"principal\", \"cache\", \"copia\"])));' ' console.log(\"copia hecha el día 90, guardada 35 días, días que faltan: \" + Math.max(0, 90 + 35 - today));' ' const q = \"En una frase corta, ¿por qué una copia de seguridad aún puede guardar datos borrados?\";' ' const sample = \"Una copia de seguridad es otra copia aparte, así que solo cambia cuando caduca.\";' ' const reply = await ask([{ role: \"user\", content: q }], sample, 60);' ' console.log(\"el modelo dijo: \" + reply.text);' '}' 'main();' >> retain.js"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Ejecuta el barrido de conservación
docker exec -w /home/node/project agent node retain.jsSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Lo que imprime el Run
| Línea | Qué muestra |
|---|---|
| caducados hoy: ["c1"] | Solo c1 supera su plazo |
| conserva el barrido: ["c2","b1","c3"] | Lo que se queda en el almacén principal |
| borrar u1 de principal y cache, queda: {"copia":[...]} | La copia aún guarda a u1 |
| borrar u1 de las tres, queda: {} | Se llegó a cada copia |
| días que faltan: 25 | Cuándo se limpia la copia |
| el modelo dijo: ... | Una frase. Las palabras cambian en cada ejecución |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.