diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce9ca4d..0bdab3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest] #, windows-latest] - swift: ["6.0.3"] + swift: ["6.2.1"] fail-fast: false steps: - uses: SwiftyLab/setup-swift@latest diff --git a/.gitignore b/.gitignore index ade9e9b..c4ca8a2 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ DerivedData/ .netrc /.build 2 .docker-compose.yml.swp +ssl +ssl.zip +*.tmp +session-state-*.json diff --git a/.swiftformat b/.swiftformat index 0b72086..5cc2cb2 100644 --- a/.swiftformat +++ b/.swiftformat @@ -11,4 +11,4 @@ --octalgrouping none --disable wrapMultilineStatementBraces --swiftversion 6.0.3 ---header "{file}\n\nCreated by David Hunt on {created}\nCopyright {created.year} FOS Computer Services, LLC\n\nLicensed under the Apache License, Version 2.0 (the "License");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License." +--header "{file}\n\nCopyright {created.year} FOS Computer Services, LLC\n\nLicensed under the Apache License, Version 2.0 (the "License");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License." diff --git a/AI Config Script.txt b/AI Config Script.txt new file mode 100644 index 0000000..1a968e9 --- /dev/null +++ b/AI Config Script.txt @@ -0,0 +1,23 @@ +Treat the attached files as follows: + +- docker-compose.yml - a docker compose file +- Dockerfile-client.txt - a docker file for the front-end 'client' server +- Dockerfile-server.txt - a docker file for the back-end server + +Modify the environment to support the following: + +- An nginx server should be placed in front of the front-end and back-end servers +- The nginx front-end port should be 443 +- The nginx back-end port should be 8081 +- The client and server ports should be 8082 and 8083 respectively +- Nginx should forward 443 requests to the front-end server +- Nginx should forward 8081 request to the back-end server +- Nginx should redirect port 80 requests to port 443 +- The machine running docker will be macos sequoia 15.5 +- The macos machine has a volume /Volumes/FOSWebService on which the logs should be placed for the servers and nginx +- Retrieve an SSL certificate for the domain *.foscomputerservices.com from AWS Certificate Manager and install it in the nginx server +- On the macos machine install postgress database +- Make the postgress database available to the back-end server +- The postgress database files should be stored on /Volumes/FOSWebService on the macos machine +- Use nginx version 1.28.0 +- Use postgress version 17 \ No newline at end of file diff --git a/Dockerfile-client b/Dockerfile-client new file mode 100644 index 0000000..fcfeda4 --- /dev/null +++ b/Dockerfile-client @@ -0,0 +1,89 @@ +# ================================ +# Build image +# ================================ + +FROM swift:6.1.0-noble AS build + +# Install OS updates +RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get install -y libjemalloc-dev + +# Set up a build area +WORKDIR /build + +# First just resolve dependencies. +# This creates a cached layer that can be reused +# as long as your Package.swift/Package.resolved +# files do not change. +COPY ./Package.* ./ +RUN swift package resolve \ + $([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true) + +# Copy entire repo into container +COPY . . + +# Build everything, with optimizations, with static linking, and using jemalloc +# N.B.: The static version of jemalloc is incompatible with the static Swift runtime. +RUN swift build -c release \ + --static-swift-stdlib \ + -Xlinker -ljemalloc \ + --product VaporLeafWebApp + +# Switch to the staging area +WORKDIR /staging + +# Copy main executable to staging area +RUN cp "$(swift build --package-path /build -c release --show-bin-path)/VaporLeafWebApp" ./ + +# Copy static swift backtracer binary to staging area +RUN cp "/usr/libexec/swift/linux/swift-backtrace-static" ./ + +# Copy resources bundled by SPM to staging area +RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \; + +# The Public and Resources are served up by the backend server +# RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true +# RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true + +# ================================ +# Run image +# ================================ +FROM ubuntu:noble + +# Make sure all system packages are up to date, and install only essential packages. +RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ + && apt-get -q update \ + && apt-get -q dist-upgrade -y \ + && apt-get -q install -y \ + libjemalloc2 \ + ca-certificates \ + tzdata \ +# If your app or its dependencies import FoundationNetworking, also install `libcurl4`. + libcurl4 \ +# If your app or its dependencies import FoundationXML, also install `libxml2`. + # libxml2 \ + && rm -r /var/lib/apt/lists/* + +# Create a vapor user and group with /VaporLeafWebApp as its home directory +RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /VaporLeafWebApp vapor + +# Switch to the new home directory +WORKDIR /VaporLeafWebApp + +# Copy built executable and any staged resources from builder +COPY --from=build --chown=vapor:vapor /staging /VaporLeafWebApp + +# Provide configuration needed by the built-in crash reporter and some sensible default behaviors. +ENV SWIFT_BACKTRACE=enable=yes,sanitize=yes,threads=all,images=all,interactive=no,swift-backtrace=./swift-backtrace-static + +# Ensure all further commands run as the vapor user +USER vapor:vapor + +# Let Docker bind to the new internal port 8082 +EXPOSE 8082 + +# Start the Vapor service when the image is run, default to listening on 8082 in production environment +ENTRYPOINT ["./VaporLeafWebApp"] +CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8082"] diff --git a/Dockerfile-nginx b/Dockerfile-nginx new file mode 100644 index 0000000..ab6d9e1 --- /dev/null +++ b/Dockerfile-nginx @@ -0,0 +1,18 @@ +# Dockerfile.nginx + +# Use the official Nginx image with version 1.28.0 as a base +FROM nginx:1.28.0 + +# Copy the custom Nginx configuration file into the container +COPY nginx.conf /etc/nginx/nginx.conf + +# Create a directory for SSL certificates inside the container +# This directory will be mounted with the host's SSL certificate files +RUN mkdir -p /etc/nginx/ssl + +# Expose the ports Nginx will listen on +EXPOSE 443 +EXPOSE 8081 + +# The default Nginx CMD will start Nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/Dockerfile b/Dockerfile-server similarity index 90% rename from Dockerfile rename to Dockerfile-server index b68b453..99b301f 100644 --- a/Dockerfile +++ b/Dockerfile-server @@ -2,7 +2,7 @@ # Build image # ================================ -FROM swift:6.0.3-noble AS build +FROM swift:6.1.0-noble AS build # Install OS updates RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ @@ -28,7 +28,8 @@ COPY . . # N.B.: The static version of jemalloc is incompatible with the static Swift runtime. RUN swift build -c release \ --static-swift-stdlib \ - -Xlinker -ljemalloc + -Xlinker -ljemalloc \ + --product VaporWebServer # Switch to the staging area WORKDIR /staging @@ -50,7 +51,7 @@ RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w # ================================ # Run image # ================================ -FROM ubuntu:jammy +FROM ubuntu:noble # Make sure all system packages are up to date, and install only essential packages. RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ @@ -60,8 +61,9 @@ RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ libjemalloc2 \ ca-certificates \ tzdata \ -# If your app or its dependencies import FoundationNetworking, also install `libcurl4`. libcurl4 \ + # Install PostgreSQL client development files for Swift Vapor + libpq-dev \ # If your app or its dependencies import FoundationXML, also install `libxml2`. # libxml2 \ && rm -r /var/lib/apt/lists/* @@ -81,9 +83,9 @@ ENV SWIFT_BACKTRACE=enable=yes,sanitize=yes,threads=all,images=all,interactive=n # Ensure all further commands run as the vapor user USER vapor:vapor -# Let Docker bind to port 8080 -EXPOSE 8080 +# Let Docker bind to the new internal port 8083 +EXPOSE 8083 -# Start the Vapor service when the image is run, default to listening on 8080 in production environment +# Start the Vapor service when the image is run, default to listening on 8083 in production environment ENTRYPOINT ["./VaporWebServer"] -CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] +CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8083"] diff --git a/FOSShowcase.xcodeproj/project.pbxproj b/FOSShowcase.xcodeproj/project.pbxproj index d83c701..b67b0bb 100644 --- a/FOSShowcase.xcodeproj/project.pbxproj +++ b/FOSShowcase.xcodeproj/project.pbxproj @@ -19,16 +19,12 @@ 632162B02C8F3F6F002B991F /* FOSTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 632162AF2C8F3F6F002B991F /* FOSTesting */; }; 6347AEF42C93CD410052EA04 /* FOSWatchShowcase Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 6347AEF32C93CD410052EA04 /* FOSWatchShowcase Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 6347AF342C93D1090052EA04 /* LandingPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AE72C8F6FC10086BAC5 /* LandingPageView.swift */; }; - 6347AF352C93D1090052EA04 /* LandingPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AEA2C8F6FC10086BAC5 /* LandingPageViewModel.swift */; }; - 6347AF362C93D1090052EA04 /* LandingPageRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AE92C8F6FC10086BAC5 /* LandingPageRequest.swift */; }; 634A5EEB2D278EA500E91622 /* SystemVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634A5EEA2D278EA500E91622 /* SystemVersion.swift */; }; 634A5EEC2D278EA500E91622 /* SystemVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634A5EEA2D278EA500E91622 /* SystemVersion.swift */; }; 634A5EEF2D28CABB00E91622 /* FOSFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 634A5EEE2D28CABB00E91622 /* FOSFoundation */; }; 634A5EF12D28CABB00E91622 /* FOSMVVM in Frameworks */ = {isa = PBXBuildFile; productRef = 634A5EF02D28CABB00E91622 /* FOSMVVM */; }; 634A5EF32D28CABB00E91622 /* FOSTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 634A5EF22D28CABB00E91622 /* FOSTesting */; }; - 635E7AEC2C8F6FC10086BAC5 /* LandingPageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AEA2C8F6FC10086BAC5 /* LandingPageViewModel.swift */; }; 635E7AED2C8F6FC10086BAC5 /* LandingPageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AE72C8F6FC10086BAC5 /* LandingPageView.swift */; }; - 635E7AEE2C8F6FC10086BAC5 /* LandingPageRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 635E7AE92C8F6FC10086BAC5 /* LandingPageRequest.swift */; }; 639D68AF2C92A513003C0601 /* FOSFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 639D68AE2C92A513003C0601 /* FOSFoundation */; }; 639D68B12C92A513003C0601 /* FOSMVVM in Frameworks */ = {isa = PBXBuildFile; productRef = 639D68B02C92A513003C0601 /* FOSMVVM */; }; 639D68B32C92A513003C0601 /* FOSTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 639D68B22C92A513003C0601 /* FOSTesting */; }; @@ -106,8 +102,6 @@ 6347AF0F2C93CD420052EA04 /* FOSWatchShowcase Watch AppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "FOSWatchShowcase Watch AppUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 634A5EEA2D278EA500E91622 /* SystemVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemVersion.swift; sourceTree = ""; }; 635E7AE72C8F6FC10086BAC5 /* LandingPageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingPageView.swift; sourceTree = ""; }; - 635E7AE92C8F6FC10086BAC5 /* LandingPageRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingPageRequest.swift; sourceTree = ""; }; - 635E7AEA2C8F6FC10086BAC5 /* LandingPageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LandingPageViewModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ @@ -170,6 +164,11 @@ path = "Tests/Watch AppUITests"; sourceTree = ""; }; + 63BF78112DE506C500A2508E /* LandingPage */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = LandingPage; + sourceTree = ""; + }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -275,8 +274,7 @@ 635E7AEB2C8F6FC10086BAC5 /* ViewModels */ = { isa = PBXGroup; children = ( - 635E7AE92C8F6FC10086BAC5 /* LandingPageRequest.swift */, - 635E7AEA2C8F6FC10086BAC5 /* LandingPageViewModel.swift */, + 63BF78112DE506C500A2508E /* LandingPage */, 634A5EEA2D278EA500E91622 /* SystemVersion.swift */, ); name = ViewModels; @@ -301,6 +299,7 @@ ); fileSystemSynchronizedGroups = ( 630FAAE22C8B76D30046A1FF /* FOSShowcase */, + 63BF78112DE506C500A2508E /* LandingPage */, ); name = FOSShowcase; packageProductDependencies = ( @@ -402,6 +401,9 @@ ); dependencies = ( ); + fileSystemSynchronizedGroups = ( + 63BF78112DE506C500A2508E /* LandingPage */, + ); name = "FOSWatchShowcase Watch App"; packageProductDependencies = ( ); @@ -457,7 +459,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1600; - LastUpgradeCheck = 1600; + LastUpgradeCheck = 1630; TargetAttributes = { 630FAADF2C8B76D30046A1FF = { CreatedOnToolsVersion = 16.0; @@ -491,6 +493,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 630FAAD72C8B76D30046A1FF; minimizedProjectReferenceProxies = 1; @@ -571,10 +574,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 635E7AEC2C8F6FC10086BAC5 /* LandingPageViewModel.swift in Sources */, 635E7AED2C8F6FC10086BAC5 /* LandingPageView.swift in Sources */, 634A5EEB2D278EA500E91622 /* SystemVersion.swift in Sources */, - 635E7AEE2C8F6FC10086BAC5 /* LandingPageRequest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -597,9 +598,7 @@ buildActionMask = 2147483647; files = ( 6347AF342C93D1090052EA04 /* LandingPageView.swift in Sources */, - 6347AF352C93D1090052EA04 /* LandingPageViewModel.swift in Sources */, 634A5EEC2D278EA500E91622 /* SystemVersion.swift in Sources */, - 6347AF362C93D1090052EA04 /* LandingPageRequest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -682,7 +681,9 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -750,7 +751,9 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; @@ -787,8 +790,8 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Sources/SwiftUIApp/Preview Content\""; - DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -828,8 +831,8 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"Sources/SwiftUIApp/Preview Content\""; - DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -863,7 +866,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; + DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MACOSX_DEPLOYMENT_TARGET = 14.6; @@ -881,7 +884,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; + DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MACOSX_DEPLOYMENT_TARGET = 14.6; @@ -899,7 +902,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; + DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; @@ -916,7 +919,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; + DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; @@ -936,7 +939,6 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Sources/Watch App/Preview Content\""; - DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = FOSWatchShowcase; @@ -967,7 +969,6 @@ CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Sources/Watch App/Preview Content\""; - DEVELOPMENT_TEAM = J9VR68AE7U; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = FOSWatchShowcase; @@ -996,7 +997,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; INFOPLIST_KEY_CFBundleDisplayName = FOSWatchShowcase; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.foscomputerservices.FOSWatchShowcase; @@ -1011,7 +1011,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; INFOPLIST_KEY_CFBundleDisplayName = FOSWatchShowcase; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.foscomputerservices.FOSWatchShowcase; @@ -1028,7 +1027,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; @@ -1049,7 +1047,6 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; @@ -1070,7 +1067,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; @@ -1090,7 +1086,6 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = J9VR68AE7U; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = NO; MARKETING_VERSION = 1.0; diff --git a/FOSShowcase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FOSShowcase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3efc314..75fd2bc 100644 --- a/FOSShowcase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/FOSShowcase.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,13 +1,13 @@ { - "originHash" : "e205dd5e1fc14bfb1ecbc3ba62c08c36a89da37f7c9da9ea1f7a3a7f886f4bdf", + "originHash" : "d6b811d02c67a57781af790fe2b6c0c1192a3cc12d8e9bff3f8797c11f7271a1", "pins" : [ { "identity" : "async-http-client", "kind" : "remoteSourceControl", "location" : "https://github.com/swift-server/async-http-client.git", "state" : { - "revision" : "2119f0d9cc1b334e25447fe43d3693c0e60e6234", - "version" : "1.24.0" + "revision" : "60235983163d040f343a489f7e2e77c1918a8bd9", + "version" : "1.26.1" } }, { @@ -24,8 +24,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/console-kit.git", "state" : { - "revision" : "966d89ae64cd71c652a1e981bc971de59d64f13d", - "version" : "4.15.1" + "revision" : "742f624a998cba2a9e653d9b1e91ad3f3a5dff6b", + "version" : "4.15.2" } }, { @@ -34,7 +34,7 @@ "location" : "https://github.com/foscomputerservices/FOSUtilities.git", "state" : { "branch" : "main", - "revision" : "1f3bd1184a98d6acaeb887962d6b8995358a151e" + "revision" : "47c77ed0fb1b62ede339e918c817ebad80e9c9ae" } }, { @@ -51,8 +51,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/routing-kit.git", "state" : { - "revision" : "8c9a227476555c55837e569be71944e02a056b72", - "version" : "4.9.1" + "revision" : "93f7222c8e195cbad39fafb5a0e4cc85a8def7ea", + "version" : "4.9.2" } }, { @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-algorithms.git", "state" : { - "revision" : "f6919dfc309e7f1b56224378b11e28bab5bccc42", - "version" : "1.2.0" + "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", + "version" : "1.2.1" } }, { @@ -69,8 +69,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-asn1.git", "state" : { - "revision" : "7faebca1ea4f9aaf0cda1cef7c43aecd2311ddf6", - "version" : "1.3.0" + "revision" : "a54383ada6cecde007d374f58f864e29370ba5c3", + "version" : "1.3.2" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "042e1c4d9d19748c9c228f8d4ebc97bb1e339b0b", + "version" : "1.0.4" } }, { @@ -82,13 +91,22 @@ "version" : "1.2.0" } }, + { + "identity" : "swift-certificates", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-certificates.git", + "state" : { + "revision" : "999fd70c7803da89f3904d635a6815a2a7cd7585", + "version" : "1.10.0" + } + }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", - "version" : "1.1.4" + "revision" : "c1805596154bb3a265fd91b8ac0c4433b4348fb0", + "version" : "1.2.0" } }, { @@ -96,8 +114,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "ff0f781cf7c6a22d52957e50b104f5768b50c779", - "version" : "3.10.0" + "revision" : "e8d6eba1fef23ae5b359c46b03f7d94be2f41fed", + "version" : "3.12.3" } }, { @@ -105,17 +123,26 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-distributed-tracing.git", "state" : { - "revision" : "6483d340853a944c96dbcc28b27dd10b6c581703", - "version" : "1.1.2" + "revision" : "a64a0abc2530f767af15dd88dda7f64d5f1ff9de", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-http-structured-headers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-http-structured-headers.git", + "state" : { + "revision" : "db6eea3692638a65e2124990155cd220c2915903", + "version" : "1.3.0" } }, { "identity" : "swift-http-types", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-types", + "location" : "https://github.com/apple/swift-http-types.git", "state" : { - "revision" : "ef18d829e8b92d731ad27bb81583edd2094d1ce3", - "version" : "1.3.1" + "revision" : "a0a57e949a8903563aba4615869310c0ebf14c03", + "version" : "1.4.0" } }, { @@ -123,8 +150,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "96a2f8a0fa41e9e09af4585e2724c4e825410b91", - "version" : "1.6.2" + "revision" : "3d8596ed08bd13520157f0355e35caed215ffbfa", + "version" : "1.6.3" } }, { @@ -132,8 +159,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-metrics.git", "state" : { - "revision" : "e0165b53d49b413dd987526b641e05e246782685", - "version" : "2.5.0" + "revision" : "4c83e1cdf4ba538ef6e43a9bbd0bcc33a0ca46e3", + "version" : "2.7.0" } }, { @@ -141,8 +168,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "dca6594f65308c761a9c409e09fbf35f48d50d34", - "version" : "2.77.0" + "revision" : "34d486b01cd891297ac615e40d5999536a1e138d", + "version" : "2.83.0" } }, { @@ -150,8 +177,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-extras.git", "state" : { - "revision" : "2e9746cfc57554f70b650b021b6ae4738abef3e6", - "version" : "1.24.1" + "revision" : "24cb15c9bc05e3e9eb5ebaf3d28517d42537bfb1", + "version" : "1.27.1" } }, { @@ -159,8 +186,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "170f4ca06b6a9c57b811293cebcb96e81b661310", - "version" : "1.35.0" + "revision" : "4281466512f63d1bd530e33f4aa6993ee7864be0", + "version" : "1.36.0" } }, { @@ -168,8 +195,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "c7e95421334b1068490b5d41314a50e70bab23d1", - "version" : "2.29.0" + "revision" : "4b38f35946d00d8f6176fe58f96d83aba64b36c7", + "version" : "2.31.0" } }, { @@ -177,8 +204,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-transport-services.git", "state" : { - "revision" : "bbd5e63cf949b7db0c9edaf7a21e141c52afe214", - "version" : "1.23.0" + "revision" : "cd1e89816d345d2523b11c55654570acd5cd4c56", + "version" : "1.24.0" } }, { @@ -186,8 +213,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-numerics.git", "state" : { - "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", - "version" : "1.0.2" + "revision" : "e0ec0f5f3af6f3e4d5e7a19d2af26b481acb6ba8", + "version" : "1.0.3" } }, { @@ -195,8 +222,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-service-context.git", "state" : { - "revision" : "0c62c5b4601d6c125050b5c3a97f20cce881d32b", - "version" : "1.1.0" + "revision" : "8946c930cae601452149e45d31d8ddfac973c3c7", + "version" : "1.2.0" + } + }, + { + "identity" : "swift-service-lifecycle", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swift-server/swift-service-lifecycle.git", + "state" : { + "revision" : "e7187309187695115033536e8fc9b2eb87fd956d", + "version" : "2.8.0" } }, { @@ -204,8 +240,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-syntax.git", "state" : { - "revision" : "0687f71944021d616d34d922343dcef086855920", - "version" : "600.0.1" + "revision" : "f99ae8aa18f0cf0d53481901f88a0991dc3bd4a2", + "version" : "601.0.1" } }, { @@ -213,8 +249,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "c8a44d836fe7913603e246acab7c528c2e780168", - "version" : "1.4.0" + "revision" : "a34201439c74b53f0fd71ef11741af7e7caf01e1", + "version" : "1.4.2" } }, { @@ -222,7 +258,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/swiftlang/swift-testing.git", "state" : { - "revision" : "18c42c19cac3fafd61cab1156d4088664b7424ae" + "revision" : "43b6f88e2f2712e0f2a97e6acc75b55f22234299" } }, { @@ -230,8 +266,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/vapor.git", "state" : { - "revision" : "4d7456c0d4b33ef82783a90ecfeae33a52a3972a", - "version" : "4.111.0" + "revision" : "4014016aad591a120f244f9b9e8a57252b7e62b4", + "version" : "4.115.0" } }, { @@ -239,8 +275,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/vapor/websocket-kit.git", "state" : { - "revision" : "4232d34efa49f633ba61afde365d3896fc7f8740", - "version" : "2.15.0" + "revision" : "8666c92dbbb3c8eefc8008c9c8dcf50bfd302167", + "version" : "2.16.1" } }, { @@ -248,8 +284,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/jpsim/Yams.git", "state" : { - "revision" : "3036ba9d69cf1fd04d433527bc339dc0dc75433d", - "version" : "5.1.3" + "revision" : "3d6871d5b4a5cd519adf233fbb576e0a2af71c17", + "version" : "5.4.0" } } ], diff --git a/FOSShowcase.xcodeproj/xcshareddata/xcschemes/FOSShowcase.xcscheme b/FOSShowcase.xcodeproj/xcshareddata/xcschemes/FOSShowcase.xcscheme index 4a4289c..f7671d2 100644 --- a/FOSShowcase.xcodeproj/xcshareddata/xcschemes/FOSShowcase.xcscheme +++ b/FOSShowcase.xcodeproj/xcshareddata/xcschemes/FOSShowcase.xcscheme @@ -1,6 +1,6 @@ LeafData { + #if DEBUG + "http://localhost:8080" + #else + "https://staging.foscomputerservices.com:8081" + #endif + } +} diff --git a/Sources/VaporLeafWebApp/Views/LandingPageView.leaf b/Sources/VaporLeafWebApp/Views/LandingPageView.leaf index 4d3abcf..28891ab 100644 --- a/Sources/VaporLeafWebApp/Views/LandingPageView.leaf +++ b/Sources/VaporLeafWebApp/Views/LandingPageView.leaf @@ -1 +1,148 @@ -#(pageTitle) +#extend("base_layout"): + #export("body"): + + + + +
+

