Example CRUD project applying Hexagonal Architecture, Domain-Driven Design (DDD), Event-Driven Architecture (EDA), Command Query Responsibility Segregation (CQRS), Behavior-Driven Development (BDD), Continuous Integration (CI), and more... in Go.
go run github.com/bastean/codexgo/v4/cmd/codexgo@latest -demo
Note
- Demo version does not require any configuration, because the required ENV values are already preset.
- Here we can find the ENV preset values that are used in the Demo.
In-Memory
implementation will be used for EventBus, CommandBus, QueryBus and Database (SQLite
).- Links to confirm and recover the account are sent through the
Terminal
with the following messages:- "Hi <username>, please confirm your account through this link: <link>".
- "Hi <username>, please reset your password through this link: <link>".
go install github.com/bastean/codexgo/v4/cmd/codexgo@latest
codexgo -h
_________ ________________
_____________ ______ /_____ ____ __ __ ____/__ __ \
_ ___/_ __ \_ __ / _ _ \__ |/_/ _ / __ _ / / /
/ /__ / /_/ // /_/ / / __/__> < / /_/ / / /_/ /
\___/ \____/ \__,_/ \___/ /_/|_| \____/ \____/
Example CRUD project applying Hexagonal Architecture, DDD, EDA, CQRS, BDD, CI, and more... in Go.
Usage: codexgo [flags]
-demo
Use preset ENV values
-env string
Path to custom ENV file
Note
- We can use the .env.demo.cli file or we can create our own
.env
file where we define our own values.- In the .env.example.cli file, we can see the values that can be used.
- If
CODEXGO_SMTP_*
is omitted, the links to confirm and recover the account are sent through theTerminal
with the following messages:- "Hi <username>, please confirm your account through this link: <link>".
- "Hi <username>, please reset your password through this link: <link>".
- We can define our own SMTP configuration by simply modifying the
CODEXGO_SMTP_*
variables, then we will be able to receive the links by mail. - If
CODEXGO_BROKER_*
is omitted, an in-memory EventBus will be used. In-Memory
implementation will be used for CommandBus and QueryBus.- If
CODEXGO_DATABASE_*
is omitted, aSQLite
in-memory database will be used. - We can use a file as a database instead of memory by defining the file name in the
CODEXGO_DATABASE_SQLITE_DSN
variable.
- If
- In the .env.example.cli file, we can see the values that can be used.
codexgo -env path/to/.env
Note
- System Requirements
- In the Demo version (.env.demo):
RabbitMQ
implementation will be used for the EventBus.- URL:
http://localhost:15672
- User/Password:
codexgo-demo
- URL:
In-Memory
implementation will be used for CommandBus and QueryBus.MongoDB
implementation will be used as Database.- Compass:
mongodb://codexgo-demo:codexgo-demo@localhost:27017
- Compass:
Mailpit
will be used as SMTP to receive emails with the links to confirm and recover the account.- URL:
http://localhost:8025
- URL:
codexGO
Server.- URL:
http://localhost:8080
- URL:
task demo
- Based on Standard Go Project Layout.
- Hooks managed by husky:
- Pre-Push:
- Scanning Repository for secrets using TruffleHog CLI and Trivy
- Pre-Commit: lint-staged
- Scanning files for secrets using TruffleHog CLI
- Formatting files using gofmt, goimports and Prettier.
- Commit-Msg: commitlint
- Check Conventional Commits rules
- Pre-Push:
- Commit message helper using czg.
- Interactive prompt that allows you to write commits following the Conventional Commits rules:
task commit
- Interactive prompt that allows you to write commits following the Conventional Commits rules:
- TruffleHog CLI: Secrets.
- Trivy: Secrets, Vulnerabilities and Misconfigurations.
- OSV-Scanner: Vulnerabilities.
*.go
: GolangCI-Lint.*.templ
: templ fmt.*.feature
(Gherkin): Cucumber extension.*.*
: Prettier cli/extension.
*.go
: deadcode.
- Random data generator: Gofakeit.
- Unit/Integration: Testify.
- Acceptance: Testify, Godog (Cucumber) and Playwright.
- Automatically managed by Release It!:
- Before/After Hooks for:
- Linting
- Testing
- Bump version based on Conventional Commits and SemVer:
- CHANGELOG generator
- Commits and Tags generator
- GitHub Releases
- Before/After Hooks for:
- Actions for:
- Setup Languages and Dependencies
- Workflows running:
- Automatically (Triggered by Push or Pull requests):
- Secrets
- Vulnerabilities
- Misconfigurations
- Linting
- Testing
- Manually (Using the Actions tab on GitHub):
- Upgrade Dependencies
- Automate Release
- Automatically (Triggered by Push or Pull requests):
- Issue Templates (Defaults).
- Multiple Features already pre-configured:
- Go
- Task
- Docker in Docker
- Light-weight Desktop (Fluxbox)
- SSH
- Extensions and their respective settings to work with:
- Go
- Task
- Docker
- templ
- Cucumber
- Gherkin
- YAML
- TOML
- Prettier
- Better Comments
- Todo Tree
- cSpell
- Dockerfile
- Multi-stage builds:
- Development
- Testing
- Build
- Production
- Multi-stage builds:
- Compose
- Switched by ENVs and Profiles.
- Message (Event/Command):
- Routing Key based on AsyncAPI Topic Definition.
- Server log files.
- Requests Rate Limiting.
- Data authentication via JWT managed by Session Cookies.
- Captcha implementation in forms.
- Form validation at the client using Fomantic - Form Validation.
- On the server, the validations are performed using the Value Objects defined in the Context.
- Account confirmation and recovery via Mail or Terminal.
- Password hashing using Bcrypt.
- cDeps
- Copies the files required by the browser dependencies from the node_modules folder and places them inside the static folder on the server.
- syncENV
- Synchronize all .env* files in the directory using an .env model.
- run
- Display the logs and redirect them to a file whose name depends on the time at which the service was run.
- Used in Production Image.
Bounded Context (App/Business/Department) > Modules (Troubleshooting) > Layers (Domain, Infrastructure & Application)
- Domain (Logic Core)
- Value Objects (Entities)
- Mother Creators
- Unit Tests
- Messages (Event/Command)
- Mother Creators
- Aggregates (Sets of Entities)
- Aggregate Root (Core Set)
- Mother Creators
- Role Interfaces (Ports)
- Repository
- Broker
- Model Interfaces
- Use Cases
- Handlers/Consumers
- Services (Abstract Logic)
- Errors (Management)
- Value Objects (Entities)
- Infrastructure (Port Adapters)
- Persistence
- Repository Mocks
- Implementations (Adapters)
- Integration Tests
- Communication
- Broker Mocks
- Implementations (Adapters)
- Integration Tests
- Persistence
- Application (Orchestration of Domain Logic)
- Use Cases
- Implementations
- Commands
- Mother Creators
- Queries/Responses
- Mother Creators
- Handlers/Consumers
- Implementations
- Unit Tests
- Use Cases
- Presentation (Consumers of Bounded Context Modules)
- Services (Mapping)
- Centralize Imports
- Initializations
- Server
- Templates
- Handlers
- API
- Views
- Routes
- API
/v*
- Views
- API
- Features (Gherkin)
- Acceptance Tests
- Services (Mapping)
The system allows users to register a new account, log in and update their data or permanently delete their account, as well as verify it through a link sent to their email.
It is a monolith where CRUD operations can be performed from different presentations to the same database, this allows us to manage users from the different presentations available, in addition to having a messaging system that allows to communicate the events occurred, thus avoiding a coupling to the source of the same.
-
pkg/context/(modules)
- It is the logical core that contains all the necessary functionalities that are agnostic of any presentation.
-
internal/pkg/service
- It is responsible for initializing all context functionalities so that they are ready for use, as well as for "mapping" certain values to centralize all imports required for presentations in a single place.
-
internal/app/(presentations)
- These applications will be used as presentations in order to serve the functionalities to an end user.
- Domain
errors.New*()
,errors.BubbleUp()
&errors.Panic()
- Only in the
Domain
layer and in the*_test.go
files can we throwerrors.Panic()
.
- Only in the
- Infrastructure
New*()
,Open()
&Close()
session
errors.New*()
&errors.BubbleUp()
- Application
Run()
,Handle()
&On()
errors.New*()
&errors.BubbleUp()
- Presentation
- Modules
Start()
&Stop()
errors.BubbleUp()
- Services / Apps
Init()
,Up()
&Down()
log.[Wrap]()
errors.New*()
&errors.BubbleUp()
- In
Apps
we will handleBubble Errors
.
- In
- Modules
- Main
log.Fatal()
&log.[Wrap]()
- Only
main()
can uselog.Fatal()
.
- Only
- Logs
[embed]
- We use
[]
to "embed" external values such as error messages, fields, etc... inside our messages.
- We use
- ENVs
os.[Getenv/LookupEnv]()
- Only handle
ENVs
directly in thePresentation
layer and in the*_test.go
files.- At the
Infrastructure
layer,ENVs
are received via arguments through function parameters.
- At the
- Only handle
- Blocks
const
,var
, &type
- We will group only those that are declared on a single line.
Create v0
branch from main
.
task git-v0
Create development branch dev0.1.0
from v0
.
task git-dev0.1.0
Create branch ci/dev0.1.0
from dev0.1.0
to ensure that the workflows run correctly with the new changes before merging them with main
.
task git-ci/dev0.1.0
Once the workflows have been successfully passed, the new changes from ci/dev0.1.0
will be merged into main
.
task git-main-ci/dev0.1.0
After releasing the new version v0.1.0
, the main
and v0
branches in our local repository will be updated.
task git-pull-v0
To end the cycle, the dev0.1.0
and ci/dev0.1.0
branches will be deleted.
task git-cleanup-dev0.1.0
git clone https://github.com/bastean/codexgo.git && cd codexgo
git clone [email protected]:bastean/codexgo.git && cd codexgo
-
System Requirements
-
Start VS Code
code .
-
Open Command Palette
- F1
-
Run
Dev Containers: Reopen in Container
-
SSH (Optional)
- We can connect to our
Dev Container
viaSSH
in the following ways:- If we have Task installed on our host, being in the root of the repository
task connect-2222-vscode-localhost
- Using the SSH Client of our host
ssh -p 2222 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o GlobalKnownHostsFile=/dev/null vscode@localhost
- Password:
vscode
- If we have Task installed on our host, being in the root of the repository
- We can connect to our
-
Desktop (Optional)
- We can connect to our
Dev Container
viaVNC
using our web browser.- URL:
http://localhost:6080
- Password:
vscode
- No password is required to connect from the local host.
- Change the default applications of the context menu (Optional)
task desktop
- File Manager:
xfe
- Terminal:
terminator
- Web Browser:
chromium
- File Manager:
- URL:
- We can connect to our
Note
- System Requirements
- We need to change
<user>
and<repository>
with our own values.
curl -sSfLO https://github.com/bastean/codexgo/archive/refs/heads/main.zip \
&& unzip main.zip \
&& mv codexgo-main <repository> \
&& rm main.zip \
&& cd <repository> \
&& task genesis \
&& git commit -m "feat(genesis): codexgo" \
&& git branch -M main \
&& git remote add github https://github.com/<user>/<repository>.git \
&& git push -u github main \
&& git status
Repository initialization from ZIP (Optional)
Icons (Template: Icon Safe Zone SVG)
favicon-512.png
(512x512)
desktop.png
(1536x860)mobile.png
(425x800)
logo.png
Social Preview (Template: GitHub Repository > Settings > General > Social preview > Download template)
social-preview.png
- Wireframe
- UML
-
Run initialization from
ZIP
(codexGO) -
Cleanup
CHANGELOG
- Everything not required
-
Add
<repository>
>assets/
- Compress
assets
- Compress
-
Update
#colors
>#<repository>
-
Update (
codexgo/v*
|codexgo
|codexGO
) ><repository>
Source Code
,Files
&Folders
-
Update
README
- Update
Logo
- Update
Description
- Add
Disclaimer
> [!IMPORTANT] > > `<repository>` is still in the early stages of development.
- Update
Tech Stack
- Remove all other sections, except:
Logo
,Description
,Disclaimer
,Badges
,Tech Stack
,Contributing
&License
- Change
v*.*.*
>v0.0.0
- Update
-
Commit, Upgrade & Push
git commit -m "chore: update codexgo to <repository>" \ && task upgrade \ && git push \ && git status
-
Rulesets
New branch ruleset
- Ruleset Name *
- Branches
- Enforcement status
- Active
- Target branches
- Include by pattern
main
v*
- Include by pattern
- Branch rules
- Restrict deletions
- Require signed commits (Optional)
- Block force pushes
- Ruleset Name *
New tag ruleset
- Ruleset Name *
- Tags
- Enforcement status
- Active
- Target tags
- Include by pattern
v*
- Include by pattern
- Tag rules
- Restrict deletions
- Require signed commits (Optional)
- Block force pushes
- Ruleset Name *
-
Secrets and variables (Optional)
- Actions
- New repository secret
BOT_GPG_PASSPHRASE
BOT_GPG_PRIVATE_KEY
gpg --armor --export-secret-key [Pub_Key_ID (*-BOT)]
- New repository secret
- Actions
-
Social preview
- Upload an image…
-
Workflows
- Release
- Run workflow
- Use workflow from
- Branch:
main
- Branch:
- Status
alpha
- Bump
minor
- Use workflow from
- Pre-release
v0.1.0-alpha.0
- Run workflow
- Release
Important
By default, the user used to create commits and tags in workflows is github-actions[bot]
, whose creations are not signed. If we want the creation of commits and tags to be signed, we must create the specified "Repository Secrets", this way by selecting GPG Sign
when manually launching a workflow everything will be created using the information obtained from the "GPG Key".
-
Actions
-
New repository secret
-
BOT_GPG_PASSPHRASE
-
BOT_GPG_PRIVATE_KEY
gpg --armor --export-secret-key [Pub_Key_ID (*-BOT)]
-
-
Important
If we want to modify the values inside some .env
file, here .env.example.demo we can see the values that can be used.
Development (.env.demo.dev)
Note
RabbitMQ
- URL:
http://localhost:15672
- User/Password:
codexgo-dev
- URL:
MongoDB
- Compass:
mongodb://codexgo-dev:codexgo-dev@localhost:27017
- Compass:
Mailpit
- URL:
http://localhost:8025
- URL:
codexGO
Server- URL:
http://localhost:8080
- URL:
codexGO
Live-Reloading Server- URL:
http://localhost:8090
- URL:
task compose-dev
task test-unit
Integration (.env.demo.test | .env.demo.test.integration)
task compose-test-integration
Acceptance (.env.demo.test | .env.demo.test.acceptance)
task compose-test-acceptance
Unit / Integration / Acceptance (.env.demo.test)
task compose-tests
Production (.env.demo.prod)
Note
- We must define our own SMTP configuration in the
CODEXGO_SMTP_*
variables, to receive the links by mail.- By default, as there are no values set, the links will be sent through the terminal.
RabbitMQ
- URL:
http://localhost:15672
- User/Password:
codexgo
- URL:
MongoDB
- Compass:
mongodb://codexgo:codexgo@localhost:27017
- Compass:
codexGO
Server- URL:
http://localhost:8080
- URL:
task compose-prod
Contributions and Feedback are always welcome!