Store timestamps as strings in the database to fix errors with postgres. Reviewed-on: #1 Co-authored-by: Michael Housh <michael@mhoush.com> Co-committed-by: Michael Housh <michael@mhoush.com>
This commit was merged in pull request #1.
This commit is contained in:
@@ -9,7 +9,8 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: git.housh.dev
|
REGISTRY: git.housh.dev
|
||||||
IMAGE_NAME: ductcalc
|
USERNAME: michael
|
||||||
|
IMAGE_NAME: ${{ gitea.repository }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push-image:
|
build-and-push-image:
|
||||||
@@ -56,5 +57,5 @@ jobs:
|
|||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:build
|
cache-from: type=registry,ref=${{ env.IMAGE_NAME }}:build
|
||||||
cache-to: mode=max,image-manifest=true,oci-mediatypes=true,type=registry,ref=${{ env.IMAGE_NAME }}:build
|
cache-to: mode=min,image-manifest=true,oci-mediatypes=true,type=inline,ref=${{ env.IMAGE_NAME }}:build
|
||||||
|
|
||||||
|
|||||||
11
.github/workflows/release.yaml
vendored
11
.github/workflows/release.yaml
vendored
@@ -9,7 +9,8 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
IMAGE_NAME: ductcalc
|
IMAGE_NAME: ${{ github.repository }}
|
||||||
|
USERNAME: m-housh
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push-image:
|
build-and-push-image:
|
||||||
@@ -27,7 +28,7 @@ jobs:
|
|||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ${{ env.REGISTRY }}
|
registry: ${{ env.REGISTRY }}
|
||||||
username: ${{ github.repository_owner }}
|
username: ${{ env.USERNAME }}
|
||||||
password: ${{ secrets.CONTAINER_TOKEN }}
|
password: ${{ secrets.CONTAINER_TOKEN }}
|
||||||
|
|
||||||
- name: Set up Docker
|
- name: Set up Docker
|
||||||
@@ -48,7 +49,7 @@ jobs:
|
|||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.USERNAME }}/${{ env.IMAGE_NAME }}
|
||||||
tags: |
|
tags: |
|
||||||
type=ref,event=branch
|
type=ref,event=branch
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
@@ -67,6 +68,6 @@ jobs:
|
|||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=registry,ref=${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:buildcache
|
cache-from: type=registry,ref=${{ env.USERNAME }}/${{ env.IMAGE_NAME }}:buildcache
|
||||||
cache-to: type=registry,ref=${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
|
cache-to: mode=max,image-manifest=true,oci-mediatypes=true,type=registry,ref=${{ env.USERNAME }}/${{ env.IMAGE_NAME }}:build
|
||||||
|
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ extension ComponentPressureLoss {
|
|||||||
.id()
|
.id()
|
||||||
.field("name", .string, .required)
|
.field("name", .string, .required)
|
||||||
.field("value", .double, .required)
|
.field("value", .double, .required)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.field(
|
.field(
|
||||||
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ extension EquipmentInfo {
|
|||||||
.field("staticPressure", .double, .required)
|
.field("staticPressure", .double, .required)
|
||||||
.field("heatingCFM", .int16, .required)
|
.field("heatingCFM", .int16, .required)
|
||||||
.field("coolingCFM", .int16, .required)
|
.field("coolingCFM", .int16, .required)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.field(
|
.field(
|
||||||
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ extension EquivalentLength {
|
|||||||
.field("type", .string, .required)
|
.field("type", .string, .required)
|
||||||
.field("straightLengths", .array(of: .int))
|
.field("straightLengths", .array(of: .int))
|
||||||
.field("groups", .data)
|
.field("groups", .data)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.field(
|
.field(
|
||||||
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ extension DatabaseClient.Migrations: DependencyKey {
|
|||||||
public static let liveValue = Self(
|
public static let liveValue = Self(
|
||||||
all: {
|
all: {
|
||||||
[
|
[
|
||||||
Project.Migrate(),
|
|
||||||
User.Migrate(),
|
User.Migrate(),
|
||||||
User.Token.Migrate(),
|
User.Token.Migrate(),
|
||||||
User.Profile.Migrate(),
|
User.Profile.Migrate(),
|
||||||
|
Project.Migrate(),
|
||||||
ComponentPressureLoss.Migrate(),
|
ComponentPressureLoss.Migrate(),
|
||||||
EquipmentInfo.Migrate(),
|
EquipmentInfo.Migrate(),
|
||||||
Room.Migrate(),
|
Room.Migrate(),
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ extension Project {
|
|||||||
.field("state", .string, .required)
|
.field("state", .string, .required)
|
||||||
.field("zipCode", .string, .required)
|
.field("zipCode", .string, .required)
|
||||||
.field("sensibleHeatRatio", .double)
|
.field("sensibleHeatRatio", .double)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.field("userID", .uuid, .required, .references(UserModel.schema, "id", onDelete: .cascade))
|
.field("userID", .uuid, .required, .references(UserModel.schema, "id", onDelete: .cascade))
|
||||||
.unique(on: "userID", "name")
|
.unique(on: "userID", "name")
|
||||||
.create()
|
.create()
|
||||||
|
|||||||
@@ -197,8 +197,8 @@ extension Room {
|
|||||||
.field("registerCount", .int8, .required)
|
.field("registerCount", .int8, .required)
|
||||||
.field("delegatedToID", .uuid, .references(RoomModel.schema, "id"))
|
.field("delegatedToID", .uuid, .references(RoomModel.schema, "id"))
|
||||||
.field("rectangularSizes", .array)
|
.field("rectangularSizes", .array)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.field(
|
.field(
|
||||||
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
"projectID", .uuid, .required, .references(ProjectModel.schema, "id", onDelete: .cascade)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ extension User.Profile {
|
|||||||
.field("zipCode", .string, .required)
|
.field("zipCode", .string, .required)
|
||||||
.field("theme", .string)
|
.field("theme", .string)
|
||||||
.field("userID", .uuid, .references(UserModel.schema, "id", onDelete: .cascade))
|
.field("userID", .uuid, .references(UserModel.schema, "id", onDelete: .cascade))
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.unique(on: "userID")
|
.unique(on: "userID")
|
||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ extension User {
|
|||||||
.id()
|
.id()
|
||||||
.field("email", .string, .required)
|
.field("email", .string, .required)
|
||||||
.field("password_hash", .string, .required)
|
.field("password_hash", .string, .required)
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.unique(on: "email")
|
.unique(on: "email")
|
||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
@@ -97,8 +97,8 @@ extension User.Token {
|
|||||||
.id()
|
.id()
|
||||||
.field("value", .string, .required)
|
.field("value", .string, .required)
|
||||||
.field("user_id", .uuid, .required, .references(UserModel.schema, "id"))
|
.field("user_id", .uuid, .required, .references(UserModel.schema, "id"))
|
||||||
.field("createdAt", .datetime)
|
.field("createdAt", .string)
|
||||||
.field("updatedAt", .datetime)
|
.field("updatedAt", .string)
|
||||||
.unique(on: "value")
|
.unique(on: "value")
|
||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ struct HomeView: HTML, Sendable {
|
|||||||
.class("btn btn-xl btn-primary mt-6"),
|
.class("btn btn-xl btn-primary mt-6"),
|
||||||
.hx.get(route: .signup(.index)),
|
.hx.get(route: .signup(.index)),
|
||||||
.hx.target("body"),
|
.hx.target("body"),
|
||||||
.hx.swap(.outerHTML)
|
.hx.swap(.outerHTML),
|
||||||
|
.hx.pushURL(true)
|
||||||
) {
|
) {
|
||||||
"Get Started"
|
"Get Started"
|
||||||
}
|
}
|
||||||
|
|||||||
1
TODO.md
1
TODO.md
@@ -23,3 +23,4 @@
|
|||||||
- [x] Privacy policy
|
- [x] Privacy policy
|
||||||
- [ ] Update README
|
- [ ] Update README
|
||||||
- [ ] Self hosting documentation
|
- [ ] Self hosting documentation
|
||||||
|
- [x] Check signup flow when using 'get-started' button from home page, it may need a push url.
|
||||||
|
|||||||
31
docker-compose.yaml
Normal file
31
docker-compose.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: docker.io/postgres:18
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- ./data:/var/lib/postgresql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ductcalc"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
|
context: .
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
- POSTGRES_HOSTNAME=db
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: healthy
|
||||||
|
ports:
|
||||||
|
- 8081:8080
|
||||||
|
healthcheck:
|
||||||
|
test: curl --fail --silent http://0.0.0.0:8080/health || exit 1
|
||||||
|
interval: 1m
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
db:
|
db:
|
||||||
image: docker.io/postgres:18
|
image: docker.io/postgres:18
|
||||||
@@ -8,7 +7,9 @@ services:
|
|||||||
- ./data:/var/lib/postgresql
|
- ./data:/var/lib/postgresql
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: ghcr.io/m-housh/ductcalc:latest
|
build:
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
|
context: .
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: .env
|
env_file: .env
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
Reference in New Issue
Block a user