initial commit, adding SQL connection and a simple testing on main

This commit is contained in:
Josepablo C.
2025-12-07 08:51:10 -06:00
commit bf78edeec0
16 changed files with 2406 additions and 0 deletions

64
.gitignore vendored Normal file
View File

@@ -0,0 +1,64 @@
# Binaries for programs and plugins
*.exe
*.exec
*.exe~
*.dll
*.so
*.dylib
*.test
# Build output (common names)
/bin/
/dist/
/build/
*.out
coverage.out
# Go tooling
go.work
# Uncomment if you don't commit vendored deps
# vendor/
# Dependency manager files (optional)
Gopkg.lock
glide.lock
# Generated code
gen/
generated/
# Environment / secrets
.env
.env.*
*.key
*.pem
# Logs
*.log
# Editor directories and files
.idea/
.vscode/
*.iml
*.sublime-project
*.sublime-workspace
# Swap/backup files
*~
*.swp
*.swo
.#*
# macOS / Windows
.DS_Store
Thumbs.db
# Container / OS artifacts
docker-compose.override.yml
# CI artifacts
coverage/
reports/
# Misc
node_modules/

29
app/go.mod Normal file
View File

@@ -0,0 +1,29 @@
module cloud.etaviaporte.com/api
go 1.23.2
require (
github.com/joho/godotenv v1.5.1
github.com/spf13/viper v1.21.0
gorm.io/driver/mysql v1.6.0
gorm.io/gorm v1.31.1
)
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.28.0 // indirect
)

61
app/go.sum Normal file
View File

@@ -0,0 +1,61 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
gorm.io/driver/mysql v1.6.0/go.mod h1:D/oCC2GWK3M/dqoLxnOlaNKmXz8WNTfcS9y5ovaSqKo=
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=

42
app/libs/database/db.go Normal file
View File

