Skip to content

Commit

Permalink
Simplify deployment, update styles
Browse files Browse the repository at this point in the history
  • Loading branch information
plutov committed Sep 13, 2024
1 parent b82f63a commit c6345b8
Show file tree
Hide file tree
Showing 19 changed files with 166 additions and 325 deletions.
32 changes: 0 additions & 32 deletions .dockerignore

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: 1.22
go-version: 1.23

- name: Check out code into the Go module directory
uses: actions/checkout@v4
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ ui/npm-debug.log*
ui/yarn-debug.log*
ui/yarn-error.log*
.DS_Store
.env
75 changes: 0 additions & 75 deletions Dockerfile

This file was deleted.

36 changes: 20 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ This approach offers a number of advantages, including:
- [x] Default theme
- [x] Custom themes support
- [x] Personalized options: intro, outro, etc.
- [x] Cookie/IP deduplication
- [x] Cookie/IP duplicate response protection
- [x] Admin user authentication
- [x] Different database options: SQLite and Postgres
- [x] Continue where you left off
- [x] Advanced validation rules
- [x] Detect survey changes in real time
- [x] Export responses in UI or via API
- [ ] Advanced question types
- [ ] Pipe answers into the following questions

Expand Down Expand Up @@ -249,37 +250,40 @@ Presents a question where users can only answer "yes" or "no".
label: Is Berlin the capital of Germany?
```

## Responses

Responses can be shown in the UI and exported as a JSON. Alternatively you can use REST API to get survey resposnes:

```bash
curl -XGET \
http://localhost:9900/app/surveys/{SURVEY_ID}/sessions?limit=100&offset=0&sort_by=created_at&order=desc
```

Where `{SURVEY_ID}` id the UUID of a given survey.

## Screenshots

<p align="center" width="100%">
<img src="https://github.com/plutov/formulosity/blob/main/screenshots/app.png" hspace="10" height="200px">
<img src="https://github.com/plutov/formulosity/blob/main/screenshots/survey.png" hspace="10" height="200px">
</p>

## Installation: Docker
## Installation & Deployment

```
docker-compose up -d --build
```
And you should be able to access the UI on http://localhost:3000 (default basic auth: `user:pass`).
## Deployment
You can deploy individual services to any cloud provider or self host them.
You can deploy individual services to any cloud provider:
- Go backend. It's packaged as a Docker container and can be deployed to any cloud provider.
- Next.js frontend. It's also packaged as a Docker container, but also can be deployed to Vercel or Netlify.
- Go backend. It's packaged as a Docker container and can be deployed anywhere.
- Next.js frontend. It's also packaged as a Docker container, but also can be deployed to Vercel for example.
- [Optional] Postgres database. You can use managed Postgres services or deploy it yourself.
The demo service (links above) is deployed to Fly.io (Go, SQLite) and Vercel (Next.js) and are under the free tiers.
There is also a combined version of Go and Next.js in the same Docker container. You can run it with:
```
docker-compose -f compose-combined.yml up -d --build
```
### Environment Variables
API:
Expand All @@ -291,14 +295,14 @@ API:
UI:
- `CONSOLE_API_ADDR_INTERNAL` - Internal address of the Go backend, e.g. `http://api:8080` (could be the same as `CONSOLE_API_ADDR` if UI amd API are not on the same network).
- `CONSOLE_API_ADDR` - Public address of the Go backend.
- `CONSOLE_API_ADDR` - Public address of the Go backend. Need to be accessible from the browser.
- `CONSOLE_API_ADDR_INTERNAL` - Internal address of the Go backend, e.g. `http://api:8080` (could be the same as `CONSOLE_API_ADDR`).
- `IRON_SESSION_SECRET` - Secret for session encryption
- `HTTP_BASIC_AUTH` - Format: `user:pass` for basic auth (optional)
## Tech Stack
- Backend: Go, Postgres, SQLite
- Backend: Go, (Postgres or SQLite)
- UI: Next.js, Tailwind CSS
## Create new SQLite/Postgres migration
Expand Down
2 changes: 1 addition & 1 deletion api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.22-alpine AS builder
FROM golang:1.23-alpine AS builder

RUN apk add build-base

Expand Down
2 changes: 1 addition & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/plutov/formulosity/api

go 1.22
go 1.23