#(services.title)

+

#(services.subtitle)

+
+
+
+ Service Icon 1 +

#(services.service1Title)

+

#(services.service1Description)

+
+
+
+
+ Service Icon 2 +

#(services.service2Title)

+

#(services.service2Description)

+
+
+
+
+ Service Icon 3 +

#(services.service3Title)

+

#(services.service3Description)

+
+
+
+
+ +
+
+
+
+ About Image +
+
+

+ #(about.title) +

+
+

#(about.subtitle1)

+

#(about.subtitle2)

+ +
Check +

#(about.fact1)

+
+
+ Check +

#(about.fact2)

+
+
+ Check +

#(about.fact3)

+
+
+ Check +

#(about.fact4)

+
+
+ Check +

#(about.fact5)

+
+
+ Check +

#(about.fact6)

+
+
+
+
+
+
+ + + + + #endexport +#endextend diff --git a/Sources/VaporLeafWebApp/Views/base_layout.leaf b/Sources/VaporLeafWebApp/Views/base_layout.leaf new file mode 100644 index 0000000..1293d30 --- /dev/null +++ b/Sources/VaporLeafWebApp/Views/base_layout.leaf @@ -0,0 +1,53 @@ + + + + + + #(pageTitle) + + + + + #import("body") + + diff --git a/Sources/VaporLeafWebApp/configure.swift b/Sources/VaporLeafWebApp/configure.swift index 12c8ced..42f776f 100644 --- a/Sources/VaporLeafWebApp/configure.swift +++ b/Sources/VaporLeafWebApp/configure.swift @@ -1,6 +1,5 @@ // configure.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -30,9 +29,18 @@ public func configure(_ app: Application) async throws { app.views.use(.leaf) app.http.server.configuration.port = 8082 + app.leaf.tags["backendURL"] = BackendURLTag() + + #if DEBUG + app.leaf.cache.isEnabled = false + #endif + let viewsPath = Bundle.module .url(forResource: "LandingPageView", withExtension: "leaf", subdirectory: "Views")! .deletingLastPathComponent() .absoluteString + .replacingOccurrences(of: "file://", with: "") + app.leaf.configuration = .init(rootDirectory: viewsPath) + app.logger.info("Views path: \(app.leaf.configuration.rootDirectory)") } diff --git a/Sources/VaporLeafWebApp/entrypoint.swift b/Sources/VaporLeafWebApp/entrypoint.swift index c4573e4..11636fe 100644 --- a/Sources/VaporLeafWebApp/entrypoint.swift +++ b/Sources/VaporLeafWebApp/entrypoint.swift @@ -1,6 +1,5 @@ // entrypoint.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Sources/VaporLeafWebApp/routes.swift b/Sources/VaporLeafWebApp/routes.swift index 95b4360..e201fa7 100644 --- a/Sources/VaporLeafWebApp/routes.swift +++ b/Sources/VaporLeafWebApp/routes.swift @@ -1,6 +1,5 @@ // routes.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -38,7 +37,12 @@ extension Application { private static func webServerURL(for request: Request) -> URL where Request: ViewModelRequest { // TODO: Support for baseURL // TODO: Use standard URL support from Request that uses Query - .init(string: "http://localhost:8080")! + #if DEBUG + .init(string: "http://localhost:8083")! .appendingPathComponent(Request.path) + #else + .init(string: "http://server:8083")! + .appendingPathComponent(Request.path) + #endif } } diff --git a/Sources/ViewModels/LandingPage/LandingPageAboutViewModel.swift b/Sources/ViewModels/LandingPage/LandingPageAboutViewModel.swift new file mode 100644 index 0000000..e86898d --- /dev/null +++ b/Sources/ViewModels/LandingPage/LandingPageAboutViewModel.swift @@ -0,0 +1,42 @@ +// LandingPageAboutViewModel.swift +// +// Copyright 2025 FOS Computer Services, LLC +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FOSFoundation +import FOSMVVM +import Foundation + +@ViewModel +public struct LandingPageAboutViewModel { + @LocalizedString public var title + @LocalizedString public var subtitle1 + @LocalizedString public var subtitle2 + @LocalizedString public var fact1 + @LocalizedString public var fact2 + @LocalizedString public var fact3 + @LocalizedString public var fact4 + @LocalizedString public var fact5 + @LocalizedString public var fact6 + + public var vmId = ViewModelId() + + public init() {} +} + +public extension LandingPageAboutViewModel { + static func stub() -> Self { + .init() + } +} diff --git a/Sources/ViewModels/LandingPage/LandingPageBannerViewModel.swift b/Sources/ViewModels/LandingPage/LandingPageBannerViewModel.swift new file mode 100644 index 0000000..aef9138 --- /dev/null +++ b/Sources/ViewModels/LandingPage/LandingPageBannerViewModel.swift @@ -0,0 +1,38 @@ +// LandingPageBannerViewModel.swift +// +// Copyright 2025 FOS Computer Services, LLC +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FOSFoundation +import FOSMVVM +import Foundation + +@ViewModel +public struct LandingPageBannerViewModel { + @LocalizedString public var titlePart1 + @LocalizedString public var titlePart2 + @LocalizedString public var titlePart3 + @LocalizedString public var subtitle + @LocalizedString public var getStartedButtonTitle + + public var vmId = ViewModelId() + + public init() {} +} + +public extension LandingPageBannerViewModel { + static func stub() -> Self { + .init() + } +} diff --git a/Sources/ViewModels/LandingPage/LandingPageFooterViewModel.swift b/Sources/ViewModels/LandingPage/LandingPageFooterViewModel.swift new file mode 100644 index 0000000..aa46845 --- /dev/null +++ b/Sources/ViewModels/LandingPage/LandingPageFooterViewModel.swift @@ -0,0 +1,49 @@ +// LandingPageFooterViewModel.swift +// +// Copyright 2025 FOS Computer Services, LLC +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FOSFoundation +import FOSMVVM +import Foundation + +@ViewModel +public struct LandingPageFooterViewModel { + @LocalizedString public var companyTitle + @LocalizedString public var aboutSubtitle + + @LocalizedString public var servicesTitle + @LocalizedString public var service1Text + @LocalizedString public var service2Text + @LocalizedString public var service3Text + @LocalizedString public var service4Text + + @LocalizedString public var quickLinksTitle + @LocalizedString public var quickLink1Text + @LocalizedString public var quickLink2Text + @LocalizedString public var quickLink3Text + @LocalizedString public var quickLink4Text + + @LocalizedString public var copyrightText + + public var vmId = ViewModelId() + + public init() {} +} + +public extension LandingPageFooterViewModel { + static func stub() -> Self { + .init() + } +} diff --git a/Sources/ViewModels/LandingPageRequest.swift b/Sources/ViewModels/LandingPage/LandingPageRequest.swift similarity index 92% rename from Sources/ViewModels/LandingPageRequest.swift rename to Sources/ViewModels/LandingPage/LandingPageRequest.swift index 37d12cf..334a923 100644 --- a/Sources/ViewModels/LandingPageRequest.swift +++ b/Sources/ViewModels/LandingPage/LandingPageRequest.swift @@ -1,7 +1,6 @@ // LandingPageRequest.swift // -// Created by David Hunt on 9/10/24 -// Copyright 2024 FOS Computer Services, LLC +// Copyright 2025 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Sources/ViewModels/LandingPage/LandingPageServicesViewModel.swift b/Sources/ViewModels/LandingPage/LandingPageServicesViewModel.swift new file mode 100644 index 0000000..a89c128 --- /dev/null +++ b/Sources/ViewModels/LandingPage/LandingPageServicesViewModel.swift @@ -0,0 +1,42 @@ +// LandingPageServicesViewModel.swift +// +// Copyright 2025 FOS Computer Services, LLC +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FOSFoundation +import FOSMVVM +import Foundation + +@ViewModel +public struct LandingPageServicesViewModel { + @LocalizedString public var title + @LocalizedString public var subtitle + + @LocalizedString public var service1Title + @LocalizedString public var service1Description + @LocalizedString public var service2Title + @LocalizedString public var service2Description + @LocalizedString public var service3Title + @LocalizedString public var service3Description + + public var vmId = ViewModelId() + + public init() {} +} + +public extension LandingPageServicesViewModel { + static func stub() -> Self { + .init() + } +} diff --git a/Sources/ViewModels/LandingPageViewModel.swift b/Sources/ViewModels/LandingPage/LandingPageViewModel.swift similarity index 73% rename from Sources/ViewModels/LandingPageViewModel.swift rename to Sources/ViewModels/LandingPage/LandingPageViewModel.swift index 536493d..99822de 100644 --- a/Sources/ViewModels/LandingPageViewModel.swift +++ b/Sources/ViewModels/LandingPage/LandingPageViewModel.swift @@ -1,6 +1,5 @@ // LandingPageViewModel.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -19,15 +18,26 @@ import FOSFoundation import FOSMVVM import Foundation +@ViewModel public struct LandingPageViewModel: RequestableViewModel { public typealias Request = LandingPageRequest @LocalizedString public var loadingTitle @LocalizedString public var pageTitle + public let banner: LandingPageBannerViewModel + public let services: LandingPageServicesViewModel + public let about: LandingPageAboutViewModel + public let footer: LandingPageFooterViewModel + public var vmId = ViewModelId() - public init() {} + public init() { + self.banner = .init() + self.services = .init() + self.about = .init() + self.footer = .init() + } } public extension LandingPageViewModel { diff --git a/Sources/ViewModels/SystemVersion.swift b/Sources/ViewModels/SystemVersion.swift index ac3eb5b..c3018bd 100644 --- a/Sources/ViewModels/SystemVersion.swift +++ b/Sources/ViewModels/SystemVersion.swift @@ -1,7 +1,6 @@ // SystemVersion.swift // -// Created by David Hunt on 1/2/25 -// Copyright 2025 FOS Computer Services, LLC +// Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Sources/Watch App/FOSWatchShowcaseApp.swift b/Sources/Watch App/FOSWatchShowcaseApp.swift index e2aa6d0..dddce73 100644 --- a/Sources/Watch App/FOSWatchShowcaseApp.swift +++ b/Sources/Watch App/FOSWatchShowcaseApp.swift @@ -1,7 +1,6 @@ // FOSWatchShowcaseApp.swift // -// Created by David Hunt on 9/12/24 -// Copyright 2024 FOS Computer Services, LLC +// Copyright 2025 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Sources/WebServer/ViewModelFactories/LandingPageViewModel+Factory.swift b/Sources/WebServer/ViewModelFactories/LandingPageViewModel+Factory.swift index b50e14f..68053b8 100644 --- a/Sources/WebServer/ViewModelFactories/LandingPageViewModel+Factory.swift +++ b/Sources/WebServer/ViewModelFactories/LandingPageViewModel+Factory.swift @@ -1,6 +1,5 @@ // LandingPageViewModel+Factory.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -17,6 +16,7 @@ import FOSFoundation import FOSMVVM +import FOSMVVMVapor import Foundation import Vapor import ViewModels diff --git a/Sources/WebServer/configure.swift b/Sources/WebServer/configure.swift index 2628a48..c812fdb 100644 --- a/Sources/WebServer/configure.swift +++ b/Sources/WebServer/configure.swift @@ -1,6 +1,5 @@ // configure.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -30,8 +29,8 @@ public func configure(_ app: Application) async throws { resourceDirectoryName: "Resources" ) - // uncomment to serve files from /Public folder - // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) + app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) + // register routes try routes(app) } diff --git a/Sources/WebServer/entrypoint.swift b/Sources/WebServer/entrypoint.swift index c4573e4..11636fe 100644 --- a/Sources/WebServer/entrypoint.swift +++ b/Sources/WebServer/entrypoint.swift @@ -1,6 +1,5 @@ // entrypoint.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Sources/WebServer/routes.swift b/Sources/WebServer/routes.swift index 797d64a..9ce34b3 100644 --- a/Sources/WebServer/routes.swift +++ b/Sources/WebServer/routes.swift @@ -1,6 +1,5 @@ // routes.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -25,10 +24,6 @@ func routes(_ app: Application) throws { "It works!" } - app.get("hello") { _ async -> String in - "Hello, world!" - } - let unauthGroup = app.routes try unauthGroup.register(viewModel: LandingPageViewModel.self) } diff --git a/Tests/.VersionedTestJSON/LandingPageAboutViewModel_1.0.0.json b/Tests/.VersionedTestJSON/LandingPageAboutViewModel_1.0.0.json new file mode 100644 index 0000000..ff44fd1 --- /dev/null +++ b/Tests/.VersionedTestJSON/LandingPageAboutViewModel_1.0.0.json @@ -0,0 +1 @@ +{"fact2":"Expertise in Swift, SwiftUI and Vapor","fact3":"We embrace the Test-Driven-Development (TDD) process","subtitle1":"Founded by David Hunt, a software developer with over 36 years of software development experience, our consulting firm specializes in building high-quality iOS and macOS applications with scalable backend solutions. We work closely with businesses of all sizes to deliver software that exceeds expectations.","title":"About Our Company","fact1":"15+ years of iOS and macOS development experience","fact6":"Continuous support and maintenance services","fact4":"Backend development with Vapor and Swift","fact5":"Seamless integration between mobile apps and cloud services","subtitle2":"Our team brings deep technical expertise and a passion for creating exceptional digital experiences that help our clients to achieve their business objectives.","vmId":{"ts":1748278758.7315922}} \ No newline at end of file diff --git a/Tests/.VersionedTestJSON/LandingPageBannerViewModel_1.0.0.json b/Tests/.VersionedTestJSON/LandingPageBannerViewModel_1.0.0.json new file mode 100644 index 0000000..473c428 --- /dev/null +++ b/Tests/.VersionedTestJSON/LandingPageBannerViewModel_1.0.0.json @@ -0,0 +1 @@ +{"titlePart2":"iOS & macOS","titlePart3":"experiences","subtitle":"We craft premium native applications and robust backend services for businesses that demand excellence.","getStartedButtonTitle":"Get Started","titlePart1":"Building exceptional","vmId":{"ts":1748278758.730629}} \ No newline at end of file diff --git a/Tests/.VersionedTestJSON/LandingPageFooterViewModel_1.0.0.json b/Tests/.VersionedTestJSON/LandingPageFooterViewModel_1.0.0.json new file mode 100644 index 0000000..c6ed0d5 --- /dev/null +++ b/Tests/.VersionedTestJSON/LandingPageFooterViewModel_1.0.0.json @@ -0,0 +1 @@ +{"copyrightText":"© 2025 FOS Computer Services, LLC. All rights reserved.","service1Text":"iOS Development","quickLink1Text":"Home","quickLink3Text":"Services","aboutSubtitle":"Expert iOS and macOS application development with robust backend solutions for businesses that demand excellence.","service4Text":"API Development","vmId":{"ts":1748278758.732205},"quickLink4Text":"Contact","companyTitle":"FOS Computer Services, LLC","quickLink2Text":"About","quickLinksTitle":"Quick Links","servicesTitle":"Services","service2Text":"macOS Development","service3Text":"Backend Services"} \ No newline at end of file diff --git a/Tests/.VersionedTestJSON/LandingPageServicesViewModel_1.0.0.json b/Tests/.VersionedTestJSON/LandingPageServicesViewModel_1.0.0.json new file mode 100644 index 0000000..a109d78 --- /dev/null +++ b/Tests/.VersionedTestJSON/LandingPageServicesViewModel_1.0.0.json @@ -0,0 +1 @@ +{"service2Description":"Professional desktop applications for macOS that leverage the full power of Apple's ecosystem.","service3Title":"Backend Development","service2Title":"macOS App Development","service3Description":"Scalable and secure backend services that support your applications with reliable API endpoints and data management.","vmId":{"ts":1748278758.7310781},"service1Description":"Native iOS applications built with Swift and SwiftUI that deliver exceptional user experiences and performance.","subtitle":"We specialize in creating seamless experiences across Apple platforms and robust backend solutions.","service1Title":"iOS App Development","title":"Our Services"} \ No newline at end of file diff --git a/Tests/.VersionedTestJSON/LandingPageViewModel_1.0.0.json b/Tests/.VersionedTestJSON/LandingPageViewModel_1.0.0.json new file mode 100644 index 0000000..1889f2c --- /dev/null +++ b/Tests/.VersionedTestJSON/LandingPageViewModel_1.0.0.json @@ -0,0 +1 @@ +{"about":{"fact2":"Expertise in Swift, SwiftUI and Vapor","subtitle1":"Founded by David Hunt, a software developer with over 36 years of software development experience, our consulting firm specializes in building high-quality iOS and macOS applications with scalable backend solutions. We work closely with businesses of all sizes to deliver software that exceeds expectations.","fact5":"Seamless integration between mobile apps and cloud services","fact4":"Backend development with Vapor and Swift","subtitle2":"Our team brings deep technical expertise and a passion for creating exceptional digital experiences that help our clients to achieve their business objectives.","fact3":"We embrace the Test-Driven-Development (TDD) process","fact6":"Continuous support and maintenance services","title":"About Our Company","vmId":{"ts":1748278758.729216},"fact1":"15+ years of iOS and macOS development experience"},"services":{"service2Description":"Professional desktop applications for macOS that leverage the full power of Apple's ecosystem.","service1Title":"iOS App Development","service3Description":"Scalable and secure backend services that support your applications with reliable API endpoints and data management.","vmId":{"ts":1748278758.729195},"service2Title":"macOS App Development","title":"Our Services","service3Title":"Backend Development","service1Description":"Native iOS applications built with Swift and SwiftUI that deliver exceptional user experiences and performance.","subtitle":"We specialize in creating seamless experiences across Apple platforms and robust backend solutions."},"loadingTitle":"Loading...","vmId":{"ts":1748278758.729165},"banner":{"getStartedButtonTitle":"Get Started","vmId":{"ts":1748278758.729176},"subtitle":"We craft premium native applications and robust backend services for businesses that demand excellence.","titlePart1":"Building exceptional","titlePart2":"iOS & macOS","titlePart3":"experiences"},"pageTitle":"FOS Computer Services, LLC -- Showcase","footer":{"copyrightText":"© 2025 FOS Computer Services, LLC. All rights reserved.","quickLink1Text":"Home","service1Text":"iOS Development","quickLink3Text":"Services","aboutSubtitle":"Expert iOS and macOS application development with robust backend solutions for businesses that demand excellence.","service4Text":"API Development","vmId":{"ts":1748278758.7292461},"quickLink4Text":"Contact","companyTitle":"FOS Computer Services, LLC","quickLink2Text":"About","quickLinksTitle":"Quick Links","service2Text":"macOS Development","servicesTitle":"Services","service3Text":"Backend Services"}} \ No newline at end of file diff --git a/Tests/FOSShowcaseTests/FOSShowcaseTests.swift b/Tests/FOSShowcaseTests/FOSShowcaseTests.swift index af9fe81..cc69b1e 100644 --- a/Tests/FOSShowcaseTests/FOSShowcaseTests.swift +++ b/Tests/FOSShowcaseTests/FOSShowcaseTests.swift @@ -1,6 +1,5 @@ // FOSShowcaseTests.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Tests/FOSShowcaseTests/LandingPageViewModelTests.swift b/Tests/FOSShowcaseTests/LandingPageViewModelTests.swift index 6ab4702..f2c7514 100644 --- a/Tests/FOSShowcaseTests/LandingPageViewModelTests.swift +++ b/Tests/FOSShowcaseTests/LandingPageViewModelTests.swift @@ -1,7 +1,6 @@ // LandingPageViewModelTests.swift // -// Created by David Hunt on 1/2/25 -// Copyright 2025 FOS Computer Services, LLC +// Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Tests/FOSShowcaseUITests/FOSShowcaseUITests.swift b/Tests/FOSShowcaseUITests/FOSShowcaseUITests.swift index e63978a..992443e 100644 --- a/Tests/FOSShowcaseUITests/FOSShowcaseUITests.swift +++ b/Tests/FOSShowcaseUITests/FOSShowcaseUITests.swift @@ -1,6 +1,5 @@ // FOSShowcaseUITests.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Tests/FOSShowcaseUITests/FOSShowcaseUITestsLaunchTests.swift b/Tests/FOSShowcaseUITests/FOSShowcaseUITestsLaunchTests.swift index 51c5ef5..6309a17 100644 --- a/Tests/FOSShowcaseUITests/FOSShowcaseUITestsLaunchTests.swift +++ b/Tests/FOSShowcaseUITests/FOSShowcaseUITestsLaunchTests.swift @@ -1,6 +1,5 @@ // FOSShowcaseUITestsLaunchTests.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Tests/ViewModelTests/LocalizableTestCase.swift b/Tests/ViewModelTests/LocalizableTestCase.swift index 097a243..ef5d431 100644 --- a/Tests/ViewModelTests/LocalizableTestCase.swift +++ b/Tests/ViewModelTests/LocalizableTestCase.swift @@ -1,6 +1,5 @@ // LocalizableTestCase.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); diff --git a/Tests/ViewModelTests/LandingPageViewModelTests.swift b/Tests/ViewModelTests/ViewModelTests.swift similarity index 63% rename from Tests/ViewModelTests/LandingPageViewModelTests.swift rename to Tests/ViewModelTests/ViewModelTests.swift index 766fcb3..8cbea4d 100644 --- a/Tests/ViewModelTests/LandingPageViewModelTests.swift +++ b/Tests/ViewModelTests/ViewModelTests.swift @@ -1,6 +1,5 @@ -// LandingPageViewModelTests.swift +// ViewModelTests.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -22,10 +21,14 @@ import Foundation import Testing import ViewModels -@Suite("Landing Page ViewModel Tests") -struct LandingPageViewModelTests: LocalizableTestCase { - @Test func structure() throws { - try expectTranslations(viewModel: LandingPageViewModel.self) +@Suite("ViewModel Tests") +struct ViewModelTests: LocalizableTestCase { + @Test func structure() async throws { + try await expectFullViewModelTests(LandingPageViewModel.self) + try await expectFullViewModelTests(LandingPageBannerViewModel.self) + try await expectFullViewModelTests(LandingPageServicesViewModel.self) + try await expectFullViewModelTests(LandingPageAboutViewModel.self) + try await expectFullViewModelTests(LandingPageFooterViewModel.self) } let locStore: LocalizationStore diff --git a/Tests/Watch AppTests/FOSWatchShowcase_Watch_AppTests.swift b/Tests/Watch AppTests/FOSWatchShowcase_Watch_AppTests.swift index b8491fd..ba80603 100644 --- a/Tests/Watch AppTests/FOSWatchShowcase_Watch_AppTests.swift +++ b/Tests/Watch AppTests/FOSWatchShowcase_Watch_AppTests.swift @@ -1,7 +1,6 @@ // FOSWatchShowcase_Watch_AppTests.swift // -// Created by David Hunt on 9/12/24 -// Copyright 2024 FOS Computer Services, LLC +// Copyright 2025 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITests.swift b/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITests.swift index d54c80d..34985b3 100644 --- a/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITests.swift +++ b/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITests.swift @@ -1,7 +1,6 @@ // FOSWatchShowcase_Watch_AppUITests.swift // -// Created by David Hunt on 9/12/24 -// Copyright 2024 FOS Computer Services, LLC +// Copyright 2025 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITestsLaunchTests.swift b/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITestsLaunchTests.swift index fba5f17..a56426b 100644 --- a/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITestsLaunchTests.swift +++ b/Tests/Watch AppUITests/FOSWatchShowcase_Watch_AppUITestsLaunchTests.swift @@ -1,7 +1,6 @@ // FOSWatchShowcase_Watch_AppUITestsLaunchTests.swift // -// Created by David Hunt on 9/12/24 -// Copyright 2024 FOS Computer Services, LLC +// Copyright 2025 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); // you may not use this file except in compliance with the License. diff --git a/Tests/WebServerTests/WebServerTests.swift b/Tests/WebServerTests/WebServerTests.swift index b2a42b1..8493a09 100644 --- a/Tests/WebServerTests/WebServerTests.swift +++ b/Tests/WebServerTests/WebServerTests.swift @@ -1,6 +1,5 @@ // WebServerTests.swift // -// Created by David Hunt on 9/10/24 // Copyright 2024 FOS Computer Services, LLC // // Licensed under the Apache License, Version 2.0 (the License); @@ -21,7 +20,7 @@ import Vapor @Suite("Vapor Initialization Tests") struct VaporInitTests { - @Test func testYamlStoreInit() { + @Test func yamlStoreInit() { let app = Application() // app.initYamlLocalization( // bundle: Bundle.module, diff --git a/deploy-fos-showcase-server.sh b/deploy-fos-showcase-server.sh deleted file mode 100755 index d96a945..0000000 --- a/deploy-fos-showcase-server.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -aws s3 cp ./docker-compose.yml s3://fos-showcase-server/docker-compose.yml --region eu-central-1 - -aws ssm send-command \ - --instance-ids "i-0288c9bac585c0cf3" \ - --document-name "AWS-RunShellScript" \ - --parameters commands=' - sudo apt-get install -y awscli && \ - aws s3 cp s3://fos-showcase-server/docker-compose.yml docker-compose.yml' \ - --comment "Download docker-compose.yml from S3" \ - --region "eu-central-1" - -aws ssm send-command \ - --instance-ids "i-0288c9bac585c0cf3" \ - --document-name "AWS-RunShellScript" \ - --parameters commands=' - sudo docker-compose pull app && \ - sudo docker-compose up -d app' \ - --comment "Updating foscompsvcs/fos-showcase-server:latest container" \ - --region "eu-central-1" diff --git a/docker-compose.yml b/docker-compose.yml index c01ad66..057d914 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,16 +14,74 @@ # x-shared_environment: &shared_environment LOG_LEVEL: ${LOG_LEVEL:-debug} - + services: - app: + nginx: + build: + context: . + dockerfile: Dockerfile-nginx # Use the Dockerfile for Nginx + ports: + - '80:80' # Nginx frontend HTTP/S (Nginx handles redirect from 443 to 443) + - '443:443' # Nginx frontend HTTP/S (Nginx handles redirect from 443 to 443) + - '8081:8081' # Nginx backend HTTP/S + volumes: + - './nginx.conf:/etc/nginx/nginx.conf:ro' # Mount the Nginx config + - './ssl:/etc/nginx/ssl:ro' # Mount SSL certificates (create this directory on host) + - '/Volumes/FOSWebService/logs/nginx:/var/log/nginx' # Mount Nginx logs to host volume + depends_on: + - client + - server + restart: unless-stopped + + client: + image: foscompsvcs/fos-showcase-client:latest + platform: linux/amd64 + build: + context: . + dockerfile: Dockerfile-client + environment: + <<: *shared_environment + # Ports are now internal, exposed to Nginx, not directly to the host + expose: + - '8082' # Expose internal port for Nginx to access + volumes: + - '/Volumes/FOSWebService/logs/client:/var/log/vapor_client' # Mount client logs to host volume + # user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user. + command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8082"] + + server: image: foscompsvcs/fos-showcase-server:latest platform: linux/amd64 build: context: . + dockerfile: Dockerfile-server environment: <<: *shared_environment - ports: - - '8080:8080' + # Add PostgreSQL connection details for the backend server + DATABASE_HOST: postgres + DATABASE_PORT: 5432 + DATABASE_NAME: mydatabase # Replace with your database name + DATABASE_USER: myuser # Replace with your database user + DATABASE_PASSWORD: mypassword # Replace with your database password + # Ports are now internal, exposed to Nginx, not directly to the host + expose: + - '8083' # Expose internal port for Nginx to access + volumes: + - '/Volumes/FOSWebService/logs/server:/var/log/vapor_server' # Mount server logs to host volume + depends_on: + - postgres # Server depends on the PostgreSQL database # user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user. - command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] + command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8083"] + + postgres: + image: postgres:17 # Updated to PostgreSQL version 17 + environment: + POSTGRES_DB: mydatabase # Database name + POSTGRES_USER: myuser # Database user + POSTGRES_PASSWORD: mypassword # Database password + PGDATA: /var/lib/postgresql/data/pgdata # Ensure data is stored in the volume + volumes: + - '/Volumes/FOSWebService/postgres_data:/var/lib/postgresql/data' # Mount PostgreSQL data to host volume + ports: + - '5432:5432' # Expose PostgreSQL port to the host for direct access if needed (optional, can be removed) + restart: unless-stopped diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..158bbf3 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,81 @@ +# nginx.conf + +worker_processes auto; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + error_log /var/log/nginx/error.log warn; + + sendfile on; + keepalive_timeout 65; + + # Redirect HTTP (port 80) to HTTPS (port 443 for client) + server { + listen 80; + server_name foscomputerservices.com *.foscomputerservices.com; + return 301 https://$host:443$request_uri; + } + + # Client (Frontend) Server - HTTPS on port 443 + server { + listen 443 ssl; + server_name foscomputerservices.com *.foscomputerservices.com; + + # SSL Certificates (will be mounted from host) + ssl_certificate /etc/nginx/ssl/foscomputerservices.com.crt; + ssl_certificate_key /etc/nginx/ssl/foscomputerservices.com.key; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20"; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Proxy to the client service + location / { + proxy_pass http://client:8082; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90; + } + } + + # Server (Backend) Server - HTTPS on port 8081 + server { + listen 8081 ssl; + server_name foscomputerservices.com *.foscomputerservices.com; + + # SSL Certificates (will be mounted from host) + ssl_certificate /etc/nginx/ssl/foscomputerservices.com.crt; + ssl_certificate_key /etc/nginx/ssl/foscomputerservices.com.key; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20"; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Proxy to the server service + location / { + proxy_pass http://server:8083; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90; + } + } +} diff --git a/start-servers.sh b/start-servers.sh new file mode 100755 index 0000000..6927e44 --- /dev/null +++ b/start-servers.sh @@ -0,0 +1,4 @@ +#!/bin/zsh + +# docker-compose build +docker-compose up \ No newline at end of file