To discuss: how a Drupal User can manage multiple CRM Contacts and whether/how that relates to CRM User.
Best practice for security is one login (Drupal User) per human who needs to log in. I propose that we design against "organizational" Drupal User accounts.
In addition to tracking that a Drupal User and a CRM Contact represent the same human, we will eventually need a way for a Drupal User to manage any number of CRM Contacts for which they are authorized.
Issue fork branch 3522243-map-demo (untested) contains the config I used to spin up a quick proof of concept of mapping Contacts' addresses. Here's a screenshot of that in action:
Please see comments in the MR
Yes, good idea.
jurgenhaas, DANSE maintainer and Member Platform supporter, replied:
that's correct, DANSE currently is built to users as recipients. Thinking about it, extending that to entities as recipient in general, shouldn't be hard. So, if DANSE otherwise is appealing, I'd be willing to make that enhancement.
We should probably move this discussion into a different issue.
As requested by @bluegeek9 in today's Member Platform meeting 📌 Member Platform (Zoom) Meeting on May 8, 2025 Active , I'm going to prototype a CRM Contact Address entity type (or Storage → Type) with an Address → field, its integration with CRM Contact via Inline Entity Form, and plotting contacts' addresses on a map to illustrate the value of using the contrib address field.
jdleonard → created an issue.
jdleonard → created an issue.
Thanks for participating @lizthompson9!
Thanks!
jdleonard → made their first commit to this issue’s fork.
@mradcliffe, Yes I think it could make sense to split this issue, but perhaps it would be wise for us to first determine the overall desired approach as there are some analogous needs across the different fields.
@freelock Good considerations. I'm arriving at the conclusion that it might not be realistic for us to determine all the likely needs up front so it would be wise to make phone number related data extensible (i.e. a field collection or entity type rather than a custom field whose columns are immutable).
A quick look at DANSE suggests to me that it isn't set up to handle non-User entities as first-class recipients. However, Notifier → has documentation making clear that it does. I posted a message in the #danse Slack channel to confirm and will report back.
Taking phone as a simple(r) example, I went down a bit of a rabbit hole.
It's late so I'm going to need to come back to this later, but some quick-ish thoughts...
There are quite a few contrib projects that define their own phone field type. There are some contrib projects that provide validation and/or a formatter for the core telephone field type. I think we should leverage some of the existing functionality provided elsewhere in contrib by A) extending one or more field types, field formatters, and/or field widgets or otherwise ensuring we don't lose out and we don't reinvent the wheel; and/or B) using a field collection or entity (see below) to allow wholesale use of an existing project's field type. Further analysis needed.
https://www.drupal.org/project/telephone_advanced →
https://www.drupal.org/project/telephone_validation →
https://www.drupal.org/project/telephone_formatter →
https://www.drupal.org/project/telephone_plus →
https://www.drupal.org/project/telephone_type →
https://www.drupal.org/project/telephone_international_widget →
https://www.drupal.org/project/phone_international →
https://www.drupal.org/project/phonenumber →
I'm increasingly wary of CRM using a field type that is essentially a bunch of fields related to a phone number, but that are quite a bit more than a phone number. More complex use cases could need to track data (that we aren't currently anticipating) about each phone number such that it would be beneficial for a phone number to be fieldable. We can't change the field schema later ✨ Field type modules cannot maintain their field schema (field type schema change C(R)UD is needed) Needs work . While there are obvious downsides, I think we should discuss using a field collection or defining an entity to capture the various data related to a phone number.
Additional things that might warrant tracking per phone number, whether as a field or a reference from some other entity to a Contact's phone number:
- Confirmation status (similar to confirming an email address)
- Opt-in/out
- Communication preferences
- Activity (e.g. calls or texts to/from)
I'm not suggesting that any of these should be tracked for 1.0 (or even necessarily in a future CRM release). Similarly, I think we should not track mobile carrier in 1.0.
I haven't gone down the rabbit hole for the other field types, but I plan to. I suspect I will come to similar conclusions.
The term CRM is definitely overloaded. While the C typically stands for Customer, I have also seen it commonly stands for Constituent or Contact as well. Regardless of the terminology, CRM aims to be a base for CRM implementations.
Member Platform is adopting and contributing to the CRM → project. Member Platform's focus is on providing the tools that membership organizations need. CRM will be the base for much of that functionality.
CRM's core is module-based. Member Platform likely will also provide some modules. In my mind, either/both projects (and definitely also other projects built on top) would provide recipes on top of the core modules. However, it is a non-goal for either project to be entirely recipe-based so as to facilitate upgrade paths and, at least in CRM's case, to facilitate a shared core which many different use cases can be served.
But to the question of whether should there be recipes to spin up a CRM: yes, absolutely! I think those will come in time.
I'm going to categorize this as a Support Request, move to the CRM project (which is perhaps the more appropriate location for it), and mark it as fixed, but others feel free to tweak my changes as you see fit.
@mradcliffe Thanks for reviewing.
I'm inclined to leave the architecture piece where it is for the time being as it might be the first question some evaluating the project will have. It's also a key differentiator.
I'm confused by "I would avoid using the Summary field" along with "the short description should be added to the Summary field of the Description on the project page", which seem to conflict.
If we use the summary field for the short description, can we safely use headers in the rest of the description?
jdleonard → changed the visibility of the branch 3515999-meta-improve-cicd to hidden.
Thanks for this @bluegeek9!
Two notes:
- Work was previously done to explicitly build mkdocs pages in MRs so that changes to docs can be QA'd. Is there a way to restore that capability with your changes?
- This is a meta issue so work should be performed in child issues, but not here. Would you please create a new child issue to capture the changes you are proposing?
Setting status to Active for this meta issue.
hestenet → credited jdleonard → .
@sorabh.v6 thank you for getting this going!
In DrupalFilesSourcePlugin::alterBackupMigrate
, I attempted to fix the addition of default config for exclude_filepaths
(which appeared to have a copy-paste typo and wasn't analogous for the three sources) though please double check that I didn't misinterpret the intent / behavior. Is exclude_private_filepaths
(for example), correctly named? It's not clear to me under what circumstances it would ever be set and thus why it was added.
I added an update hook to add the Assets Files source for existing sites. However, running it results in:
TypeError: Symfony\Component\Console\Formatter\OutputFormatter::format(): Argument #1 ($message) must be of type ?string, array given
I haven't been able to figure out why.
I also added some relevant test assertions. Undoubtedly some additional tests would be wise. In particular, testing with and without a site's use of $settings['file_assets_path']
including pre-10.1 sites (for which the assets file stream does not exist).
The update hook should probably also take into account whether the assets file stream exists to avoid creating a useless source. However, the source wouldn't then be created upon a site upgrading to 10.1. Not sure how to address this.
I don't currently have time to pursue this further so unassigning.
Hmm, I had opened this issue here rather than on the uikit because there is no contrast issue with a link in an alert in storybook. Please let me know how to tell when to open here vs. uikit.
Screenshot showing secondary button contrast issue:
I started a comparison page: https://www.drupal.org/docs/extending-drupal/contributed-modules/compari... →
Could use more input from those more familiar with the different Drupal-native CRM modules so setting this issue to "Needs Work".
Needs more detailed comparison of Drupal-native CRMs and needs more context for most of the external CRM integration modules.
Added detail about CRM Core
Updated issue summary with a start.
I'll take a stab at a first draft.
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue. See original summary → .
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue.
I'm asking the Member Platform team to dive into this during today's Slack meeting.
jdleonard → created an issue.
Thanks Jim!
@ressa I'll quickly invite you to join #member-platform and #crm on Drupal Slack.
Could you please share your motivation and interest in your proposal?
There are some efforts underway and would love to get you plugged in!
jdleonard → created an issue.
Added link to recording
jdleonard → created an issue.
jdleonard → created an issue.
+1 to this request. I'm getting warnings that are resolved by uninstalling the Shortcut module (I identified Shortcut module menu items as what CT was choking on). However, there are further complications from removing a dependency of CT.
Warning: Undefined array key "url" in _civictheme_preprocess_menu_items() (line 40 of themes/contrib/civictheme/includes/menu.inc).
_civictheme_preprocess_menu_items() (Line: 225)
civictheme_preprocess_menu()
call_user_func_array() (Line: 261)
Drupal\Core\Theme\ThemeManager->render() (Line: 446)
Drupal\Core\Render\Renderer->doRender() (Line: 459)
Drupal\Core\Render\Renderer->doRender() (Line: 203)
Drupal\Core\Render\Renderer->render() (Line: 484)
Drupal\Core\Template\TwigExtension->escapeFilter() (Line: 44)
__TwigTemplate_a365b731b5ce1a0993c8b86627098b29->doDisplay() (Line: 388)
Twig\Template->yield() (Line: 344)
Twig\Template->display() (Line: 359)
Twig\Template->render() (Line: 51)
Twig\TemplateWrapper->render() (Line: 33)
twig_render_template() (Line: 348)
Drupal\Core\Theme\ThemeManager->render() (Line: 446)
Drupal\Core\Render\Renderer->doRender() (Line: 459)
Drupal\Core\Render\Renderer->doRender() (Line: 203)
Drupal\Core\Render\Renderer->render() (Line: 120)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 593)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 119)
Drupal\Core\Render\Renderer->renderInIsolation() (Line: 146)
Drupal\Core\Render\Renderer->doRenderPlaceholder() (Line: 683)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}()
Fiber->start() (Line: 691)
Drupal\Core\Render\Renderer->replacePlaceholders() (Line: 563)
Drupal\Core\Render\Renderer->doRender() (Line: 203)
Drupal\Core\Render\Renderer->render() (Line: 108)
Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}() (Line: 593)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 107)
Drupal\Core\Render\Renderer->renderRoot() (Line: 244)
Drupal\Core\Render\HtmlResponseAttachmentsProcessor->renderPlaceholders() (Line: 74)
Drupal\big_pipe\Render\BigPipeResponseAttachmentsProcessor->processAttachments() (Line: 45)
Drupal\Core\EventSubscriber\HtmlResponseSubscriber->onRespond() (Line: 246)
Symfony\Component\EventDispatcher\EventDispatcher::Symfony\Component\EventDispatcher\{closure}() (Line: 206)
Symfony\Component\EventDispatcher\EventDispatcher->callListeners() (Line: 56)
Symfony\Component\EventDispatcher\EventDispatcher->dispatch() (Line: 216)
Symfony\Component\HttpKernel\HttpKernel->filterResponse() (Line: 204)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 709)
Drupal\Core\DrupalKernel->handle() (Line: 19)
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue.
This looks good to me. The new link destination is sensible and, importantly, doesn't 404. +1 RTBC
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue.
Adding requested pings
jdleonard → created an issue.
Present :)
Added Google Doc link
Tweaked Slack agenda starter
To avoid introducing another proprietary system into our open source project's workflows, I'm closing this issue. Anyone should feel free to re-open if they feel there's significant value in using Luma to manage our meetings.
Updated issue summary to make the purpose/scope more clear, more simply describe all potential early adopters as "interested" rather than "declared" / "undeclared", and add URLs to existing early adopters' sites.
@skessler Thank you for contributing this!
Could I trouble you to copy this to 🌱 Real organization use cases / requirements Active and close this issue as as duplicate? This will help us keep the issue queue maintainable.
Would it make sense to parallelize the "test" stage next to the "build" stage (and have "deploy" stage dependent on the other two)? Won't make much difference for a while, but in theory? Also wonder whether "build" should be "build-docs" and "deploy" should be "deploy-docs" given we will eventually have other tasks that could probably be performed in parallel. I'm undoubtedly over-optimizing...
Nice one!
jdleonard → created an issue.
jdleonard → created an issue.
jdleonard → created an issue.