Git Product home page Git Product logo

spezi's Introduction

Spezi

Build and Test codecov DOI

Open-source framework for rapid development of modern, interoperable digital health applications.

Overview

Note

Refer to the Initial Setup instructions on how to integrate Spezi into your application!

Spezi introduces a standards-based modular approach to building digital health applications.

Screenshot displaying the UI of the onboarding module. Screenshot displaying the UI of the onboarding module. Screenshot displaying the UI of the contact module. Screenshot displaying the UI of the contact module. Screenshot displaying the UI of the questionnaire module. Screenshot displaying the UI of the questionnaire module.
The Spezi Onboarding Module The Spezi Contact Module The Spezi Questionnaire Module
Screenshot displaying the account setup view with an email and password prompt and a Sign In with Apple button using the Spezi Account module. Screenshot displaying the account setup view with an email and password prompt and a Sign In with Apple button using the Spezi Account module. Three different kinds of text fields showing validation errors in red text using Spezi Validation package. Three different kinds of text fields showing validation errors in red text using Spezi Validation package. A Chat View of a locally executed LLM using the Spezi LLM module. A Chat View of a locally executed LLM using the Spezi LLM module.
The Spezi Account Module The SpeziValidation package of the Spezi Views Module. The Spezi LLM Module

The best way to get started and explore the functionality of Spezi is by taking a look at the Spezi Template Application. The application incorporates a wide variety of sophisticated modules and demonstrates the usage of these modules in a simple-to-use and easy-to-extend application.

An Ecosystem of Modules

You can find a list of modules and reusable Swift Packages offered by the Spezi team at Stanford at the Swift Package Index Stanford Spezi page.

Note

Spezi relies on an ecosystem of modules. Think about what modules you want to build and contribute to the open-source community! Refer to the Spezi Guide and Documentation Guide about the requirements for Spezi-based software and the Module documentation to learn more about building your modules.

Learn more about Spezi at spezi.stanford.edu. Reach out to us on social media and use the Stanford Spezi Discussion Forum to ask any Spezi-related questions or share the projects you built with Spezi.

Check out the Stanford Biodesign Digital Health GitHub organization and Stanford Biodesign Digital Health website at bdh.stanford.edu, for example, applications built with Spezi and some of our related open-source and research projects.

The Spezi Building Blocks

Note

The Spezi Guide and Documentation Guide guides define the requirements for Spezi-based modules, including terminology, hints, and examples on structuring your Spezi module, Swift Package, and surrounding repository.

A Standard defines the key coordinator that orchestrates the data flow in the application by meeting requirements defined by modules. You can learn more about the Standard protocol and when it is advised to create your own standard in your application in the Standard documentation.

A Module defines a software subsystem providing distinct and reusable functionality. Modules can use the constraint mechanism to enforce a set of requirements to the standard used in the Spezi-based software where the module is used. Modules also define dependencies on each other to reuse functionality and can communicate with other modules by offering and collecting information. They can also conform to different protocols to provide additional access to Spezi features, such as lifecycle management and triggering view updates in SwiftUI using the observable mechanisms in Swift. You can learn more about modules in the Module documentation.

For more information, please refer to the API documentation.

Contributing

Contributions to this project are welcome. Please make sure to read the contribution guidelines and the contributor covenant code of conduct first.

License

This project is licensed under the MIT License. See Licenses for more information.

Spezi Footer Spezi Footer

spezi's People

Contributors

philippzagar avatar pschmiedmayer avatar supereg avatar vishnuravi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spezi's Issues

Validate That Modules Are Only Created Once

Problem

We currently have no unit test that validates that modules are actually only instantiated once using the Spezi configuration mechanism. We have that implicit assumption but need to ensure that modules are only instantiated once, even if they are defined as dependencies using an initializer as well as module configurations in the configuration.

Solution

Create a small unit test that validates this functionality.

Additional context

This would be a great first issue for someone who wants to get familiar with the dependency management mechanism in Spezi.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Remove Generic Type Constraints for Components

Problem

Using a component in SwiftUI views requires the definition of the component standard even when a component is not constraining the Standard and when the generic constraint is not used in the view:

struct HealthKitPermissions: View {
    @EnvironmentObject var healthKitDataSource: HealthKit<FHIR>
    
    // ...
}

