Giter Site home page Giter Site logo

beaconcms / beacon Goto Github PK

View Code? Open in Web Editor NEW
764.0 30.0 80.0 6.16 MB

Open-source content management system (CMS) built with Phoenix LiveView. Faster render times to boost SEO performance, even for the most content-heavy pages.

Home Page: https://beaconcms.org

License: MIT License

Elixir 98.91% HTML 0.37% CSS 0.31% JavaScript 0.42%
cms elixir elixir-lang phoenix phoenix-framework phoenix-liveview

beacon's Introduction

Beacon

Performance without compromising productivity.

Beacon is a content management system (CMS) built with Phoenix LiveView. It brings the rendering speed benefits of Phoenix to even the most content-heavy pages with faster render times to boost SEO performance.

Guides

Check out the guides to get started:

Demo

A sample application running latest Beacon is available at https://github.com/BeaconCMS/beacon_demo

Status

Pre-release version. You can expect incomplete features and breaking changes before a stable v0.1.0 is released.

Main components:

Contributing

Check out the CONTRIBUTING.md doc for overall guidelines to contribute to this project, then follow the Local Development steps to run a local project or watch the video below to understand more about Beacon internals:

YouTube card - ElixirConf 2023 - Leandro Pereira - Beacon: The next generation of CMS in Phoenix LiveView

Local Development

The file dev.exs is a self-contained Phoenix application running Beacon with sample data and code reloading enabled. Follow these steps to get a site up and running:

  1. Install dependencies, build assets, and run database setup:
mix setup

If deps compilation fails, make sure your environment has the compilers installed. On Ubuntu look for the build_essential package, on macOS install utilities with xcode-select --install

  1. Execute the dev script:
iex --sname core -S mix dev

Note that running a named node isn't required unless you're running Beacon LiveAdmin too.

Finally, visit any of the routes defined in dev.exs, eg: http://localhost:4001/dev

Looking for help with your Elixir project?

DockYard logo

At DockYard we are ready to help you build your next Elixir project. We have a unique expertise in Elixir and Phoenix development that is unmatched and we love to write about Elixir.

Have a project in mind? Get in touch!

beacon's People

Contributors

alexandrexaviersm avatar apb9785 avatar aymanosman avatar bcardarella avatar christiantovar avatar cibernox avatar dependabot[bot] avatar dukeweezo avatar dvslabs avatar edborsa avatar feliperenan avatar gitkumi avatar hubertpompecki avatar kgautreaux avatar kianmeng avatar kkyb123 avatar kyleboe avatar leandrocp avatar lucas-cegatti avatar mattvanhorn avatar mfeckie avatar polvalente avatar ryanjafari avatar ryanwinchester avatar schrockwell avatar serabe avatar supernintendo avatar thefirstavenger avatar theodowling avatar xn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

beacon's Issues

Add credo

  • Add credo dep and config
  • Add a job on CI calling mix credo --strict when lint=true
  • Fix existing issues

Form builder

This is a post v0.1 thing but we should start to think about the scope of this feature.

We will need a way to dynamically build forms. This could be a subset functionality of the pagebuilder but certainly far more complex than just editing content.

Editing and creating new data sources

Currently all data sources require a re-deployment to make changes. These should be editable at runtime. At the very least setting custom data source scoping per page path.

Dummy app

As a PO, I would like to have dummy application to help development

Smart reload on publish page

Currently, when publishing a single page, we call load_from_db which reloads every page, component, layout, and stylesheet. We should instead call a new function that reloads the single page and the layout it uses (since the layout needs to regenerate the css based on the new page).

General Improvements: Localization: first class citizen

Hi,
I am not sure if you have already tackled this topic: translations.
The world has seen some CMSs in the past where the ability to translate things was just added later via plugins etc., which quite often resulted in clumsy development experience (e.g. interop with other addons etc.) and UX for the content authors.
For sure there are others which integrate translatable content very well.
I just wanted to wake your awareness on this topic, because I believe it will be useful feature.

Cheers

