If the difference between each brand is just UI related, I would put a put a new search view, for each brand, in the project level. And use the data model and services from the feature level.
If you are required to write all new code for each brand. Spend some time understanding those differences and see if you can refactor your code down so the differences can be achieved by passing in custom predicates and models. This would allow you to keep search in the feature level and have the custom predicates in the project level.
If all that fails and the differences are too great to share code, I would put the different search projects in the project level.
The project level is for site specific one-off functionality. You just need to understand exactly how unique is each new search requirement.
Spend some time and look at how Habitat uses its search service. Each Feature passes in the requirements like templates, facets and search terms into the Foundation layer. This allows you to now have to rewrite search code in each feature.
public class NewsIndexingProvider : ProviderBase, ISearchResultFormatter, IQueryPredicateProvider
{
public Expression<Func<SearchResultItem, bool>> GetQueryPredicate(IQuery query)
{
var fieldNames = new[] {Templates.NewsArticle.Fields.Title_FieldName, Templates.NewsArticle.Fields.Summary_FieldName, Templates.NewsArticle.Fields.Body_FieldName};
return GetFreeTextPredicateService.GetFreeTextPredicate(fieldNames, query);
}
public string ContentType => DictionaryPhraseRepository.Current.Get("/News/Search/Content Type", "News");
public IEnumerable<ID> SupportedTemplates => new[] {Templates.NewsArticle.ID};
public void FormatResult(SearchResultItem item, ISearchResult formattedResult)
{
var contentItem = item.GetItem();
if (contentItem == null)
{
return;
}
formattedResult.Title = FieldRenderer.Render(contentItem, Templates.NewsArticle.Fields.Title.ToString());
formattedResult.Description = FieldRenderer.Render(contentItem, Templates.NewsArticle.Fields.Summary.ToString());
formattedResult.Media = ((ImageField)contentItem.Fields[Templates.NewsArticle.Fields.Image])?.MediaItem;
formattedResult.ViewName = "~/Views/News/NewsSearchResult.cshtml";
}
}