Your career: the additional sections of the list, one shape for all of them and one checklist #692
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#692
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?
The maintainer's list, under Your career, ends with “Additional accolades:” and eight names: “Presentations, Conferences, Seminars, Honours and awards, Memberships, References, Citations, Courses”. Postulo has a place for none of them. This is the tracker for the five issues that add them. It decides once how a new section is shaped and holds the list of every place a section has to be added, so each of the five says only what is different about it.
What exists today
SECTIONS(src/postulo/resume/registry.py:28-80) gives each its slug, model, form and headings;OVERVIEW_ORDER(:83-91) is the seven the career page shows, the skills being shown inside their groups. Each is aResumeItem(src/postulo/resume/models.py:34-62). None of the eight names exists; the nearest areLinkKind.PUBLICATION(:280),Certification(:215-228),Project(:198-212) and, for a person,jobs.Contact(src/postulo/jobs/models.py:604-646).src/postulo/resume/views.py:45-50,resume/urls.py). The isolation sweep therefore names one section,experience(tests/security/test_isolation_sweep.py:405-409); a new model has no isolation test unless one is written.registry.py:1-6). A few are held in step by a test (the candidate reader againstRESUME_FIELDS,tests/test_candidate_file.py:393-398; the sidebar againstOVERVIEW_ORDER,tests/test_career_sections.py; every create form,tests/test_career_ordering.py:230-250). Most are held by nothing.elsewritten for education. The plain-text and Word output readsitem.nameanditem.role(src/postulo/documents/rendering.py:303-319), and its portfolio branch readsitem.qualificationanditem.institution(:374-383), so a model without those fields raisesAttributeError. The HTML themes printentry.item.name,roleand the dates in the finalelseofbase_cv.html:127-162, and the qualification and institution in that ofbase_portfolio.html:131-152. The wiki tells a plugin theme to extend these bases (Writing a plugin, “A theme, if you set documents”), so such a theme inherits whatever the bases do.search_careercovers experience, education, projects, certifications and skills (src/postulo/core/search.py:458-515); its links end#experience,#education,#projects(:510), while the overview's anchors aresection-<slug>(src/postulo/templates/resume/overview.html:39,resume/views.py:77-78), so a hit lands at the top of the page. Recorded as a fact; the five existing links are outside this list.src/postulo/api/routers/has noresumemodule. #303's dialog covers the rows of Your details (src/postulo/accounts/removals.py); a career entry is deleted on a confirmation page (resume/views.py:304-313), which a new section gets for free.SectionSpec.labeland.plural(registry.py:18-25) head the career page;SECTION_LABELS(documents/rendering.py:41-49) heads a CV, drawn in the CV's language (:259). The person cannot retitle a section. #689's built-in names are about languages and carry no section names.EmploymentHistory,EducationHistory, languages, skills,ProjectsandOthers, the last two as Projects (src/postulo/plugins/europass/candidate.py:136-147,:603-619); any other part of the profile holding text is named in the review page's notice “nowhere to go in Postulo yet” (:622-644,tests/test_europass_candidate.py:550-577). The older format'sAchievement, of every type, becomes one Project named after its heading (plugins/europass/reader.py:471-483, JSON:741-751).Checked against
mainatf09b6010b.Proposal
SECTIONS(and overOVERVIEW_ORDERfor the two lists a CV reads,SECTION_LABELSand the importer's CV-entry map, since a single skill is on a CV only inside its group) that fails, naming the section and the list, when a registered section is missing fromTRANSLATION_SECTIONS,RESUME_FIELDS,RESUME_MODELS,candidate.KINDS_BY_BLOCK,SECTION_LABELSor the importer's two maps, unless it is on a short list of named exceptions each with its reason (one today:linkis missing from the importer's CV-entry map, so a link on a CV is skipped on restore, which #470 fixes and so removes the exception; #696 adds one: a reference holds data about another person and the candidate file carries none). It also asks that each model has an explicit decision inTRANSLATABLE(an entry, or a named “translates nothing”) and that a CV holding one entry of every section renders to HTML, plain text and Word. The importer's maps are local variables (src/postulo/core/importer.py:532,:905); they become module-level, or are derived fromexport.RESUME_MODELS. The registry docstring is rewritten to point at the test. This is the one piece of work in this issue itself.mainwith its tests and wiki lines:ResumeItemwithordering = ("order", "pk"), a migration, an admin entry (resume/admin.py), demo data (core/management/commands/seed_demo.py). Form:resume/forms.py, help text in the project's voice (#205). Registry:SECTIONSandOVERVIEW_ORDER, which drive the career page, the sidebar anchors and counts, every view above and the CV picker (documents/forms.py:386-432).templates/resume/overview.htmlwhere the entry's name and highlights are not what the row should say (it branches for links and skill groups,:74-99); the plain preview (templates/resume/preview.html,ResumePreviewView,resume/views.py:334-353, hard-coded per kind); thecountsdictionary (:98-106), which no template undertemplates/resume/reads.resume/translatable.py:27-35(absent means nothing is translatable, as forCertification, pinned bytests/test_career_languages.py:83-86) andTRANSLATION_SECTIONS(core/export.py:153-162).SECTION_LABELS;_section_blocksand_entry_blocks(plain text and Word); a branch inbase_cv.htmland one inbase_portfolio.html; and how a plugin theme that writes its own section loop would print an unknown kind.RESUME_FIELDSandRESUME_MODELS(core/export.py:343-415), the importer'ssection_modelsanddate_fields(core/importer.py:532-541) and its CV-entry map (:905-912), which is keyed by model name and has nolinktoday (#470 completes it);FORMAT_VERSION(:80, 29 atf09b6010b) up by one from whatever it is when the commit lands, with its line in the history comment.Kindinresume/candidate.py:176-276(namesanddatessay what makes two entries the same one;label,subandongoingwhat the review page prints),NOT_READ,CANDIDATE_FORMAT(core/export.py:104, 4) up by one with its line inSHAPES(tests/test_candidate_file.py:372-387), the counts on the file page (resume/views_candidate.py:35-49).search_careerif the section should be found, linking to the real#section-<slug>.Record(resume/importing.py:26-67, onpostulo.plugins.api) gains a list with a default, andis_empty,counts,apply(:115) and the review page'sCOUNT_LABELS,_summarise,_to_session,_from_session(resume/views.py:503-661) follow.Recordchanged); the CHANGELOG line; strings in the working catalogues (en-GB, fr-FR, pt-PT as drafts) and Weblate (#349).pgettextcontext where the English word is ambiguous (below).Decisions
These are recommendations the maintainer has not confirmed.
kindand general columns (title, organisation, role, date, place, link, text), which is how Europass held them until 2020, oneAchievementper heading with a code and a text; (c) a table per shape (an event, a body, a person). Recommended: (a). Europass's current format types them (EventType,Referee,OrganizationAffiliation), so typed fields map to it one to one and a kind table would have to be taken apart again to be written. The sections differ in what is required and what is personal data (hours on a course, a person's agreement on a referee, a role at an event); a kind table makes every column nullable and every rule anif kind ==in a form, a candidate reader and a CV renderer that are all written per model today, and the candidate reader and archive already name their blocks and identity fields per section (Kind.names,RESUME_FIELDS). The cost is six models and the checklist six times, which the guard is for.OVERVIEW_ORDERafter Languages; (b) grouped under one “Additional information” heading, as Europass does; (c) empty ones hidden behind an “Add a section” menu. Recommended: (a), in the note's order with References moved to the end, where a CV puts them: events, honours and awards, memberships, courses, citations, references. The sidebar (#175) exists for this and its rule that an empty section is listed stays; an empty section costs one heading and one line.OVERVIEW_ORDERalso orders the CV picker's groups; what a CV prints follows its own entries (documents/rendering.py:117-148). Revisit (b) or (c) if the page proves heavy.resume/models.py:65-74) that #683, #685 and #686 reopen. An association is not an employer. Recommended: each of the three starts as text, asCertification.issueris today, so none waits on g1. Then it takes g1's mechanism unchanged, in a later commit of its own issue: the text stays the CV's wording and an optional link to one of the owner's companies is added, a company the career form creates being marked “from the career”, which leaves it out of the posting, contact and agency pickers, the table and the map until a posting, contact or application is attached. That marker is how a club or a prize body is kept from becoming somewhere to apply. #671's role registry offers them first, never required: division 94, “Activities of membership organisations” (section T insrc/postulo/jobs/data/nace-2.1.json), for memberships; the “awarding body” role of #686 for honours; the “place of learning” role of #685 for courses. The note asks for companies only for experience, learning and certification, so this extension is the drafters' and the maintainer may decline it.pgettextcontext fixes it:msgid "Reference"already means a reference letter (documents/kinds.py:65; “Référence” in the fr-FR draft) andmsgid "Role"a job (“Poste”). (b) was not checked language by language and the portal's wording may change; (c) is a feature of its own.Achievementparagraphs keep arriving as one Project each, because splitting prose into entries is a guess and an import saves nothing on a guess. No Europass writer is proposed (Postulo writes none,plugins/europass/__init__.pyis an importer), but the fields are chosen so one could be written.linkcame to be missing from the importer's CV map.Prior art
No dependency is proposed: this is a set of tables on the project's own registry, with section names and fields taken from Europass's schemas rather than invented (the rule of #266 and #653).
Verified, by reading in this session the Commission's Europass XML schema definition v4.0.1 (
Candidate.xsd“Europass2 1.0.1, 02 June 2020”), its EUROPASS2 CV XML Schema Documentation v3.0.0 (DG EMPL, 2020), the older Europass XML schema documentation v3.4.0 (§4.7.6) and Cedefop's instructions of 2002-2017:AchievementcodeSpeakingHistory/SpeakingEvent(EventName,Description); orConferencesAndSeminarsconferencesConferencesAndSeminars/ConferenceAndSeminar(EventType:Title,Date,Location,Description,Link)seminars,workshopshonors_awardsHonourAwardDateis a child of the activity type ofNetworksAndMembershipsandSocialAndPoliticalActivities; otherwiseOthersOthersas a ProjectmembershipsNetworksAndMemberships/NetworkAndMembership(activity:Title,Date,Description,Link,Location) andOrganizationAffiliations/OrganizationAffiliation(OrganizationNamewithvalidFromandvalidToattributes,Location,Link)referencesEmploymentReferences/Referee(RefereeTypeCode,PersonName,Communication,YearsKnownNumber,Comment,Role,Link)citationsOthersOthersas a ProjectcoursesNetworksAndMembershipsas “memberships/involvement in professional associations, societies, political parties, sports clubs, etc.” andOrganizationAffiliationsas including “membership in a union”, which is why #693 treats memberships as possibly special-category data.Certifications, for which Postulo has a section, is not in the reader'sREADset either, so a certification in a file is named in the notice and not read. The legacyAchievementdescription is one prose field per heading, not a list of entries.Builds on
Issues #175 (the career in sections), #131 (entries in other languages; free-text organisations), #181 (the candidate file), #203 (the order of entries), #244 and #54 (the Europass reader), #318 (the real-download check), #303, #308, #349. New issues of this set: #683 (organisation as a company, “from the career”), #671 (roles and the divisions that qualify), #685, #686, #687 (publications), #689, #666 (reference letters), #669 (a document that proves an entry).
Needed by
#693, #694, #695, #696 and #697.
Done when
tests/test_career_sections.py(new test, importer maps readable) fails on a section missing from any list in step 1 and passes with the eight kinds there today and the one named exception (linkin the CV-entry map, until #470); a CV holding one entry of each kind renders in HTML, plain text and Word (tests/test_document_formats.py,tests/test_documents.py).tests/test_candidate_file.pyfingerprint,tests/test_export.py).tests/test_wiki_surface.pyis untouched unless a child adds a name topostulo.plugins.api;tests/test_page_coverage.pyneeds no entry (no new URL);tests/security/test_isolation_sweep.pyand a per-section test cover each new model; strings are 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 (#692).