Asset source

Similar to how the data source is agnostic where the data is coming from (i.e. db, api, etc...) I think we should have something similar for asset sources. From on top of that functionality for uploading of assets.

Things to think about:

  • how to retrieve a collection of assets, should asset source be queryable?
  • how should URLs to each asset be resolved?

Demo, mix dev, GET 127.0.0.1:4000/dev/assets/admin.css 404

Hey trying to launch the demo:

  • mix setup
  • mix dev
  • i get the following error
GET http://127.0.0.1:4000/dev/assets/admin.css net::ERR_ABORTED 404 (Not Found)

The admin.css does exist in priv/dev/static/assets/admin.css so not sure what else could be happening here?

Tailwind compilation

As a PO, I would like to have functionality for Tailwind to be compiled at runtime (on the fly). It gives the possibility for the user to add own classes into Tailwind, compile those and use

PAY ATTENTION: Tailwind must be compiled at runtime

mix beacon.install generator

Similar to phx.gen.auth and others, a generator to inject beacon into an existing app, either single or umbrella. That could lower the barrier to adoption.

It should perform most of the steps described in README providing a sane default to get started.

Core -> Webfiles and Metatags: Schema.org tags

See #122 (comment) for implementation details.


In addition to the meta tag support we should be using schema.org tags for better SEO. Here is what dockyard.com is currently rendering:

  <script id="ember899" class="ember-view" type="application/ld+json">{
  "@type": "Blog",
  "name": "DockYard Insights - DockYard Blog",
  "url": "https://dockyard.com/blog",
  "copyrightYear": 2023,
  "publisher": {
    "@type": "Corporation",
    "name": "DockYard",
    "url": "https://dockyard.com",
    "legalName": "DockYard, Inc."
  },
  "@context": "http://schema.org"
}
</script>

  <script id="ember913" class="ember-view" type="application/ld+json">{
  "@type": "BlogPosting",
  "headline": "LiveView Native Yearly Update",
  "description": "First LiveView Native update of 2023!",
  "datePublished": "2023-01-17T16:30:00.921Z",
  "publisher": {
    "@type": "Corporation",
    "name": "DockYard",
    "url": "https://dockyard.com",
    "legalName": "DockYard, Inc."
  },
  "mainEntityOfPage": "https://dockyard.com/blog",
  "genre": [
    "Engineering",
    "Elixir",
    "Mobile"
  ],
  "url": "https://dockyard.com/blog/2023/01/17/liveview-native-yearly-update",
  "author": {
    "@type": "Person",
    "name": "Brian Cardarella"
  },
  "@context": "http://schema.org"
}
</script>

Verifier: https://validator.schema.org/#url=https%3A%2F%2Fdockyard.com%2Fblog%2F2023%2F01%2F17%2Fliveview-native-yearly-update

Asset Manager

We need an interface for managing all assets that are uploaded to a site managed by Beacon.

I'd prefer that the asset manager does not permit directories. It should be a flat file system that allows for the following

This should be a LiveView UI and available/unique per-site in Beacon

Assets should be stored in the database as binary data types

[BE] Page Meta tags

As a PO I would like to manage meta tags. We can have them preconfigured and be able to change. As well users can create meta tags by themselves. Meta tags could be for the whole page as well as for the piece of content. User has an ability to edit meta tags and delete them as well.

CSS support

Right now there is no way to add custom CSS. At least not a great way. I see there being two paths on how to handle CSS.

  • traditional stylesheets that are compiled into a single stylesheet - this is the most complicated method but would probably be the most accepted. Basically there would need to be a way to take each style sheet represented as an AST that are merged into a single AST then output as a single stylesheet that can be accessed via a URL. Implementation-wise this could be compiled functions similar to the Heex compilation method we're using. We'd need an CSS parser though, preferably without a C compilation requirement.
  • inline styles - this one will likely get some hate and I don't disagree. The inline styles would definitely increase the bytes per page. This method would certainly be easy to implement and far cleaner.

