Adds 4 BDD scenarios covering the passwordless magic-link flow:
- Happy path (request -> email arrives -> consume -> JWT)
- Token cannot be consumed twice (single-use guarantee)
- Missing token returns 400
- Unknown token returns 401
Implementation:
- features/auth/magic_link.feature with the gherkin spec
- pkg/bdd/steps/magic_link_steps.go: per-scenario unique recipient
(`<scenario-key>-<8hex>@bdd.local`, ADR-0030), Mailpit-driven token
extraction, regex parse of the consume URL
- pkg/bdd/steps/scenario_state.go: 2 fields added (MagicLinkEmail,
MagicLinkToken)
- pkg/bdd/steps/steps.go: register 5 new step regexes
Bug fix exposed by the BDD run:
- pkg/user/api/magic_link_handler.go: passwordless-signup random password
was 96 hex chars (48 bytes) which overflowed bcrypt's 72-byte input
limit, breaking first-link signup. Reduced to 64 hex chars (32 bytes,
256 bits entropy).
Test infra fix:
- pkg/bdd/testserver/server.go: createTestConfig() builds the
Config literal directly (no Viper defaults), so add explicit Email +
MagicLink config so the From address is set when the handler sends
via local Mailpit.
Mistral wrote the feature file, magic_link_steps.go, scenario_state.go
edit, and steps.go edit autonomously in a worktree workspace. Claude
fixed the bcrypt overflow + the test-config gap exposed during verification.
Most authoring by Mistral Vibe (mistral-vibe-cli-latest).
Per-package isolated Postgres schema with migrations. Local benchmark: 12.87s sequential → 4.51s parallel = 2.85x. ADR-0025 status to Implemented. CI uses BDD_SCHEMA_ISOLATION=true.
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
NewPostgresRepositoryFromDSN factory + BuildSchemaIsolatedDSN helper + integration test proving per-schema isolation works at repo level. Foundation for T12. Wiring into testserver is stage 2/2.
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
Extends cache service to /api/v1/greet (per-name 60s) and adds POST /api/admin/cache/flush. ~95% Mistral autonomous via ICM workspace, trainer finalized commit/PR (test scaffold did not compile).
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
Phase 1 part 2 of ADR-0022 (companion to PR #22 rate-limit). In-memory cache service via go-cache, used by /api/version (60s TTL).
6/6 unit tests pass. ~95% Mistral autonomous via ICM workspace, cost €2.50 stages 01-02 (50% reduction vs T5 thanks to pre-extracted snippets in shared/).
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
Adds Kubernetes-style /api/healthz endpoint with status/version/uptime_seconds/timestamp.
Non-breaking — /api/health preserved. Includes unit test (passes locally) and BDD scenario (validated by CI).
Généré ~95% en autonomie par Mistral Vibe via workspace ICM ~/Work/Vibe/workspaces/healthz-feature/.
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
## Summary
Closes#15
When `logging.json: true` (or `DLC_LOGGING_JSON=true`), the logger was unconditionally initialised to console/text format at the top of `LoadConfig()`, so early log lines — most visibly **"Config file loaded"** — were always written as human-readable text regardless of configuration.
## Root cause
Classic chicken-and-egg: the format flag lives inside the config that is being loaded. The format-switch block only ran *after* `v.Unmarshal()`, too late for the config-file log.
## Changes
### `pkg/config/config.go`
- Add `peekJSONLogging()`: resolves the JSON flag **before** any log is emitted by (1) checking `DLC_LOGGING_JSON` directly via `os.Getenv`, then (2) doing a minimal throwaway Viper pre-read of the config file for the `logging.json` key. This mirrors Viper's own priority order without parsing the full config twice.
- Apply the resolved format immediately and emit **"Logging configured"** as the very first log line.
- Remove the now-redundant format-switch block that ran after `Unmarshal()`.
### `scripts/start-server.sh`, `test-graceful-shutdown.sh`, `test-opentelemetry.sh`
- Replace hardcoded `PROJECT_DIR` path with a dynamic `SCRIPTS_DIR=$(dirname $(realpath ${BASH_SOURCE[0]}))` derivation so scripts work from any worktree or clone location.
## Test plan
- [x] `go test ./pkg/...` — all pass
- [x] `scripts/test-graceful-shutdown.sh` — all JSON valid, all startup logs present
- [x] Manual smoke test: first line is `{"level":"info",...,"message":"Logging configured"}`, every line is valid JSON
Reviewed-on: #16
Co-authored-by: Gabriel Radureau <arcodange@gmail.com>
Co-committed-by: Gabriel Radureau <arcodange@gmail.com>
- Add swag fmt to git pre-commit hook and CI/CD pipeline
- Create comprehensive CONTRIBUTING.md guide with AI section
- Update ADR-0013 with swag fmt documentation
- Fix swagger generation to include all endpoints
- Improve local testing scripts and workflows
- Update Dockerfile for better swagger handling
- Fix CI/CD workflow file references
- Add Version field to telemetry.Setup struct
- Include service.version attribute in OpenTelemetry resource
- Pass version.Short() from server to telemetry initialization
- Follows OpenTelemetry semantic conventions for better observability
- Enables version tracking in production traces
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Add ADR-0012 documenting the decision to format only staged Go files
- Update ADR README.md with new entry
- Document rationale, alternatives, and verification results
- Include future considerations for monitoring and CI/CD integration
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- Added /api/v2/greet POST endpoint with JSON request/response
- Implemented ServiceV2 with Hello my friend <name>! greeting format
- Added api.v2_enabled feature flag (default: false)
- Extended BDD tests to cover v2 scenarios
- Maintained full backward compatibility with v1 API
- Added DLC_API_V2_ENABLED environment variable support
- Created ADR 0010-api-v2-feature-flag.md
- Updated configuration system to support API versioning
Finalize BDD testing framework with:
- Unified step definitions using StepContext struct
- Proper server verification in theServerIsRunning step
- Robust JSON response handling with escaping and newline trimming
- Updated documentation reflecting current implementation
- Test validation script to ensure test quality
- All tests passing with proper black box testing
Key files updated:
- pkg/bdd/steps/steps.go: Unified step definitions
- pkg/bdd/testserver/client.go: Robust response validation
- pkg/bdd/README.md: Godog pattern guide
- doc/BDD_GUIDE.md: Updated usage guide
- adr/0008-bdd-testing.md: Updated ADR with current approach
- scripts/run-bdd-tests.sh: Test validation script
The BDD framework is now production-ready with comprehensive
documentation and proper testing practices.
Implement comprehensive BDD testing framework using Godog:
- Added feature files for greet and health endpoints
- Created test server that runs on port 9191
- Implemented step definitions using Godog's exact patterns
- Fixed undefined step warnings by following Godog conventions
- All tests passing with proper response validation
- Maintained black box testing principles
Key files:
- pkg/bdd/steps/steps.go - Step definitions using StepContext struct
- pkg/bdd/testserver/ - Test server implementation
- features/*.feature - BDD feature files
- pkg/bdd/README.md - Documentation for proper step patterns
The implementation follows Godog's exact pattern suggestions to avoid
undefined step warnings and provides comprehensive API testing.
The time.Sleep(100ms) after OpenTelemetry shutdown was removed as it's
not necessary for proper log writing. Zerolog automatically flushes logs
on program exit, and the remaining 1-second sleep for readiness
propagation is sufficient.
Tested that all shutdown logs are properly written without the sleep.
- Add scripts/build.sh to compile binaries into bin/ directory
- Move all zerolog setup logic from cmd/server/main.go to pkg/config
- Add log level configuration support (trace, debug, info, warn, error, fatal, panic)
- Simplify cmd/server/main.go from 57 to 27 lines (53% reduction)
- Update .gitignore to use bin/ directory instead of individual files
- Document build process and bin directory in AGENTS.md
- Maintain backward compatibility with all existing functionality
- Simplify cmd/server/main.go from 158 to 57 lines (64% reduction)
- Move HTTP server creation, graceful shutdown, and context management to pkg/server
- Add Run() method to encapsulate server lifecycle management
- Maintain all existing functionality and OpenTelemetry integration
- Improve separation of concerns and code organization
This refactoring makes cmd/server/main.go a thin entrypoint while moving all server implementation details to the pkg/server package, following Go best practices for package organization.
Add server and greet binaries to .gitignore