@@ -0,0 +1,42 @@
package database
import (
"log"
"github.com/joho/godotenv"
"github.com/spf13/viper"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var shared_db_connection *gorm.DB
func initDB() *gorm.DB {
// load .env into environment (so viper can read them)
if err := godotenv.Load(); err != nil {
log.Println(".env not found or could not be loaded; proceeding with existing environment variables")
}
viper.AutomaticEnv() // read from environment
sql_dsn := viper.GetString("SQL_DSN")
if sql_dsn == "" {
log.Fatal("SQL_DSN must be set in .env or environment")
}
db, err := gorm.Open(mysql.Open(sql_dsn), &gorm.Config{})
if err != nil {
log.Fatalf("failed to connect to MySQL Server: %v", err)
}
log.Println("connected to MySQL Server")
return db
}
func Init() *gorm.DB {
if shared_db_connection == nil {
shared_db_connection = initDB()
}
return shared_db_connection
}

View File

@@ -0,0 +1,124 @@
/**
* @file schema.rbac.go
* @brief RBAC schema models for GORM
*
* This file defines the base database models used by the RBAC
* (Role-Based Access Control) system. Models map to the following
* tables: user_types, users, auth_identities, auth_credentials,
* roles, permissions, role_permissions and user_roles.
*
* The structs include GORM tags for column names and relationships:
* - UserType: types of users.
* - User: main user record; links to UserType, AuthIdentity and UserRole.
* - AuthIdentity: external identity providers; links to AuthCredential.
* - AuthCredential: stored credentials for an identity.
* - Role: role definitions and their permissions and assigned users.
* - Permission: permission definitions.
* - RolePermission: join table between Role and Permission.
* - UserRole: join table between User and Role with optional expiration.
*
* These models are intended for use with GORM to perform ORM operations
* against the RBAC schema.
*/
package rbac
import (
"time"
)
type UserType struct {
ID uint `gorm:"primaryKey;column:id"`
Name string `gorm:"type:text;column:name"`
Description *string `gorm:"type:text;column:description"`
}
func (UserType) TableName() string { return "user_types" }
type User struct {
ID uint `gorm:"primaryKey;column:id"`
UserTypeID uint `gorm:"column:user_type"`
Name string `gorm:"type:text;column:name"`
LastName string `gorm:"type:text;column:last_name"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
UserType UserType `gorm:"foreignKey:UserTypeID;references:ID"`
AuthIdentities []AuthIdentity `gorm:"foreignKey:UserID;references:ID"`
UserRoles []UserRole `gorm:"foreignKey:UserID;references:ID"`
}
func (User) TableName() string { return "users" }
type AuthIdentity struct {
ID uint `gorm:"primaryKey;column:id"`
UserID uint `gorm:"column:user_id"`
Provider string `gorm:"type:text;column:provider"`
Identifier string `gorm:"type:text;column:identifier"`
IsPrimary bool `gorm:"column:is_primary"`
IsVerified bool `gorm:"column:is_verified"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
User User `gorm:"foreignKey:UserID;references:ID"`
Credentials []AuthCredential `gorm:"foreignKey:IdentityID;references:ID"`
}
func (AuthIdentity) TableName() string { return "auth_identities" }
type AuthCredential struct {
ID uint `gorm:"primaryKey;column:id"`
IdentityID uint `gorm:"column:identity_id"`
Password string `gorm:"type:text;column:password"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
Identity AuthIdentity `gorm:"foreignKey:IdentityID;references:ID"`
}
func (AuthCredential) TableName() string { return "auth_credentials" }
type Role struct {
ID uint `gorm:"primaryKey;column:id"`
Name string `gorm:"type:text;column:name"`
Description *string `gorm:"type:text;column:description"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
RolePermissions []RolePermission `gorm:"foreignKey:RoleID;references:ID"`
UserRoles []UserRole `gorm:"foreignKey:RoleID;references:ID"`
}
func (Role) TableName() string { return "roles" }
type Permission struct {
ID uint `gorm:"primaryKey;column:id"`
Name string `gorm:"type:text;column:name"`
Description *string `gorm:"type:text;column:description"`
RolePermissions []RolePermission `gorm:"foreignKey:PermissionID;references:ID"`
}
func (Permission) TableName() string { return "permissions" }
type RolePermission struct {
ID uint `gorm:"primaryKey;column:id"`
RoleID uint `gorm:"column:role_id"`
PermissionID uint `gorm:"column:permission_id"`
Role Role `gorm:"foreignKey:RoleID;references:ID"`
Permission Permission `gorm:"foreignKey:PermissionID;references:ID"`
}
func (RolePermission) TableName() string { return "role_permissions" }
type UserRole struct {
ID uint `gorm:"primaryKey;column:id"`
UserID uint `gorm:"column:user_id"`
RoleID uint `gorm:"column:role_id"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
ExpiresAt *time.Time `gorm:"column:expires_at"`
User User `gorm:"foreignKey:UserID;references:ID"`
Role Role `gorm:"foreignKey:RoleID;references:ID"`
}
func (UserRole) TableName() string { return "user_roles" }

34
app/main.go Normal file
View File

@@ -0,0 +1,34 @@
package main
import (
"fmt"
database "cloud.etaviaporte.com/api/libs/database"
rbac "cloud.etaviaporte.com/api/libs/database/schemas/rbac"
)
func main() {
var connection = database.Init()
// Prepare a variable to hold the fetched user record.
// Replace rbac.User with the actual struct name if different.
var user rbac.User
// Fetch the user whose primary key is 1.
// GORM's First method, when given a numeric id as the second argument, queries by primary key.
result := connection.First(&user, 1)
// result.Error holds any error from the DB operation (including "record not found").
// result.RowsAffected tells how many rows were returned.
if result.Error != nil {
// Handle the error (could be gorm.ErrRecordNotFound or a DB/connection error).
// For learning purposes we print the error and exit main.
fmt.Printf("failed to fetch user with id=1: %v\n", result.Error)
return
}
// If no error, user now contains the row from the database.
// Print the struct with field names and values to inspect the loaded data.
fmt.Printf("User fetched: %+v\n", user)
}

182
app/openapi.yaml Normal file
View File

@@ -0,0 +1,182 @@
openapi: 3.0.3
info:
title: Authorization API
version: "1.0.0"
description: Simple authorization endpoints for login, refresh, logout and getting current user info.
servers:
- url: http://localhost:8080
description: Local development server
paths:
/auth/login:
post:
summary: Obtain access and refresh tokens
tags:
- Auth
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Tokens issued
content:
application/json:
schema:
$ref: '#/components/schemas/TokenResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/refresh:
post:
summary: Refresh access token using a refresh token
tags:
- Auth
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RefreshRequest'
responses:
'200':
description: New tokens
content:
application/json:
schema:
$ref: '#/components/schemas/TokenResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/logout:
post:
summary: Revoke refresh token / logout
tags:
- Auth
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/RevokeRequest'
responses:
'204':
description: Successfully logged out (no content)
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/me:
get:
summary: Get current authenticated user
tags:
- Auth
security:
- bearerAuth: []
responses:
'200':
description: Current user profile
content:
application/json:
schema:
$ref: '#/components/schemas/UserProfile'
'401':
$ref: '#/components/responses/Unauthorized'
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
LoginRequest:
type: object
required:
- username
- password
properties:
username:
type: string
example: user@example.com
password:
type: string
format: password
example: secret123
TokenResponse:
type: object
properties:
accessToken:
type: string
example: eyJhbGciOi...
refreshToken:
type: string
example: dummyr3fr3sht0k3n
expiresIn:
type: integer
description: Seconds until access token expiration
example: 3600
RefreshRequest:
type: object
required:
- refreshToken
properties:
refreshToken:
type: string
RevokeRequest:
type: object
required:
- refreshToken
properties:
refreshToken:
type: string
UserProfile:
type: object
properties:
id:
type: string
example: "123e4567-e89b-12d3-a456-426614174000"
username:
type: string
example: user@example.com
email:
type: string
example: user@example.com
Error:
type: object
properties:
code:
type: string
example: invalid_request
message:
type: string
example: "Detailed error message"
responses:
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Authentication failed or missing credentials
content:
application/json:
schema:
$ref: '#/components/schemas/Error'

1
db/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.bak

23
db/Dockerfile Normal file
View File

@@ -0,0 +1,23 @@
# Original author : https://github.com/yobasystems/alpine-mariadb.git
FROM alpine:latest
ARG BUILD_DATE
ARG VCS_REF
RUN apk add --no-cache mariadb mysql-client mariadb-server-utils pwgen && \
rm -f /var/cache/apk/*
RUN mkdir /schemas
COPY schemas /schemas
ADD scripts/run.sh /scripts/run.sh
RUN mkdir /docker-entrypoint-initdb.d && \
mkdir /scripts/pre-exec.d && \
mkdir /scripts/pre-init.d && \
chmod -R 755 /scripts
EXPOSE 3306
VOLUME ["/var/lib/mysql"]
ENTRYPOINT ["/scripts/run.sh"]

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 159 KiB

BIN
db/Models/model.mwb Normal file

Binary file not shown.

View File

@@ -0,0 +1,55 @@
-- Creation of basic User Types
INSERT INTO user_types (name, description) VALUES ('root','An easy way to identify the root user of the system');
INSERT INTO user_types (name, description) VALUES ('company_owner','Company Owner');
INSERT INTO user_types (name, description) VALUES ('company_manager','Company Level manager');
INSERT INTO user_types (name, description) VALUES ('company_staff','Company Level Staff Memeber');
INSERT INTO user_types (name, description) VALUES ('company_driver','Company Level Driver Member');
INSERT INTO user_types (name, description) VALUES ('company_observer','Company Level Driver Member');
-- Creation of first user
INSERT INTO users (user_type,name,last_name,created_at,updated_at) VALUES (1,'Pablo','Cruz',NOW(),NOW()); -- root -> root
-- Creation of basic roles
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("root","Root role with no restricted access",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_admin","System Level Admin",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_developer","System Level Developer",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_reader","System Level Read Only",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("system_staff","System Level staff member",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_owner","Unrestricted access to company resources",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_manager","Access as manager to company resources",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_staff","Access as staff to company resources",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_driver","Simple access to company resources",NOW(),NOW());
INSERT INTO roles (name, description, created_at, updated_at) VALUES ("company_observer","Limited access to company resources",NOW(),NOW());
-- Creation of basic permissions
INSERT INTO permissions (name, description) VALUES ("root","Root role with no restricted access");
INSERT INTO permissions (name, description) VALUES ("system.admin","System Level Admin");
INSERT INTO permissions (name, description) VALUES ("system.developer","System Level Developer");
INSERT INTO permissions (name, description) VALUES ("system.reader","System Level Reader");
INSERT INTO permissions (name, description) VALUES ("system.staff","System Level Staff Member");
INSERT INTO permissions (name, description) VALUES ("company.owner","Unrestricted access to company resources");
INSERT INTO permissions (name, description) VALUES ("company.manager","Admin access to company resources");
INSERT INTO permissions (name, description) VALUES ("company.staff","Staff access to company resources");
INSERT INTO permissions (name, description) VALUES ("company.driver","Driver with simple access to company resources");
INSERT INTO permissions (name, description) VALUES ("company.observer","Observer with simple access to company resources");
-- Link of basic roles with its permissions
INSERT INTO role_permissions (role_id, permission_id) VALUES( 1, 1 ); -- root -> root
INSERT INTO role_permissions (role_id, permission_id) VALUES( 2, 2 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 3, 3 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 4, 4 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 5, 5 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 6, 6 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 7, 7 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 8, 8 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 9, 9 );
INSERT INTO role_permissions (role_id, permission_id) VALUES( 10, 10 );
-- Link of Root User with its role
INSERT INTO user_roles (user_id, role_id, created_at ) VALUES (1,1,NOW()); -- root -> root
-- Create Root Auth Identity and credentials
INSERT INTO auth_identities (user_id, provider, identifier, is_primary, is_verified, created_at, updated_at ) VALUES (1,"email","josepablo134@gmail.com",1,1,NOW(),NOW()); -- root access with email
INSERT INTO auth_credentials (identity_id, password, created_at, updated_at) VALUES (1, "PasswordGoesHere", NOW(), NOW());

View File

@@ -0,0 +1,174 @@
-- MySQL Script generated by MySQL Workbench
-- Sun Dec 7 08:38:42 2025
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
-- -----------------------------------------------------
-- Schema u947463964_etaviaporte
-- -----------------------------------------------------
-- -----------------------------------------------------
-- Schema u947463964_etaviaporte
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `u947463964_etaviaporte` DEFAULT CHARACTER SET utf8 ;
USE `u947463964_etaviaporte` ;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`user_types`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_types` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
`description` TEXT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`users`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_type` INT UNSIGNED NOT NULL,
`name` TEXT NOT NULL,
`last_name` TEXT NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
PRIMARY KEY (`id`),
INDEX `fk_users_user_types1_idx` (`user_type` ASC) VISIBLE,
CONSTRAINT `fk_users_user_types1`
FOREIGN KEY (`user_type`)
REFERENCES `u947463964_etaviaporte`.`user_types` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`auth_identities`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_identities` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT UNSIGNED NOT NULL,
`provider` TEXT NOT NULL,
`identifier` TEXT NOT NULL COMMENT 'email, phone google, facebook, etc.',
`is_primary` TINYINT NOT NULL DEFAULT 0,
`is_verified` TINYINT NOT NULL DEFAULT 0,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
INDEX `fk_auth_identities_users_idx` (`user_id` ASC) VISIBLE,
CONSTRAINT `fk_auth_identities_users`
FOREIGN KEY (`user_id`)
REFERENCES `u947463964_etaviaporte`.`users` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`auth_credentials`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`auth_credentials` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`identity_id` INT UNSIGNED NOT NULL,
`password` TEXT NOT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
INDEX `fk_auth_credentials_auth_identities1_idx` (`identity_id` ASC) VISIBLE,
CONSTRAINT `fk_auth_credentials_auth_identities1`
FOREIGN KEY (`identity_id`)
REFERENCES `u947463964_etaviaporte`.`auth_identities` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`roles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`roles` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
`description` TEXT NULL,
`created_at` DATETIME NOT NULL,
`updated_at` DATETIME NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`permissions`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`permissions` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
`description` TEXT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`role_permissions`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`role_permissions` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`role_id` INT UNSIGNED NOT NULL,
`permission_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
INDEX `fk_role_permissions_roles1_idx` (`role_id` ASC) VISIBLE,
INDEX `fk_role_permissions_permissions1_idx` (`permission_id` ASC) VISIBLE,
CONSTRAINT `fk_role_permissions_roles1`
FOREIGN KEY (`role_id`)
REFERENCES `u947463964_etaviaporte`.`roles` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_role_permissions_permissions1`
FOREIGN KEY (`permission_id`)
REFERENCES `u947463964_etaviaporte`.`permissions` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `u947463964_etaviaporte`.`user_roles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `u947463964_etaviaporte`.`user_roles` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT UNSIGNED NOT NULL,
`role_id` INT UNSIGNED NOT NULL,
`created_at` DATETIME NOT NULL,
`expires_at` DATETIME NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
INDEX `fk_user_roles_users1_idx` (`user_id` ASC) VISIBLE,
INDEX `fk_user_roles_roles1_idx` (`role_id` ASC) VISIBLE,
CONSTRAINT `fk_user_roles_users1`
FOREIGN KEY (`user_id`)
REFERENCES `u947463964_etaviaporte`.`users` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT `fk_user_roles_roles1`
FOREIGN KEY (`role_id`)
REFERENCES `u947463964_etaviaporte`.`roles` (`id`)
ON DELETE CASCADE
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

20
db/README.md Normal file
View File

@@ -0,0 +1,20 @@
# ETAv2SQL
# MySQL Databse schema
![etaviaporte](./Models/assets/Modelv2.0.0.png)
# Docker
## Build Docker image
docker buildx build -t eta/eta-db
## Run Docker container
```{.sh}
docker run --name eta-db -d -p3306:3306 eta/eta-db
docker logs -f eta-db
```
Container will generate automatically a SQL root password

12
db/scripts/migrate.sh Normal file
View File

@@ -0,0 +1,12 @@
#! /bin/bash
# This script does not avoid invalid queries while applying changes
USER=developer
HOST=127.0.0.2
PASS=Password1234
DBNAME=etaviaporte
mysqldump -h$HOST -u$USER -p$PASS $DBNAME > temp_copy.sql
mysql -h$HOST -u$USER -p$PASS < model.sql
mysql -h$HOST -u$USER -p$PASS < model_init.sql

111
db/scripts/run.sh Normal file
View File

@@ -0,0 +1,111 @@
#!/bin/sh
# execute any pre-init scripts
for i in /scripts/pre-init.d/*sh
do
if [ -e "${i}" ]; then
echo "[i] pre-init.d - processing $i"
. "${i}"
fi
done
if [ -d "/run/mysqld" ]; then
echo "[i] mysqld already present, skipping creation"
chown -R mysql:mysql /run/mysqld
else
echo "[i] mysqld not found, creating...."
mkdir -p /run/mysqld
chown -R mysql:mysql /run/mysqld
fi
if [ -d /var/lib/mysql/mysql ]; then
echo "[i] MySQL directory already present, skipping creation"
chown -R mysql:mysql /var/lib/mysql
echo "[i] MySQL root Password:" $(cat /schemas/password.txt)
else
echo "[i] MySQL data directory not found, creating initial DBs"
chown -R mysql:mysql /var/lib/mysql
mysql_install_db --user=mysql --ldata=/var/lib/mysql > /dev/null
if [ "$MYSQL_ROOT_PASSWORD" = "" ]; then
MYSQL_ROOT_PASSWORD=`pwgen 16 1`
echo "[i] MySQL root Password: $MYSQL_ROOT_PASSWORD"
fi
MYSQL_DATABASE=${MYSQL_DATABASE:-""}
MYSQL_USER=${MYSQL_USER:-""}
MYSQL_PASSWORD=${MYSQL_PASSWORD:-""}
tfile=`mktemp`
if [ ! -f "$tfile" ]; then
return 1
fi
cat << EOF > $tfile
USE mysql;
FLUSH PRIVILEGES ;
GRANT ALL ON *.* TO 'root'@'%' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ;
GRANT ALL ON *.* TO 'root'@'localhost' identified by '$MYSQL_ROOT_PASSWORD' WITH GRANT OPTION ;
SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
DROP DATABASE IF EXISTS test ;
FLUSH PRIVILEGES ;
EOF
if [ "$MYSQL_DATABASE" != "" ]; then
echo "[i] Creating database: $MYSQL_DATABASE"
if [ "$MYSQL_CHARSET" != "" ] && [ "$MYSQL_COLLATION" != "" ]; then
echo "[i] with character set [$MYSQL_CHARSET] and collation [$MYSQL_COLLATION]"
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET $MYSQL_CHARSET COLLATE $MYSQL_COLLATION;" >> $tfile
else
echo "[i] with character set: 'utf8' and collation: 'utf8_general_ci'"
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` CHARACTER SET utf8 COLLATE utf8_general_ci;" >> $tfile
fi
if [ "$MYSQL_USER" != "" ]; then
echo "[i] Creating user: $MYSQL_USER with password $MYSQL_PASSWORD"
echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* to '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD';" >> $tfile
fi
fi
/usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < $tfile
rm -f $tfile
for f in /docker-entrypoint-initdb.d/*; do
case "$f" in
*.sql) echo "$0: running $f"; /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;;
*.sql.gz) echo "$0: running $f"; gunzip -c "$f" | /usr/bin/mysqld --user=mysql --bootstrap --verbose=0 --skip-name-resolve --skip-networking=0 < "$f"; echo ;;
*) echo "$0: ignoring or entrypoint initdb empty $f" ;;
esac
echo
done
echo
echo 'MySQL init process done. Ready for start up.'
echo
echo "exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0" "$@"
# Saving plain password
echo $MYSQL_ROOT_PASSWORD > /schemas/password.txt
# # After 5 seconds (once mysql is up) create schema.
# $(sleep 5 && /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify.sql &&\
# /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify_zones.sql &&\
# /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/wincify_categories.sql &&\
# /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD < /schemas/system.sql &&\
# /usr/bin/mysql -uroot -p$MYSQL_ROOT_PASSWORD wincify_system < /schemas/wincifySystem_init.sql ) &\
fi
# execute any pre-exec scripts
for i in /scripts/pre-exec.d/*sh
do
if [ -e "${i}" ]; then
echo "[i] pre-exec.d - processing $i"
. ${i}
fi
done
exec /usr/bin/mysqld --user=mysql --console --skip-name-resolve --skip-networking=0 $@