Needs grooming: Preserve AISL template footer notes through import and rendering

Aperta
#29 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
25/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
aws, django, python

Direzione di ricerca

Read Relay AGENTS, docs/PROCESS, and the existing template model and service code, including mailing.models.py, mailing/services/api.py, transactional_versions, and transactional_markdown. Run the relevant baseline tests plus make test and make lint before any extraction. Done means the approved template ownership preserves schema, API, immutable versions, selected rendering, and no-UI behavior with the specified footer tests passing.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

enhancement

Preserve authored template footer notes in the Relay backend

Stage and dependencies

Proposed PM grooming for existing #29, under preservation parent #30 P01/P02. Implementation is blocked pending the Relay model/template API/render owners' exact scope/path acknowledgements, including the current ui/aisl work and reserved migration0030. Do not open a duplicate issue or assign that migration number from the reviewed source alone.

Read Relay AGENTS, docs/PROCESS, PM role, architecture/data-model/API/operations and #30. Reviewed source is cdf3a9a25de8bd63af8ee45285983d28a3aa13a0; donor semantics are bound to AISL f9a3b0432864d40f6f12a85382df4a25c4e3f98f. Current source references are static findings, not test proof.

The user requires existing authored footer content and recipient/operator experience to survive. Existing AISL screens/routes/tasks remain through thin adapters until preservation is accepted. This issue adds a backend metadata/render contract; it authorizes no UI controls, navigation, layout, copy, route removal or redesign. Agents do not access production databases/credentials. Actual export/import, publish, sends, deployment and adoption are later authorized owner work.

Problem and goal

AISL EmailTemplateOverride replaces subject/body/footer as one record. footer_note is literal authored text, up to500 characters in the donor field, with empty default. Its HTML chrome escapes the note; the plain-text renderer appends it with presentation-only outer whitespace trimming, before verification and unsubscribe actions. Footer text is not a second Django-template program or trusted HTML.

Relay drafts, immutable versions, API payloads, import/transfer projections and render sources currently omit footer_note. wrap_email_html already accepts it but the version/send path does not pass it; plain text currently carries substituted Markdown without footer. Preserve the field through one template-domain owner and a canonical snapshot/render source. Never strip or truncate stored footer content or reconstruct it from body/subject.

Bounded scope and child boundaries

  • This issue owns footer field storage and validation, canonical draft/version serialization, immutable publication copy, selected render-source propagation, and native footer composition/render contract. Existing endpoints, model identities, table names and import paths stay stable.
  • The P01 normalized-bundle consumer child owns whole-bundle preflight/atomic apply, dynamic override-only catalog/context metadata and file/override reconciliation. It calls this issue's footer validator/serializer; no AISL Python import, second exporter or per-file partial importer is added here. Do not fix unrelated subject stripping/classification/context rules inside #29.
  • P02 owns the generic first-class rendering profile and complete subject/body/plain-text/HTML/chrome/footer/action parity. #29 carries literal footer data and supports escaped HTML/plain-text composition through that native contract, without a site import or copied AISL renderer. The native footer contract must preserve full content and placement; native Relay default chrome is not proof of donor equivalence. Adoption remains blocked until P02 synthetic recipient comparison passes.
  • Dynamic verify/unsubscribe decisions, greeting/timezone and delivery-time links remain minimal AISL adapter P07 inputs. Footer author text is distinct from those policies and must not mint tokens, change classification or create a team sender kind.
  • Existing old-instance transfer and #26 history work remain owned separately. Generic template transfer field projection may need a coordinated metadata seam to prevent future field loss, but no production rerun or history import belongs here. Exact projection changes need the transfer owner's ACK.

Contract

  1. Store footer_note on draft and immutable published version with empty-string default for legacy rows. A string, including empty/whitespace-only and Unicode/multiline content, is retained exactly in storage and API/snapshot output. Proposed capacity matches donor's supported500 characters; accept exact500 and reject501 rather than truncate. Reject explicit null, booleans, numbers, lists and objects with field-scoped validation before persistence. If owner/schema review selects a wider generic capacity, record it and its boundary tests; never choose a narrower capacity or silently coerce values.
  2. Existing full-replacement template PUT retains documented behavior: omitted footer means empty, explicit empty clears the draft, invalid footer leaves the entire draft unchanged. GET/upsert/version/publish output exposes one footer key consistently. Unknown/foreign template/version/client isolation and existing error/status shapes remain. Field omission semantics of separate generic transfer/bundle protocols are versioned by their owners; absent legacy footer maps to empty, not a destructive change to immutable snapshots.
  3. Publishing snapshots footer together with the same draft subject/body/context/category at that state transition. Later draft edits/clearing affect only a newly published version. Existing published versions remain immutable; old rows gain default empty rather than receiving a later draft footer. Resolve explicit version, latest published version, or never-published draft with existing precedence. No fallback that takes a published body and current draft footer.
  4. One canonical selected render source feeds preview, dry run and durable send. The selected footer is composed exactly once into escaped HTML and a plain-text counterpart. Do not template-evaluate its {{variables}} or {%blocks%}, mark it safe, Markdown-render it, duplicate it, or persist trimmed text. Plain-text presentation may follow donor outer trimming; comparison records this explicit behavior. Verification/unsubscribe action placement follows P02/P07 contract, with authored footer before those actions. Full pre-rendered HTML/text sources need an explicit supported composition/profile contract; reject unsupported nonempty-footer/source combinations before message/queue work rather than silently omit or double-wrap existing content.
  5. Preview and dry-run remain no-write/no-queue/no-network operations. Real/test-send allowlist, idempotency, suppression, render-source precedence and audit semantics remain existing Relay contracts; #29 does not change transport retry or live-history behavior. Parent donor test-send equivalence remains its separate preservation gate.
  6. Existing admin/other forms must not inadvertently acquire a new footer control through model auto-discovery or clear a backend footer on an unrelated edit. Preserve current fieldsets/rendered workflow and bind future editing UI to its own owner/card. No visible feature disappears.

