generated from coulomb/repo-seed
feat: minimal IHP scaffold — T01-T05, T08 of IRP-WP-0001
- flake.nix adapted from inter-hub: appName=ihp-railiance-probe, stripped to core packages, GHC 9.10.3 Bug 1+2 overlays carried verbatim (pname check updated to ihp-railiance-probe-models) - IHP project scaffold: Main.hs, Config.hs, App.cabal, Setup.hs, Makefile - Schema: probes table (id, name, created_at) - Health endpoint: GET /healthz → "ok" (HealthController) - Probes CRUD: ProbesController + 4 views (Index, New, Show, Edit) - Hspec test suite: Test/ProbeControllerSpec covers /probes and /healthz - Helm chart in chart/: deployment, service, ingress, secret templates - devenv.nix, devenv.yaml, .ghci, tailwind config Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
7
.ghci
Normal file
7
.ghci
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
:set -XNoImplicitPrelude
|
||||||
|
:def loadFromIHP \file -> (System.Environment.getEnv "IHP_LIB") >>= (\ihpLib -> readFile (ihpLib <> "/" <> file))
|
||||||
|
:loadFromIHP applicationGhciConfig
|
||||||
|
:set -j1
|
||||||
|
:set -fkeep-going
|
||||||
|
:set -fwrite-interface
|
||||||
|
import IHP.Prelude
|
||||||
57
App.cabal
Normal file
57
App.cabal
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
-- Stub cabal file — only for HLS/tooling support. Not used by the build.
|
||||||
|
-- See flake.nix for actual package management.
|
||||||
|
name: App
|
||||||
|
version: 0.1.0.0
|
||||||
|
license: AllRightsReserved
|
||||||
|
license-file: LICENSE
|
||||||
|
author: Developers
|
||||||
|
maintainer: developers@example.com
|
||||||
|
build-type: Simple
|
||||||
|
cabal-version: >=1.10
|
||||||
|
|
||||||
|
executable App
|
||||||
|
main-is: Main.hs
|
||||||
|
build-depends:
|
||||||
|
ihp,
|
||||||
|
base,
|
||||||
|
wai,
|
||||||
|
text,
|
||||||
|
hspec,
|
||||||
|
ihp-hspec
|
||||||
|
hs-source-dirs: .
|
||||||
|
default-language: Haskell2010
|
||||||
|
extensions:
|
||||||
|
OverloadedStrings
|
||||||
|
, NoImplicitPrelude
|
||||||
|
, ImplicitParams
|
||||||
|
, Rank2Types
|
||||||
|
, DisambiguateRecordFields
|
||||||
|
, NamedFieldPuns
|
||||||
|
, DuplicateRecordFields
|
||||||
|
, OverloadedLabels
|
||||||
|
, FlexibleContexts
|
||||||
|
, TypeSynonymInstances
|
||||||
|
, FlexibleInstances
|
||||||
|
, QuasiQuotes
|
||||||
|
, TypeFamilies
|
||||||
|
, PackageImports
|
||||||
|
, ScopedTypeVariables
|
||||||
|
, RecordWildCards
|
||||||
|
, TypeApplications
|
||||||
|
, DataKinds
|
||||||
|
, InstanceSigs
|
||||||
|
, DeriveGeneric
|
||||||
|
, MultiParamTypeClasses
|
||||||
|
, TypeOperators
|
||||||
|
, DeriveDataTypeable
|
||||||
|
, MultiWayIf
|
||||||
|
, UndecidableInstances
|
||||||
|
, BlockArguments
|
||||||
|
, PartialTypeSignatures
|
||||||
|
, LambdaCase
|
||||||
|
, DefaultSignatures
|
||||||
|
, EmptyDataDeriving
|
||||||
|
, BangPatterns
|
||||||
|
, FunctionalDependencies
|
||||||
|
, StandaloneDeriving
|
||||||
|
, DerivingVia
|
||||||
1
Application/Fixtures.sql
Normal file
1
Application/Fixtures.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-- No fixtures for probe.
|
||||||
7
Application/Schema.sql
Normal file
7
Application/Schema.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
|
CREATE TABLE probes (
|
||||||
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
9
Config/Config.hs
Normal file
9
Config/Config.hs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module Config where
|
||||||
|
|
||||||
|
import IHP.Prelude
|
||||||
|
import IHP.Environment
|
||||||
|
import IHP.FrameworkConfig
|
||||||
|
|
||||||
|
config :: ConfigBuilder
|
||||||
|
config = do
|
||||||
|
pure ()
|
||||||
21
Main.hs
Normal file
21
Main.hs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module Main where
|
||||||
|
import IHP.Prelude
|
||||||
|
|
||||||
|
import Config
|
||||||
|
import qualified IHP.Server
|
||||||
|
import IHP.RouterSupport
|
||||||
|
import IHP.FrameworkConfig
|
||||||
|
import IHP.Job.Types
|
||||||
|
import Web.FrontController
|
||||||
|
import Web.Types
|
||||||
|
|
||||||
|
instance FrontController RootApplication where
|
||||||
|
controllers =
|
||||||
|
[ mountFrontController WebApplication
|
||||||
|
]
|
||||||
|
|
||||||
|
instance Worker RootApplication where
|
||||||
|
workers _ = []
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = IHP.Server.run config
|
||||||
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
CSS_FILES += ${IHP}/static/vendor/bootstrap.min.css
|
||||||
|
CSS_FILES += ${IHP}/static/vendor/flatpickr.min.css
|
||||||
|
CSS_FILES += static/app.css
|
||||||
|
|
||||||
|
JS_FILES += ${IHP}/static/vendor/jquery-3.6.0.slim.min.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/timeago.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/popper.min.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/bootstrap.min.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/flatpickr.js
|
||||||
|
JS_FILES += ${IHP}/static/helpers.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/morphdom-umd.min.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/turbolinks.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/turbolinksInstantClick.js
|
||||||
|
JS_FILES += ${IHP}/static/vendor/turbolinksMorphdom.js
|
||||||
|
|
||||||
|
include ${IHP}/Makefile.dist
|
||||||
4
PIPELINE_LOG.md
Normal file
4
PIPELINE_LOG.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Pipeline Validation Log
|
||||||
|
|
||||||
|
| Date | SHA | Build | Push | Deploy | Smoke |
|
||||||
|
|------|-----|-------|------|--------|-------|
|
||||||
13
Test/Main.hs
Normal file
13
Test/Main.hs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module Main where
|
||||||
|
|
||||||
|
import Test.Hspec
|
||||||
|
import IHP.Prelude
|
||||||
|
import qualified Test.ProbeControllerSpec as ProbeController
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = hspec do
|
||||||
|
describe "Sanity" do
|
||||||
|
it "1 + 1 = 2" do
|
||||||
|
1 + 1 `shouldBe` (2 :: Int)
|
||||||
|
|
||||||
|
ProbeController.spec
|
||||||
14
Test/ProbeControllerSpec.hs
Normal file
14
Test/ProbeControllerSpec.hs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module Test.ProbeControllerSpec where
|
||||||
|
|
||||||
|
import Test.Hspec
|
||||||
|
import IHP.HSpec
|
||||||
|
|
||||||
|
spec :: Spec
|
||||||
|
spec = describe "ProbeController" do
|
||||||
|
it "GET /probes returns 200" do
|
||||||
|
response <- get "/probes"
|
||||||
|
response `shouldRespondWith` 200
|
||||||
|
|
||||||
|
it "GET /healthz returns 200" do
|
||||||
|
response <- get "/healthz"
|
||||||
|
response `shouldRespondWith` 200
|
||||||
7
Web/Controller/Health.hs
Normal file
7
Web/Controller/Health.hs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module Web.Controller.Health where
|
||||||
|
|
||||||
|
import Web.Controller.Prelude
|
||||||
|
import Web.Types
|
||||||
|
|
||||||
|
instance Controller HealthController where
|
||||||
|
action HealthAction = renderPlain "ok"
|
||||||
12
Web/Controller/Prelude.hs
Normal file
12
Web/Controller/Prelude.hs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
module Web.Controller.Prelude
|
||||||
|
( module Web.Types
|
||||||
|
, module Generated.Types
|
||||||
|
, module IHP.Prelude
|
||||||
|
, module IHP.ControllerPrelude
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Web.Types
|
||||||
|
import Generated.Types
|
||||||
|
import IHP.Prelude
|
||||||
|
import IHP.ControllerPrelude
|
||||||
|
import Web.Routes ()
|
||||||
42
Web/Controller/Probes.hs
Normal file
42
Web/Controller/Probes.hs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
module Web.Controller.Probes where
|
||||||
|
|
||||||
|
import Web.Controller.Prelude
|
||||||
|
import Web.View.Probes.Index
|
||||||
|
import Web.View.Probes.New
|
||||||
|
import Web.View.Probes.Show
|
||||||
|
import Web.View.Probes.Edit
|
||||||
|
|
||||||
|
instance Controller ProbesController where
|
||||||
|
action ProbesAction = do
|
||||||
|
probes <- query @Probe |> fetch
|
||||||
|
render IndexView { .. }
|
||||||
|
|
||||||
|
action NewProbeAction = do
|
||||||
|
let probe = newRecord @Probe
|
||||||
|
render NewView { .. }
|
||||||
|
|
||||||
|
action ShowProbeAction { probeId } = do
|
||||||
|
probe <- fetch probeId
|
||||||
|
render ShowView { .. }
|
||||||
|
|
||||||
|
action CreateProbeAction = do
|
||||||
|
newRecord @Probe
|
||||||
|
|> fill @'["name"]
|
||||||
|
|> createRecord
|
||||||
|
redirectTo ProbesAction
|
||||||
|
|
||||||
|
action EditProbeAction { probeId } = do
|
||||||
|
probe <- fetch probeId
|
||||||
|
render EditView { .. }
|
||||||
|
|
||||||
|
action UpdateProbeAction { probeId } = do
|
||||||
|
probe <- fetch probeId
|
||||||
|
probe
|
||||||
|
|> fill @'["name"]
|
||||||
|
|> updateRecord
|
||||||
|
redirectTo ProbesAction
|
||||||
|
|
||||||
|
action DeleteProbeAction { probeId } = do
|
||||||
|
probe <- fetch probeId
|
||||||
|
deleteRecord probe
|
||||||
|
redirectTo ProbesAction
|
||||||
36
Web/FrontController.hs
Normal file
36
Web/FrontController.hs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
module Web.FrontController where
|
||||||
|
|
||||||
|
import IHP.RouterPrelude
|
||||||
|
import IHP.ControllerPrelude
|
||||||
|
import IHP.ViewPrelude (Html, hsx, Layout)
|
||||||
|
import Generated.Types
|
||||||
|
import Web.Types
|
||||||
|
import Web.Routes ()
|
||||||
|
|
||||||
|
import Web.Controller.Health ()
|
||||||
|
import Web.Controller.Probes ()
|
||||||
|
|
||||||
|
instance FrontController WebApplication where
|
||||||
|
controllers =
|
||||||
|
[ parseRoute @HealthController
|
||||||
|
, parseRoute @ProbesController
|
||||||
|
]
|
||||||
|
|
||||||
|
instance InitControllerContext WebApplication where
|
||||||
|
initContext = do
|
||||||
|
setLayout defaultLayout
|
||||||
|
|
||||||
|
defaultLayout :: (?context :: ControllerContext, ?request :: Request) => Layout
|
||||||
|
defaultLayout inner = [hsx|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>ihp-railiance-probe</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{inner}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|]
|
||||||
16
Web/Routes.hs
Normal file
16
Web/Routes.hs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module Web.Routes where
|
||||||
|
|
||||||
|
import IHP.RouterPrelude
|
||||||
|
import Generated.Types
|
||||||
|
import Web.Types
|
||||||
|
|
||||||
|
instance CanRoute HealthController where
|
||||||
|
parseRoute' = do
|
||||||
|
pathPrefix "/healthz"
|
||||||
|
endOfInput
|
||||||
|
pure HealthAction
|
||||||
|
|
||||||
|
instance HasPath HealthController where
|
||||||
|
pathTo HealthAction = "/healthz"
|
||||||
|
|
||||||
|
instance AutoRoute ProbesController
|
||||||
21
Web/Types.hs
Normal file
21
Web/Types.hs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module Web.Types where
|
||||||
|
|
||||||
|
import IHP.Prelude
|
||||||
|
import IHP.ModelSupport
|
||||||
|
import Generated.Types
|
||||||
|
|
||||||
|
data WebApplication = WebApplication deriving (Eq, Show)
|
||||||
|
|
||||||
|
data HealthController
|
||||||
|
= HealthAction
|
||||||
|
deriving (Eq, Show, Data)
|
||||||
|
|
||||||
|
data ProbesController
|
||||||
|
= ProbesAction
|
||||||
|
| NewProbeAction
|
||||||
|
| ShowProbeAction { probeId :: !(Id Probe) }
|
||||||
|
| CreateProbeAction
|
||||||
|
| EditProbeAction { probeId :: !(Id Probe) }
|
||||||
|
| UpdateProbeAction { probeId :: !(Id Probe) }
|
||||||
|
| DeleteProbeAction { probeId :: !(Id Probe) }
|
||||||
|
deriving (Eq, Show, Data)
|
||||||
12
Web/View/Prelude.hs
Normal file
12
Web/View/Prelude.hs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
module Web.View.Prelude
|
||||||
|
( module Web.Types
|
||||||
|
, module Generated.Types
|
||||||
|
, module IHP.Prelude
|
||||||
|
, module IHP.ViewPrelude
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Web.Types
|
||||||
|
import Generated.Types
|
||||||
|
import IHP.Prelude
|
||||||
|
import IHP.ViewPrelude
|
||||||
|
import Web.Routes ()
|
||||||
17
Web/View/Probes/Edit.hs
Normal file
17
Web/View/Probes/Edit.hs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module Web.View.Probes.Edit where
|
||||||
|
|
||||||
|
import Web.View.Prelude
|
||||||
|
|
||||||
|
data EditView = EditView { probe :: Probe }
|
||||||
|
|
||||||
|
instance View EditView where
|
||||||
|
html EditView { .. } = [hsx|
|
||||||
|
<h1>Edit Probe</h1>
|
||||||
|
{renderForm probe}
|
||||||
|
|]
|
||||||
|
|
||||||
|
renderForm :: Probe -> Html
|
||||||
|
renderForm probe = formFor probe [hsx|
|
||||||
|
{textField #name}
|
||||||
|
{submitButton}
|
||||||
|
|]
|
||||||
22
Web/View/Probes/Index.hs
Normal file
22
Web/View/Probes/Index.hs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
module Web.View.Probes.Index where
|
||||||
|
|
||||||
|
import Web.View.Prelude
|
||||||
|
|
||||||
|
data IndexView = IndexView { probes :: [Probe] }
|
||||||
|
|
||||||
|
instance View IndexView where
|
||||||
|
html IndexView { .. } = [hsx|
|
||||||
|
<h1>Probes</h1>
|
||||||
|
<a href={NewProbeAction}>New Probe</a>
|
||||||
|
<ul>
|
||||||
|
{forEach probes renderProbe}
|
||||||
|
</ul>
|
||||||
|
|]
|
||||||
|
|
||||||
|
renderProbe :: Probe -> Html
|
||||||
|
renderProbe probe = [hsx|
|
||||||
|
<li>
|
||||||
|
<a href={ShowProbeAction probe.id}>{probe.name}</a>
|
||||||
|
<a href={DeleteProbeAction probe.id} class="js-delete">Delete</a>
|
||||||
|
</li>
|
||||||
|
|]
|
||||||
17
Web/View/Probes/New.hs
Normal file
17
Web/View/Probes/New.hs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module Web.View.Probes.New where
|
||||||
|
|
||||||
|
import Web.View.Prelude
|
||||||
|
|
||||||
|
data NewView = NewView { probe :: Probe }
|
||||||
|
|
||||||
|
instance View NewView where
|
||||||
|
html NewView { .. } = [hsx|
|
||||||
|
<h1>New Probe</h1>
|
||||||
|
{renderForm probe}
|
||||||
|
|]
|
||||||
|
|
||||||
|
renderForm :: Probe -> Html
|
||||||
|
renderForm probe = formFor probe [hsx|
|
||||||
|
{textField #name}
|
||||||
|
{submitButton}
|
||||||
|
|]
|
||||||
11
Web/View/Probes/Show.hs
Normal file
11
Web/View/Probes/Show.hs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module Web.View.Probes.Show where
|
||||||
|
|
||||||
|
import Web.View.Prelude
|
||||||
|
|
||||||
|
data ShowView = ShowView { probe :: Probe }
|
||||||
|
|
||||||
|
instance View ShowView where
|
||||||
|
html ShowView { .. } = [hsx|
|
||||||
|
<h1>{probe.name}</h1>
|
||||||
|
<a href={ProbesAction}>Back</a>
|
||||||
|
|]
|
||||||
6
chart/Chart.yaml
Normal file
6
chart/Chart.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: ihp-railiance-probe
|
||||||
|
description: Minimal IHP probe app for Railiance01 pipeline validation
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "0.1.0"
|
||||||
38
chart/templates/deployment.yaml
Normal file
38
chart/templates/deployment.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}
|
||||||
|
labels:
|
||||||
|
app: {{ .Release.Name }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: {{ .Release.Name }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: {{ .Release.Name }}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: {{ .Release.Name }}
|
||||||
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: {{ .Values.secretName }}
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: {{ .Values.resources.limits.memory }}
|
||||||
|
cpu: {{ .Values.resources.limits.cpu }}
|
||||||
|
requests:
|
||||||
|
memory: {{ .Values.resources.requests.memory }}
|
||||||
|
cpu: {{ .Values.resources.requests.cpu }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /healthz
|
||||||
|
port: 8000
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
20
chart/templates/ingress.yaml
Normal file
20
chart/templates/ingress.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: traefik
|
||||||
|
spec:
|
||||||
|
rules:
|
||||||
|
- host: {{ .Values.ingress.host }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ .Release.Name }}
|
||||||
|
port:
|
||||||
|
number: {{ .Values.service.port }}
|
||||||
|
{{- end }}
|
||||||
11
chart/templates/secret.yaml
Normal file
11
chart/templates/secret.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ .Values.secretName }}
|
||||||
|
annotations:
|
||||||
|
"helm.sh/resource-policy": keep
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
IHP_SESSION_SECRET: "REPLACE_ME"
|
||||||
|
DATABASE_URL: "REPLACE_ME"
|
||||||
|
IHP_BASEURL: "http://{{ .Values.ingress.host }}"
|
||||||
11
chart/templates/service.yaml
Normal file
11
chart/templates/service.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .Release.Name }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
selector:
|
||||||
|
app: {{ .Release.Name }}
|
||||||
|
ports:
|
||||||
|
- port: {{ .Values.service.port }}
|
||||||
|
targetPort: {{ .Values.service.targetPort }}
|
||||||
25
chart/values.yaml
Normal file
25
chart/values.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
image:
|
||||||
|
repository: 92.205.130.254:32166/coulomb/ihp-railiance-probe
|
||||||
|
tag: latest
|
||||||
|
pullPolicy: Always
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 80
|
||||||
|
targetPort: 8000
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
host: probe.coulomb.social
|
||||||
|
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
cpu: 200m
|
||||||
|
requests:
|
||||||
|
memory: 128Mi
|
||||||
|
cpu: 50m
|
||||||
|
|
||||||
|
secretName: ihp-railiance-probe-env
|
||||||
9
default.nix
Normal file
9
default.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# For backwards compatibility using flake.nix
|
||||||
|
(import
|
||||||
|
(
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/35bb57c0c8d8b62bbfd284272c928ceb64ddbde9.tar.gz";
|
||||||
|
sha256 = "sha256:1prd9b1xx8c0sfwnyzkspplh30m613j42l1k789s521f4kv4c2z2";
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }).defaultNix
|
||||||
24
devenv.nix
Normal file
24
devenv.nix
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{ pkgs, lib, config, inputs, ... }:
|
||||||
|
{
|
||||||
|
env.GHCRTS = "-A32m -M2g";
|
||||||
|
|
||||||
|
env.IHP_LIB = "${inputs.ihp.packages.${pkgs.stdenv.system}.ihp-env-var-backwards-compat}";
|
||||||
|
env.IHP = "${inputs.ihp.packages.${pkgs.stdenv.system}.ihp-env-var-backwards-compat}";
|
||||||
|
|
||||||
|
languages.haskell.enable = true;
|
||||||
|
languages.haskell.package = pkgs.ghc.ghc.withPackages (p: with p; [
|
||||||
|
p.ihp
|
||||||
|
cabal-install
|
||||||
|
hlint
|
||||||
|
hspec
|
||||||
|
p.ihp-hspec
|
||||||
|
]);
|
||||||
|
languages.haskell.lsp.enable = false;
|
||||||
|
|
||||||
|
packages = [
|
||||||
|
pkgs.ghc.ghcid
|
||||||
|
pkgs.nodePackages.tailwindcss
|
||||||
|
];
|
||||||
|
|
||||||
|
processes.tailwind.exec = "tailwindcss -c tailwind/tailwind.config.js -i ./tailwind/app.css -o static/app.css --watch=always";
|
||||||
|
}
|
||||||
5
devenv.yaml
Normal file
5
devenv.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
inputs:
|
||||||
|
ihp:
|
||||||
|
url: github:digitallyinduced/ihp/df3922d1a7166b131674efa3d3555ed7195ddf70
|
||||||
|
overlays:
|
||||||
|
- default
|
||||||
118
flake.nix
Normal file
118
flake.nix
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
ihp.url = "github:digitallyinduced/ihp/v1.5";
|
||||||
|
nixpkgs.follows = "ihp/nixpkgs";
|
||||||
|
nixpkgs-nixos.follows = "ihp/nixpkgs-nixos";
|
||||||
|
flake-parts.follows = "ihp/flake-parts";
|
||||||
|
devenv.follows = "ihp/devenv";
|
||||||
|
systems.follows = "ihp/systems";
|
||||||
|
devenv-root = {
|
||||||
|
url = "file+file:///dev/null";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = inputs@{ self, nixpkgs, nixpkgs-nixos, ihp, flake-parts, systems, ... }:
|
||||||
|
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||||
|
|
||||||
|
systems = import systems;
|
||||||
|
imports = [ ihp.flakeModules.default ];
|
||||||
|
|
||||||
|
perSystem = { pkgs, config, lib, ... }: {
|
||||||
|
ihp = {
|
||||||
|
appName = "ihp-railiance-probe";
|
||||||
|
enable = true;
|
||||||
|
projectPath = ./.;
|
||||||
|
packages = with pkgs; [
|
||||||
|
tailwindcss
|
||||||
|
];
|
||||||
|
haskellPackages = p: with p; [
|
||||||
|
p.ihp
|
||||||
|
base
|
||||||
|
wai
|
||||||
|
text
|
||||||
|
];
|
||||||
|
devHaskellPackages = p: with p; [
|
||||||
|
cabal-install
|
||||||
|
hlint
|
||||||
|
hspec
|
||||||
|
ihp-hspec
|
||||||
|
];
|
||||||
|
|
||||||
|
withHoogle = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
# OCI container image for Kubernetes deployment.
|
||||||
|
# Build: nix build .#docker
|
||||||
|
# Push: skopeo copy docker-archive:result docker://92.205.130.254:32166/coulomb/ihp-railiance-probe:SHA
|
||||||
|
packages.docker = config.packages.unoptimized-docker-image;
|
||||||
|
|
||||||
|
devenv.shells.default = {
|
||||||
|
overlays = lib.mkAfter [
|
||||||
|
(final: prev: {
|
||||||
|
ghc = prev.ghc.extend (hfinal: hprev: {
|
||||||
|
mkDerivation = args:
|
||||||
|
let drv = hprev.mkDerivation args;
|
||||||
|
in if (args.pname or "") == "ihp-railiance-probe-models"
|
||||||
|
then drv.overrideAttrs (old: {
|
||||||
|
# GHC 9.10.3 Bug 1: Generated.ActualTypes.hi overflow.
|
||||||
|
# Bug 2: libHSghc-9.10.3-5702.a truncated — use ghc-iserv-dyn.
|
||||||
|
configureFlags = (old.configureFlags or []) ++ [
|
||||||
|
"--ghc-option=-O0"
|
||||||
|
"--ghc-option=-fomit-interface-pragmas"
|
||||||
|
"--disable-split-sections"
|
||||||
|
"--ghc-option=-j1"
|
||||||
|
"--ghc-option=-fexternal-interpreter"
|
||||||
|
"--ghc-option=-pgmi"
|
||||||
|
"--ghc-option=${hprev.ghc}/lib/ghc-9.10.3/bin/ghc-iserv-dyn"
|
||||||
|
];
|
||||||
|
postUnpack = (old.postUnpack or "") + ''
|
||||||
|
_actual="$sourceRoot/build/Generated/ActualTypes.hs"
|
||||||
|
_types=$(
|
||||||
|
{
|
||||||
|
awk '/^data [A-Z]|^newtype [A-Z]/{print $2"(..)"}
|
||||||
|
/^type [A-Z]/{print $2}' \
|
||||||
|
"$sourceRoot/build/Generated/Enums.hs"
|
||||||
|
find "$sourceRoot/build/Generated/ActualTypes" -name "*.hs" | \
|
||||||
|
sort | while IFS= read -r _m; do
|
||||||
|
awk '/^data [A-Z]|^newtype [A-Z]/{print $2"(..)"}
|
||||||
|
/^type [A-Z]/{print $2}' "$_m"
|
||||||
|
done
|
||||||
|
} | sort -u
|
||||||
|
)
|
||||||
|
_exports=$(echo "$_types" | \
|
||||||
|
awk 'NR==1{printf " %s", $0; next} {printf "\n , %s", $0} END{printf "\n"}')
|
||||||
|
_imports=$(awk '/^import Generated\./{print}' "$_actual")
|
||||||
|
{
|
||||||
|
printf 'module Generated.ActualTypes\n ( %s ) where\n' "$_exports"
|
||||||
|
printf '%s\n' "$_imports"
|
||||||
|
} > "$_actual.new" && mv "$_actual.new" "$_actual"
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
else drv;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
env.GHCRTS = "-A32m -M2g";
|
||||||
|
|
||||||
|
processes = {
|
||||||
|
tailwind.exec = "tailwindcss -c tailwind/tailwind.config.js -i ./tailwind/app.css -o static/app.css --watch=always";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nixConfig = {
|
||||||
|
extra-substituters = [
|
||||||
|
"https://devenv.cachix.org"
|
||||||
|
"https://cachix.cachix.org"
|
||||||
|
"https://digitallyinduced.cachix.org"
|
||||||
|
];
|
||||||
|
extra-trusted-public-keys = [
|
||||||
|
"devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="
|
||||||
|
"cachix.cachix.org-1:eWNHQldwUO7G2VkjpnjDbWwy4KQ/HNxht7H4SSoMckM="
|
||||||
|
"digitallyinduced.cachix.org-1:y+wQvrnxQ+PdEsCt91rmvv39qRCYzEgGQaldK26hCKE="
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
0
static/.gitkeep
Normal file
0
static/.gitkeep
Normal file
3
tailwind/app.css
Normal file
3
tailwind/app.css
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
11
tailwind/tailwind.config.js
Normal file
11
tailwind/tailwind.config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./Web/View/**/*.hs",
|
||||||
|
"./Web/FrontController.hs",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user