moov-io / customers Goto Github PK
View Code? Open in Web Editor NEWCustomer registry supporting Know Your Customer (KYC), Customer Identification Program (CIP), and OFAC checks
Home Page: https://moov.io
License: Apache License 2.0
Customer registry supporting Know Your Customer (KYC), Customer Identification Program (CIP), and OFAC checks
Home Page: https://moov.io
License: Apache License 2.0
We will need the option to debug accounts calls in Customers. This enhances our ability to debug calls for support issues.
Verifying addresses exist will come up as a feature to add into Customers. We would do this with several external API's as various customers will have existing deals with vendors and want to use them.
Edit: Lots of these services will support bulk API's, so would it be acceptable for Customers to check addresses in an async fashion? Does Customers need to re-check the address on some interval?
In #122 we added HolderName
to an Account
. This is a legal name of the account. Typically this varies from the Customer name in business
Customers - the holder name would be an individual and Customer name is their business.
We need to verify the holder name passes an OFAC check.
Now that Watchman 0.13.0 is released (renamed from OFAC) we'll need to update and rename the references in our code.
For CIP status validation we need to verify the SSN is valid and belongs to a living US citizen.
There's a government service for doing this: https://www.ssa.gov/employer/ssnv.htm
Issue: moov-io/paygate#169
Let's write a guide (with a docker-compose setup) for running Customers and Watchman locally. A few people are starting to use it and wanting to just run these two apps.
POST /customers/{customerID}/accounts/{accountID}/validate
Request:
{
"strategy": "instant"
}
Response:
{
"link_token":"link-sandbox-32771002-45e1-4f9b-93fd-f12442f8aa44",
"expiration":"2020-08-25T13:07:19Z"
}
User should add Plaid Link integration depending on their paltform. Here is example for web:
<html>
<body>
<button id="link-button">Verify Account with Plaid</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdn.plaid.com/link/v2/stable/link-initialize.js"></script>
<script type="text/javascript">
var handler;
// get link_token for Plaid Link
$.post('/verify', {}, function(data){
handler = Plaid.create({
token: data.link_token,
onSuccess: function(public_token) {
console.log("public token", public_token);
// send public_token to api to verify account
$.ajax({
type: "PUT",
url: "/verify",
data: {
public_token: public_token,
},
success: function(data) {
console.log("Verification result: ", data);
// it should return account with status: verified
},
});
},
});
});
$('#link-button').on('click', function(e) {
handler.open();
});
</script>
</body>
</html>
PUT /customers/{customerID}/accounts/{accountID}/validate
Request:
{
"strategy": "instant",
"public_token": "public-sandbox-59eb4718-93d8-41a0-a338-9d731d83e549"
}
Response:
{
"accountID": "e1b1544a",
"maskedAccountNumber": "0001027028",
"routingNumber": "051504597",
"status": "validated", // verified?
"type": "checking"
}
Customers Version: ``
What were you trying to do?
Trying to run tests in cmd/server/accounts/validator/mx/strategy_test.go
What did you expect to see?
Test passed
What did you see?
Test failed due to api creds issued by MX
How can we reproduce the problem?
Run the test cmd/server/accounts/validator/mx/strategy_test.go:TestStrategy
What were you trying to do?
Customers (this repository/service) gets confused with Customer (model) and multiple Customer objects (Customers) a bit too much. We need a better way to refer to this service vs the Customer model.
What did you expect to see?
A clear name for this service.
Options
What were you trying to do?
To deploy on OpenShift we need to use their base image. This allows a common setup for deployment, scanning, etc.
Also, publish the images to https://quay.io/, Red Hat’s image repository.
We should design a graphic or two for Customer's network calls. This will help quickly explain what's involved when running Customers.
Related to #99
For customer management, it'd be useful to extend the functionality of the GET /customers endpoint.
Consider having GET /customers
return a paginated list of results. My immediate need is for the sort order to be by date created.
For any paginated response, it's useful to know when you've hit the end of the series by either having the total count in the response or a marker on the response to signal the end.
We could do this in all sorts of ways, but typical REST might be something like
GET /customers?orderBy=createdAt&orderDirection=desc&limitTo=50
Also related, filtering the list of customers by status
and createdAt
(before or after), would be a solid start.
Customers Version: v0.5.0-dev
Now that Accounts have their own OFAC searches (on HolderName) they can be rejected for a positive match. We need to reject that account.
See the Customers flow.
https://github.com/moov-io/customers/blob/v0.5.0-dev2/cmd/server/approval_ofac.go#L139-L148
We will need the option to debug fed calls in Customers. This enhances our ability to debug calls for support issues.
I was wondering what implications the data stored in Customers has with GDPR. It's my understanding that if even one EU citizen uses our product we're supposed to comply with all of their regulations, which is pretty complicated to do. Any personal information is subject to deletion requests and must be only minimally collected.
type customerRequest struct {
FirstName string `json:"firstName"`
MiddleName string `json:"middleName"`
LastName string `json:"lastName"`
NickName string `json:"nickName"`
Suffix string `json:"suffix"`
BirthDate time.Time `json:"birthDate"`
Email string `json:"email"`
SSN string `json:"SSN"`
Phones []phone `json:"phones"`
Addresses []address `json:"addresses"`
Metadata map[string]string `json:"metadata"`
}
cc @wadearnold thoughts?
We need to support TLS in our HTTP server. This protects requests from inspection along the various network paths and routing. It's also required as part of several guidelines and audit requirements.
We need to support uploading and parsing documents (e.g. barcodes) to help verify a customer's identity. This typically includes Drivers Licenses (for legal name) and a utility bill (for addresses).
There will be generic blob storage on the backend for each document (with encryption, ideally on immutable storage).
Notes: #9
In the larger Moov cluster of services ACH Transfers need to have certain verification levels on Originators and Receivers. This status needs to be exposed as part of the Customer model so paygate (and others) can compare and reject unidentified Customers.
Notes: #9
Customers Version: master
What were you trying to do?
TestGetCustomersWithVerifiedStatus
on master
right now is a flakey test. It seems to fail without the mainline code changing.
https://github.com/moov-io/customers/pull/139/checks?check_run_id=1109215732 was failing because of this test
It seems the similar tests added at the same time can be flakey.
What did you expect to see?
Tests should only fail when the code is broken, not for flakey reasons.
How can we reproduce the problem?
$ go test ./cmd/server/ -count 100 -run TestGetCustomersWithVerifiedStatus -v
--- FAIL: TestGetCustomersWithVerifiedStatus (0.03s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x78 pc=0x4b0528d]
goroutine 55 [running]:
testing.tRunner.func1.1(0x4d78760, 0x5752bb0)
/usr/local/Cellar/go/1.15/libexec/src/testing/testing.go:1057 +0x30d
testing.tRunner.func1(0xc0000d6a80)
/usr/local/Cellar/go/1.15/libexec/src/testing/testing.go:1060 +0x41a
panic(0x4d78760, 0x5752bb0)
/usr/local/Cellar/go/1.15/libexec/src/runtime/panic.go:969 +0x175
github.com/moov-io/customers/cmd/server.TestGetCustomersWithVerifiedStatus(0xc0000d6a80)
/Users/adam/code/src/github.com/moov-io/customers/cmd/server/customer_search_test.go:200 +0x3ad
testing.tRunner(0xc0000d6a80, 0x4f4eef0)
/usr/local/Cellar/go/1.15/libexec/src/testing/testing.go:1108 +0xef
created by testing.(*T).Run
/usr/local/Cellar/go/1.15/libexec/src/testing/testing.go:1159 +0x386
FAIL github.com/moov-io/customers/cmd/server 0.127s
FAIL
What were you trying to do?
We need to support running Customer's HTTP servers with TLS for all communications. This is required for production installs and needs to be documented in our guides.
After templating we need to confirm this is documented.
KYC (wikipedia consists of collecting legal name, address, and date of birth from a customer and validating them to "sufficiently affirm" the existence of the customer and their ability to transfer funds.
KYC is required in order to process transactions for a human in the US and typically uses a Drivers license to validate.
Notes: #9
We need to allow and store an arbitrary map of ID's (salesforceId, etc) to centralize lookups and foreign key relationships. This helps integrate external services with this project by offering one location to store all relationships with a customer.
Notes: #9
Documents that a vendor or FI distribute may need to be acknowledged by each customer before money can be moved. Sometimes these documents are updated and require a re-ack.
We need to support this in Customers and have it presented in the same endpoint paygate (and others) use to read the current status/situation for a Customer.
Currently, all data is stored in SQLLite in memory. Customers and the event log should be configured to be stored in a restart persistent data stores such as MySQL or Postgres.
The response body for GET /customers/:customerID/documents
is an array of objects, but when there are no documents the response is null
instead of an empty array.
Receivers (in paygate) need to be periodically updated, so Customers should support refreshing the OFAC results for a given Customer object. Callers can use it in dashboards or on a schedule depending on their business logic.
When launching the test containers of Watchman all data files are downloaded. This causes problems if the files fail to download (e.g. periodic downtime).
Should watchman's docker image include data files from the time it was built? Watchman would still download them on the interval, but have an initial set.
Customers needs to send emails to validate Receivers by having them click a link. Also, we can use this setup for notifications and marketing later on.
What were you trying to do?
We need to convert Customers over to our templater which is used for all projects. This will help setup authn/z and a unified routing setup as our other apps have.
What did you expect to see?
A unified setup across all of our applications.
We need to store social security numbers (SSN) and they can only be stored encrypted. The Go CDK has support for "Secrets" which supports the main cloud provider systems or vault. We should support GCP, AWS, and Vault as a start.
This will be used with CIP status transitions (a valid SSN is required).
#5 has talked about needing more restrictive authz around some endpoints in the Customers app. Wade mentions
"We should probably limit the OAuth security scope for this action and the action should be logged. I see a "backend" application for approving these in the future."
We should look at using an existing solution like https://github.com/ory/oathkeeper or https://github.com/ory/hydra (not exactly sure the difference) instead of our home grown auth solution to limit these with users and groups.
There are several levels of identity verification of customers, they are (in order, case insensitive):
When we implement these it should be done with a type that can be compared (i.e. integers) so that KYC < CIP
and we can use comparisons like customer.IdentityVerification < KYC
in our codebase.
Notes: #9
We will need the option to debug paygate calls in Customers. This enhances our ability to debug calls for support issues.
With the changes to our auth stack we need to read a new header X-User
for the userID.
Had a meeting with @wadearnold on this project.
"Customer" meeting with Wade
- KYC is required before OFAC
- CIP: Customer Identification Program (for Banks and Fiancial Service companies)
- KYC (3 pieces) vs CIP (4 pieces w/ SSN)
- If we hold deposits for a customer then we need their SSN
- Validate legal name, address,
Originators need KYC and OFAC
Receivers need OFAC checks (think about allowing KYC on them too)
Allow arbitrary map of ID's (salesforceId, etc) to centralize lookups and foreign key relationships
KYC / CIP are 'affirmative' (reasonably sure) whereas OFAC is a negative match (rejection)
Identity Verification of Customer
- Rejected (level 0)
- ReviewRequired (level 1)
- None (level 2)
- OFAC Only (Run check on data I give) (level 3)
- KYC: (3 pieces of info, with workflow that verifies each) (level 4)
- legal name, address, and date of birth
- CIP: (4 pieces, with SSN) (level 5)
- pull credit check with SSN (verify DoB, address, etc)
- required to hold deposits
- require drivers license
Auth (in Customer model) might not be restricted to one Customer
- think teller or internal employee
Profile photos (driver license) are hidden to avoid discrimination.
Documents: DriversLicense (Legal name) and Utility Bill (Address)
Wade started on an endpoint for creating a Customer, which is a good start. We should consolidate the GL Customer model and related meta-objects and move them into this project.
Also, there's an Apache project that offers similar models.
Customers Version: master
Right now I see ./client
and ./pkg/client
in the project. We converted to ./pkg/client
so I'm not sure if ./client
was from a bad merge, but we should clean it up.
https://github.com/moov-io/customers/tree/master/client
https://github.com/moov-io/customers/tree/master/pkg/client
Also, let's regenerate and push any unstaged changes as a result of this.
We need to keep models isolated and have previously done this with X-User-ID
. This is often confused a bit with "users" in terms of auth or something, but instead we're going to namespace on X-Namespace
. The updated naming removes an unintended connection with an auth stack.
We will need the option to debug watchman calls in Customers. This enhances our ability to debug calls for support issues.
Today I can input the same routing number, account number and type combination for a customer. Should our service allow this? Would erroring expose too much information about a customer and account within Moov? (presumably you could get the full account number with the same authorization)
My worry of duplicate accounts is then needing to build functionality to merge the accounts together to make reporting on transaction history meaningful.
TODO: some docs/notes on parsing PDF417 barcodes (which are common on the back of a drivers license)
Issue: moov-io/paygate#169
As part of a Customer's related data needs to be beneficiary information. This would be a name and contact point (email, phone) which can be used in the event of a Customers death.
When we create a customer let's check OFAC and store that result for use later (when we try and Verify a customer to OFAC or higher). It doesn't need to be part of the HTTP endpoint and if it fails the later status will require a new lookup.
This repo is missing a contributing guide referenced in the README
.
Customers Version: v0.5.0-dev
What were you trying to do?
When uploading a document that file is not encrypted. These files can contain PII and should be encrypted at rest.
What did you expect to see?
Data should be protected and encrypted at rest.
You can't mount the sqlite file customers.db from within a docker container, as it outputs to the root directory. It should probably output to "/data/" just like Paygate.
This is a nit pick, but when updating the status of an account directly from the status endpoint, the response is a 200
but it does not include a body. A 204
would be preferred so frontend client code doesn't try to response.json()
an empty response OR include a body in the response.
We need to support searching all Customer
records stored in the database. This allows the UI and other programs to find records. Creating transfers can occur well after the initial creation and UI's / services will need to relocate the correct customerID
to use.
Initially I'm thinking of the following endpoint with a bunch of query params.
GET /customers
?name=<string>
(optional) used and split across first/last names, returns fuzzy results?email=<string>
(optional) exact match (with .
's removed)?type=<string>
(optional) individual
and business
filterThoughts @InfernoJJ and @joshsadler ?
Disclaimers are agreements between an FI and customer. They can deliver information or serve as acknowledgement of terms and conditions for money transfers.
For example, used in moov-io/paygate#98
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.