Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This file excludes paths from the Docker build context.
#
# By default, Docker's build context includes all files (and folders) in the
# current directory. Even if a file isn't copied into the container it is still sent to
# the Docker daemon.
#
# There are multiple reasons to exclude files from the build context:
#
# 1. Prevent nested folders from being copied into the container (ex: exclude
# /assets/node_modules when copying /assets)
# 2. Reduce the size of the build context and improve build time (ex. /build, /deps, /doc)
# 3. Avoid sending files containing sensitive information
#
# More information on using .dockerignore is available here:
# https://docs.docker.com/engine/reference/builder/#dockerignore-file

.dockerignore

# Ignore git, but keep git HEAD and refs to access current commit hash if needed:
#
# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat
# d0b8727759e1e0e7aa3d41707d12376e373d5ecc
.git
!.git/HEAD
!.git/refs

# Common development/test artifacts
/cover/
/doc/
/test/
/tmp/
.elixir_ls

# Mix artifacts
/_build/
/deps/
*.ez

# Generated on crash by the VM
erl_crash.dump

# Static artifacts - These should be fetched and built inside the Docker image
/assets/node_modules/
/priv/static/assets/
/priv/static/cache_manifest.json
6 changes: 6 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
import_deps: [:ecto, :ecto_sql, :phoenix],
subdirectories: ["priv/*/migrations"],
plugins: [Phoenix.LiveView.HTMLFormatter],
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
]
18 changes: 18 additions & 0 deletions .github/workflows/fly-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/

name: Fly Deploy
on:
push:
branches:
- main
jobs:
deploy:
name: Deploy app
runs-on: ubuntu-latest
concurrency: deploy-group # optional: ensure only one action runs at a time
steps:
- uses: actions/checkout@v4
- uses: superfly/flyctl-actions/setup-flyctl@master
- run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Temporary files, for example, from tests.
/tmp/

# Ignore package tarball (built via "mix hex.build").
kounia-*.tar

# Ignore assets that are produced by build tools.
/priv/static/assets/

# Ignore digested assets cache.
/priv/static/cache_manifest.json

# In case you use Node.js/npm, you want to ignore these.
npm-debug.log
/assets/node_modules/

2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
elixir 1.18.3-otp-27
erlang 27.3.4
101 changes: 101 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian
# instead of Alpine to avoid DNS resolution issues in production.
#
# https://hub.docker.com/r/hexpm/elixir/tags?name=ubuntu
# https://hub.docker.com/_/ubuntu/tags
#
# This file is based on these images:
#
# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
# - https://hub.docker.com/_/debian/tags?name=bookworm-20250428-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: docker.io/hexpm/elixir:1.18.3-erlang-27.3.4-debian-bookworm-20250428-slim
#
ARG ELIXIR_VERSION=1.18.3
ARG OTP_VERSION=27.3.4
ARG DEBIAN_VERSION=bookworm-20250428-slim

ARG BUILDER_IMAGE="docker.io/hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="docker.io/debian:${DEBIAN_VERSION}"

FROM ${BUILDER_IMAGE} AS builder

# install build dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential git \
&& rm -rf /var/lib/apt/lists/*

# prepare build dir
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force \
&& mix local.rebar --force

# set build ENV
ENV MIX_ENV="prod"

# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config

# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

RUN mix assets.setup

COPY priv priv

COPY lib lib

COPY assets assets

# compile assets
RUN mix assets.deploy

# Compile the release
RUN mix compile

# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/

COPY rel rel
RUN mix release

# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE} AS final

RUN apt-get update \
&& apt-get install -y --no-install-recommends libstdc++6 openssl libncurses5 locales ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen \
&& locale-gen

ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8

WORKDIR "/app"
RUN chown nobody /app

# set runner ENV
ENV MIX_ENV="prod"

# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/kounia ./

USER nobody

# If using an environment that doesn't automatically reap zombie processes, it is
# advised to add an init process such as tini via `apt-get install`
# above and adding an entrypoint. See https://github.com/krallin/tini for details
# ENTRYPOINT ["/tini", "--"]

CMD ["/app/bin/server"]
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Kounia

To start your Phoenix server:

* Run `mix setup` to install and setup dependencies
* Start Phoenix endpoint with `mix phx.server` or inside IEx with `iex -S mix phx.server`

Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.

Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html).

## Learn more

* Official website: https://www.phoenixframework.org/
* Guides: https://hexdocs.pm/phoenix/overview.html
* Docs: https://hexdocs.pm/phoenix
* Forum: https://elixirforum.com/c/phoenix-forum
* Source: https://github.com/phoenixframework/phoenix
102 changes: 102 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* See the Tailwind configuration guide for advanced usage
https://tailwindcss.com/docs/configuration */

