Place a postal address on the map: companies, contacts and the person's own, each only when asked #702
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#702
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: “Companies with full address = coordinates = pin on a map. Contact (Person, Department, User) with full address = coordinates = pin on a map.” A postal address has no coordinates, a company has no postal address yet, and the map's rule today is city level and nothing finer. The engine, the precision and the privacy line are decided in #700; this issue puts coordinates on addresses and decides who is pinned by default.
What exists today
PostalAddressholds kind, label, street, postcode, town, region, country and a primary flag, through a generic relation, and no coordinates (src/postulo/core/models.py:486-570). It is unique per owner and deliberately not across the instance, so two accounts can hold one address (#92). “Valid cannot mean verified”: nothing about an address is looked up (docs/THREAT-MODEL.md:30-47).RULESinsrc/postulo/plugins/postal_rules/rules.py:135holds 37 countries' postcode forms and what an address carries; the plugin says “a format check is not a verification”: nothing there knows whether an address exists or whether a town goes with a postcode. A postcode's form is checked; its place is not known anywhere.src/postulo/accounts/models.py:282) and a contact (src/postulo/jobs/models.py:635). A company cannot (#329, open, unmilestoned), and aDepartmentis a name only (jobs/models.py:568-601; #329 recommends no addresses for departments for now). “Department” in the list is therefore not possible to pin until one of those changes.Company.locationresolves to a city coordinate offline (src/postulo/jobs/places.py,Company.apply_location_guess); an address's town and country could be resolved the same way with no new data.src/postulo/core/gdpr.py:101-114,contact_document) and erased with the contact (erase_contact,:277); the record of processing is drawn from the installed plugins (:379). The threat model says a leaked home address is “somewhere somebody can be found”, and a CV prints a town and country and never a street.src/postulo/jobs/views.py:147-199,src/postulo/templates/jobs/company_map.html).allCountries.zip, 19.7 MB); some countries are partial (for Canada, the Netherlands and the United KingdomallCountries.zipholds only the first part of each code), and its readme gives the UK file a Royal Mail copyright notice of its own. It is a file of the same kindplaces.pyalready reads.Checked against
mainatf09b6010b.Proposal
latitude,longitude, where they came from (town, postcode, a street-level place the person asked for, set by hand) and when, onPostalAddress; nullable, never required, never shown as a field to type.Decisions
:48-55) carried to addresses.PostalAddress: one address has one point; a pin table would need its own ownership, deletion and archive handling for nothing.Builds on
Issues #92 (several addresses, not unique across the instance), #306 (an address checked against its country), #329 (companies get addresses), #366, #579. #700 decides engine and precision; #701 is the precise point from Wikidata.
Needed by
#703 (several addresses, several pins).
Done when
tests/test_postal_addresses.py: an address with a known town and country is resolved to a town-level point on save and a postcode-level point where the file has it; an unknown one stays unplaced without an error; a second owner never sees the first's pins; a contact's address is not pinned until asked.tests/test_company_map.py: pins appear in the list as text and, where drawn, match it; an unpinned contact never appears; the person's own address never appears on the overview.tests/test_gdpr.py: a contact's export carries its coordinates and erasing the contact removes them.tests/test_export.py: the archive format goes up by one (src/postulo/core/export.pyFORMAT_VERSION: one more than whateverFORMAT_VERSIONis when the commit lands (29 atf09b6010b);tests/test_export.py:96follows it) and the round trip keeps them; the candidate format (4) does not change, because addresses are not in the career block.ProfileOutand the contact and company schemas: expose or deliberately omit, said in the schema), search (coordinates are not searched), CV print choice (#308: a pin never prints), the processing record (src/postulo/core/gdpr.py),tests/test_wiki_surface.pyfor any new plugin-surface name,tests/test_page_coverage.pyandtests/security/test_isolation_sweep.pyfor any new page, 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.