Le Reglement General sur la Protection des Donnees (RGPD) pose des exigences concretes pour le developpement logiciel. En tant que developpeur ABAP Cloud, vous devez mettre en oeuvre ces exigences techniquement. Cet article montre comment developper des applications conformes au RGPD dans ABAP Cloud.
Exigences RGPD pour les developpeurs
Le RGPD definit des droits pour les personnes concernees qui ont un impact direct sur le developpement :
| Droit | Article | Implementation technique |
|---|---|---|
| Droit d’acces | Art. 15 | Fonction d’export de donnees |
| Droit de rectification | Art. 16 | Fonctions de modification |
| Droit a l’effacement | Art. 17 | Concept de suppression |
| Droit a la limitation | Art. 18 | Fonction de blocage |
| Portabilite des donnees | Art. 20 | Export en format standard |
| Droit d’opposition | Art. 21 | Gestion du consentement |
Principes techniques
Le RGPD exige la Privacy by Design et la Privacy by Default :
Privacy by Design :┌─────────────────────────────────────────────────────┐│ Integrer la protection des donnees dans toutes ││ les phases de developpement │├─────────────────────────────────────────────────────┤│ • Collecte minimale de donnees ││ • Verifier la finalite ││ • Definir les durees de conservation ││ • Implementer le chiffrement ││ • Activer la journalisation des acces │└─────────────────────────────────────────────────────┘Implementer un concept de suppression (Data Retention)
Un concept de suppression definit quand et comment les donnees personnelles sont supprimees. Dans ABAP Cloud, vous l’implementez via des Retention Rules et des jobs de suppression correspondants.
Definir une table de retention
@EndUserText.label: 'Durees de conservation par categorie de donnees"@AbapCatalog.enhancement.category: #NOT_EXTENSIBLEdefine table zretention_rules { key client : abap.clnt not null; key data_category : abap.char(30) not null; retention_period_days : abap.int4; deletion_method : abap.char(10); -- HARD, SOFT, ANON legal_basis : abap.char(100); last_review_date : abap.dats; responsible_role : abap.char(30);}Implementer le service de suppression
CLASS zcl_gdpr_deletion_service DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_deletion_result, data_category TYPE string, records_deleted TYPE i, records_failed TYPE i, deletion_date TYPE timestampl, END OF ty_deletion_result, tt_deletion_results TYPE STANDARD TABLE OF ty_deletion_result WITH EMPTY KEY.
METHODS: execute_retention_deletion RETURNING VALUE(rt_results) TYPE tt_deletion_results,
delete_customer_data IMPORTING iv_customer_id TYPE zcustomer_id iv_deletion_type TYPE string DEFAULT 'HARD" RETURNING VALUE(rv_success) TYPE abap_bool,
get_retention_period IMPORTING iv_data_category TYPE string RETURNING VALUE(rv_days) TYPE i.
PRIVATE SECTION. METHODS: get_deletion_candidates IMPORTING iv_data_category TYPE string iv_cutoff_date TYPE d RETURNING VALUE(rt_keys) TYPE ztt_entity_keys,
perform_hard_delete IMPORTING it_keys TYPE ztt_entity_keys RETURNING VALUE(rv_count) TYPE i,
perform_soft_delete IMPORTING it_keys TYPE ztt_entity_keys RETURNING VALUE(rv_count) TYPE i,
log_deletion IMPORTING iv_category TYPE string iv_count TYPE i iv_method TYPE string.ENDCLASS.
CLASS zcl_gdpr_deletion_service IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_results) = execute_retention_deletion( ).
LOOP AT lt_results INTO DATA(ls_result). out->write( |Categorie : { ls_result-data_category }| ). out->write( |Supprimes : { ls_result-records_deleted }| ). out->write( |Echoues : { ls_result-records_failed }| ). out->write( |---| ). ENDLOOP. ENDMETHOD.
METHOD execute_retention_deletion. " Recuperer toutes les Retention Rules actives SELECT * FROM zretention_rules INTO TABLE @DATA(lt_rules).
DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
LOOP AT lt_rules INTO DATA(ls_rule). " Calculer la date limite DATA(lv_cutoff_date) = lv_today - ls_rule-retention_period_days.
" Determiner les candidats a la suppression DATA(lt_candidates) = get_deletion_candidates( iv_data_category = ls_rule-data_category iv_cutoff_date = lv_cutoff_date ).
" Effectuer la suppression DATA(lv_deleted) = COND #( WHEN ls_rule-deletion_method = 'HARD" THEN perform_hard_delete( lt_candidates ) WHEN ls_rule-deletion_method = 'SOFT" THEN perform_soft_delete( lt_candidates ) WHEN ls_rule-deletion_method = 'ANON" THEN anonymize_records( lt_candidates ) ELSE 0 ).
" Journaliser le resultat log_deletion( iv_category = ls_rule-data_category iv_count = lv_deleted iv_method = ls_rule-deletion_method ).
APPEND VALUE #( data_category = ls_rule-data_category records_deleted = lv_deleted records_failed = lines( lt_candidates ) - lv_deleted deletion_date = utclong_current( ) ) TO rt_results. ENDLOOP. ENDMETHOD.
METHOD delete_customer_data. " Suppression individuelle pour demande de personne concernee TRY. CASE iv_deletion_type. WHEN 'HARD'. " Suppression irrevocable DELETE FROM zcustomer WHERE customer_id = @iv_customer_id. DELETE FROM zcustomer_contact WHERE customer_id = @iv_customer_id. DELETE FROM zcustomer_address WHERE customer_id = @iv_customer_id.
WHEN 'SOFT'. " Marquage comme supprime UPDATE zcustomer SET is_deleted = @abap_true, deletion_date = @( cl_abap_context_info=>get_system_date( ) ) WHERE customer_id = @iv_customer_id.
WHEN 'ANONYMIZE'. " Anonymisation au lieu de suppression UPDATE zcustomer SET first_name = 'ANONYMISE', last_name = 'ANONYMISE', phone = '000000000', is_anonymized = @abap_true WHERE customer_id = @iv_customer_id. ENDCASE.
rv_success = abap_true.
CATCH cx_sy_open_sql_db. rv_success = abap_false. ENDTRY. ENDMETHOD.
METHOD get_retention_period. SELECT SINGLE retention_period_days FROM zretention_rules WHERE data_category = @iv_data_category INTO @rv_days.
IF sy-subrc <> 0. rv_days = 365 * 10. " Defaut : 10 ans ENDIF. ENDMETHOD.
" ... autres methodes
ENDCLASS.RAP Action pour la suppression
" Behavior Definitiondefine behavior for ZI_Customer alias Customerimplementation in class zbp_i_customer unique{ // Suppression RGPD comme Action action deletePersonalData result [1] $self;
// Soft Delete au lieu de suppression physique delete ( features : instance );}" Behavior ImplementationMETHOD deletePersonalData. DATA(lo_deletion_service) = NEW zcl_gdpr_deletion_service( ).
LOOP AT keys INTO DATA(ls_key). DATA(lv_success) = lo_deletion_service->delete_customer_data( iv_customer_id = ls_key-CustomerId iv_deletion_type = 'ANONYMIZE' ).
IF lv_success = abap_true. " Retourner le resultat READ ENTITIES OF zi_customer IN LOCAL MODE ENTITY Customer ALL FIELDS WITH VALUE #( ( %key = ls_key-%key ) ) RESULT DATA(lt_customers).
result = VALUE #( FOR customer IN lt_customers ( %tky = customer-%tky %param = customer ) ). ELSE. APPEND VALUE #( %tky = ls_key-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Suppression echouee' ) ) TO reported-customer. ENDIF. ENDLOOP.ENDMETHOD.Anonymisation des donnees
L’anonymisation rend les donnees irrevocablement non attribuables a une personne. C’est une alternative a la suppression lorsque les donnees sont necessaires pour des statistiques.
Service d’anonymisation
CLASS zcl_gdpr_anonymization DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_field_rule, field_name TYPE string, anon_method TYPE string, -- MASK, HASH, RANDOM, CONSTANT, NULLIFY constant_value TYPE string, END OF ty_field_rule, tt_field_rules TYPE STANDARD TABLE OF ty_field_rule WITH EMPTY KEY.
METHODS: anonymize_customer IMPORTING iv_customer_id TYPE zcustomer_id RETURNING VALUE(rv_success) TYPE abap_bool,
anonymize_field IMPORTING iv_value TYPE any iv_method TYPE string iv_constant TYPE string OPTIONAL RETURNING VALUE(rv_result) TYPE string,
generate_pseudonym IMPORTING iv_original TYPE string RETURNING VALUE(rv_pseudonym) TYPE string.
ENDCLASS.
CLASS zcl_gdpr_anonymization IMPLEMENTATION.
METHOD anonymize_customer. " Definir les regles d'anonymisation DATA(lt_rules) = VALUE tt_field_rules( ( field_name = 'FIRST_NAME' anon_method = 'CONSTANT' constant_value = 'ANON' ) ( field_name = 'LAST_NAME' anon_method = 'CONSTANT' constant_value = 'ANON' ) ( field_name = 'EMAIL' anon_method = 'HASH' ) ( field_name = 'PHONE' anon_method = 'MASK' ) ( field_name = 'BIRTH_DATE' anon_method = 'NULLIFY' ) ( field_name = 'ADDRESS' anon_method = 'CONSTANT' constant_value = 'Anonymise' ) ).
" Charger les donnees client SELECT SINGLE * FROM zcustomer WHERE customer_id = @iv_customer_id INTO @DATA(ls_customer).
IF sy-subrc <> 0. rv_success = abap_false. RETURN. ENDIF.
" Anonymiser les champs ls_customer-first_name = anonymize_field( iv_value = ls_customer-first_name iv_method = 'CONSTANT" iv_constant = 'ANON' ).
ls_customer-last_name = anonymize_field( iv_value = ls_customer-last_name iv_method = 'CONSTANT" iv_constant = 'ANON' ).
ls_customer-email = anonymize_field( iv_value = ls_customer-email iv_method = 'HASH' ).
ls_customer-phone = anonymize_field( iv_value = ls_customer-phone iv_method = 'MASK' ).
ls_customer-is_anonymized = abap_true. ls_customer-anonymization_date = cl_abap_context_info=>get_system_date( ).
" Sauvegarder les donnees anonymisees UPDATE zcustomer FROM @ls_customer.
rv_success = xsdbool( sy-subrc = 0 ). ENDMETHOD.
METHOD anonymize_field. CASE iv_method. WHEN 'MASK'. " Masquer partiellement (par ex. ***1234) DATA(lv_length) = strlen( iv_value ). IF lv_length > 4. rv_result = repeat( val = '*' occ = lv_length - 4 ) && substring( val = iv_value off = lv_length - 4 len = 4 ). ELSE. rv_result = repeat( val = '*' occ = lv_length ). ENDIF.
WHEN 'HASH'. " Hash a sens unique (non reversible) TRY. cl_abap_message_digest=>create_md5( EXPORTING if_data = cl_abap_codepage=>convert_to( iv_value ) IMPORTING ef_hashstring = rv_result ). CATCH cx_abap_message_digest. rv_result = 'HASH_ERROR'. ENDTRY.
WHEN 'RANDOM'. " Generer une valeur aleatoire rv_result = cl_system_uuid=>create_uuid_x16_static( ).
WHEN 'CONSTANT'. " Valeur de remplacement fixe rv_result = iv_constant.
WHEN 'NULLIFY'. " Valeur vide rv_result = ''.
WHEN OTHERS. rv_result = iv_value. ENDCASE. ENDMETHOD.
METHOD generate_pseudonym. " Pseudonyme deterministe (meme original = meme pseudonyme) DATA(lv_salt) = 'GDPR_PSEUDONYM_SALT_2024'. DATA(lv_input) = lv_salt && iv_original.
TRY. cl_abap_message_digest=>create_sha256( EXPORTING if_data = cl_abap_codepage=>convert_to( lv_input ) IMPORTING ef_hashstring = DATA(lv_hash) ).
" Creer un pseudonyme plus court et lisible rv_pseudonym = 'PSN_' && substring( val = lv_hash len = 12 ). CATCH cx_abap_message_digest. rv_pseudonym = 'PSN_ERROR'. ENDTRY. ENDMETHOD.
ENDCLASS.Pseudonymisation vs. Anonymisation
| Aspect | Pseudonymisation | Anonymisation |
|---|---|---|
| Reversible | Oui, avec une cle | Non |
| Statut RGPD | Donnees personnelles | Donnees non personnelles |
| Application | Traitement | Statistiques, archivage |
| Exemple | PSN_A3F82B | ANON |
Mettre en oeuvre le droit d’acces (Data Export)
Les personnes concernees ont le droit d’obtenir toutes les donnees stockees a leur sujet dans un format lisible par machine.
Service d’export de donnees
CLASS zcl_gdpr_data_export DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. TYPES: BEGIN OF ty_export_section, category TYPE string, data TYPE REF TO data, END OF ty_export_section, tt_export_sections TYPE STANDARD TABLE OF ty_export_section WITH EMPTY KEY.
METHODS: export_customer_data IMPORTING iv_customer_id TYPE zcustomer_id RETURNING VALUE(rv_json) TYPE string,
export_as_json IMPORTING it_sections TYPE tt_export_sections RETURNING VALUE(rv_json) TYPE string,
create_export_request IMPORTING iv_customer_id TYPE zcustomer_id iv_request_type TYPE string RETURNING VALUE(rv_request_id) TYPE sysuuid_x16.
ENDCLASS.
CLASS zcl_gdpr_data_export IMPLEMENTATION.
METHOD export_customer_data. DATA: lt_sections TYPE tt_export_sections.
" 1. Donnees de base SELECT SINGLE customer_id, first_name, last_name, email, phone, birth_date, created_at FROM zcustomer WHERE customer_id = @iv_customer_id INTO @DATA(ls_customer).
IF sy-subrc = 0. GET REFERENCE OF ls_customer INTO DATA(lr_customer). APPEND VALUE #( category = 'Donnees de base' data = lr_customer ) TO lt_sections. ENDIF.
" 2. Adresses SELECT address_type, street, city, postal_code, country FROM zcustomer_address WHERE customer_id = @iv_customer_id INTO TABLE @DATA(lt_addresses).
IF sy-subrc = 0. GET REFERENCE OF lt_addresses INTO DATA(lr_addresses). APPEND VALUE #( category = 'Adresses' data = lr_addresses ) TO lt_sections. ENDIF.
" 3. Commandes SELECT order_id, order_date, status, total_amount, currency FROM zorder WHERE customer_id = @iv_customer_id INTO TABLE @DATA(lt_orders).
IF sy-subrc = 0. GET REFERENCE OF lt_orders INTO DATA(lr_orders). APPEND VALUE #( category = 'Commandes' data = lr_orders ) TO lt_sections. ENDIF.
" 4. Communications SELECT communication_date, channel, subject FROM zcommunication_log WHERE customer_id = @iv_customer_id INTO TABLE @DATA(lt_communications).
IF sy-subrc = 0. GET REFERENCE OF lt_communications INTO DATA(lr_comms). APPEND VALUE #( category = 'Communications' data = lr_comms ) TO lt_sections. ENDIF.
" 5. Historique des consentements SELECT consent_type, consent_date, consent_status, ip_address FROM zconsent_log WHERE customer_id = @iv_customer_id INTO TABLE @DATA(lt_consents).
IF sy-subrc = 0. GET REFERENCE OF lt_consents INTO DATA(lr_consents). APPEND VALUE #( category = 'Consentements' data = lr_consents ) TO lt_sections. ENDIF.
" Exporter en JSON rv_json = export_as_json( lt_sections ). ENDMETHOD.
METHOD export_as_json. DATA: lo_json TYPE REF TO cl_sxml_string_writer.
" Construire la structure JSON DATA(lo_writer) = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
lo_writer->open_element( name = 'gdpr_export' ). lo_writer->open_element( name = 'export_date' ). lo_writer->write_value( |{ cl_abap_context_info=>get_system_date( ) DATE = ISO }| ). lo_writer->close_element( ).
LOOP AT it_sections INTO DATA(ls_section). lo_writer->open_element( name = ls_section-category ).
" Serialiser les donnees en JSON DATA(lv_section_json) = /ui2/cl_json=>serialize( data = ls_section-data->* pretty_name = /ui2/cl_json=>pretty_mode-low_case ).
lo_writer->write_value( lv_section_json ). lo_writer->close_element( ). ENDLOOP.
lo_writer->close_element( ).
rv_json = cl_abap_codepage=>convert_from( lo_writer->get_output( ) ). ENDMETHOD.
METHOD create_export_request. " Journaliser la demande d'export rv_request_id = cl_system_uuid=>create_uuid_x16_static( ).
INSERT INTO zgdpr_requests VALUES @( VALUE #( request_id = rv_request_id customer_id = iv_customer_id request_type = iv_request_type " EXPORT, DELETE, RECTIFY request_date = cl_abap_context_info=>get_system_date( ) request_time = cl_abap_context_info=>get_system_time( ) status = 'NEW" requestor = cl_abap_context_info=>get_user_technical_name( ) ) ). ENDMETHOD.
ENDCLASS.RAP Action pour l’export de donnees
" Behavior Definitiondefine behavior for ZC_Customer alias Customer{ // Export de donnees comme Action avec retour JSON action ( features : instance ) exportMyData result [1] $self;}" Dans la Projection View, un champ virtuel pour le lien d'exportdefine view entity ZC_Customer as projection on ZI_Customer{ key CustomerId, FirstName, LastName, Email,
// Champ virtuel pour le telechargement d'export @UI.hidden: true cast( '' as abap.string ) as ExportData}Gestion du consentement
Les consentements doivent etre documentes, revocables et prouvables.
Modele de donnees pour le consentement
@EndUserText.label: 'Categories de consentement"define table zconsent_types { key client : abap.clnt not null; key consent_type : abap.char(30) not null; description : abap.char(200); legal_basis : abap.char(100); is_mandatory : abap_boolean; default_duration : abap.int4; -- Jours}
@EndUserText.label: 'Journal des consentements"define table zconsent_log { key client : abap.clnt not null; key consent_id : sysuuid_x16 not null; customer_id : zcustomer_id; consent_type : abap.char(30); consent_status : abap.char(10); -- GRANTED, WITHDRAWN, EXPIRED consent_date : abap.dats; consent_time : abap.tims; expiry_date : abap.dats; ip_address : abap.char(45); user_agent : abap.char(500); consent_text : abap.string; withdrawal_date : abap.dats; withdrawal_reason : abap.char(200);}Service de consentement
CLASS zcl_consent_manager DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. CONSTANTS: BEGIN OF gc_consent_status, granted TYPE string VALUE 'GRANTED', withdrawn TYPE string VALUE 'WITHDRAWN', expired TYPE string VALUE 'EXPIRED', END OF gc_consent_status.
METHODS: grant_consent IMPORTING iv_customer_id TYPE zcustomer_id iv_consent_type TYPE string iv_ip_address TYPE string OPTIONAL iv_user_agent TYPE string OPTIONAL RETURNING VALUE(rv_consent_id) TYPE sysuuid_x16,
withdraw_consent IMPORTING iv_customer_id TYPE zcustomer_id iv_consent_type TYPE string iv_reason TYPE string OPTIONAL RETURNING VALUE(rv_success) TYPE abap_bool,
check_consent IMPORTING iv_customer_id TYPE zcustomer_id iv_consent_type TYPE string RETURNING VALUE(rv_granted) TYPE abap_bool,
get_consent_status IMPORTING iv_customer_id TYPE zcustomer_id RETURNING VALUE(rt_consents) TYPE ztt_consent_status,
expire_old_consents.
ENDCLASS.
CLASS zcl_consent_manager IMPLEMENTATION.
METHOD grant_consent. " Charger les details du type de consentement SELECT SINGLE * FROM zconsent_types WHERE consent_type = @iv_consent_type INTO @DATA(ls_type).
IF sy-subrc <> 0. RETURN. ENDIF.
" Calculer la date d'expiration DATA(lv_today) = cl_abap_context_info=>get_system_date( ). DATA(lv_expiry) = COND #( WHEN ls_type-default_duration > 0 THEN lv_today + ls_type-default_duration ELSE '99991231' ).
" Creer un nouveau consentement rv_consent_id = cl_system_uuid=>create_uuid_x16_static( ).
INSERT INTO zconsent_log VALUES @( VALUE #( consent_id = rv_consent_id customer_id = iv_customer_id consent_type = iv_consent_type consent_status = gc_consent_status-granted consent_date = lv_today consent_time = cl_abap_context_info=>get_system_time( ) expiry_date = lv_expiry ip_address = iv_ip_address user_agent = iv_user_agent consent_text = ls_type-description ) ).
" Invalider l'ancien consentement UPDATE zconsent_log SET consent_status = @gc_consent_status-withdrawn WHERE customer_id = @iv_customer_id AND consent_type = @iv_consent_type AND consent_id <> @rv_consent_id AND consent_status = @gc_consent_status-granted. ENDMETHOD.
METHOD withdraw_consent. DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
UPDATE zconsent_log SET consent_status = @gc_consent_status-withdrawn, withdrawal_date = @lv_today, withdrawal_reason = @iv_reason WHERE customer_id = @iv_customer_id AND consent_type = @iv_consent_type AND consent_status = @gc_consent_status-granted.
rv_success = xsdbool( sy-subrc = 0 ). ENDMETHOD.
METHOD check_consent. DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
SELECT SINGLE @abap_true FROM zconsent_log WHERE customer_id = @iv_customer_id AND consent_type = @iv_consent_type AND consent_status = @gc_consent_status-granted AND expiry_date >= @lv_today INTO @rv_granted. ENDMETHOD.
METHOD get_consent_status. SELECT consent_type, consent_status, consent_date, expiry_date FROM zconsent_log WHERE customer_id = @iv_customer_id ORDER BY consent_date DESCENDING INTO TABLE @rt_consents. ENDMETHOD.
METHOD expire_old_consents. DATA(lv_today) = cl_abap_context_info=>get_system_date( ).
UPDATE zconsent_log SET consent_status = @gc_consent_status-expired WHERE expiry_date < @lv_today AND consent_status = @gc_consent_status-granted. ENDMETHOD.
ENDCLASS.Verification du consentement dans la logique metier
METHOD send_marketing_email. DATA(lo_consent) = NEW zcl_consent_manager( ).
" Verifier si le consentement marketing existe IF lo_consent->check_consent( iv_customer_id = iv_customer_id iv_consent_type = 'MARKETING_EMAIL' ) = abap_false. " Pas de consentement - ne pas envoyer l'email RAISE EXCEPTION TYPE zcx_no_consent EXPORTING textid = zcx_no_consent=>no_marketing_consent. ENDIF.
" Envoyer l'email marketing " ...ENDMETHOD.Integration SAP Information Lifecycle Management
SAP ILM offre une solution integree pour la conservation et la suppression des donnees.
Configuration ILM
CLASS zcl_ilm_integration DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. METHODS: register_business_object IMPORTING iv_object_name TYPE string iv_table_name TYPE tabname,
set_retention_rule IMPORTING iv_object_name TYPE string iv_retention_days TYPE i,
execute_blocking IMPORTING iv_object_name TYPE string,
execute_destruction IMPORTING iv_object_name TYPE string.
ENDCLASS.
CLASS zcl_ilm_integration IMPLEMENTATION.
METHOD register_business_object. " Enregistrer l'objet ILM via SARA/ILM_DESTRUCTION " Note : Dans ABAP Cloud via APIs " ... ENDMETHOD.
METHOD set_retention_rule. " Definir la regle de conservation dans ILM " Generalement fait via le Customizing " ... ENDMETHOD.
METHOD execute_blocking. " Phase Residence/Retention " Les donnees sont bloquees pour modification " ... ENDMETHOD.
METHOD execute_destruction. " End of Purpose - Supprimer les donnees " Execute via le job ILM " ... ENDMETHOD.
ENDCLASS.CDS View compatible ILM
@EndUserText.label: 'Donnees client avec ILM"@ObjectModel.dataCategory: #MASTER@ObjectModel.lifecycle.dateField: 'CreatedAt' -- Pour la determination ILMdefine view entity ZI_Customer_ILM as select from zcustomer{ key customer_id as CustomerId, first_name as FirstName, last_name as LastName,
@Semantics.systemDateTime.createdAt: true created_at as CreatedAt,
@ObjectModel.lifecycle.status: #BLOCKED is_blocked as IsBlocked,
@ObjectModel.lifecycle.status: #DELETED is_deleted as IsDeleted}Checklist pour la conformite RGPD
Checklist de developpement
| Point de verification | Implemente | Remarque |
|---|---|---|
| Minimisation des donnees | ||
| Collecter uniquement les champs necessaires | ☐ | |
| Reduire les champs obligatoires au minimum | ☐ | |
| Pas de collecte “en reserve” | ☐ | |
| Limitation de la finalite | ||
| Finalite d’utilisation documentee | ☐ | |
| Consentement obtenu pour chaque finalite | ☐ | |
| Pas de detournement de finalite | ☐ | |
| Limitation de la conservation | ||
| Durees de conservation definies | ☐ | |
| Jobs de suppression implementes | ☐ | |
| Archivage configure | ☐ | |
| Droits des personnes concernees | ||
| Fonction d’information presente | ☐ | |
| Fonction de rectification presente | ☐ | |
| Fonction de suppression presente | ☐ | |
| Fonction de blocage presente | ☐ | |
| Fonction d’export presente | ☐ | |
| Securite | ||
| Controle d’acces implemente | ☐ | |
| Chiffrement lors de la transmission | ☐ | |
| Journalisation activee | ☐ | |
| Documentation | ||
| Registre des traitements a jour | ☐ | |
| Documentation technique presente | ☐ | |
| Analyse d’impact effectuee | ☐ |
Checklist de revue de code pour le RGPD
" ❌ NON conforme au RGPDDATA: gv_customer_ssn TYPE string. " Donnees sensibles globales
" ✅ Conforme au RGPDDATA(lo_customer) = zcl_customer_handler=>get_instance( iv_customer_id ).DATA(lv_masked_ssn) = lo_customer->get_masked_ssn( ).
" ❌ NON conforme au RGPD - Logging avec donnees personnellesMESSAGE |Client { ls_customer-name } a la commande { lv_order_id }| TYPE 'I'.
" ✅ Conforme au RGPD - Pas de donnees personnelles dans le logMESSAGE |Commande { lv_order_id } creee| TYPE 'I'.
" ❌ NON conforme au RGPD - Export illimiteSELECT * FROM zcustomer INTO TABLE @DATA(lt_all_customers).
" ✅ Conforme au RGPD - Verification d'autorisation et journalisationIF lo_auth->check_export_authorization( ) = abap_true. lo_audit->log_data_export( iv_reason = 'CUSTOMER_REQUEST' ). SELECT * FROM zcustomer WHERE customer_id = @iv_customer_id INTO TABLE @DATA(lt_customer_data).ENDIF.Bonnes pratiques
1. Privacy by Design
" Minimisation des donnees des le modele de donneesdefine table zcustomer_minimal { key customer_id : sysuuid_x16; -- Pseudonyme au lieu du nom display_name : abap.char(100); -- Optionnel email_hash : abap.char(64); -- Email hashe created_at : timestampl; " PAS DE : Date de naissance, adresse, telephone - si non necessaire}2. Protection des donnees par defaut
" Par defaut : Traitement minimal des donneesMETHOD constructor. " Le consentement n'est PAS automatiquement suppose me->consent_status = gc_consent_status-not_given.
" Le marketing n'est PAS active par defaut me->marketing_enabled = abap_false.
" Les donnees ne sont PAS conservees indefiniment me->retention_date = cl_abap_context_info=>get_system_date( ) + 365.ENDMETHOD.3. Chiffrement
" Stocker les donnees sensibles chiffreesMETHOD encrypt_pii_data. TRY. DATA(lo_crypto) = cl_abap_symmetric_cipher=>get_aes256( ). rv_encrypted = lo_crypto->encrypt( if_data = cl_abap_codepage=>convert_to( iv_plain_text ) if_key = get_encryption_key( ) ). CATCH cx_abap_symmetric_cipher. " Gestion d'erreur ENDTRY.ENDMETHOD.Resume
| Exigence RGPD | Solution ABAP Cloud |
|---|---|
| Droit a l’effacement | RAP Action + Deletion Service |
| Anonymisation | Anonymization Service |
| Droit d’acces | Export de donnees en JSON |
| Gestion du consentement | Consent Service + CDS Views |
| Conservation | Integration ILM |
| Journalisation | Application Logging |
La conformite RGPD necessite une prise en compte coherente des exigences de protection des donnees dans l’ensemble de l’application - du modele de donnees a la logique metier jusqu’a l’interface utilisateur.
Sujets connexes
- Authorization Checks - Implementer les verifications d’autorisation
- Documents de modification - Journaliser les modifications de donnees
- RAP Actions & Functions - Actions pour les operations RGPD