@import "tailwindcss" source(none);
@source "../css";
@source "../js";
@source "../../lib/kounia_web";

/* A Tailwind plugin that makes "hero-#{ICON}" classes available.
The heroicons installation itself is managed by your mix.exs */
@plugin "../vendor/heroicons";

/* daisyUI Tailwind Plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui.js
Make sure to look at the daisyUI changelog: https://daisyui.com/docs/changelog/ */
@plugin "../vendor/daisyui" {
themes: false;
}

/* daisyUI theme plugin. You can update this file by fetching the latest version with:
curl -sLO https://github.com/saadeghi/daisyui/releases/latest/download/daisyui-theme.js
We ship with two themes, a light one inspired on Phoenix colors and a dark one inspired
on Elixir colors. Build your own at: https://daisyui.com/theme-generator/ */
@plugin "../vendor/daisyui-theme" {
name: "dark";
default: false;
prefersdark: true;
color-scheme: "dark";
--color-base-100: oklch(30.33% 0.016 252.42);
--color-base-200: oklch(25.26% 0.014 253.1);
--color-base-300: oklch(20.15% 0.012 254.09);
--color-base-content: oklch(97.807% 0.029 256.847);
--color-primary: oklch(58% 0.233 277.117);
--color-primary-content: oklch(96% 0.018 272.314);
--color-secondary: oklch(58% 0.233 277.117);
--color-secondary-content: oklch(96% 0.018 272.314);
--color-accent: oklch(60% 0.25 292.717);
--color-accent-content: oklch(96% 0.016 293.756);
--color-neutral: oklch(37% 0.044 257.287);
--color-neutral-content: oklch(98% 0.003 247.858);
--color-info: oklch(58% 0.158 241.966);
--color-info-content: oklch(97% 0.013 236.62);
--color-success: oklch(60% 0.118 184.704);
--color-success-content: oklch(98% 0.014 180.72);
--color-warning: oklch(66% 0.179 58.318);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(58% 0.253 17.585);
--color-error-content: oklch(96% 0.015 12.422);
--radius-selector: 0.25rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.21875rem;
--size-field: 0.21875rem;
--border: 1.5px;
--depth: 1;
--noise: 0;
}

@plugin "../vendor/daisyui-theme" {
name: "light";
default: true;
prefersdark: false;
color-scheme: "light";
--color-base-100: oklch(98% 0 0);
--color-base-200: oklch(96% 0.001 286.375);
--color-base-300: oklch(92% 0.004 286.32);
--color-base-content: oklch(21% 0.006 285.885);
--color-primary: oklch(70% 0.213 47.604);
--color-primary-content: oklch(98% 0.016 73.684);
--color-secondary: oklch(55% 0.027 264.364);
--color-secondary-content: oklch(98% 0.002 247.839);
--color-accent: oklch(0% 0 0);
--color-accent-content: oklch(100% 0 0);
--color-neutral: oklch(44% 0.017 285.786);
--color-neutral-content: oklch(98% 0 0);
--color-info: oklch(62% 0.214 259.815);
--color-info-content: oklch(97% 0.014 254.604);
--color-success: oklch(70% 0.14 182.503);
--color-success-content: oklch(98% 0.014 180.72);
--color-warning: oklch(66% 0.179 58.318);
--color-warning-content: oklch(98% 0.022 95.277);
--color-error: oklch(58% 0.253 17.585);
--color-error-content: oklch(96% 0.015 12.422);
--radius-selector: 0.25rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.21875rem;
--size-field: 0.21875rem;
--border: 1.5px;
--depth: 1;
--noise: 0;
}

/* Add variants based on LiveView classes */
@custom-variant phx-click-loading (.phx-click-loading&, .phx-click-loading &);
@custom-variant phx-submit-loading (.phx-submit-loading&, .phx-submit-loading &);
@custom-variant phx-change-loading (.phx-change-loading&, .phx-change-loading &);

/* Make LiveView wrapper divs transparent for layout */
[data-phx-session] { display: contents }

/* This file is for your main application CSS */
Loading