Cohesive ownership and size strategy

User-required portable coding standard applies: one business owner, DRY, thin APIs, explicit transactions, no ternaries, simple loops, new functions at most30 lines/new handwritten files at most300. Do not grow already oversized files/functions without a genuine documented tool/framework/cohesion constraint. A two-field addition or absent mechanical size gate is not an exception. Committed Relay has no coding-standard file; repository-specific configuration/commands follow Relay, and a guidance port is separate.

Proposed extraction for owner review, not arbitrary fragments:

  • Extract the complete coupled EmailTemplate and EmailTemplateVersion declarations, including Meta/constraints/indexes/managers/immutability, into one cohesive template-domain model module (proposed mailing/template_models.py). Keep mailing.models.EmailTemplate/EmailTemplateVersion explicit re-exports so existing callers/admin/tests remain stable. Preserve Django app/model labels, db_table, relationships, related names, discovery and migration deconstruction.
  • Resolve their existing shared TimeStampedModel dependency without a circular import: a cohesive shared abstract model-base owner (proposed mailing/model_base.py), explicitly re-exported through mailing.models. Template-to-client references use equivalent lazy relationships if needed. Move the whole existing base once; do not clone fields or invent an inheritance/mixin hierarchy merely to hide line counts. Verify identical schema state before the intentional footer migration. If this extraction conflicts with current owner work, stop/re-groom rather than append fields under an automatic waiver.
  • Extract the complete template payload/validation/upsert concern from oversized mailing/services/api.py into a cohesive template service (proposed mailing/services/template_contracts.py), retaining public API imports/error type/transaction boundaries through thin forwarding or re-exports. Generic validation/error helpers keep one owner; avoid circular dependencies. This moves a business concern, not one-field helpers dispersed across files. Preserve existing subject/body behavior while adding footer validation.
  • Reuse the existing transactional_versions render-source/publication owner and transactional_markdown composition owner. Use a shared renderer seam for footer, not competing preview/send implementations. Any oversized transactional/transfer/API-doc module only calls the extracted owner or coordinated canonical metadata projection; actual unavoidable framework/cohesion exceptions require written review, not a preset line budget.

Verification and acceptance

  • Baseline behavior characterization before extraction, then same tests after extraction: Django apps.get_model and stable mailing.models imports, admin registration, model labels/tables/constraints/foreign keys; migration autodetection sees no remove/recreate/rename solely from extraction. Fresh and pre-existing database migrate/reverse/reapply retain draft/version counts, IDs, relations and published text. New footer field is the sole intentional schema delta; allocate next migration after current-owner ACK.
  • API tests: empty/missing/explicit clear, Unicode/multiline/whitespace, exact500/501, wrong types, foreign client and invalid footer atomic rollback. Assert byte-identical stored/returned/snapshot values and unchanged subject/body. Generic bundle/transfer metadata contract fixtures consume the same validator/serializer without running a donor importer or network.
  • Version tests: draft footerA→publishv1→edit/clear→publishv2; explicitv1/latest/draft preview and send select the correct footer, never hybrid snapshots. Existing immutability/update/delete/version precedence tests pass. Existing queued/rendered messages are not rewritten by migration.
  • Render tests: literal tags/HTML characters escaped and not evaluated, nonempty and empty footer, no double composition; HTML/plain-text selected-version preview/dry-run/send equality and safe unsupported-source rejection before any durable work. Synthetic donor-bound footer fixtures compare HTML escaping/placement and plain-text content/order with named/nameless/context variants. P02 retains complete donor chrome/format/action parity across dynamic inventory; #29 capability acceptance alone never establishes it.
  • No-UI tests: current admin form fields/fieldsets and unrelated edit preserve backend footer; existing catalog/routes/operator view/template tests remain. Independently rendered recipient evidence is required where output changes; no screenshot exemption based on backend-file names alone.
  • Independent Tester runs fresh relevant Relay unit/service/view tests and current make test/make lint gates, with SES/SQS stubs and assigned environment ownership; records actual commands/exits/frozen hashes. PM reviews actual terminal evidence after role gates. No production sends or borrowed source/CI evidence.

Done when this bounded footer contract and its cohesive ownership/extraction are independently tested/accepted, exact write overlaps have ACKs, docs/API schema state truthfully report support, and existing APIs/UI/model identities/published versions are preserved. Parent #30 remains open; normalized whole-bundle import, complete rendering-profile parity, real overrides, D13/R6.1 and A6.1/adoption/cutover receipts remain separate pending gates.

Lingua principale
Python
Stelle
0
Fork
0
Merge medio
11m
PR unite (30g)
4

Preparare l'ambiente

  • Include un Dockerfile o un file Docker Compose
  • Nessun modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di DataTalksClub/relay

Tutte le issue di DataTalksClub/relay

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.