diff --git a/.github/workflows/deploy-backend.yml b/.github/workflows/deploy-backend.yml new file mode 100644 index 0000000..5ea6656 --- /dev/null +++ b/.github/workflows/deploy-backend.yml @@ -0,0 +1,19 @@ +name: deploy-backend + +on: + push: + branches: [ "main" ] + +steps: + - uses: actions/checkout@v3 + name: Check out code + + - uses: mr-smithers-excellent/docker-build-push@v6 + name: Build & push Docker image + with: + image: cess-advisor-backend + tags: latest + registry: ghcr.io + dockerfile: Dockerfile + username: ${{ secrets.GHCR_USERNAME }} + password: ${{ secrets.GHCR_TOKEN }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index be83a3a..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: deploy - -on: - push: - branches: [ "main" ] - -jobs: - deploy: - name: Deploy - runs-on: ubuntu-latest - steps: - - name: executing remote ssh commands - uses: appleboy/ssh-action@v1.0.3 - with: - command_timeout: 30m - host: ${{ secrets.HOST }} - username: ${{ secrets.USERNAME }} - port: ${{ secrets.PORT }} - key: ${{ secrets.KEY }} - script: ${{ secrets.SCRIPT }} diff --git a/.gitignore b/.gitignore index 30b98b3..d0b4476 100644 --- a/.gitignore +++ b/.gitignore @@ -14,5 +14,6 @@ package .env .env.* !.env.example +!.env.template vite.config.js.timestamp-* vite.config.ts.timestamp-* diff --git a/README.md b/README.md index 6bb43d3..0a18128 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,9 @@ **Cess Advisor** 🐪🚽 is a _stupid_ yet really _useful_ web app that helps you find a _suitable toilet_ when you are in a hurry. - ## Tech stack -In short: **OCaml** 🐪 (Sihl) + **JavaScript** 🤢 (Svelte) + **PostgreSQL** 🐘 + Docker 🐳 + GitHub Actions 🚀 +TL;DR: **OCaml** 🐪 (Sihl) + **JavaScript** 🤢 (Svelte) + **PostgreSQL** 🐘 > [!TIP] > If you want to preserve your mental health, you should **NOT** write JavaScript code _(and frontends in general)_. OCaml is just better. @@ -17,25 +16,47 @@ In short: **OCaml** 🐪 (Sihl) + **JavaScript** 🤢 (Svelte) + **PostgreSQL** - Backend: **OCaml** 🐪 - [Sihl](https://github.com/oxidizing/sihl): OCaml framework for building web apps - - [Opium](https://github.com/rgrinberg/opium/): OCaml framework for managing HTTP requests + - [Opium](https://github.com/rgrinberg/opium/): OCaml library for managing HTTP requests - [Caqti](https://github.com/paurkedal/ocaml-caqti): OCaml library for interacting with databases - [Yojson](https://github.com/ocaml-community/yojson): OCaml library for JSON serialization - [Validate](https://github.com/Axot017/validate): OCaml library for validating schemas -- Frontend: **JavaScript** ⚛️ - - [Sveltekit](https://kit.svelte.dev/): JavaScript framework for frontend web development +- Frontend: **JavaScript** 🤢 + - [Sveltekit](https://kit.svelte.dev/): JavaScript framework for web development - [Tailwind CSS](https://tailwindcss.com/): CSS framework - [DaisyUI](https://daisyui.com/): Tailwind components library - Database: 🐘 - [PostgreSQL](https://www.postgresql.org/): relational database -- Deployment: 🐳 - - [Docker](https://www.docker.com/): containerization - - [GitHub Actions](https://docs.github.com/en/actions): CI/CD + + +## Deployment + +TL;DR: **Docker** 🐳 + **GitHub Actions** 🤖 for backend and **Cloudflare Pages** ☁️ for frontend + +
+Detailed deployment + +- Backend: **Docker** 🐳 + **GitHub Actions** 🤖 + - each time a commit is pushed to the `main` branch, `deploy` GitHub action is triggered + - the action builds the Docker image and pushes it to the GitHub container registry + - the image is then pulled by my homelab server (periodically checked with Watchtower) and the container is started + - the backend is available at [https://cessadvisorapi.favo02.dev](https://cessadvisorapi.favo02.dev) + +- **Frontend**: **Cloudflare Pages** ☁️ + - each time a commit is pushed to the `main` branch, the Cloudflare pages integration detects the change + - the integration builds the Sveltekit app with some magic + - the frontend is available at [https://cessadvisor.pages.dev](https://cessadvisor.pages.dev) (and [https://cessadvisor.favo02.dev](https://cessadvisor.favo02.dev))
+## Contributing + +Each contribution is **welcome**, especially building alteranive better frontends _(if you are brave enough to write JavaScript code)_ that uses the same API. + +Please follow the [conventions](#conventions) below. + ## Conventions
diff --git a/backend/backend.opam b/backend/backend.opam index 269a655..8af5365 100644 --- a/backend/backend.opam +++ b/backend/backend.opam @@ -10,13 +10,13 @@ doc: "https://github.com/Favo02/cess-advisor" bug-reports: "https://github.com/Favo02/cess-advisor/issues" depends: [ "ocaml" {>= "5.0.0"} - "dune" {>= "3.10" & >= "3.15.0"} - "sihl" {>= "3.0.5"} - "caqti-driver-postgresql" {>= "2.1.1"} - "lwt_ppx" {>= "2.1.0"} - "ppx_yojson_conv" {>= "v0.16.0"} - "validate" {>= "1.1.0"} - "safepass" {>= "3.0"} + "dune" {>= "3.10"} + "sihl" + "caqti-driver-postgresql" + "lwt_ppx" + "ppx_yojson_conv" + "validate" + "safepass" "odoc" {with-doc} ] build: [ diff --git a/backend/dune-project b/backend/dune-project index abbc1ec..26ba5f8 100644 --- a/backend/dune-project +++ b/backend/dune-project @@ -21,10 +21,10 @@ (description "REST API for Cess Advisor, a toilet review system") (depends (ocaml (>= 5.0.0)) - (dune (>= 3.15.0)) - (sihl (>= 3.0.5)) - (caqti-driver-postgresql (>= 2.1.1)) - (lwt_ppx (>= 2.1.0)) - (ppx_yojson_conv (>= v0.16.0)) - (validate (>= 1.1.0)) - (safepass (>= 3.0)))) + dune + sihl + caqti-driver-postgresql + lwt_ppx + ppx_yojson_conv + validate + safepass)) diff --git a/backend/src/main.ml b/backend/src/main.ml index 8325c32..a9c477c 100644 --- a/backend/src/main.ml +++ b/backend/src/main.ml @@ -27,7 +27,7 @@ let auth = Web.choose ~scope: "/api" ~middlewares: [ require_login; verify_expir Web.post "/reviews/create" Handlers.Reviews.create; ] -let router = Web.choose ~middlewares: [ logger; ] [ +let router = Web.choose ~middlewares: [ logger; Opium.Middleware.allow_cors (); ] [ public; no_auth; auth; diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 4b7e7e5..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -version: '3' - -services: - - backend: - container_name: cess-advisor-backend - restart: unless-stopped - build: - context: . - volumes: - - './logs:/app/logs' - ports: - - 3057:3000 diff --git a/frontend/.env.template b/frontend/.env.template new file mode 100644 index 0000000..4c78f38 --- /dev/null +++ b/frontend/.env.template @@ -0,0 +1,7 @@ +# template for .env file + +# production (the default URL is already set) +VITE_API_URL=https://cessadvisorapi.favo02.dev + +# development +# VITE_API_URL=http://localhost:3000 diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index ca60e35..f5bb561 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -11,7 +11,7 @@ onMount(async () => { try { - const response = await axios.get("/api/stats"); + const response = await axios.get(`${import.meta.env.VITE_API_URL}/api/stats`); users_count = response.data.users; toilets_count = response.data.toilets; reviews_count = response.data.reviews; diff --git a/frontend/src/routes/login/+page.svelte b/frontend/src/routes/login/+page.svelte index bc489c2..779549e 100644 --- a/frontend/src/routes/login/+page.svelte +++ b/frontend/src/routes/login/+page.svelte @@ -9,7 +9,7 @@ try { loading = true; - const response = await axios.post("/api/login", { username, password }); + const response = await axios.post(`${import.meta.env.VITE_API_URL}/api/login`, { username, password }); if (response.status === 200) { alert("Login successful"); diff --git a/frontend/src/routes/logout/+page.svelte b/frontend/src/routes/logout/+page.svelte index 369be6a..528e472 100644 --- a/frontend/src/routes/logout/+page.svelte +++ b/frontend/src/routes/logout/+page.svelte @@ -7,7 +7,7 @@ try { loading = true; - const response = await axios.post("/api/logout"); + const response = await axios.post(`${import.meta.env.VITE_API_URL}/api/logout`); if (response.status === 200) { alert("Logout successful"); diff --git a/frontend/src/routes/profile/+page.svelte b/frontend/src/routes/profile/+page.svelte index d161e45..bbfa813 100644 --- a/frontend/src/routes/profile/+page.svelte +++ b/frontend/src/routes/profile/+page.svelte @@ -1,7 +1,7 @@

Profile

diff --git a/frontend/vite.config.js b/frontend/vite.config.js index c3711ae..bbf8c7d 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -2,10 +2,5 @@ import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; export default defineConfig({ - plugins: [sveltekit()], - server: { - proxy: { - '/api': 'http://localhost:3000' - } - } + plugins: [sveltekit()] });