Core -> Asset Manager -> Image Optimization: Converting to .WEBP

When uploading images we should force an optimization process

  1. convert all image types to webp format
  2. output several image sizes and serve with srcset

I may be dating myself but is Imagemagick still the best way to do this?

FROM MEETING FEB 27 2023:
As discussed in a meeting we have to do next:

  • Brute force all images in S3 (basic script hitting images one-by-one, etc) for the DY.COM
  • Convert to .webp
  • Constrain to size
  • Constrain on width to preserve aspect ratio
    This is not the paved path - trying to get to launch
    If an image has a width under the constraint, don’t touch it other than convert it to .webp
    Width max: 2880
    Maintain aspect ratio at 85% quality

FYI @schrockwell @leandrocp @xn

Load compiled runtime CSS

That's a follow up of #30

The compiled runtime_css that is injected into layout assigns:

runtime_css: \"""
#{runtime_css}
\"""

Should be loaded in root.html.heex similar to the other resources:

<%= meta_tags(assigns) %>
<title><%= page_title(assigns) %></title>
<%= linked_stylesheets(assigns) %>
<%= stylesheet_tag(assigns) %>

layout_id_for_path/1 is undefined after following installation instructions

Hi, this project looks great and I'm excited to try it out! Unfortunately, following the installation instructions doesn't seem to work right now and results in the following error:

UndefinedFunctionError at GET /my_site/home
function BeaconWeb.LiveRenderer.Page6A217F0F7032720EB50A1A2FBF258463.layout_id_for_path/1 is undefined (module BeaconWeb.LiveRenderer.Page6A217F0F7032720EB50A1A2FBF258463 is not available)

image

This is true when adding beacon to an existing application as well as a new one when starting from scratch. I'm using:

  • Elixir 1.14.3
  • Phoenix 1.17.0-rc2

Logs:

[info] GET /my_site/home
[debug] Processing with BeaconWeb.PageLive.path/2
  Parameters: %{"path" => ["home"]}
  Pipelines: [:browser]
[debug] failed for the 1 time, retrying
[debug] failed for the 2 time, retrying
[debug] failed for the 3 time, retrying
[debug] failed for the 4 time, retrying
[debug] failed for the 5 time, retrying
[debug] failed for the 6 time, retrying
[debug] failed for the 7 time, retrying
[debug] failed for the 8 time, retrying
[debug] failed for the 9 time, retrying
[debug] failed for the 10 time, retrying
[debug] failed 10 times
[info] Sent 500 in 1160ms
[error] #PID<0.646.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.645.0>, stream id 1) terminated
Server: localhost:4000 (http)
Request: GET /my_site/home
** (exit) an exception was raised:
    ** (UndefinedFunctionError) function BeaconWeb.LiveRenderer.Page6A217F0F7032720EB50A1A2FBF258463.layout_id_for_path/1 is undefined (module BeaconWeb.LiveRenderer.Page6A217F0F7032720EB50A1A2FBF258463 is not available)
        BeaconWeb.LiveRenderer.Page6A217F0F7032720EB50A1A2FBF258463.layout_id_for_path(["home"])
        (beacon 0.1.0-dev) lib/beacon/loader.ex:41: Beacon.Loader.call_function_with_retry/4
        (beacon 0.1.0-dev) lib/beacon_web/live/page_live.ex:23: BeaconWeb.PageLive.mount/3
        (phoenix_live_view 0.18.11) lib/phoenix_live_view/utils.ex:335: anonymous fn/6 in Phoenix.LiveView.Utils.maybe_call_live_view_mount!/5
        (telemetry 1.2.1) /Users/hubert/code/my_app/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
        (phoenix_live_view 0.18.11) lib/phoenix_live_view/static.ex:278: Phoenix.LiveView.Static.call_mount_and_handle_params!/5
        (phoenix_live_view 0.18.11) lib/phoenix_live_view/static.ex:119: Phoenix.LiveView.Static.render/3
        (phoenix_live_view 0.18.11) lib/phoenix_live_view/controller.ex:39: Phoenix.LiveView.Controller.live_render/3
        (phoenix 1.7.0-rc.2) lib/phoenix/router.ex:425: Phoenix.Router.__call__/5
        (my_app 0.1.0) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.plug_builder_call/2
        (my_app 0.1.0) lib/plug/debugger.ex:136: MyAppWeb.Endpoint."call (overridable 3)"/2
        (my_app 0.1.0) lib/my_app_web/endpoint.ex:1: MyAppWeb.Endpoint.call/2
        (phoenix 1.7.0-rc.2) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
        (plug_cowboy 2.6.0) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2
        (cowboy 2.9.0) /Users/hubert/code/my_app/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
        (cowboy 2.9.0) /Users/hubert/code/my_app/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
        (cowboy 2.9.0) /Users/hubert/code/my_app/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
        (stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

Asset management (EXTERNAL)

As a PO, I want to store assets somewhere. Assets: images, videos, logos, files (all file types must be supported) as well as the CMS templates. We can use database (PostgreSQL for example) or Amazon S3, or other solutions here.
As well we have to have the functionality to manage assets (CRUD - create content, read content (search), update content, delete content)

  • Research the proper storage for the assets
  • Adding CRUD functionality (~12 days)

Tailwind integration for the BeaconCMS

As a PO, I would like to integrate Tailwind framework as a default CSS framework for the BeaconCMS, to use it for styling inside the Page Builder in the future

If it is only for Tailwind integration, then it is 5 hours

Tailwind config file for the users

As a PO, I would like to expose Tailwind config file tailwind.js.config for the users to let them use their own global (whole app) styling (fonts and colors) without any CSS framework

Blocked by "Tailwind compilation"

Expose the file
Make sure the configuration file is valid

[Proposal] - Router Macros

Router Macros

Introduce router macros to encapsulate route definition and allow customization on the site level.

beacon_site(path, opts \\ [])

Where opts:

  • live_socket_path (optional) - same as LiveDashboard and Oban
  • data_source (optional) - the current config :beacon, :data_source is global, one module for all sites. By having the config on the site level we can make it explicit which module belogs to each site or none if a site doesn't have a data source linked to it.
  • tailwind_config (optional) - path to a tailwind.config.js file used to compile CSS for that site. Config on the site level so each site may have it's own customization, or just don't provide one to use the default config embedded in beacon. This config would be foundation to fix the issue #96

Example:

beacon_site "/marketing"

generates:

scope "/", BeaconWeb do
  live_session :beacon_marketing, session: %{"beacon_site" => "marketing"} do
    live "/marketing/*path", PageLive, :path
  end
end

Note that:

  • The macro would generate the whole scope because the BeaconWeb namespace is essentially private, the user should not be able to change it, as PageLive is private.
  • We can provide other opts to allow further customizations but that would be the minimal.
  • BeaconWeb.Plug is not needed anymore, the root layout option would be injected in the live_session opts.

beacon_admin(path, opts \\ [])

The path here would be used to resolve the routes in the admin pages.

beacon_api(path, opts \\ [])

Similar to the other ones.

References

Views

We need a way to dynamically manage View helpers.

Context:
In DeadViews, we have a Controller, a Template, and a View, and helpers for the Template go in the View. In LiveView, these helpers go in the LiveView module. For Beacon, we don't have a LiveView module that the end user can modify, we dynamically load the template based on the path, and #19 will define the event handling.

Instead of having the developer hard code views, we should provide view helpers that are scoped to the template being rendered.

Custom live view socket path

Currently it's connecting to the live socket provided by the host application at /live but that may not be case for every app and we want to support custom paths. For that an option live_socket_path is provided on beacon_site router macro but it has no effect currently (it's not implemented)

live_socket_path = Keyword.get(opts, :live_socket_path, "/live")

That value has to be fetched and injected into the runtime layout https://github.com/BeaconCMS/beacon/blob/924202e757243b941154e576b18c13d447829ca0/lib/beacon_web/components/layouts/runtime.html.heex so it can be passed to live socket

let socketPath = document.querySelector("html").getAttribute("phx-socket") || "/live"
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveView.LiveSocket(socketPath, Phoenix.Socket, {params: {_csrf_token: csrfToken}});

Similar to how it's done on LiveDashboard.

LiveData not found error

We need to have a nicer interface for when no pattern matches on the BeaconLiveData implementation. Right now it throws a function not found error.

Handle Events

We need a way to handle LiveView events. The first pass at this will be to add an event schema to define what event mappings happen for a given page. It will have page, event pattern, and code fields. The code field will be Elixir code loaded into the handle_event function.

Path Not Found Handler

We should have a better handler for instances where a given path is not found. Right now it raises a function not found error.

Hosting and Tenant: Multiple domains hosting

As a PO, I would like to have multiple domain/apps hosting for BeaconCMS and have configuration/options to manage those from the CMS

/Beacon's ability to host multiple domains is a long-term goal, not critical for launch. For now academy.dockyard.com, getfirefly.org, native.live, and beaconcms.org will stay on Netlify/

Beacon CMS doesn't work with Phoenix 1.7.0-rc.0

Hey Guys,

I'm excited about using Beacon CMS in my project.

I just created a new app using latest release candidate and when I tried to add {:beacon, github: "beaconCMS/beacon"} to mix file and ran mix deps.get, I got following error:

mix deps.get
* Updating beacon (https://github.com/beaconCMS/beacon.git)
origin/HEAD set to main
* Updating safe_code (https://github.com/TheFirstAvenger/safe_code.git)
origin/HEAD set to main
Resolving Hex dependencies...
#Incompatibility<#Term<your app>, cause: {:conflict, #Incompatibility<#Term<not phoenix_live_view 0.18.3 (optional)>, cause: {:conflict, #Incompatibility<#Term<the lock>, #Term<not phoenix_live_view 0.18.3 (optional)>, cause: :dependency>, #Incompatibility<#Term<your app>, #Term<not the lock>, cause: :dependency>}>, #Incompatibility<#Term<your app>, #Term<not phoenix_live_view ~> 0.17.5>, cause: :dependency>}>
Resolution completed in 0.048s
Because "the lock" specifies phoenix_live_view 0.18.3, phoenix_live_view 0.18.3 is required.
So, because your app depends on phoenix_live_view ~> 0.17.5, version solving failed.
** (Mix) Hex dependency resolution failed

elixir --version
Erlang/OTP 25 [erts-13.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit]

Elixir 1.14.2 (compiled with Erlang/OTP 25)

Analytics, company info

Currently Plausible doesn't have an out of the box way to determine if an IP address is from a corporate range, this is important for marketing to determine where inbound traffic is coming from.

This is a simple lookup. First step is to download, crawl, and parse all of the ranges and associated company info from: https://www.cidr-report.org/as2.0/autnums.html

However, what we need to determine is if this violates GDPR.

Documentation/screenshots

Hi.

Is it planned to add some documentation?
The required minimum is, IMHO, some screenshots of CMS UI, list of features, how to add content and change page appearance. For pro users it could be API spec, example of writing plugins and so on.

Add support to set Page Title in the page level

Currently a site may define a page title in the layout level

field :title, :string
which in turn is used to resolve every page title under that layout, see
def page_title(%{layout_assigns: %{page_title: page_title}}), do: page_title
def page_title(%{__dynamic_layout_id__: layout_id, __site__: site}) do
%{title: title} = compiled_layout_assigns(site, layout_id)
title
end
def page_title(_) do
Logger.warn("No page title set")
""
end
and
<title><%= page_title(assigns) %></title>

We want to add a field :title in https://github.com/BeaconCMS/beacon/blob/2b391396cd1815e3f9b97389fa4a3ba7f03ad10a/lib/beacon/pages/page.ex so the page title can be customized per page.

In the future we may support the callback page_title in Beacon.DataSource.Behaviour to further customize page titles, for eg to support dynamic values or prefix/suffix as previously explored and suggested by @schrockwell

Meta tag support

We have layout meta tags but we also need per-page meta tags.

The app should essentially do a Map.merge on three sets of Meta tags:

  1. site-wide - these are default tags that we always want to render unless there are higher priority overlapping tags
  2. layout
  3. page

On each page render we first get the Map of site tags, then merge the layout tags, then the page tags. Tags are considered unique based upon the element name and id_key_name and id_key_value. For example:

<meta name="foorbar" content"abc"> and <meta name="foobar" content="def">. In this case they conflict and the later will overwrite the former.

<meta name="foobar" content="abc"> and <meta name="barbaz" content="def"> these do not conflict and will both render

<meta name="foobar" content="abc"> and <link name="foobar" content="def"> these do not conflict and will both render

<meta name="foobar" content="abc"> and <meta property="foobar" content="def"> these do not conflict and will both render

Some meta tags deviate from name being the id_key. For example, both are valid meta tags:

<meta name="foobar" content="..."> and <meta property="foobar" content="..."> the key name needs to be accounted for. The data model could probably be:

%{element: "meta", id_key: "name", id_key_value: "foobar", content_key: "content", content_value: "..."}

Components and Pages: Preserve scroll position

This is a problem in LiveView but we can solve it on our own. Pages currently don't preserve scroll position. See:

scroll.issue.3.mp4

I solved this a few years ago in ember-router-scroll: https://github.com/DockYard/ember-router-scroll/blob/master/addon/services/router-scroll.js

We'll need to pull in some JS resources to implement in Beacon. Two cases need to be accounted for:

  1. preserving scroll position when navigating to a new page then back to the original
  2. preserving scroll position when reloading a page (hard refresh also respects position)
  3. if opening a new tab to the same URL or navigating forward from A, to B, and pushing a new instance of A to the history stack it shouldn't inherit the scroll position of the original visit of A but if I go back in history it should

Components and Pages: User-defined function components

We want to allow users to define their own function components. That will deprecate remove the existing my_component feature, see #84 (comment)

The first step is to define such function components:

Similar to the CoreComponents provided by Phoenix, Beacon will provide a UserComponents to hold user-defined components that can be created as:

Beacon.Components.create_component!(%{
  site: "my_site",
  name: "greet",
  attrs: [
    %{name: "name", type: "string", required: true}
  ],
  body: """
  <p>Hello, <%= @name %>!</p>
  """
})

Which internally compiles to:

defmodule BeaconWeb.LiveRenderer.UserComponents{site_hash} do
  use Phoenix.Component
  
  attr :name, :string, required: true
  def greet(assigns) do
    ~H"""
    <p>Hello, <%= @name %>!</p>
    """
  end
end

And then one can use it in layouts and pages:

Beacon.Pages.create_page!(%{
  path: "home",
  site: "my_site",
  layout_id: layout_id,
  template: """
  <main>
    <BeaconWeb.Components.dynamic component={"greet"} name="Jane" />
  </main>
  """
})

Notes:

  • Name collision may happen by sharing the same module to hold all components. We could explore custom namespaces but keeping it simple for now.

Phoenix style

As a PO, I would like to have Phoenix framework style implemented by default for the BeaconCMS

For discussion

Blocked by "Tailwind integration for the BeaconCMS"

Telemetry based analytics

As a PO, I would like to have telemetry inside the BeaconCMS for the internal use. Events used for buttons, links, etc. must be helpful in case of analytics and product management to make future decisions. We have to research potential candidates here or create our own solution (preferable). If we'll go with own solution, we have to choose temporary one, before our own telemetry will be implemented. We can check as a potential candidates: Plausible, Superset?

Blocked by #70

  • Research potential candidates for analytics
  • Create own solution (depends on research)
  • Integrate chosen solution

Phoenix and LiveView upgrade

As a PO, I would like to upgrade Phoenix to version 1.7 and LiveView to version 0.18. We can use it as a building block to build pages

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.