{"id":13983662,"url":"https://github.com/benbjohnson/wtf","last_synced_at":"2025-05-15T23:03:27.835Z","repository":{"id":43805487,"uuid":"311804365","full_name":"benbjohnson/wtf","owner":"benbjohnson","description":"WTF Dial is an example web application written in Go.","archived":false,"fork":false,"pushed_at":"2022-10-31T16:04:13.000Z","size":2969,"stargazers_count":1790,"open_issues_count":5,"forks_count":114,"subscribers_count":27,"default_branch":"main","last_synced_at":"2025-05-15T23:02:54.033Z","etag":null,"topics":["application","go"],"latest_commit_sha":null,"homepage":"https://wtfdial.com/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/benbjohnson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-10T22:55:10.000Z","updated_at":"2025-05-13T22:38:50.000Z","dependencies_parsed_at":"2022-08-12T10:50:23.804Z","dependency_job_id":null,"html_url":"https://github.com/benbjohnson/wtf","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benbjohnson%2Fwtf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benbjohnson%2Fwtf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benbjohnson%2Fwtf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benbjohnson%2Fwtf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benbjohnson","download_url":"https://codeload.github.com/benbjohnson/wtf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254436944,"owners_count":22070946,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["application","go"],"created_at":"2024-08-09T05:01:50.751Z","updated_at":"2025-05-15T23:03:27.815Z","avatar_url":"https://github.com/benbjohnson.png","language":"Go","readme":"WTF Dial ![GitHub release](https://img.shields.io/github/v/release/benbjohnson/wtf) ![test](https://github.com/benbjohnson/wtf/workflows/test/badge.svg) ![deploy](https://github.com/benbjohnson/wtf/workflows/deploy/badge.svg)\n========\n\nThis project provides a real-time dashboard for teams to view how f-cked up they \ncurrently are. Each team member provides input to specify the level at which\nthey feel the team is currently messed up. These values range from 0% (meaning\nteam feels there are no WTF situations) to 100% (meaning the members feel the\nteam is completely f-cked).\n\nThe idea for this came from [Peter Bourgon's tweets][tweets].\n\n[tweets]: https://twitter.com/peterbourgon/status/765935213507649537\n\n\n## How to use this repository\n\nThis repository was built to help others learn how to build a fully functioning\nGo application. It can be used in several ways:\n\n1. As a reference—the code is well documented. Honestly, too documented for most\n   projects but the goal here is to be as clear as possible for anyone reading\n   the code.\n\n2. As a walkthrough—companion blog posts will be added to the [Go Beyond](https://www.gobeyond.dev/)\n   web site that walk through the various parts of the application and explain the design choices.\n   You can find the initial blog post here: https://www.gobeyond.dev/wtf-dial/\n   \n3. Ask questions in the [GitHub Discussions](https://github.com/benbjohnson/wtf/discussions) board.\n\nYou can also see the project structure overview below to get a quick overview\nof the application structure.\n\n\n## Project structure\n\nThe `wtf` project organizes code with the following approach:\n\n1. Application domain types go in the root—`User`, `UserService`, `Dial`, etc.\n2. Implementations of the application domain go in subpackages—`sqlite`, `http`, etc.\n3. Everything is tied together in the `cmd` subpackages—`cmd/wtf` \u0026 `cmd/wtfd`.\n\n\n### Application domain\n\nThe application domain is the collection of types which define what your\napplication does without defining how it does it. For example, if you were to\ndescribe what WTF Dial does to a non-technical person, you would describe it in\nterms of _Users_ and _Dials_.\n\nWe also include interfaces for managing our application domain data types which\nare used as contracts for the underlying implementations. For example, we define\na `wtf.DialService` interface for CRUD (Create/Read/Update/Delete) actions and\nSQLite does the actual implementation.\n\nThis allows all packages to share a common understanding of what each service\ndoes. We can swap out implementations, or more importantly, we can layer\nimplementations on top of one another. We could, for example, add a Redis\ncaching layer on top of our database layer without having the two layers know\nabout one another as long as they both implement the same common interface.\n\n\n### Implementation subpackages\n\nMost subpackages are used as an adapter between our application domain  and the\ntechnology that we're using to implement the domain. For example,\n`sqlite.DialService` implements the `wtf.DialService` using SQLite.\n\nThe subpackages generally should not know about one another and should\ncommunicate in terms of the application domain.\n\nThese are separated out into the following packages:\n\n- `http`—Implements services over HTTP transport layer.\n- `inmem`—Implements in-memory event listener service \u0026 subscriptions.\n- `sqlite`—Implements services on SQLite storage layer.\n\nThere is also a `mock` package which implements simple mocks for each of the\napplication domain interfaces. This allows each subpackage's unit tests to share\na common set of mocks so layers can be tested in isolation.\n\n\n### Binary packages\n\nThe implementation subpackages are loosely coupled so they need to be wired\ntogether by another package to actually make working software. That's the job\nof the `cmd` subpackages which produce the final binary.\n\nThere are two binaries:\n\n- `wtfd`—the WTF server\n- `wtf`—the client CLI application\n\nEach of these binaries collect the services together in different ways depending\non the use case.\n\nThe `wtfd` server binary creates a `sqlite` storage layer and adds the `http`\ntransport layer on top. The `wtf` client binary doesn't have a storage layer.\nIt only needs the client side `http` transport layer.\n\nThe `cmd` packages are ultimately the interface between the application domain\nand the operator. That means that configuration types \u0026 CLI flags should live\nin these packages.\n\n\n### Other packages\n\nA few smaller packages don't fall into the organization listed above:\n\n- `csv`—implements a `csv.DialEncoder` for encoding a list of Dial objects to\n  a writer using the CSV format.\n- `http/html`-groups together HTML templates used by the `http` package.\n\n\n\n## Development\n\nYou can build `wtf` locally by cloning the repository, then run:\n\n```sh\n$ make \n$ go install ./cmd/...\n```\n\nThe `wtfd` server uses GitHub for authentication so you'll need to [create a new\nGitHub OAuth App](https://github.com/settings/applications/new). Set the value\nof the authorization callback URL to `http://HOST[:PORT]/oauth/github/callback`,\nwhere `HOST[:PORT]` is the host name or IP address at which clients can access\nthe `wtfd` server, with an optional port number (e.g. `localhost:3000` when\nrunning locally).\n\nNext, you'll need to setup a configuration file in `~/wtfd.conf`:\n\n```toml\n[github]\nclient-id     = \"00000000000000000000\"\nclient-secret = \"0000000000000000000000000000000000000000\"\n\n[http]\naddr      = \":3000\"\nblock-key = \"0000000000000000000000000000000000000000000000000000000000000000\"\nhash-key  = \"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"\n```\n\nReplace the GitHub `client-id` \u0026 `client-secret` with the values from the\nGitHub OAuth application you registered.\n\nThe `[http]` section can be left as-is for a local environment. The key fields\nneed random hex values for generating secure cookies but all zeros is ok for\nlocal testing.\n\nFinally, run the `wtfd` server and open the web site at [`http://localhost:3000`](http://localhost:3000):\n\n```\n$ $GOPATH/bin/wtfd\n```\n\n\n### Storybook\n\nThe `wtf-storybook` binary allows you to test UI views with prepopulated data.\nThis can make it easier to quickly test certain scenarios without needing to \nset up your backend database.\n\nTo run storybook, simply build it and run it:\n\n```sh\n$ go install ./cmd/wtf-storybook\n$ wtf-storybook\nListening on http://localhost:3001\n```\n\nTo add a new view, add an entry to the `routes` variable:\n\n```go\nvar routes = []*Route{\n\t// Show dial listing when user has no dials.\n\t{\n\t\tName: \"Dial listing with data\",\n\t\tPath: \"/dials-with-no-data\",\n\t\tRenderer: \u0026html.DialIndexTemplate{\n\t\t\tDials: []*wtf.Dial{},\n\t\t},\n\t},\n}\n```\n\nThen navigate to https://localhost:3001 and you'll see it displayed in the list.\n\n\n### SQLite\n\nBy default, the SQLite tests run against in-memory databases. However, you can\nspecify the `-dump` flag for the tests to write data out to temporary files. This\nworks best when running against a single test.\n\n```sh\n$ go test -run=MyTest -dump ./sqlite\nDUMP=/tmp/sy9j7nks0zq2vr4s_nswrx8h0000gn/T/375403844/db\n```\n\nYou can then inspect that database using the `sqlite3` CLI to see its contents.\n\n\n## Contributing\n\nThis application is built for educational purposes so additional functionality\nwill likely be rejected. Please feel free to submit an issue if you're\ninterested in seeing something added. Please do not simply submit a pull request.\n\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenbjohnson%2Fwtf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenbjohnson%2Fwtf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenbjohnson%2Fwtf/lists"}