A Human Resource Information System designed for pharmacy operations, built with Go and PostgreSQL.
- Employee Management: Track employee information, shift fees, and attendance visibility
- Work Log Tracking: Record detailed work logs with multiple work types and patient information
- Attendance System: Monitor daily attendance with configurable attendance types
- Salary Calculation: Comprehensive salary management with three component types:
- Static components (recurring monthly)
- Additional components (one-time per month)
- Dynamic components (calculated from work logs and attendance)
- Salary Snapshots: Preserve historical salary data for record-keeping
- RESTful API: Clean HTTP API with JSON responses
- Go 1.25.0 or higher
- PostgreSQL 12 or higher
- Jujutsu (jj) for version control
- Clone the repository:
jj git clone <repository-url>
cd apotek-hris- Install dependencies:
go mod download- Set up configuration files:
cp config/config.example.yaml config/config.yaml
cp config/secret.example.yaml config/secret.yaml- Edit configuration files with your database credentials and server settings.
Configuration is split across two files:
config/config.yaml - General configuration:
database:
host: localhost
port: 5432
db_name: apotek_hris
ssl_mode: disable
server:
port: 8080
host: 0.0.0.0config/secret.yaml - Sensitive credentials:
database:
user: your_db_user
password: your_db_passwordConfiguration can be overridden using environment variables.
- Create a PostgreSQL database:
CREATE DATABASE apotek_hris;- Run migrations:
go run . migrate upStart the server:
go run . serveThe API will be available at http://localhost:8080
Health check endpoint:
curl http://localhost:8080/healthWhen running with Docker, interactive API documentation is automatically generated using Redocly:
- Interactive Docs:
GET /docs- Beautiful, interactive API documentation
Open in your browser:
open http://localhost:8080/docsThe complete API documentation is available as an OpenAPI 3.1.0 specification:
- OpenAPI Spec:
GET /docs/openapi.yaml - Source File:
docs/openapi.yaml
View the spec:
curl http://localhost:8080/docs/openapi.yamlYou can also use tools like Swagger Editor or Redocly to visualize the OpenAPI specification.
All API endpoints are prefixed with /api/v1.
GET /api/v1/employees- List all employeesPOST /api/v1/employees- Create new employee
GET /api/v1/work-types- List all work typesPOST /api/v1/work-types- Create new work type
GET /api/v1/work-logs- List work logsPOST /api/v1/work-logs- Create new work logGET /api/v1/work-logs/{id}/for-patient- Print work log for patientDELETE /api/v1/work-logs/{id}- Soft delete work log
GET /api/v1/attendances- Get attendances between datesGET /api/v1/attendances/types- List attendance typesPOST /api/v1/attendances/types- Create attendance typePUT /api/v1/attendances/{employeeID}/{date}- Upsert attendance
GET /api/v1/salary/{employeeID}/static-components- Get employee static componentsPOST /api/v1/salary/{employeeID}/static-components- Create static componentDELETE /api/v1/salary/{employeeID}/static-components/{id}- Delete static componentGET /api/v1/salary/{month}/{employeeID}/additional-components- Get additional componentsPOST /api/v1/salary/{month}/{employeeID}/additional-components- Create additional componentPOST /api/v1/salary/{month}/additional-components/bulk- Bulk create additional components for multiple employeesDELETE /api/v1/salary/{month}/{employeeID}/additional-components/{id}- Delete additional componentGET /api/v1/salary/{month}/{employeeID}/extra-infos- Get extra infosPOST /api/v1/salary/{month}/{employeeID}/extra-infos- Create extra infoDELETE /api/v1/salary/{month}/{employeeID}/extra-infos/{id}- Delete extra infoGET /api/v1/salary/{month}/{employeeID}- Calculate salary for employee and monthGET /api/v1/salary/snapshots- List salary snapshotsPOST /api/v1/salary/snapshots- Create salary snapshotGET /api/v1/salary/snapshots/{id}- Get salary snapshotDELETE /api/v1/salary/snapshots/{id}- Delete salary snapshot
This project uses Jujutsu (jj) for version control. Always start work from an empty change:
jj new # Create new empty change
# Make your changes
jj describe -m "message" # Describe your change
jj new # Create new empty change for next workgo test ./...go run . migrate create add_new_featureThis creates a pair of migration files (up and down) in the migrations/ directory.
Build the binary:
go build -o apotek-hrisRun the binary:
./apotek-hris serveBuild the Docker image:
docker build -t apotek-hris .Run with Docker:
docker run -p 8080:8080 apotek-hris- Language: Go 1.25.0
- Database: PostgreSQL with pgx/v5 driver
- HTTP Router: Chi (go-chi/chi/v5)
- CLI Framework: Cobra
- Configuration: Viper
- Database Migrations: golang-migrate
- Decimal Arithmetic: shopspring/decimal (for precise financial calculations)
- Validation: go-playground/validator
.
├── cmd/hris/ # CLI commands
├── internal/ # Domain modules
│ ├── hris/ # Employee and work log management
│ ├── attendance/ # Attendance tracking
│ ├── salary/ # Salary calculation
│ └── config/ # Configuration loading
├── pkg/ # Reusable packages
│ ├── database/ # Database connection
│ ├── server/ # HTTP server
│ ├── httpx/ # HTTP helpers
│ └── timex/ # Time utilities
├── migrations/ # SQL migrations
└── config/ # Configuration files
The application is configured for Indonesian pharmacy operations:
- Timezone: Asia/Jakarta
- Locale: Indonesian (id_ID)
This project is licensed under the GNU GPLv3 License - see the LICENSE file for details.