diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4b661f8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Build context for backend/Dockerfile is the repo root (the backend's +# Package.swift references the local ../CocoaHeadsCore package). +# Exclude everything except what the image build needs. +* +!backend +!CocoaHeadsCore +backend/.build/ +backend/.swiftpm/ +CocoaHeadsCore/.build/ +CocoaHeadsCore/.swiftpm/ diff --git a/.github/workflows/deploy-backend.yml b/.github/workflows/deploy-backend.yml deleted file mode 100644 index 68ca0e6..0000000 --- a/.github/workflows/deploy-backend.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Deploy Backend - -on: - workflow_dispatch: - inputs: - branch: - description: 'Branch to deploy' - required: true - default: 'develop' - type: choice - options: - - develop - -jobs: - deploy: - name: Deploy to AWS - runs-on: ubuntu-latest - - steps: - - name: Deploy to AWS Server - uses: appleboy/ssh-action@v1.2.0 - with: - host: ${{ secrets.AWS_HOST }} - username: ${{ secrets.AWS_USERNAME }} - key: ${{ secrets.AWS_SSH_KEY }} - port: ${{ secrets.AWS_PORT || 22 }} - script: | - # Set the branch to deploy - export DEPLOY_BRANCH="${{ github.event.inputs.branch }}" - - # Navigate to the project directory - cd ${{ secrets.REPO_PATH || '/home/ubuntu/CHConferenceApp' }} - - # Run the deployment script - cd backend - bash deploy.sh - - - name: Deployment Status - if: success() - run: | - echo "✓ Backend deployed successfully from branch: ${{ github.event.inputs.branch }}" - echo "✓ Deployment completed at: $(date)" - - - name: Deployment Failed - if: failure() - run: | - echo "✗ Backend deployment failed" - echo "Please check the AWS server logs for more details" - exit 1 diff --git a/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/EventDetailUI.swift b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/EventDetailUI.swift index 87f1885..ddb3055 100644 --- a/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/EventDetailUI.swift +++ b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/EventDetailUI.swift @@ -5,12 +5,12 @@ // Created by Mauricio on 5/7/25. // -import SwiftUI +import Foundation // TODO: .largeLink(URL) -> LPLinkPresentation public indirect enum EventDetailUI: Codable, Sendable { - case card(title: String?, edges: Edge.Set, insetBy: CGFloat?, ui: [EventDetailUI]) + case card(title: String?, edges: ServerEdge.Set, insetBy: CGFloat?, ui: [EventDetailUI]) case carousel(ui: [EventDetailUI]) // TODO: Action -> openURL instead of direct URL case callToAction(title: String, url: URL, systemImage: String?) diff --git a/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/Edge+Codable.swift b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge+Codable.swift similarity index 91% rename from CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/Edge+Codable.swift rename to CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge+Codable.swift index e6d4692..ede4661 100644 --- a/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/Edge+Codable.swift +++ b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge+Codable.swift @@ -1,22 +1,18 @@ // -// Edge+Codable.swift -// CocoaHeadsKit +// ServerEdge+Codable.swift +// CocoaHeadsCore // // Created by Mauricio on 5/7/25. // -import SwiftUI - -// TODO: Move this to `Common` - -extension Edge.Set: @retroactive Codable { +extension ServerEdge.Set: Codable { private enum CodingKeys: String, CodingKey { case top, leading, bottom, trailing, all, horizontal, vertical } public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - var edges: Edge.Set = [] + var edges: ServerEdge.Set = [] if try container.decodeIfPresent(Bool.self, forKey: .top) == true { edges.insert(.top) diff --git a/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge.swift b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge.swift new file mode 100644 index 0000000..317b01b --- /dev/null +++ b/CocoaHeadsCore/Sources/CocoaHeadsCore/ServerDrivenUI/EventDetail/ServerEdge.swift @@ -0,0 +1,33 @@ +// +// ServerEdge.swift +// CocoaHeadsCore +// +// Created by Mauricio on 8/4/26. +// + +// Platform-neutral mirror of SwiftUI.Edge, so server-driven UI models +// compile on Linux and stay free of SwiftUI. Raw values match SwiftUI's, +// making the bridge to SwiftUI.Edge.Set a plain rawValue conversion. +public enum ServerEdge: Int8, CaseIterable, Sendable { + case top, leading, bottom, trailing + + public struct Set: OptionSet, Sendable { + public let rawValue: Int8 + + public init(rawValue: Int8) { + self.rawValue = rawValue + } + + public init(_ e: ServerEdge) { + self.init(rawValue: 1 << e.rawValue) + } + + public static let top = Set(.top) + public static let leading = Set(.leading) + public static let bottom = Set(.bottom) + public static let trailing = Set(.trailing) + public static let horizontal: Set = [.leading, .trailing] + public static let vertical: Set = [.top, .bottom] + public static let all: Set = [.top, .leading, .bottom, .trailing] + } +} diff --git a/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/EventDetailRenderer.swift b/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/EventDetailRenderer.swift index 98fdcc8..8038037 100644 --- a/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/EventDetailRenderer.swift +++ b/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/EventDetailRenderer.swift @@ -24,7 +24,7 @@ public struct EventDetailRenderer: View { private func render(ui: EventDetailUI) -> some View { switch ui { case .card(title: let title, edges: let edges, insetBy: let insets, ui: let innerUI): - Card(title: title, contentInset: (edges, insets)) { + Card(title: title, contentInset: (edges.swiftUI, insets)) { EventDetailRenderer(ui: innerUI) } case .carousel(ui: let innerUI): diff --git a/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/ServerEdge+SwiftUI.swift b/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/ServerEdge+SwiftUI.swift new file mode 100644 index 0000000..1391f83 --- /dev/null +++ b/CocoaHeadsKit/Sources/CocoaHeadsKit/Events/ServerEdge+SwiftUI.swift @@ -0,0 +1,28 @@ +// +// ServerEdge+SwiftUI.swift +// CocoaHeadsKit +// +// Created by Mauricio on 8/4/26. +// + +import CocoaHeadsCore +import SwiftUI + +extension ServerEdge.Set { + /// SwiftUI counterpart of this edge set, for use in view modifiers. + public var swiftUI: SwiftUI.Edge.Set { + .init(rawValue: rawValue) + } +} + +extension ServerEdge { + /// SwiftUI counterpart of this edge. + public var swiftUI: SwiftUI.Edge { + switch self { + case .top: .top + case .leading: .leading + case .bottom: .bottom + case .trailing: .trailing + } + } +} diff --git a/backend/Dockerfile b/backend/Dockerfile index 008f1bf..a485b0c 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -16,12 +16,15 @@ WORKDIR /build # This creates a cached layer that can be reused # as long as your Package.swift/Package.resolved # files do not change. -COPY ./Package.* ./ +# CocoaHeadsCore is a local package referenced as ../CocoaHeadsCore, +# so it must sit next to /build inside the container. +COPY CocoaHeadsCore /CocoaHeadsCore +COPY backend/Package.* ./ RUN swift package resolve \ $([ -f ./Package.resolved ] && echo "--force-resolved-versions" || true) -# Copy entire repo into container -COPY . . +# Copy backend sources into container +COPY backend/ ./ RUN mkdir /staging diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index a408e19..aa4d5d5 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -29,7 +29,8 @@ services: app: image: backend:latest build: - context: . + context: .. + dockerfile: backend/Dockerfile environment: <<: *shared_environment depends_on: @@ -41,7 +42,8 @@ services: migrate: image: backend:latest build: - context: . + context: .. + dockerfile: backend/Dockerfile environment: <<: *shared_environment depends_on: @@ -52,7 +54,8 @@ services: revert: image: backend:latest build: - context: . + context: .. + dockerfile: backend/Dockerfile environment: <<: *shared_environment depends_on: