{"id":23095200,"url":"https://github.com/pauluswi/tulip","last_synced_at":"2025-10-15T05:19:20.467Z","repository":{"id":215762385,"uuid":"444726479","full_name":"pauluswi/tulip","owner":"pauluswi","description":"Is a microservice which provides payment token service.","archived":false,"fork":false,"pushed_at":"2022-01-11T02:11:18.000Z","size":3592,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-03T19:34:01.197Z","etag":null,"topics":["ewallet","fintech","go","golang","jwt","microservice","payment","tokenization"],"latest_commit_sha":null,"homepage":"","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/pauluswi.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-05T08:38:31.000Z","updated_at":"2022-02-17T06:21:12.000Z","dependencies_parsed_at":null,"dependency_job_id":"bf735dc6-c46c-4a68-9629-c5fb7dd8f650","html_url":"https://github.com/pauluswi/tulip","commit_stats":null,"previous_names":["pauluswi/tulip"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pauluswi/tulip","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pauluswi%2Ftulip","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pauluswi%2Ftulip/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pauluswi%2Ftulip/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pauluswi%2Ftulip/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pauluswi","download_url":"https://codeload.github.com/pauluswi/tulip/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pauluswi%2Ftulip/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279053099,"owners_count":26094046,"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","status":"online","status_checked_at":"2025-10-15T02:00:07.814Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ewallet","fintech","go","golang","jwt","microservice","payment","tokenization"],"created_at":"2024-12-16T22:19:55.147Z","updated_at":"2025-10-15T05:19:20.409Z","avatar_url":"https://github.com/pauluswi.png","language":"Go","readme":"# Tulip\n\nIs a microservice which provides payment token service for application users.\n\n![Build](https://github.com/pauluswi/tulip/actions/workflows/build.yml/badge.svg)\n[![codecov](https://codecov.io/gh/pauluswi/tulip/branch/master/graph/badge.svg)](https://codecov.io/gh/pauluswi/tulip)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n\n## Description\n\nA transactional-based token usually used for transactions at merchant or retail store such as purchasing goods and use ewallet as a payment method. The customer's ewallet app will produce a payment token and merchant can use it to initiate payment processing.\n\n![](2022-01-09-09-02-36.png)\n\nTulip will provide payment token service like generate a transaction-based token, validate the token and query all payment tokens based on customer ID. This token can be used for one specific transaction only. The token format is 6 digit of numeric data type and has an expiration date time. To secure data transmission between parties, we use JSON Web Token (JWT) Authentication.\n\n## Project Layout\n\nTulip uses the following project layout:\n\n```\n.\n├── cmd                  main applications of the project\n│   └── server           the API server application\n├── config               configuration files for different environments\n├── internal             private application and library code\n│   ├── paytoken         payment token-related features\n│   ├── auth             authentication feature\n│   ├── config           configuration library\n│   ├── entity           entity definitions and domain logic\n│   ├── errors           error types and handling\n│   ├── healthcheck      healthcheck feature\n│   └── test             helpers for testing purpose\n├── migrations           database migrations\n├── pkg                  public library code\n│   ├── accesslog        access log middleware\n│   ├── graceful         graceful shutdown of HTTP server\n│   ├── log              structured and context-aware logger\n│   └── pagination       paginated list\n└── testdata             test data scripts\n```\n\nThe top level directories `cmd`, `internal`, `pkg` are commonly found in other popular Go projects, as explained in\n[Standard Go Project Layout](https://github.com/golang-standards/project-layout).\n\nWithin `internal` and `pkg`, packages are structured by features in order to achieve the so-called\n[screaming architecture](https://blog.cleancoder.com/uncle-bob/2011/09/30/Screaming-Architecture.html). For example,\nthe `paytoken` directory contains the application logic related with the payment token feature.\n\nWithin each feature package, code are organized in layers (API, service, repository), following the dependency guidelines\nas described in the [clean architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html).\n\n# Getting Started\n\n```shell\n# download the repo\ngit clone https://github.com/pauluswi/tulip.git\n\ncd tulip\n\n# start a PostgreSQL database server in a Docker container\nmake db-start\n\n# seed the database with some test data\nmake testdata\n\n# run the RESTful API server\nmake run\n```\n\nAt this time, you have a RESTful API server running at `http://127.0.0.1:8080`.\nIt provides the following endpoints:\n\n- `GET /healthcheck`: a healthcheck service provided for health checking purpose (needed when implementing a server cluster)\n- `POST /v1/login`: authenticates a user and generates a JWT\n- `POST /v1/generate`: generate a 6 digit of numeric token\n- `POST /v1/validate`: validate the token whether still valid and not expired\n- `GET /v1/getpaytokens/:customer_id`: return all payment(s) token belong to a customer\n\nTry the URL `http://localhost:8080/healthcheck` in a browser, and you should see something like `\"OK v1.0.0\"` displayed.\n\nIf you have `cURL` or some API client tools (e.g. [Postman](https://www.getpostman.com/)), you may try the following\nmore complex scenarios:\n\n```shell\n# authenticate the user via: POST /v1/login\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"username\": \"demo\", \"password\": \"pass\"}' http://localhost:8080/v1/login\n# should return a JWT token like: {\"token\":\"...JWT token here...\"}\n\n# with the above JWT token, access the album resources, such as: GET /v1/xxx\n# start example\ncurl -X GET -H \"Authorization: Bearer ...JWT token here...\" http://localhost:8080/v1/xxx\n# end example\n\n# with the above JWT token, hit a endpoint to generate a payment token\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"customer_id\": \"08110001\"}' -H \"Authorization: Bearer ...JWT token here...\" http://localhost:8080/v1/generate\n\n# with the above JWT token, hit a endpoint to validate a payment token\ncurl -X POST -H \"Content-Type: application/json\" -d '{\"token\": \"343758\"}' -H \"Authorization: Bearer ...JWT token here...\" http://localhost:8080/v1/validate\n\n# with the above JWT token, hit a endpoint to get all payment token for a specific customer\ncurl -X GET -H \"Authorization: Bearer ...JWT token here...\" http://localhost:8080/v1/getpaytokens/\u003ccustomerid\u003e\n\n```\n\n## Updating Database Schema\n\nWe use [database migration](https://en.wikipedia.org/wiki/Schema_migration) to manage the changes of the\ndatabase schema over the whole project development phase. The following commands are commonly used with regard to database\nschema changes:\n\n```shell\n# Execute new migrations made by you or other team members.\n# Usually you should run this command each time after you pull new code from the code repo.\nmake migrate\n\n# Create a new database migration.\n# In the generated `migrations/*.up.sql` file, write the SQL statements that implement the schema changes.\n# In the `*.down.sql` file, write the SQL statements that revert the schema changes.\nmake migrate-new\n\n# Revert the last database migration.\n# This is often used when a migration has some issues and needs to be reverted.\nmake migrate-down\n\n# Clean up the database and rerun the migrations from the very beginning.\n# Note that this command will first erase all data and tables in the database, and then\n# run all migrations.\nmake migrate-reset\n```\n\n## Managing Configurations\n\nThe application configuration is represented in `internal/config/config.go`. When the application starts,\nit loads the configuration from a configuration file as well as environment variables. The path to the configuration\nfile is specified via the `-config` command line argument which defaults to `./config/local.yml`. Configurations\nspecified in environment variables should be named with the `APP_` prefix and in upper case. When a configuration\nis specified in both a configuration file and an environment variable, the latter takes precedence.\n\nThe `config` directory contains the configuration files named after different environments. For example,\n`config/local.yml` corresponds to the local development environment and is used when running the application\nvia `make run`.\n\nDo not keep secrets in the configuration files. Provide them via environment variables instead. For example,\nyou should provide `Config.DSN` using the `APP_DSN` environment variable. Secrets can be populated from a secret\nstorage (e.g. HashiCorp Vault) into environment variables in a bootstrap script (e.g. `cmd/server/entryscript.sh`)\n\n## Unit Testing and Its Coverage\n\nFor testability purpose, unit testings are provided.\nWe can use golang test package.\n\n```shell\n$ go test -v internal/paytoken/*.go -race -coverprofile=coverage.out\n=== RUN   TestAPI\n=== RUN   TestAPI/get_all\n=== RUN   TestAPI/get_unknown\n=== RUN   TestAPI/generate_ok\n=== RUN   TestAPI/generate_auth_error\n=== RUN   TestAPI/generate_input_error\n=== RUN   TestAPI/validate_ok\n=== RUN   TestAPI/validate_auth_error\n=== RUN   TestAPI/validate_input_error\n--- PASS: TestAPI (0.00s)\n    --- PASS: TestAPI/get_all (0.00s)\n    --- PASS: TestAPI/get_unknown (0.00s)\n    --- PASS: TestAPI/generate_ok (0.00s)\n    --- PASS: TestAPI/generate_auth_error (0.00s)\n    --- PASS: TestAPI/generate_input_error (0.00s)\n    --- PASS: TestAPI/validate_ok (0.00s)\n    --- PASS: TestAPI/validate_auth_error (0.00s)\n    --- PASS: TestAPI/validate_input_error (0.00s)\n=== RUN   TestRepository\n--- PASS: TestRepository (0.16s)\n=== RUN   Test_service_TokenCycle\n--- PASS: Test_service_TokenCycle (0.00s)\nPASS\ncoverage: 78.1% of statements\nok      command-line-arguments  0.671s  coverage: 78.1% of statements\n```\n\n## Deployment\n\nThe application can be run as a docker container. You can use `make build-docker` to build the application\ninto a docker image. The docker container starts with the `cmd/server/entryscript.sh` script which reads\nthe `APP_ENV` environment variable to determine which configuration file to use. For example,\nif `APP_ENV` is `qa`, the application will be started with the `config/qa.yml` configuration file.\n\nYou can also run `make build` to build an executable binary named `server`. Then start the API server using the following\ncommand,\n\n```shell\n./server -config=./config/prod.yml\n```\n\n## Reference\n\nGo RESTful API (Boilerplate)\nhttps://github.com/qiangxue/go-rest-api\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpauluswi%2Ftulip","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpauluswi%2Ftulip","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpauluswi%2Ftulip/lists"}