Diploma, diploma supplement and certificate as kinds of document, each tied to the entry it proves #669
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#669
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
From the list of 2026-10-02, under Documents: "Add diploma, supplement diploma, and certificates, including EDC." A certificate can be uploaded today. A diploma and a diploma supplement cannot be told apart from "Other", and none of them is tied to the entry of the career record it is the proof of. The EDC (a European Digital Credential, assumed here to be the Europass one) is #670.
What exists today
DocumentKind.CERTIFICATE("Certificate") is a kind Postulo holds rather than writes: "somebody else issues these, and Postulo keeps the file" (src/postulo/documents/kinds.py:61,:179). There is no diploma and no diploma supplement. The registry takes a new kind without a migration, because the pickers read it through a callable (kinds.py:91-105,:131-133);tests/test_document_kinds.py:33-47fails if a stored kind is not described and the other way round.kind_specsbuilds one per registered kind, on unless unset (documents/stores.py:112-125).UploadedDocumenthas a title, a kind, a file, notes, a language, a checksum and a version chain (documents/models.py:564-640).Education(qualification, institution, place, dates, grade;resume/models.py:101-117) andCertification(name, issuer, issued on, expires on, credential link;:211-222) have no document. The career record travels without documents (the candidate file), and the wiki says what it leaves out.CVItemuses a generic relation "because … six nullable foreign keys … would need widening every time a new kind of item is added" (documents/models.py:378-413), and the importer resolves it by section and local id (core/importer.py:966-977). The accolades in #693 to #697 will add more sections.jsonorxml(documents/models.py:585-589).Checked against
mainatf09b6010b.Proposal
DocumentKind.DIPLOMA("Diploma") andDocumentKind.DIPLOMA_SUPPLEMENT("Diploma supplement"), registered with the others as held, not authored, with labels in the catalogues. Certificate stays as it is. The "Reference" kind of #666 is unrelated.UploadedDocument.proves: a generic link (content_type,object_id, optional) to one of the owner's career entries, asCVItemdoes, limited to the models that can be proven (EducationandCertificationnow, a section later by adding one line). Written only through a form field that offers the owner's own entries, labelled by what they say ("BSc Computer Science, University of Aveiro"), and checked again on save that the entry has the same owner. A diploma and its supplement point at the same entry; an entry may have several documents; a document proves at most one entry.proveson its documents (a receiver, asforget_the_source_of_a_renderclears a render's source,documents/signals.py:72-89); aGenericRelationon the entry would delete the diploma with it, which is the opposite of what is wanted.Decisions
CVItemdoes. Two nullable keys would be enough today and would have to be widened for each accolade section; a link on the entry's side (a many-to-many) would put a private document into the career block, which #684 to #686 and the candidate file both read.institutionandissuerfree text; the link does not change that.Builds on
#28 and #133 (letter and document kinds, closed), #131 (career entries, closed), #663 (the integrity of an uploaded document matters most for these).
Needed by
#670 (an EDC is a certificate or a diploma with a seal), #684 (an entry with an EQF level may show its proof).
Done when
tests/test_document_kinds.py: the two kinds are described and storable (the existing tests at:33-47cover it once they are registered), a store connection has a switch for each, and a plugin can still register another.tests/test_documents.py(new tests): a diploma and a supplement can be uploaded and both point at oneEducationentry; the form offers only the owner's own entries; another person's entry is refused by the form and by the save; deleting the entry clears the link and keeps the files; deleting the document leaves the entry.tests/test_career_sections.py: the career page shows the number of documents on an entry and links to them.tests/test_export.py: the archive carriesprovesas a section and a local id and restores it; an older archive loads with no links.core/export.pyFORMAT_VERSION, 29 onf09b6010b; one more than whatever it is when the commit lands); the candidate format (4) is unchanged, and a test pins that the candidate file carries no document link; the API (api/routers/documents.py) returnsproveson an upload; search is unchanged (titles and notes); CV print choice (#308) does not apply; processing record (core/gdpr.py) unchanged, the same kind of data as any upload;tests/test_wiki_surface.pydoes not apply (no plugin-surface name);tests/test_page_coverage.pyandtests/security/test_isolation_sweep.pyneed no entry unless a page is added; strings in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate (#349).From the list of improvements of 2026-10-02.
Landed on main with a green Forgejo CI run. Its entry in the CHANGELOG's Unreleased section ends in (#669).