first commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
.git
|
||||
.ai-workspace
|
||||
node_modules
|
||||
javascript
|
||||
*.s9pk
|
||||
log/*
|
||||
tmp/*
|
||||
storage/*
|
||||
test
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/.bundle
|
||||
/log/*
|
||||
/tmp/*
|
||||
!/log/.keep
|
||||
!/tmp/.keep
|
||||
/storage/*
|
||||
!/storage/.keep
|
||||
/node_modules
|
||||
/javascript
|
||||
/*.s9pk
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# Local AI workspace
|
||||
.ai-workspace/
|
||||
@@ -0,0 +1 @@
|
||||
3.4.5
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
FROM ruby:3.4.5-slim-bookworm
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update -qq && apt-get install --no-install-recommends -y \
|
||||
build-essential curl libpq-dev libyaml-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY Gemfile Gemfile.lock ./
|
||||
RUN bundle config set without "development test" && \
|
||||
bundle install && \
|
||||
rm -rf /usr/local/bundle/cache
|
||||
|
||||
COPY . .
|
||||
RUN chmod +x bin/rails bin/rake
|
||||
|
||||
ENV RAILS_ENV=production \
|
||||
RAILS_LOG_TO_STDOUT=true \
|
||||
RAILS_SERVE_STATIC_FILES=true \
|
||||
PORT=3000
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
|
||||
@@ -0,0 +1,16 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
ruby ">= 3.3.0", "< 3.5"
|
||||
|
||||
gem "rails", "~> 8.0.2"
|
||||
gem "pg", "~> 1.5"
|
||||
gem "puma", ">= 5.0"
|
||||
gem "bootsnap", require: false
|
||||
|
||||
group :development, :test do
|
||||
gem "debug", platforms: %i[mri windows], require: "debug/prelude"
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem "minitest-reporters"
|
||||
end
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
mail (>= 2.8.0)
|
||||
actionmailer (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
mail (>= 2.8.0)
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
nokogiri (>= 1.8.5)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
useragent (~> 0.16)
|
||||
actiontext (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
activejob (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
activerecord (8.0.5.1)
|
||||
activemodel (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
timeout (>= 0.4.0)
|
||||
activestorage (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
marcel (~> 1.0)
|
||||
activesupport (8.0.5.1)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
concurrent-ruby (~> 1.0, >= 1.3.1)
|
||||
connection_pool (>= 2.2.5)
|
||||
drb
|
||||
i18n (>= 1.6, < 2)
|
||||
logger (>= 1.4.2)
|
||||
minitest (>= 5.1)
|
||||
securerandom (>= 0.3)
|
||||
tzinfo (~> 2.0, >= 2.0.5)
|
||||
uri (>= 0.13.1)
|
||||
ansi (1.6.0)
|
||||
base64 (0.3.0)
|
||||
benchmark (0.5.0)
|
||||
bigdecimal (4.1.2)
|
||||
bootsnap (1.24.6)
|
||||
msgpack (~> 1.2)
|
||||
builder (3.3.0)
|
||||
concurrent-ruby (1.3.8)
|
||||
connection_pool (3.0.2)
|
||||
crass (1.0.7)
|
||||
date (3.5.1)
|
||||
debug (1.11.1)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
drb (2.2.3)
|
||||
erb (6.0.7)
|
||||
erubi (1.13.1)
|
||||
globalid (1.4.0)
|
||||
activesupport (>= 6.1)
|
||||
i18n (1.15.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
io-console (0.8.2)
|
||||
irb (1.18.0)
|
||||
pp (>= 0.6.0)
|
||||
prism (>= 1.3.0)
|
||||
rdoc (>= 4.0.0)
|
||||
reline (>= 0.4.2)
|
||||
logger (1.7.0)
|
||||
loofah (2.25.2)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.9.1)
|
||||
logger
|
||||
mini_mime (>= 0.1.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
marcel (1.2.1)
|
||||
mini_mime (1.1.5)
|
||||
minitest (6.0.6)
|
||||
drb (~> 2.0)
|
||||
prism (~> 1.5)
|
||||
minitest-reporters (1.8.0)
|
||||
ansi
|
||||
builder
|
||||
minitest (>= 5.0, < 7)
|
||||
ruby-progressbar
|
||||
msgpack (1.8.4)
|
||||
net-imap (0.6.6)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
net-protocol
|
||||
net-protocol (0.2.2)
|
||||
timeout
|
||||
net-smtp (0.5.1)
|
||||
net-protocol
|
||||
nio4r (2.7.5)
|
||||
nokogiri (1.19.4-aarch64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-aarch64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-arm-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-arm-linux-musl)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-x86_64-linux-gnu)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.19.4-x86_64-linux-musl)
|
||||
racc (~> 1.4)
|
||||
pg (1.6.3)
|
||||
pg (1.6.3-aarch64-linux)
|
||||
pg (1.6.3-aarch64-linux-musl)
|
||||
pg (1.6.3-arm64-darwin)
|
||||
pg (1.6.3-x86_64-darwin)
|
||||
pg (1.6.3-x86_64-linux)
|
||||
pg (1.6.3-x86_64-linux-musl)
|
||||
pp (0.6.4)
|
||||
prettyprint
|
||||
prettyprint (0.2.0)
|
||||
prism (1.9.0)
|
||||
puma (8.0.2)
|
||||
nio4r (~> 2.0)
|
||||
racc (1.8.1)
|
||||
rack (3.2.6)
|
||||
rack-session (2.1.2)
|
||||
base64 (>= 0.1.0)
|
||||
rack (>= 3.0.0)
|
||||
rack-test (2.2.0)
|
||||
rack (>= 1.3)
|
||||
rackup (2.3.1)
|
||||
rack (>= 3)
|
||||
rails (8.0.5.1)
|
||||
actioncable (= 8.0.5.1)
|
||||
actionmailbox (= 8.0.5.1)
|
||||
actionmailer (= 8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
actiontext (= 8.0.5.1)
|
||||
actionview (= 8.0.5.1)
|
||||
activejob (= 8.0.5.1)
|
||||
activemodel (= 8.0.5.1)
|
||||
activerecord (= 8.0.5.1)
|
||||
activestorage (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 8.0.5.1)
|
||||
rails-dom-testing (2.3.0)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.7.1)
|
||||
loofah (~> 2.25, >= 2.25.2)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
railties (8.0.5.1)
|
||||
actionpack (= 8.0.5.1)
|
||||
activesupport (= 8.0.5.1)
|
||||
irb (~> 1.13)
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0, >= 1.2.2)
|
||||
tsort (>= 0.2)
|
||||
zeitwerk (~> 2.6)
|
||||
rake (13.4.2)
|
||||
rbs (4.1.2)
|
||||
logger
|
||||
prism (>= 1.6.0)
|
||||
tsort
|
||||
rdoc (8.0.0)
|
||||
erb
|
||||
prism (>= 1.6.0)
|
||||
rbs (>= 4.0.0)
|
||||
tsort
|
||||
reline (0.7.0)
|
||||
io-console (~> 0.5)
|
||||
ruby-progressbar (1.13.0)
|
||||
securerandom (0.4.1)
|
||||
thor (1.5.0)
|
||||
timeout (0.6.1)
|
||||
tsort (0.2.0)
|
||||
tzinfo (2.0.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uri (1.1.1)
|
||||
useragent (0.16.11)
|
||||
websocket-driver (0.8.2)
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
zeitwerk (2.8.3)
|
||||
|
||||
PLATFORMS
|
||||
aarch64-linux
|
||||
aarch64-linux-gnu
|
||||
aarch64-linux-musl
|
||||
arm-linux-gnu
|
||||
arm-linux-musl
|
||||
arm64-darwin
|
||||
x86_64-darwin
|
||||
x86_64-linux
|
||||
x86_64-linux-gnu
|
||||
x86_64-linux-musl
|
||||
|
||||
DEPENDENCIES
|
||||
bootsnap
|
||||
debug
|
||||
minitest-reporters
|
||||
pg (~> 1.5)
|
||||
puma (>= 5.0)
|
||||
rails (~> 8.0.2)
|
||||
|
||||
CHECKSUMS
|
||||
actioncable (8.0.5.1) sha256=5adb700c605a7ef7628f87dc7a6da20cd5f0ceac782a59055c864ea51a77d7c7
|
||||
actionmailbox (8.0.5.1) sha256=f8b72eadf53b3e285df8f2d1f6533012abf5a0a001180abe436aea3139eeaed6
|
||||
actionmailer (8.0.5.1) sha256=c3d2b3f96e1989ea25f51699786a97fcb2536eb7abfc2a667cb8f2376ec08403
|
||||
actionpack (8.0.5.1) sha256=a5595c9d824d68884ddc4d3965ab78c897760d3752e190df7efe897371caa1eb
|
||||
actiontext (8.0.5.1) sha256=370e90d35feb4313fc18ccef658776427d5bdd13126f266933b828a77e2125b2
|
||||
actionview (8.0.5.1) sha256=472a108b9cc2295c4ac3ff09b028045e619875801f48c556f0085210b9cb1440
|
||||
activejob (8.0.5.1) sha256=142407a21b6c3cbc6ddd92ca111ac18ea5c40298eb94d81845cd897a072a6880
|
||||
activemodel (8.0.5.1) sha256=559be32aa9c40db7a3ee0aef926d4508a9ebd22f96f7276c11326d21a7dff4a4
|
||||
activerecord (8.0.5.1) sha256=9252968fce404d75eb17092498a440d472167f2f8deee32b4658d6552b1eeea7
|
||||
activestorage (8.0.5.1) sha256=239742932b2fdcf0ead175e0889dbd385a36da2168fd7bde023aaad88ef745f2
|
||||
activesupport (8.0.5.1) sha256=329a4280c4fbcfcf338ae2cb9df28b0b14527929dba105e10b3604516d998710
|
||||
ansi (1.6.0) sha256=ac9ea0c0ea8d32fb4e271348e609963ac78882f34b73836c2a02b3622e666658
|
||||
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
||||
benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
|
||||
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
||||
bootsnap (1.24.6) sha256=c60bab88c70332290f0a2636a288f675299eb4f804a02a3c085b42eca9da164a
|
||||
builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f
|
||||
concurrent-ruby (1.3.8) sha256=b2f1be836e968ccc78ccfce277ea79c72a88633f22306782c16ff23fb415d1e1
|
||||
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
||||
crass (1.0.7) sha256=94868719948664c89ddcaf0a37c65048413dfcb1c869470a5f7a7ceb5390b295
|
||||
date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
|
||||
debug (1.11.1) sha256=2e0b0ac6119f2207a6f8ac7d4a73ca8eb4e440f64da0a3136c30343146e952b6
|
||||
drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
|
||||
erb (6.0.7) sha256=c5ca6dc25b0ef974a44dc8f59fe847577122483b1968a38dec305c60bf91ee92
|
||||
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
|
||||
globalid (1.4.0) sha256=037f12fbf1d9d7a014d501c2d5c77356fd4ddd96d7a7991d6700bba96706f427
|
||||
i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
|
||||
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
||||
irb (1.18.0) sha256=de9454a0703a54704b9811a5ef31a60c86949fbf4013fcf244fabc7c775248e3
|
||||
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||
loofah (2.25.2) sha256=2007f746959ac65552456e04b433e83deb22759ab38c838b4445c70e43425918
|
||||
mail (2.9.1) sha256=06574eca475253d6c18145dd70af80d0eb970182d55053497c5f4d797ea160e8
|
||||
marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f
|
||||
mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
|
||||
minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1
|
||||
minitest-reporters (1.8.0) sha256=8ce5280fb73ad3178ae525454df169b6f28c1b38b1d088ea91815d3a370ba384
|
||||
msgpack (1.8.4) sha256=4411c22d350dd1c20250f7eada3cca2695438c2f769cf0782f0cd065d90a3e7b
|
||||
net-imap (0.6.6) sha256=96aa4ee50df3060203e649efc341f53480b791d49e150f2fdebf68beb141a8df
|
||||
net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
|
||||
net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
|
||||
net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
|
||||
nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
|
||||
nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
|
||||
nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
|
||||
nokogiri (1.19.4-arm-linux-gnu) sha256=a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
|
||||
nokogiri (1.19.4-arm-linux-musl) sha256=588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
|
||||
nokogiri (1.19.4-arm64-darwin) sha256=a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
|
||||
nokogiri (1.19.4-x86_64-darwin) sha256=7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
|
||||
nokogiri (1.19.4-x86_64-linux-gnu) sha256=379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
|
||||
nokogiri (1.19.4-x86_64-linux-musl) sha256=17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
|
||||
pg (1.6.3) sha256=1388d0563e13d2758c1089e35e973a3249e955c659592d10e5b77c468f628a99
|
||||
pg (1.6.3-aarch64-linux) sha256=0698ad563e02383c27510b76bf7d4cd2de19cd1d16a5013f375dd473e4be72ea
|
||||
pg (1.6.3-aarch64-linux-musl) sha256=06a75f4ea04b05140146f2a10550b8e0d9f006a79cdaf8b5b130cde40e3ecc2c
|
||||
pg (1.6.3-arm64-darwin) sha256=7240330b572e6355d7c75a7de535edb5dfcbd6295d9c7777df4d9dddfb8c0e5f
|
||||
pg (1.6.3-x86_64-darwin) sha256=ee2e04a17c0627225054ffeb43e31a95be9d7e93abda2737ea3ce4a62f2729d6
|
||||
pg (1.6.3-x86_64-linux) sha256=5d9e188c8f7a0295d162b7b88a768d8452a899977d44f3274d1946d67920ae8d
|
||||
pg (1.6.3-x86_64-linux-musl) sha256=9c9c90d98c72f78eb04c0f55e9618fe55d1512128e411035fe229ff427864009
|
||||
pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570
|
||||
prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
|
||||
prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
|
||||
puma (8.0.2) sha256=c8ed871dfbbe66448ea9ffd46692342d9804d4071522b52b5331b7b6e7b686fb
|
||||
racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
|
||||
rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
|
||||
rack-session (2.1.2) sha256=595434f8c0c3473ae7d7ac56ecda6cc6dfd9d37c0b2b5255330aa1576967ffe8
|
||||
rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463
|
||||
rackup (2.3.1) sha256=6c79c26753778e90983761d677a48937ee3192b3ffef6bc963c0950f94688868
|
||||
rails (8.0.5.1) sha256=c91cefbf38881876ddbe67b5e0246eb985d27d60c6bb1cd7034b4261de0ba495
|
||||
rails-dom-testing (2.3.0) sha256=8acc7953a7b911ca44588bf08737bc16719f431a1cc3091a292bca7317925c1d
|
||||
rails-html-sanitizer (1.7.1) sha256=e797a7c9b01e567307e317c576b49ab4168017e63eea4dba9ce3cb587e2f22c2
|
||||
railties (8.0.5.1) sha256=da1958e1d9dab04691a2f8721b3ff7fab323715d37f103c19972dedfd644d5c7
|
||||
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
||||
rbs (4.1.2) sha256=050eb1d8b508f1233bed929c0f2c7052302f7adf295230d9cb314e9024078f48
|
||||
rdoc (8.0.0) sha256=03bf8c08a9639658855a0cfd77c0abca8325c227693f7f33f82957811348c469
|
||||
reline (0.7.0) sha256=5b012d8e55dbf9d450f12bde2cf7d15ff546ae80b3f8f3b30e570d431815583d
|
||||
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
||||
securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
|
||||
thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
|
||||
timeout (0.6.1) sha256=78f57368a7e7bbadec56971f78a3f5ecbcfb59b7fcbb0a3ed6ddc08a5094accb
|
||||
tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
|
||||
tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
|
||||
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
|
||||
useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844
|
||||
websocket-driver (0.8.2) sha256=97c556b019bf3410b4961002ac501621e9322d3f8a7bc02161a09301cc4c4146
|
||||
websocket-extensions (0.1.5) sha256=1c6ba63092cda343eb53fc657110c71c754c56484aad42578495227d717a8241
|
||||
zeitwerk (2.8.3) sha256=2c85125a8467ce069e20123d1e709a08955c9d29c118c25b46b7b7fafdbb92e5
|
||||
|
||||
RUBY VERSION
|
||||
ruby 4.0.6
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.16
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Todo Back contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,3 @@
|
||||
ARCHES := x86
|
||||
|
||||
include node_modules/@start9labs/start-sdk/s9pk.mk
|
||||
@@ -0,0 +1,41 @@
|
||||
# Todo Back
|
||||
|
||||
Todo Back is a deliberately small Rails JSON API packaged as a native StartOS 0.4 service. Its purpose is to validate the complete local-build → `.s9pk` → sideload workflow before investing in a larger application.
|
||||
|
||||
## API
|
||||
|
||||
- `GET /up` — Rails and PostgreSQL health check
|
||||
- `GET /todos` — list todos
|
||||
- `GET /todos/:id` — fetch one todo
|
||||
- `POST /todos` — create with `{ "todo": { "title": "...", "completed": false } }`
|
||||
- `PATCH /todos/:id` — update title and/or completion state
|
||||
- `DELETE /todos/:id` — delete a todo
|
||||
|
||||
## Architecture
|
||||
|
||||
The package builds the Rails application from the root `Dockerfile` and runs PostgreSQL 17 as a second StartOS subcontainer. PostgreSQL data, Rails local storage, and generated secrets are persisted in separate StartOS volumes. On every start, PostgreSQL becomes healthy, `bin/rails db:prepare` runs, and then Puma starts on port 3000. StartOS publishes that port as an API interface and terminates TLS.
|
||||
|
||||
`SECRET_KEY_BASE` and the database password are generated during installation and stored in the backed-up config volume. Backups use the SDK PostgreSQL dump integration and also include config and local storage.
|
||||
|
||||
## Development
|
||||
|
||||
Install application dependencies and run tests:
|
||||
|
||||
```sh
|
||||
bundle install
|
||||
bin/rails db:prepare
|
||||
bin/rails test
|
||||
```
|
||||
|
||||
Build the x86_64 sideload package from inside a StartOS packaging workspace:
|
||||
|
||||
```sh
|
||||
npm install
|
||||
make x86
|
||||
```
|
||||
|
||||
The resulting `todo-back_x86_64.s9pk` can be uploaded from StartOS under **System → Sideload Service**.
|
||||
|
||||
## Status
|
||||
|
||||
This is an unauthenticated MVP intended for sideload testing on a trusted network. Add authentication before exposing its interface beyond trusted gateways.
|
||||
@@ -0,0 +1,3 @@
|
||||
require_relative "config/application"
|
||||
|
||||
Rails.application.load_tasks
|
||||
@@ -0,0 +1,5 @@
|
||||
# Updating
|
||||
|
||||
The Rails application is developed in this repository. Update Ruby and gems deliberately in `Gemfile`, `.ruby-version`, `Gemfile.lock`, and `Dockerfile` together.
|
||||
|
||||
The PostgreSQL image is pinned in `startos/manifest/index.ts`. Before changing it, confirm the exact official image tag exists and review PostgreSQL upgrade requirements. Update `startos/versions/current.ts` and its release notes for every package release.
|
||||
@@ -0,0 +1,9 @@
|
||||
class ApplicationController < ActionController::API
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
|
||||
|
||||
private
|
||||
|
||||
def render_not_found
|
||||
render json: { error: "not_found" }, status: :not_found
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
class HealthController < ActionController::API
|
||||
def show
|
||||
ActiveRecord::Base.connection.select_value("SELECT 1")
|
||||
head :ok
|
||||
rescue ActiveRecord::ActiveRecordError
|
||||
head :service_unavailable
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,41 @@
|
||||
class TodosController < ApplicationController
|
||||
before_action :set_todo, only: %i[show update destroy]
|
||||
|
||||
def index
|
||||
render json: Todo.order(created_at: :desc)
|
||||
end
|
||||
|
||||
def show
|
||||
render json: @todo
|
||||
end
|
||||
|
||||
def create
|
||||
todo = Todo.new(todo_params)
|
||||
todo.save!
|
||||
render json: todo, status: :created
|
||||
rescue ActiveRecord::RecordInvalid => error
|
||||
render json: { errors: error.record.errors }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def update
|
||||
@todo.update!(todo_params)
|
||||
render json: @todo
|
||||
rescue ActiveRecord::RecordInvalid => error
|
||||
render json: { errors: error.record.errors }, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def destroy
|
||||
@todo.destroy!
|
||||
head :no_content
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_todo
|
||||
@todo = Todo.find(params[:id])
|
||||
end
|
||||
|
||||
def todo_params
|
||||
params.expect(todo: %i[title completed])
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
class ApplicationRecord < ActiveRecord::Base
|
||||
primary_abstract_class
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
class Todo < ApplicationRecord
|
||||
validates :title, presence: true, length: { maximum: 255 }
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
# Package assets
|
||||
|
||||
No additional package assets are required by the MVP.
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
APP_PATH = File.expand_path("../config/application", __dir__)
|
||||
require_relative "../config/boot"
|
||||
require "rails/commands"
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env ruby
|
||||
require_relative "../config/boot"
|
||||
require "rake"
|
||||
Rake.application.run
|
||||
@@ -0,0 +1,4 @@
|
||||
require_relative "config/environment"
|
||||
|
||||
run Rails.application
|
||||
Rails.application.load_server
|
||||
@@ -0,0 +1,16 @@
|
||||
require_relative "boot"
|
||||
|
||||
require "rails"
|
||||
require "active_model/railtie"
|
||||
require "active_job/railtie"
|
||||
require "active_record/railtie"
|
||||
require "action_controller/railtie"
|
||||
|
||||
Bundler.require(*Rails.groups)
|
||||
|
||||
module TodoBack
|
||||
class Application < Rails::Application
|
||||
config.load_defaults 8.0
|
||||
config.api_only = true
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
require "bundler/setup"
|
||||
require "bootsnap/setup" if ENV.fetch("RAILS_ENV", "development") == "production"
|
||||
@@ -0,0 +1,16 @@
|
||||
default: &default
|
||||
adapter: postgresql
|
||||
encoding: unicode
|
||||
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 5) %>
|
||||
url: <%= ENV["DATABASE_URL"] %>
|
||||
|
||||
development:
|
||||
<<: *default
|
||||
database: todo_back_development
|
||||
|
||||
test:
|
||||
<<: *default
|
||||
database: todo_back_test
|
||||
|
||||
production:
|
||||
<<: *default
|
||||
@@ -0,0 +1,3 @@
|
||||
require_relative "application"
|
||||
|
||||
Rails.application.initialize!
|
||||
@@ -0,0 +1,8 @@
|
||||
require "active_support/core_ext/integer/time"
|
||||
|
||||
Rails.application.configure do
|
||||
config.enable_reloading = true
|
||||
config.eager_load = false
|
||||
config.consider_all_requests_local = true
|
||||
config.active_support.deprecation = :log
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
require "active_support/core_ext/integer/time"
|
||||
|
||||
Rails.application.configure do
|
||||
config.enable_reloading = false
|
||||
config.eager_load = true
|
||||
config.consider_all_requests_local = false
|
||||
config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
|
||||
config.log_tags = [:request_id]
|
||||
config.logger = ActiveSupport::TaggedLogging.logger($stdout)
|
||||
config.active_support.report_deprecations = false
|
||||
config.assume_ssl = true
|
||||
config.force_ssl = false
|
||||
config.hosts.clear
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
Rails.application.configure do
|
||||
config.enable_reloading = false
|
||||
config.eager_load = ENV["CI"].present?
|
||||
config.consider_all_requests_local = true
|
||||
config.action_dispatch.show_exceptions = :rescuable
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
threads_count = ENV.fetch("RAILS_MAX_THREADS", 5)
|
||||
threads threads_count, threads_count
|
||||
port ENV.fetch("PORT", 3000)
|
||||
environment ENV.fetch("RAILS_ENV", "development")
|
||||
pidfile ENV["PIDFILE"] if ENV["PIDFILE"]
|
||||
plugin :tmp_restart
|
||||
@@ -0,0 +1,4 @@
|
||||
Rails.application.routes.draw do
|
||||
get "up" => "health#show", as: :rails_health_check
|
||||
resources :todos, only: %i[index show create update destroy]
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class CreateTodos < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
create_table :todos do |t|
|
||||
t.string :title, null: false
|
||||
t.boolean :completed, null: false, default: false
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" role="img" aria-label="Todo Back">
|
||||
<rect width="128" height="128" rx="28" fill="#1f2937"/>
|
||||
<path d="M35 65l18 18 40-43" fill="none" stroke="#34d399" stroke-width="13" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 289 B |
@@ -0,0 +1,15 @@
|
||||
# Todo Back
|
||||
|
||||
Todo Back provides a small REST API for testing a native StartOS service installation.
|
||||
|
||||
After starting the service, open **Interfaces** and copy the Todo API URL. Use `/todos` to manage items. For example:
|
||||
|
||||
```sh
|
||||
curl "$TODO_API/todos"
|
||||
|
||||
curl -X POST "$TODO_API/todos" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"todo":{"title":"Test StartOS sideload","completed":false}}'
|
||||
```
|
||||
|
||||
The service has no login in this MVP. Keep the interface limited to trusted gateways. PostgreSQL data and generated internal secrets are included in StartOS backups.
|
||||
Generated
+1670
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "todo-back-startos",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "rm -rf ./javascript && ncc build startos/index.ts -o ./javascript",
|
||||
"prettier": "prettier --write startos",
|
||||
"check": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@start9labs/start-sdk": "2.0.9"
|
||||
},
|
||||
"overrides": {
|
||||
"@start9labs/start-sdk": "$@start9labs/start-sdk"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.19.0",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"prettier": "^3.6.2",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { sdk } from '../sdk'
|
||||
|
||||
export const actions = sdk.Actions.of()
|
||||
@@ -0,0 +1,23 @@
|
||||
import { storeJson } from './fileModels/store.json'
|
||||
import { sdk } from './sdk'
|
||||
import { databaseName, databaseUser } from './utils'
|
||||
|
||||
export const { createBackup, restoreInit } = sdk.setupBackups(async () =>
|
||||
sdk.Backups.withPgDump({
|
||||
imageId: 'postgres',
|
||||
dbVolume: 'postgres',
|
||||
mountpoint: '/var/lib/postgresql/data',
|
||||
pgdataPath: '',
|
||||
database: databaseName,
|
||||
user: databaseUser,
|
||||
password: async () => {
|
||||
const password = await storeJson
|
||||
.read(value => value.databasePassword)
|
||||
.once()
|
||||
if (!password) throw new Error('Database password is not initialized')
|
||||
return password
|
||||
},
|
||||
})
|
||||
.addVolume('config')
|
||||
.addVolume('storage'),
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
import { sdk } from './sdk'
|
||||
|
||||
export const setDependencies = sdk.setupDependencies(async () => ({}))
|
||||
@@ -0,0 +1,12 @@
|
||||
import { FileHelper, z } from '@start9labs/start-sdk'
|
||||
import { sdk } from '../sdk'
|
||||
|
||||
const shape = z.object({
|
||||
databasePassword: z.string().min(32).catch(''),
|
||||
secretKeyBase: z.string().min(64).catch(''),
|
||||
})
|
||||
|
||||
export const storeJson = FileHelper.json(
|
||||
{ base: sdk.volumes.config, subpath: 'store.json' },
|
||||
shape,
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
export const DEFAULT_LANG = 'en_US'
|
||||
|
||||
const dict = {
|
||||
Database: 0,
|
||||
'The database is not ready': 1,
|
||||
'Todo API': 2,
|
||||
'The Todo API is ready': 3,
|
||||
'The Todo API is not ready': 4,
|
||||
'REST API for todo items': 5,
|
||||
} as const
|
||||
|
||||
export type I18nKey = keyof typeof dict
|
||||
export type LangDict = Record<(typeof dict)[I18nKey], string>
|
||||
export default dict
|
||||
@@ -0,0 +1,8 @@
|
||||
import { LangDict } from './default'
|
||||
|
||||
export default {
|
||||
es_ES: { 0: 'Base de datos', 1: 'La base de datos no está lista', 2: 'API de tareas', 3: 'La API de tareas está lista', 4: 'La API de tareas no está lista', 5: 'API REST para tareas' },
|
||||
de_DE: { 0: 'Datenbank', 1: 'Die Datenbank ist nicht bereit', 2: 'Aufgaben-API', 3: 'Die Aufgaben-API ist bereit', 4: 'Die Aufgaben-API ist nicht bereit', 5: 'REST-API für Aufgaben' },
|
||||
pl_PL: { 0: 'Baza danych', 1: 'Baza danych nie jest gotowa', 2: 'API zadań', 3: 'API zadań jest gotowe', 4: 'API zadań nie jest gotowe', 5: 'REST API dla zadań' },
|
||||
fr_FR: { 0: 'Base de données', 1: "La base de données n'est pas prête", 2: 'API de tâches', 3: "L'API de tâches est prête", 4: "L'API de tâches n'est pas prête", 5: 'API REST pour les tâches' },
|
||||
} satisfies Record<string, LangDict>
|
||||
@@ -0,0 +1,5 @@
|
||||
import { setupI18n } from '@start9labs/start-sdk'
|
||||
import defaultDict, { DEFAULT_LANG } from './dictionaries/default'
|
||||
import translations from './dictionaries/translations'
|
||||
|
||||
export const i18n = setupI18n(defaultDict, translations, DEFAULT_LANG)
|
||||
@@ -0,0 +1,8 @@
|
||||
export { createBackup } from './backups'
|
||||
export { main } from './main'
|
||||
export { init, uninit } from './init'
|
||||
export { actions } from './actions'
|
||||
import { buildManifest } from '@start9labs/start-sdk'
|
||||
import { manifest as sdkManifest } from './manifest'
|
||||
import { versionGraph } from './versions'
|
||||
export const manifest = buildManifest(versionGraph, sdkManifest)
|
||||
@@ -0,0 +1,18 @@
|
||||
import { actions } from '../actions'
|
||||
import { restoreInit } from '../backups'
|
||||
import { setDependencies } from '../dependencies'
|
||||
import { setInterfaces } from '../interfaces'
|
||||
import { sdk } from '../sdk'
|
||||
import { versionGraph } from '../versions'
|
||||
import { seedSecrets } from './seedSecrets'
|
||||
|
||||
export const init = sdk.setupInit(
|
||||
restoreInit,
|
||||
versionGraph,
|
||||
setInterfaces,
|
||||
setDependencies,
|
||||
actions,
|
||||
seedSecrets,
|
||||
)
|
||||
|
||||
export const uninit = sdk.setupUninit(versionGraph)
|
||||
@@ -0,0 +1,18 @@
|
||||
import { utils } from '@start9labs/start-sdk'
|
||||
import { storeJson } from '../fileModels/store.json'
|
||||
import { sdk } from '../sdk'
|
||||
|
||||
export const seedSecrets = sdk.setupOnInit(async (effects, kind) => {
|
||||
if (kind !== 'install') return
|
||||
|
||||
await storeJson.merge(effects, {
|
||||
databasePassword: utils.getDefaultString({
|
||||
charset: 'a-z,A-Z,0-9',
|
||||
len: 48,
|
||||
}),
|
||||
secretKeyBase: utils.getDefaultString({
|
||||
charset: 'a-z,A-Z,0-9',
|
||||
len: 128,
|
||||
}),
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
import { i18n } from './i18n'
|
||||
import { sdk } from './sdk'
|
||||
import { appPort } from './utils'
|
||||
|
||||
export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
|
||||
const host = sdk.MultiHost.of(effects, 'api')
|
||||
const origin = await host.bindPort(appPort, {
|
||||
protocol: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
alpn: { specified: ['http/1.1'] },
|
||||
preferredExternalPort: 443,
|
||||
addXForwardedHeaders: true,
|
||||
auth: null,
|
||||
},
|
||||
})
|
||||
|
||||
const api = sdk.createInterface(effects, {
|
||||
name: i18n('Todo API'),
|
||||
id: 'api',
|
||||
description: i18n('REST API for todo items'),
|
||||
type: 'api',
|
||||
masked: false,
|
||||
schemeOverride: null,
|
||||
username: null,
|
||||
path: '/',
|
||||
query: {},
|
||||
})
|
||||
|
||||
return [await origin.export([api])]
|
||||
})
|
||||
@@ -0,0 +1,97 @@
|
||||
import { storeJson } from './fileModels/store.json'
|
||||
import { i18n } from './i18n'
|
||||
import { sdk } from './sdk'
|
||||
import { appPort, databaseName, databaseUser } from './utils'
|
||||
|
||||
export const main = sdk.setupMain(async ({ effects }) => {
|
||||
const secrets = await storeJson.read().once()
|
||||
if (!secrets?.databasePassword || !secrets.secretKeyBase) {
|
||||
throw new Error('Todo Back secrets have not been initialized')
|
||||
}
|
||||
|
||||
const databaseUrl = `postgresql://${databaseUser}:${secrets.databasePassword}@127.0.0.1:5432/${databaseName}`
|
||||
const appEnv = {
|
||||
DATABASE_URL: databaseUrl,
|
||||
SECRET_KEY_BASE: secrets.secretKeyBase,
|
||||
RAILS_ENV: 'production',
|
||||
RAILS_LOG_TO_STDOUT: 'true',
|
||||
PORT: String(appPort),
|
||||
}
|
||||
|
||||
const postgresSub = sdk.SubContainer.of(
|
||||
effects,
|
||||
{ imageId: 'postgres' },
|
||||
sdk.Mounts.of().mountVolume({
|
||||
volumeId: 'postgres',
|
||||
subpath: null,
|
||||
mountpoint: '/var/lib/postgresql/data',
|
||||
readonly: false,
|
||||
}),
|
||||
'postgres-subcontainer',
|
||||
)
|
||||
|
||||
const appSub = sdk.SubContainer.of(
|
||||
effects,
|
||||
{ imageId: 'app' },
|
||||
sdk.Mounts.of().mountVolume({
|
||||
volumeId: 'storage',
|
||||
subpath: null,
|
||||
mountpoint: '/app/storage',
|
||||
readonly: false,
|
||||
}),
|
||||
'app-subcontainer',
|
||||
)
|
||||
|
||||
return sdk.Daemons.of(effects)
|
||||
.addDaemon('postgres', {
|
||||
subcontainer: postgresSub,
|
||||
exec: {
|
||||
command: sdk.useEntrypoint(['-c', 'listen_addresses=127.0.0.1']),
|
||||
env: {
|
||||
POSTGRES_DB: databaseName,
|
||||
POSTGRES_USER: databaseUser,
|
||||
POSTGRES_PASSWORD: secrets.databasePassword,
|
||||
PGDATA: '/var/lib/postgresql/data',
|
||||
},
|
||||
},
|
||||
ready: {
|
||||
display: i18n('Database'),
|
||||
fn: () =>
|
||||
sdk.healthCheck.runHealthScript(
|
||||
[
|
||||
'pg_isready',
|
||||
'-h',
|
||||
'127.0.0.1',
|
||||
'-U',
|
||||
databaseUser,
|
||||
'-d',
|
||||
databaseName,
|
||||
],
|
||||
postgresSub,
|
||||
{ errorMessage: i18n('The database is not ready') },
|
||||
),
|
||||
},
|
||||
requires: [],
|
||||
})
|
||||
.addOneshot('database-prepare', {
|
||||
subcontainer: appSub,
|
||||
exec: { command: ['bin/rails', 'db:prepare'], env: appEnv },
|
||||
requires: ['postgres'],
|
||||
})
|
||||
.addDaemon('app', {
|
||||
subcontainer: appSub,
|
||||
exec: {
|
||||
command: ['bundle', 'exec', 'puma', '-C', 'config/puma.rb'],
|
||||
env: appEnv,
|
||||
},
|
||||
ready: {
|
||||
display: i18n('Todo API'),
|
||||
fn: () =>
|
||||
sdk.healthCheck.checkWebUrl(effects, `http://127.0.0.1:${appPort}/up`, {
|
||||
successMessage: i18n('The Todo API is ready'),
|
||||
errorMessage: i18n('The Todo API is not ready'),
|
||||
}),
|
||||
},
|
||||
requires: ['database-prepare'],
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
export const short = {
|
||||
en_US: 'A minimal, self-hosted JSON API for todo items.',
|
||||
es_ES: 'Una API JSON mínima y autohospedada para tareas.',
|
||||
de_DE: 'Eine minimale, selbst gehostete JSON-API für Aufgaben.',
|
||||
pl_PL: 'Minimalne, samodzielnie hostowane API JSON dla zadań.',
|
||||
fr_FR: 'Une API JSON minimale et auto-hébergée pour les tâches.',
|
||||
}
|
||||
|
||||
export const long = {
|
||||
en_US: 'Create, read, update, and delete todo items through a small Rails API backed by PostgreSQL.',
|
||||
es_ES: 'Crea, consulta, actualiza y elimina tareas mediante una pequeña API Rails respaldada por PostgreSQL.',
|
||||
de_DE: 'Erstellen, lesen, aktualisieren und löschen Sie Aufgaben über eine kleine Rails-API mit PostgreSQL.',
|
||||
pl_PL: 'Twórz, odczytuj, aktualizuj i usuwaj zadania przez małe API Rails oparte na PostgreSQL.',
|
||||
fr_FR: 'Créez, consultez, modifiez et supprimez des tâches via une petite API Rails utilisant PostgreSQL.',
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { setupManifest } from '@start9labs/start-sdk'
|
||||
import { long, short } from './i18n'
|
||||
|
||||
export const manifest = setupManifest({
|
||||
id: 'todo-back',
|
||||
title: 'Todo Back',
|
||||
license: 'MIT',
|
||||
packageRepo: 'https://github.com/alextab93/todo-back',
|
||||
upstreamRepo: 'https://github.com/alextab93/todo-back',
|
||||
marketingUrl: 'https://github.com/alextab93/todo-back',
|
||||
donationUrl: null,
|
||||
description: { short, long },
|
||||
volumes: ['config', 'postgres', 'storage'],
|
||||
images: {
|
||||
app: {
|
||||
source: { dockerBuild: {} },
|
||||
arch: ['x86_64'],
|
||||
},
|
||||
postgres: {
|
||||
source: { dockerTag: 'postgres:17.6-bookworm' },
|
||||
arch: ['x86_64'],
|
||||
},
|
||||
},
|
||||
dependencies: {},
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
import { StartSdk } from '@start9labs/start-sdk'
|
||||
import { manifest } from './manifest'
|
||||
|
||||
export const sdk = StartSdk.of().withManifest(manifest).build(true)
|
||||
@@ -0,0 +1,3 @@
|
||||
export const appPort = 3000
|
||||
export const databaseName = 'todo_back_production'
|
||||
export const databaseUser = 'todo_back'
|
||||
@@ -0,0 +1,16 @@
|
||||
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
|
||||
|
||||
export const current = VersionInfo.of({
|
||||
version: '0.1.1:0',
|
||||
releaseNotes: {
|
||||
en_US: 'Fix PostgreSQL readiness checks and HTTP/1.1 proxying; health now verifies the database.',
|
||||
es_ES: 'Corrige las comprobaciones de PostgreSQL y el proxy HTTP/1.1; la salud ahora verifica la base de datos.',
|
||||
de_DE: 'Korrigiert PostgreSQL-Prüfungen und HTTP/1.1-Proxying; der Status prüft nun die Datenbank.',
|
||||
pl_PL: 'Poprawia test PostgreSQL i proxy HTTP/1.1; kontrola stanu sprawdza teraz bazę danych.',
|
||||
fr_FR: 'Corrige les contrôles PostgreSQL et le proxy HTTP/1.1 ; la santé vérifie désormais la base de données.',
|
||||
},
|
||||
migrations: {
|
||||
up: async () => {},
|
||||
down: IMPOSSIBLE,
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
import { VersionGraph } from '@start9labs/start-sdk'
|
||||
import { current } from './current'
|
||||
|
||||
export const versionGraph = VersionGraph.of({ current, other: [] })
|
||||
@@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class TodoTest < ActiveSupport::TestCase
|
||||
test "requires a title" do
|
||||
assert_not Todo.new(title: "").valid?
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
require_relative "../config/environment"
|
||||
require "rails/test_help"
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "@start9labs/start-sdk/tsconfig.base.json",
|
||||
"include": ["startos/**/*.ts", "node_modules/**/startos"]
|
||||
}
|
||||
Reference in New Issue
Block a user