https://github.com/markbattistella/formlogger
FormLogger is a drop-in SwiftUI-compatible manager for logging bugs, feature requests, and feedback - with flexible support for custom UI and backends. You can roll your own interface while leveraging the powerful FormManager. It’s designed to integrate with lightweight backends (like a Cloudflare Worker) that push issues to GitHub via their API.
https://github.com/markbattistella/formlogger
automation github-issues ios ipados macos swift swiftui tvos visionos watchos
Last synced: about 2 months ago
JSON representation
FormLogger is a drop-in SwiftUI-compatible manager for logging bugs, feature requests, and feedback - with flexible support for custom UI and backends. You can roll your own interface while leveraging the powerful FormManager. It’s designed to integrate with lightweight backends (like a Cloudflare Worker) that push issues to GitHub via their API.
- Host: GitHub
- URL: https://github.com/markbattistella/formlogger
- Owner: markbattistella
- License: mit
- Created: 2025-06-03T09:45:38.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2026-03-08T11:23:00.000Z (3 months ago)
- Last Synced: 2026-03-08T14:45:33.562Z (3 months ago)
- Topics: automation, github-issues, ios, ipados, macos, swift, swiftui, tvos, visionos, watchos
- Language: Swift
- Homepage: https://swiftpackageindex.com/markbattistella/FormLogger/documentation
- Size: 91.8 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# FormLogger



`FormLogger` is a drop-in SwiftUI-compatible manager for logging bugs, feature requests, and feedback - with flexible support for custom UI and backends. You can roll your own interface while leveraging the powerful `FormManager`. It's designed to integrate with lightweight backends (like a Cloudflare Worker) that push issues to GitHub via their API.
## Features
- **Input validation:** Ensures title, description, and (optional) contact details are properly filled and formatted.
- **Customisable view model:** Use the underlying `FormManager` to power your own UI with full control over behaviour.
- **Repository routing:** Supports single, multiple, or selectively overridden repositories based on form type.
- **Log attachment:** Automatically collects and submits log data alongside user input for better context.
- **Async submission:** Handles network requests using `async`/`await`, with detailed progress and error state handling.
## Installation
Add `FormLogger` to your Swift project using Swift Package Manager.
```swift
dependencies: [
.package(url: "https://github.com/markbattistella/FormLogger", from: "1.0.0")
]
```
Alternatively, you can add `FormLogger` using Xcode by navigating to `File > Add Packages` and entering the package repository URL.
## Usage
With full control you can leverage the `FormManager` to power your own interface:
### Capabilities
- `userInput`: Contains title, description, and optional contact info.
- `formType`: Enum of `.bug`, `.feature`, or `.feedback`.
- `isFormValid`: Boolean indicating if user input is valid.
- `isProcessing`: Boolean showing if submission is ongoing.
- `submit()`: Async method that validates, collects logs, and sends to backend.
- `currentProgress`: Double value from 0–1 for progress.
- `currentProgressLabel`: String description of current progress state.
## Configuration
You can customise how form submissions are routed to repositories using the `RepositoryResolver`.
This modular setup ensures you can scale your feedback system as your project grows - from a single inbox to a fully segmented triage workflow.
There are three main strategies depending on your needs:
### Single Repository
Use a single repository for all form types - bugs, features, and feedback. This is a great setup if you're just starting out or want to centralise everything in one place.
```swift
let singleRepoConfig = PreviewFormConfig(
repository: .single(
Repository(
username: "markbattistella",
repository: "feedback-logger"
)
)
)
```
In this setup, all issues - regardless of type - are submitted to the same repository. It's simple, clean, and requires minimal setup.
### Multiple Repositories
Use different repositories depending on the type of form being submitted. Ideal when you want to separate concerns, visibility, or contributor access.
```swift
let multiRepoConfig = PreviewFormConfig(
repository: .multiple([
.bug: Repository(
username: "markbattistella",
repository: "bug-tracker"
),
.feature: Repository(
username: "markbattistella",
repository: "feature-requests"
),
.feedback: Repository(
username: "markbattistella",
repository: "feedback-logger"
)
])
)
```
This gives you fine-grained control:
- Bugs could be logged to a private internal repo.
- Feedback might go to a public or community-accessible submodule.
- Feature requests could be tracked openly so others can view and upvote them.
### Partial Override
Start with a shared repository for all form types, but selectively override one or two categories. Great for workflows where most issues can be public, but certain categories (like bugs) need privacy.
```swift
let overrideRepoConfig = PreviewFormConfig(
repository: .partial(
shared: Repository(
username: "markbattistella",
repository: "feedback-logger"
),
overrides: [
.bug: Repository(
username: "markbattistella",
repository: "bugs-internal"
)
]
)
)
```
Perfect when:
- Feedback and feature requests are sent to a public-facing repo.
- Bug reports go to a private, locked-down internal repo accessible only to your team.
## Validation
Before submission, `FormManager` checks the user's input for completeness and correctness. If validation fails, it throws a `FormValidationError`.
```swift
public struct FormValidationError: Error {
public let invalidFields: Set
}
```
Each invalid field is represented by a `FormField` enum, making it easy to highlight or handle specific errors in your UI.
Validation covers:
- **Title:** Cannot be empty or just whitespace.
- **Description:** Required, trimmed, and validated.
- **Contact Info:** Optional, but if enabled, both name and email must be valid.
- Email format is checked using a *very* basic regex pattern.
You can access validation state live via:
```swift
viewModel.isFormValid // Bool
```
Or if you wish to get the invalid fields for display you can access `fieldErrors`:
```swift
// example
if let error = viewModel.fieldErrors[.title] {
Text(error)
.font(.caption)
.foregroundColor(.red)
}
```
### HTTP Response Handling
When a form is submitted, the backend response is captured as a `FormResponse`, which conforms to `Error`.
```swift
public enum FormResponse: Error {
case badRequest // 400
case unauthorized // 401
case serverError // 500
case unexpectedError // any other failure
case successMessage // 200–299 success
}
```
## Backend System
While `FormLogger` is backend-agnostic, it's built to work beautifully with lightweight systems.
> [!CAUTION]
> The log file sent in the multipart form is GZIP-compressed and saved with a `.gz` extension. It must be decompressed on the backend using a GZIP-compatible decompression method.
### What I used
I've set mine up using:
- A GitHub App for API authentication
- A Cloudflare Worker to receive and forward form data
- Logs and metadata are submitted as a multipart form
> [!TIP]
> I wrote about setting this up for yourself - [part 1](https://markbattistella.com/writings/2025/rethinking-feedback-p1/), [part 2](https://markbattistella.com/writings/2025/rethinking-feedback-p2/), [part 3](https://markbattistella.com/writings/2025/rethinking-feedback-p3/), and [part 4](https://markbattistella.com/writings/2025/rethinking-feedback-p4/)
This lets me forward validated SwiftUI form data directly to GitHub as an issue — but you can use any backend that accepts JSON and logs.
## Contributing
Contributions are welcome! Please fork the repository and submit a pull request for any features, fixes, or improvements.
## License
`FormLogger` is available under the MIT license. See the LICENCE file for more information.