- Introduction
- Architecture
- Data Model
- API Documentation
- Codebase
- Deployment / Installation
- Conclusion
Pawsitively Purrfect is a project aimed at providing an online platform for pet adoption. This platform is designed to help pet lovers find their perfect furry companions while also providing a way for animal shelters and rescue organizations to showcase their available pets.
The "Pawsitively Purrfect" platform provides a user-friendly interface for browsing pets based on different search criteria such as pet type, breed, location, and more. Users can view detailed information about each pet and contact the pet's owner or the organization responsible for its care.
In addition to helping pets find their forever homes, "Pawsitively Purrfect" also provides a way for animal shelters to manage their available pets and adoption applications. With this platform, they can easily add new pets, update pet information, and track adoption applications.
The System consists of three major Components mainly.
- Backend Server: The backend server is built using Golang and GraphQL, with the Flamego web framework. It consists of multiple layers, including:
- Resolver: Handles incoming GraphQL queries and mutations, and maps them to specific service functions.
- Service: Implements business logic and interacts with repositories.
- Repository:: Provides an abstraction layer between the service layer and the database layer.
- Databases: The system uses both NoSQL and SQL databases. ArangoDB is used as a NoSQL database, and Postgres is used as a SQL database, implemented using gRPC.
- Frontend: The frontend is built using Tailwind CSS and includes basic pages such as login, register, and profile pages.
The system uses a layered architecture that separates concerns and ensures loose coupling between the different components. It includes the following layers:
- Frontend: The frontend layer provides the user interface for the system and the main interface is yet to be built.
- GraphQL API: The GraphQL API layer handles incoming requests from the frontend and translates them into queries and mutations that can be executed by the backend.
- Resolver: The resolver layer maps the incoming GraphQL requests to their corresponding service methods.
- Service: The service layer contains the business logic of the system and performs the necessary operations on the data.
- Repository: The repository layer provides an abstraction layer over the database and handles the storage and retrieval of data.
- Database: The database layer stores the data used by the system and is responsible for ensuring its consistency and integrity.
This layered architecture enables the system to be easily extensible and maintainable, as changes to one layer do not affect the others.
Data flows through our system as follows:
- The frontend client sends a request to the backend server using GraphQL.
- The request is received by the GraphQL API layer, which validates and parses the request.
- The request is then passed to the resolver layer, which maps the request to the corresponding service methods.
- The service layer contains the business logic of the system and performs the necessary operations on the data.
- The repository layer provides an abstraction layer over the database and handles the storage and retrieval of data.
- The database layer stores the data used by the system and is responsible for ensuring its consistency and integrity.
- The requested data is retrieved from the database and returned to the service layer.
- The service layer processes the data and returns the response to the resolver layer.
- The resolver layer maps the response to the GraphQL schema and returns it to the GraphQL API layer.
- The GraphQL API layer sends the response back to the frontend client.
The "Pawsitively Purrfect" project uses a relational data model to store information about users, pets, shelters, and pet adoptions. There's also option to use NoSQL type database instead of SQL type database.
There are four main entities in the data model: User, Pet, Shelter, and Pet Adoption. The entities have various attributes that define them, and have different relationships between them.
Here's a breakdown of the different entities and their relationships:
-
User Entity:
The User entity represents the users of the platform. User has various attributes such as their full name, email, username, location etc. Each User can adopt multiple Pets from a Shelter which is also owned by a User. -
Shelter Entity:
The Shelter entity represents the shelters on the platform. Shelter has various attributes such as its name, description, contact information etc. Each shelter can have only one owner, represented by the OwnerID attribute. Each shelter can own multiple pets. -
Pet Entity:
The Pet entity represents the pets on the platform. Pet has various attributes such as its name, type, breed, adoption status etc. The AdoptionStatus attribute represents whether the pet is available for adoption or has already been adopted. Each pet belongs to one shelter, represented by the ShelterID attribute. However, a pet can be adopted by a user, which is represented by a PetAdoption record. -
PetAdoption Entity:
The PetAdoption entity represents the adoption of pets by users. Each PetAdoption record has a unique ID and is associated with a specific pet and a specific user.
JSON Schemas for the entities used in the "Pawsitively Purrfect" project:
User:
{
"type": "object",
"properties": {
"id": {"type": "string"},
"firstName": {"type": "string"},
"lastName": {"type": "string"},
"bio": {"type": "string"},
"location": {"type": "string"},
"avatar": {"type": "string"},
"username": {"type": "string"},
"email": {"type": "string"},
"passwordHash": {"type": "string"},
"isActive": {"type": "boolean"},
"isAdmin": {"type": "boolean"},
"createdUnix": {"type": "integer"},
"updatedUnix": {"type": "integer"},
"lastLoginUnix": {"type": "integer"}
}
}
Shelter:
{
"type": "object",
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"description": {"type": "string"},
"website": {"type": "string"},
"location": {"type": "string"},
"contactInformation": {"type": "string"},
"logo": {"type": "string"},
"numberOfPets": {"type": "integer"},
"ownerID": {"type": "string"}
}
}
Pet:
{
"type": "object",
"properties": {
"id": {"type": "string"},
"name": {"type": "string"},
"type": {"type": "string"},
"breed": {"type": "string"},
"gender": {"type": "string"},
"photo": {"type": "string"},
"adoptionStatus": {"type": "string"},
"shelterID": {"type": "string"}
}
}
PetAdoption:
{
"type": "object",
"properties": {
"id": {"type": "string"},
"petID": {"type": "string"},
"userID": {"type": "string"}
}
}
And here's an example of some sample data that could be inserted into these tables:
User:
ID | FirstName | LastName | Bio | Location | Avatar | Username | PasswordHash | IsActive | IsAdmin | CreatedUnix | UpdatedUnix | LastLoginUnix | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | John | Doe | I love dogs! | New York, NY | john.jpg | johnd | john@pawsshelter.com | 1234567890 | true | false | 1620187800 | 1620187800 | 1620187800 |
2 | Jane | Smith | I am a cat lover! | Los Angeles, CA | jane.jpg | janes | jane@furryfriends.org | 0987654321 | true | false | 1620187800 | 1620187800 | 1620187800 |
3 | Bob | Johnson | I love all animals! | Seattle, WA | bob.jpg | bobj | bob@happytailsrescue.org | 1357908642 | true | true | 1620187800 | 1620187800 | 1620187800 |
Shelter:
ID | Name | Description | Website | Location | ContactInformation | Logo | NumberOfPets | OwnerID |
---|---|---|---|---|---|---|---|---|
1 | PAWS | Animal rescue organization | www.pawsshelter.com | New York, NY | contact@pawsshelter.com | pawsshelterlogo.jpg | 100 | 1 |
2 | Furry Friends | Purrfect home for your furry friends | www.furryfriends.org | Los Angeles, CA | contact@furryfriends.org | furryfriendslogo.jpg | 75 | 2 |
3 | Happy Tails | Helping pets find their forever homes | www.happytailsrescue.org | Seattle, WA | contact@happytailsrescue.org | happytailslogo.jpg | 50 | 3 |
Pet:
ID | Name | Type | Breed | Gender | Photo | AdoptionStatus | ShelterID |
---|---|---|---|---|---|---|---|
1 | Max | Dog | Labrador Retriever | Male | maxphoto.jpg | Available | 1 |
2 | Bella | Cat | Siamese | Female | bellaphoto.jpg | Adopted | 1 |
3 | Lucy | Dog | Bulldog | Female | lucyphoto.jpg | Available | 2 |
4 | Simba | Cat | Maine Coon | Male | simbaphoto.jpg | Available | 2 |
5 | Charlie | Dog | Golden Retriever | Male | charliephoto.jpg | Adopted | 3 |
PetAdoption:
ID | PetID | UserID |
---|---|---|
1 | 2 | 1 |
2 | 5 | 2 |
3 | 3 | 1 |
The Pawsitively Purrfect is a GraphQL server that provides a set of endpoints for managing users, pets, shelters, and pet adoptions. The API allows clients to query and mutate data using a single GraphQL endpoint.
The Pawsitively Purrfect API has the following endpoints:
The server some Rest APIs to view the website documentation, login, register and view profile page from UI.
-
/docs
- Serves the GraphQL documentation -
/user/login
- Serves Login Page -
/user/register
- Serves Registration Page -
/logout
- Logout page -
/{name}
- User profile page
-
/graphql
- The main endpoint for the GraphQL server. -
You can find the full GraphQL documentation in pawsitively-purrfect.tiiny.site.
Project Structures:
- .github/
- workflows/
- ci.yml
- release.yml
- api/
- graphql/
- resolvers/
- resolver.go
- pet.go
- shelter.go
- user.go
- schema/
- params.go
- schema.go
- http/
- handlers/
- graphql.go
- user.go
- middlewares/
- auth.go
- context.go
- rate_limit.go
- session_csrf.go
- routes.go
- cmd/
- config.go
- root.go
- serve.go
- grpc.go
- configs/
- .pawsitively-purrfect.yaml
- config.go
- infra/
- database/
- nosql/
- arangodb/
- arangodb.go
- mongodb/
- mock/
- mock.go
- database.go
- sql/
- postgres/
- pb/
- postgres_grpc.pb.go
- posgres.pb.go
- server/
- postgres.go
- health.go
- table_sync.go
- database.go
- logr/
- logger.go
- models/
- gqtypes/
- pet.go
- shelter.go
- types.go
- user.go
- pet_adoption.go
- errors.go
- pet.go
- shelter.go
- user.go
- pet_adoption.go
- pkg/
- decode.go
- hash.go
- path.go
- proto/
- database/
- postgres.proto
- repos/
- pet/
- pet.go
- pet_mock.go
- shelter/
- shelter.go
- shelter_mock.go
- user/
- user.go
- user_mock.go
- pet_adoption/
- pet_adoption.go
- pet_adoption_mock.go
- pet.go
- shelter.go
- user.go
- pet_adoption.go
- services/
- all/
- all.go
- pet/
- pet.go
- shelter/
- shelter.go
- user/
- user.go
- pet.go
- shelter.go
- user.go
- templates/
- images/
- logo/
- docs.tmpl
- login.tmpl
- register.tmpl
- profile.tmpl
- templates.go
- main.go
- docker-compose.yml
- Dockerfile
- Makefile
- README.md
We can use either ArangoDB (NoSQL) or Postgres (SQL) as database backend for the Pawsitively Purrfect
Application.
The postgres database layer is served with gRPC server. So, if we wish to use Postgres as our database, we will have to run an extra gRPC server to serve the Postgres db.
For local development mode, we first have to clone the repository from Github.
- Clone the repository
$ mkdir -p $HOME/go/src/github.com/masudur-rahman $ git clone git@github.com:masudur-rahman/pawsitively-purrfect.git $ cd pawsitively-purrfect
- To get the best experience with the login consistency, Run the following command
$ sudo echo '127.0.0.1 pawsitively.purrfect' >> /etc/hosts
- Run the
Pawsitively Purrfect
Application
We can start the server following either of the following processes.- Running without gRPC server
$ make run $ # It actually runs `docker compose up` command $ # ArangoDB is used as the database
- Running with gRPC server
$ make run-with-grpc $ # It actually runs `docker compose up --file docker-compose-grpc.yml $ # Postgres is used as thye database but the postgres is served through a gRPC server
Pawsitively Purrfect
application should be up and running. To access it head out to http://pawsitively.purrfect:62783 - Running without gRPC server
To deploy Pawsitively Purrfect
applicaiton in production environment, the preferred way is through Helm Chart.
First you need to add the repo for the helm chart.
$ helm repo add masud https://masudur-rahman.github.io/helm-charts/stable
$ helm repo update
$ helm search repo masud/pawsitively-purrfect
Just like running application in local environment, we have two installation procedures here too.
-
Installing without gRPC server
$ helm upgrade --install pawsitively-purrfect masud/pawsitively-purrfect -n purrfect --create-namespace
-
Installing with gRPC server
$ helm upgrade --install pawsitively-purrfect masud/pawsitively-purrfect -n purrfect \ --create-namespace --set grpc.enabled=true
-
Verify Installation To check if
Pawsitively Purrfect
is installed, run the following command:$ kubectl get pods -n purrfect -l "app.kubernetes.io/instance=pawsitively-purrfect" NAME READY STATUS RESTARTS AGE pawsitively-purrfect-698f968b44-d5mt6 1/1 Running 0 15s pawsitively-purrfect-arangodb-78db5b45bf-2wklw 1/1 Running 0 10s
To see the detailed configuration options, visit here.
The Pawsitively Purrfect
is a GraphQL API written in Go that provides pet adoption functionalities such as creating and updating pet profiles, managing pet adoption applications, and enabling communication between adopters and shelter staff.
The API uses either ArangoDB or Postgres as its database backend and can be run with or without a gRPC server.
In the future, the application can be further improved by adding support for must columns in SQL database implementations, which will allow updating columns with zero values. Additionally, more queries and mutations can be added to the API to enhance its functionalities further. Finally, a frontend can be developed to provide a user-friendly interface for interacting with the API.