In addition, defining a new component requires the definition of a component standard even though the component might not have any constraints on the Standard (e.g., the storage modules: https://github.com/StanfordSpezi/SpeziStorage)

Solution

It would be great if the injection of the components could happen without generic constraints like:

struct HealthKitPermissions: View {
    @EnvironmentObject var healthKitDataSource: HealthKit
    
    // ...
}

In addition, the creation of a component does not require a generic type or fixed-defined type alias. The requirements should rather be moved to the Standard and not to the Component.

Additional context

An alternative would be creating a type alias on a global level of a Spezi-based application within the View scope, e.g.:

extension View {
    typealias HealthKitComponent = HealthKit<FHIR>
}

which allows the usage in a view using

struct HealthKitPermissions: View {
    @EnvironmentObject var healthKitDataSource: HealthKitComponent
    
    // ...
}

Unfortunately, this is a very application-specific solution and hides the complexity while not accessing the usage of components outside of a view or when passing them between components.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Automatically Inject `ObservableObject` Instances

Problem

We currently only inject objects in the SwiftUI environment that conform to ObservableObjectProvider. Unfortunately, this is sometimes unintuitive when developers just want to create a simple component that conforms to ObservableObject and should be injected in the SwiftUI environment, and developers do not need or are not aware of the ObservableObjectProvider protocol.

Solution

We should also check for instances conforming to ObservableObject and inject them into the SwiftUI environment.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Inject Spezi Components as ViewModifier into the SwiftUI view hierarchy

Use Case

There is a general need for Spezi Components to either inject information or retrieve information from the SwiftUI view hierarchy. We already have the ObservableObjectProvider to inject Observable Objects into the view hierarchy.
However, components might want to do more. There is a use case for SpeziAccount, where Account Services might want to inject view components globally (e.g., an alert box to reauthenticate on security related operations) or SpeziFirebase that requires access to the AuthorizationController that is part of the SwiftUI Environment.

Problem

Doing any of this, except for injecting ObservableObjects, is not supported by Spezi and requires custom modifiers or, generally, requires a manual approach.

Solution

A viable solution is to make all Component s conform to the SwiftUI ViewModifier protocol and injecting the into the global View hierarchy within the global spezi(_:) modifier.

This has several benefits:

  • The component can inject arbitrary information or UI elements into the view hierarchy allowing for great flexibility.
  • One can use arbitrary SwiftUI property wrappers within the Component. This might allow for easier state sharing (e.g. as a Binding) with subsystems of a component.
  • Spezi's own property wrappers can make use of SwiftUI functionality (this point would motivate a out of the box conformance to ViewModifier).

Alternatives considered

Alternatives, where a Component provides a set of ViewModifiers (e.g. via a property wrapper similar to @Provide) were discussed. But generally those approaches reduce the flexibility or don't result in the same benefits as listed above. You wouldn't be able to use SwiftUI modifiers within your Component and it would increase the steps necessary to inject a view modifier into the view hierarchy.

Additional context

CC: @PSchmiedmayer

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Easily accessible logger infrastructure for Components and Modules

Problem

Currently, every implementing Component is responsible to create and manage their instances of a Logger. This impose the following problems:

  • Creating a Logger is often times a multi-step process and could be considered tedious. This might result in developers not adopting at all or falling back to non-structured logging techniques like a simple print statement. Both goes against our aims of have maintainable and traceable code.
  • Developers might not have good guidance on what identifiers to choose (e.g., subsystem and category labels). This might result in choosing inconsistent identifiers.

Solution

This issue proposes a solution where Components or Modules can easily access a Logger instance that is tied to their specific implementation, such that:

  • It is easy to access.
  • It provides strong and consistent defaults for the logger subsystem and category.

Ultimately we want to encourage increased usage of log message such that we have maintainable code that is easy to debug.

Additional context

For some context, we currently have the internal SpeziLogger KnowledgeSource stored inside the SharedRepository of the Spezi instance which provides the global default logger for the Spezi framework.

A potential solution to address this issue could be implementing some kind of @Logger property wrapper which can be used inside Component and Module implementations. The property wrapper would make use of the SpeziStorage repository to retrieve and store the logger instance, similar to the SpeziLogger knowledge source.

One might need to think what challenges this design creates. How easy is it for the Component to pass around the Logger to other types which are created and managed by the Component?

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Add DocC Documentation Articles

Problem

I suggest addingditional documentation in the DocC-based documentation to provide content for beginners and more experienced developers who want to use Spezi in their apps or want to build their own modules.

Solution

It would be good to add additional documentation in the DocC-based documentation bundle that focuses on the following topics:

  • The Spezi Ecosystem: A summary of the prime modules that we offer in Spezi with links to their documentation and use cases.
  • Integrating a module in a Spezi-based app: A step-by-step article that can be linked in other Swift packages on how to include a Spezi module in an iOS App (or other Swift Package) using the Swift Package manager, adding the component to the configuration, and potentially using views or an ObservableObject in the SwiftUI environment.
  • An article on building your own model, including the lifecycle of a module (init, configure), reusing functionality using @Dependency, and maybe some more advanced elements
  • An article on advanced components featured and how to use them, e.g., @Collect and Knowledge sources.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Extend XCTSpezi to Support the Individual Creation of Modules and Components

Problem

Similar to #63, the creation of modules and components in the setting of a unit test is essential to investigate behavior of components in a unit test.

The current code in unit test used in the Spezi ecosystem looks something like the following example from the Spezi Scheduler module:

let scheduler = Scheduler<SchedulerTestsStandard, String>(tasks: [initialTasks])
let localStorageDependency = Mirror(reflecting: scheduler).children
    .compactMap {
        $0.value as? _DependencyPropertyWrapper<LocalStorage<SchedulerTestsStandard>, SchedulerTestsStandard>
    }
    .first
localStorageDependency?.inject(dependency: LocalStorage())
scheduler.configure()

Manually iterating over the properties using a Mirror might not be the desirable behaviour and can lead to errors and undefined behaviour.

Solution

The XCTSpezi Module should provide an easy mechanism to create components/modules in unit tests and needs to provide a mechanism to define the injected components or create components if they are default initializable.

The exact design of the API is up to debate. Feel free to add a comment in this issue about design ideas and concepts around the creation of the API and how you would like to implement the feature.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Migrate from the Observable Object Protocol to the Observable Macro

Problem

Starting with iOS 17, iPadOS 17, macOS 14, tvOS 17, and watchOS 10, SwiftUI provides support for Observation, a Swift-specific implementation of the observer design pattern. More context is provided in the Migrating from the Observable Object protocol to the Observable macro article.
Spezi should be at the forefront of modern development for mobile applications and should therefore use and support Observation.

Solution

Follow the best practices outline in Managing model data in your app- Create connections between your app’s data model and views. and other documentation about the Observation mechanism in Spezi and sub sequentially in the Spezi modules.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Support the Component/Module Creation for Xcode Previews

Problem

Using some code in a SwiftUI view that, e.g., uses an @EnvironmentObject injected by Spezi requires the manual annotation in the SwiftUI preview to inject this object:

struct ScheduleView: View {
    @EnvironmentObject var scheduler: TemplateApplicationScheduler
    
    
    var body: some View {
        // ...
    }
}


struct SchedulerView_Previews: PreviewProvider {
    static var previews: some View {
        ScheduleView()
            .environmentObject(TemplateApplicationScheduler())
    }
}

While this is possible for simple components with no @Dependency-annotated components, injecting more complex components that require the injection of dependencies makes this difficult.

Solution

We propose the creation of a .previewComponent(...) or .previewComponents(...) view modifier that injects a specified amount of components in the environment.

The modifier would also require the definition of the associated standard or any generic requirement that are imposed on a component.

Additional context

Input on the design of this preview injection mechanism is greatly welcome. Please leave your thoughts and comments under this issue.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Type-safe Validation of Standard Constraints

Problem

Currently, there is no compile-time validation of the enforcement of constraints to the Standard in the configuration. E.g., the following code would compile even though the ExampleStandard does not conform to ExampleConstraint:

protocol ExampleConstraint: Standard {
    // ...
}

class ExampleComponent: Component {
    @StandardActor var standard: any ExampleConstraint
   
    // ...
}

actor ExampleStandard: Standard {
    // ...
}

var configuration: Configuration {
    Configuration(standard: ExampleStandard()) {
        ExampleComponent()
        // ...
    }
}

Solution

The compiler should emit a warning that the ExampleStandard does not conform to ExampleConstraint when defining it in the Configuration.

Unfortunately, this doesn't seem to be easily achievable in Swift and needs some further investigation.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Update Documentation in Conformance to the Documentation Guide

Problem

The current documentation in Spezi provides a good overview of the API and includes documentation for most public APIs. In line with the newly published Stanford Spezi Documentation Guide, we should update the documentation in accordance with the guidelines.

Solution

The documentation should be updated to provide more insightful inline documentation, improve the README file and the DocC landing page in conformance with the Stanford Spezi Documentation Guide.

  • Update inline documentation, including links and other elements noted in the Code Documentation section.
  • Improve the DocC landing page as detailed in the Landing Page section.
  • Add a graphic and visual representation of the Spezi setup and architecture.
  • Improve the READMe as noted in the README section.

Additional context

This PR is related to #82

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Enforcing Protocol Conformance for Standard Constraints

Use Case

At the current point, we can not enforce that a Standard Constraint actually conforms to the Standard protocol.

Problem

We need to enforce protocol conformance for existential types at compile time or runtime.
Currently, it is possible to define a constraint without conforming it to Standard, resulting in issues with actor isolation and undefined runtime behavior or runtime crashes:

protocol StandardConstraint {
    // ...
}

Solution

We have created a forum thread to ask for advice on this problem: https://forums.swift.org/t/enforcing-protocol-conformance-for-existential-types-at-compiletime-or-runtime/66215.

We are unaware of any possible solutions to enforce the protocol conformance on runtime or compile time.

A possible element to explore might be the usage of a macro instead of a property wrapper for the @StandardActor usage. Using a macro might give us more insights about the type and possible enforce more elements.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Complete Concurrency Checking

Problem

With Swift 6 approaching in a few months and nightly builds already being available we should ensure that all our packages are working well with all Swift concurrency checks.

Solution

Enable strict concurrency checking in the Swift Package in a PR and ensure that we don't have any warnings remaining in the packages as we develop new features or fix bugs from now.

The UI Testing App target should also enable Enable strict concurrency checking.

The corresponding PR should fix all related warnings when enabling strict concurrency checking.

Additional context

We should consider adding SWIFT_TREAT_WARNINGS_AS_ERRORS = YES to our general workflows to ensure all warnings are flagged as errors during our CI setup.

Code of Conduct

  • I agree to follow this project's Code of Conduct and Contributing Guidelines

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.