require (
github.com/fsnotify/fsnotify v1.7.0
Expand Down
25 changes: 0 additions & 25 deletions compose-combined.yml

This file was deleted.

7 changes: 5 additions & 2 deletions ui/src/app/app/surveys/[survey_uuid]/responses/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ export default async function ResponsesPage({

const surveySessionsResp = await getSurveySessions(
currentSurvey.uuid,
`limit=${SurveySessionsLimit}&offset=0&sort_by=created_at&order=desc`
`limit=${SurveySessionsLimit}&offset=0&sort_by=created_at&order=desc`,
''
)
if (surveySessionsResp.error) {
errMsg = 'Unable to fetch survey sessions'
Expand All @@ -53,9 +54,11 @@ export default async function ResponsesPage({
)
}

const apiURL = process.env.CONSOLE_API_ADDR || ''

return (
<AppLayout>
<SurveyResponsesPage currentSurvey={currentSurvey} />
<SurveyResponsesPage currentSurvey={currentSurvey} apiURL={apiURL} />
</AppLayout>
)
}
9 changes: 2 additions & 7 deletions ui/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'styles/global.css'
import { ReactNode } from 'react'
import { Metadata } from 'next'
import { siteConfig } from 'lib/siteConfig'
import { dm_sans, inter } from 'lib/fonts'

export const metadata: Metadata = {
title: {
Expand Down Expand Up @@ -31,13 +30,9 @@ type LayoutProps = { children?: ReactNode }

export default async function RootLayout({ children }: LayoutProps) {
return (
<html
lang="en"
className={`${inter.variable} ${dm_sans.variable}`}
suppressHydrationWarning
>
<html lang="en" className="dark" suppressHydrationWarning>
<head />
<body className="bg-slate-1 font-sans text-slate-12">{children}</body>
<body className="bg-slate-1 text-slate-12">{children}</body>
</html>
)
}
37 changes: 6 additions & 31 deletions ui/src/components/app/AppLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use client'

import { ReactNode, useState } from 'react'
import { usePathname } from 'next/navigation'
import { Badge, Navbar, Sidebar } from 'flowbite-react'
import { LogoIcon } from 'components/ui/LogoIcon'
import { siteConfig } from 'lib/siteConfig'
import { HiViewGrid, HiMenu, HiOutlineBookOpen } from 'react-icons/hi'
import { HiMenu, HiOutlineBookOpen } from 'react-icons/hi'
import 'styles/app.css'

type AppLayoutProps = {
Expand All @@ -14,25 +13,16 @@ type AppLayoutProps = {

export default function AppLayout({ children }: AppLayoutProps) {
const [isSidebarOpen, setIsSidebarOpen] = useState(false)
const pathname = usePathname()

const navigation = [
{
name: 'Surveys',
href: `/app`,
icon: HiViewGrid,
},
]

return (
<main className="mb-auto flex-grow dark">
<Navbar
fluid
className="fixed w-full z-20 top-0 dark:bg-gray-950 border-b border-slate-6 px-5 sm:px-5"
className="fixed w-full z-20 top-0 bg-gray-950 border-b border-slate-6 px-5 sm:px-5"
>
<button
type="button"
className="inline-flex items-center p-2 text-sm text-gray-500 rounded-lg lg:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
className="inline-flex items-center p-2 text-sm rounded-lg lg:hidden focus:outline-none focus:ring-2 focus:ring-gray-200 text-gray-400 hover:bg-gray-700 dark:focus:ring-gray-600"
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
>
<HiMenu className="w-6 h-6" />
Expand All @@ -46,29 +36,14 @@ export default function AppLayout({ children }: AppLayoutProps) {
</Navbar>

<Sidebar
className={`sidebar fixed z-10 top-0 h-screen dark dark:bg-gray-800 ${
className={`sidebar fixed z-10 top-0 h-screen bg-gray-800 ${
isSidebarOpen ? '' : ' hidden lg:block'
}`}
>
<Sidebar.Items>
<Sidebar.ItemGroup>
{navigation.map((item) => (
<Sidebar.Item
key={item.name}
href={item.href}
icon={item.icon}
className={
pathname && pathname.startsWith(item.href)
? 'bg-gray-700'
: ''
}
>
{item.name}
</Sidebar.Item>
))}
</Sidebar.ItemGroup>
<Sidebar.ItemGroup>
<Sidebar.Item
className="bg-gray-100 hover:bg-gray-400"
href="https://github.com/plutov/formulosity"
icon={HiOutlineBookOpen}
>
Expand All @@ -80,7 +55,7 @@ export default function AppLayout({ children }: AppLayoutProps) {
<div className="mb-3 flex items-center">
<Badge color="warning">Beta</Badge>
</div>
<div className="mb-3 text-sm text-cyan-900 dark:text-gray-400">
<div className="mb-3 text-sm text-gray-400">
<p>{siteConfig.name} is currently in beta.</p>
</div>
</Sidebar.CTA>
Expand Down
Loading

0 comments on commit c6345b8

Please sign in to comment.