Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
74a5b2c
update gitignore
DJAngel973 Oct 16, 2026
7ac4af0
docs: align README with implementation project
DJAngel973 Oct 16, 2026
8e7b85d
docs: add the implementation plan file to refine and finalize the pro…
DJAngel973 Oct 17, 2026
1d355c6
Merge branch 'main' into feature/practices
DJAngel973 Oct 17, 2026
5b8c43a
delete script 07-seed-sql the administrator must create using bootstr…
DJAngel973 Oct 18, 2026
c469095
The database container is checked to verify users and administrators
DJAngel973 Oct 18, 2026
e01241e
feat(auth): add controlled first admin bootstrap
DJAngel973 Oct 18, 2026
5ed10ff
docs: add rule of git for agents
DJAngel973 Oct 18, 2026
3113ef9
feat(auht): add email validation using jakarta
DJAngel973 Oct 19, 2026
263aade
tests: add validation with jakarta
DJAngel973 Oct 19, 2026
669a5e9
feat(docker): add bootstrap variable configuration
DJAngel973 Oct 19, 2026
ac0342f
Merge branch 'feature/practices' of github.com:DJAngel973/Secure-Wall…
DJAngel973 Oct 19, 2026
25abf2d
Merge branch 'main' into feature/practices
DJAngel973 Oct 19, 2026
6790403
fix(persistence): map IP addresses as PostgreSQL INET
DJAngel973 Oct 20, 2026
47e96ca
fix(wallet): align updated timestamp mapping
DJAngel973 Oct 20, 2026
1b84db0
feat: the regular expression is implemented with all characters
DJAngel973 Oct 20, 2026
2f38422
Merge branch 'main' into feature/practices
DJAngel973 Oct 20, 2026
450373f
fix(persistence): map PostgreSQL enums as named types
DJAngel973 Oct 20, 2026
acffb6d
Merge branch 'main' into feature/practices
DJAngel973 Oct 20, 2026
5188ccb
fix(test): align H2 security tests with PostgreSQL enum mappings
DJAngel973 Oct 20, 2026
9cb798f
chore(dev): add local test and Docker workflow scripts
DJAngel973 Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ void methodName_condition_expectation() {
- `@Transactional` behavior → requires Spring context
- Hibernate queries → requires DB

### Verification Gate
- After every code, SQL, configuration, or test change, run `./scripts/test.sh` before reporting the work as verified.
- Before recommending a commit or push, report the test result. Do not recommend either when the test gate fails.
- If the change affects Docker runtime configuration, also verify the relevant Docker Compose startup path.

---

## Security Rules — NEVER Violate
Expand Down
48 changes: 12 additions & 36 deletions scripts/dev-start.sh
Original file line number Diff line number Diff line change
@@ -1,42 +1,18 @@
#!/bin/bash
# ================================================================
# dev-start.sh — Start local development environment
# Usage: ./script/dev-start.sh
# ================================================================
#!/usr/bin/env bash
# Start the complete local environment declared in docker-compose.yml.
# Usage: ./scripts/dev-start.sh
set -euo pipefail

# Move to project root regardless of where script is called from
cd "$(dirname "$0")/.." || exit 1
cd "$(dirname "$0")/.."

# 1. Load .env FIRST — Docker Compose needs these variables to start
# set -a exports ALL variables defined after it
# source .env reads the file
# set +a stops auto-exporting
if [ ! -f .env ]; then
echo "ERROR: .env file not found. Copy .env.example and fill in your values."
if [[ ! -f .env ]]; then
echo "ERROR: .env not found. Copy .env.example to .env and set private values."
exit 1
fi
set -a && source .env && set +a
echo "Environment variables loaded."

# 2. Start PostgreSQL container
echo "Starting PostgreSQL..."
docker compose up -d postgres
# Docker Compose reads .env itself. Do not source it in Bash: passwords may
# contain characters such as $, / or ! that should remain literal values.
docker compose up -d --build
docker compose ps

# 3. Wait for PostgreSQL to be healthy (uses healthcheck defined in docker-compose.yml)
echo "Waiting for PostgreSQL to be ready..."
until docker compose exec -T postgres pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB" 2>/dev/null; do
sleep 1
done
echo "PostgreSQL is ready."

# 4. Start Spring Boot with dev profile (background + PID)
# WHY background + PID file: allows dev-stop.sh to kill only THIS process,
# not any other Java project running on the same machine.
echo "Starting Spring Boot on port ${SERVER_PORT:-8080}..."
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev &
SPRING_PID=$!
echo "$SPRING_PID" > .spring-boot.pid
echo "Spring Boot PID: $SPRING_PID (saved to .spring-boot.pid)"

# Wait keeps the script alive so you can see logs — Ctrl+C to stop
wait
echo "Environment started. Inspect API logs with: docker compose logs -f wallet-api"
35 changes: 9 additions & 26 deletions scripts/dev-stop.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
#!/bin/bash
# ================================================================
# dev-stop.sh — Stop local development environment
# Usage: ./script/dev-stop.sh
# ================================================================
#!/usr/bin/env bash
# Stop the complete Docker Compose environment without deleting database data.
# Usage: ./scripts/dev-stop.sh
set -euo pipefail

cd "$(dirname "$0")/.." || exit 1
cd "$(dirname "$0")/.."

# 1. Stop Spring Boot using PID file
# WHY PID file instead of pkill: isolates THIS project — won't kill other Java apps.
echo "Stopping Spring Boot..."
if [ -f .spring-boot.pid ]; then
PID=$(cat .spring-boot.pid)
if kill "$PID" 2>/dev/null; then
echo "Spring Boot stopped (PID $PID)."
else
echo "Spring Boot process (PID $PID) was not running."
fi
rm -f .spring-boot.pid
else
echo "No .spring-boot.pid found. Spring Boot may not be running."
fi

echo "Stopping PostgreSQL container..."
docker compose stop postgres
echo "PostgreSQL stopped."

echo "Done. All services stopped."
# `stop` preserves the PostgreSQL bind-mounted data directory. A destructive
# reset must always be an explicit, separate action.
docker compose stop
echo "Environment stopped. Database data was preserved."
10 changes: 10 additions & 0 deletions scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Run the same Maven verification gate used by the CI build-and-test job.
# Usage: ./scripts/test.sh
set -euo pipefail

cd "$(dirname "$0")/.."

# `clean` prevents stale compiled classes from hiding errors. Tests use the
# `test` Spring profile and H2; Docker/PostgreSQL are not required.
SPRING_PROFILES_ACTIVE=test ./mvnw clean test --no-transfer-progress
2 changes: 2 additions & 0 deletions src/main/java/com/wallet/secure/audit/entity/AuditLog.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public class AuditLog {
* The specific action that occurred.
* Maps to PostgreSQL ENUM audit_action (02-types.sql).
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "action", nullable = false, length = 50)
private AuditAction action;
Expand All @@ -75,6 +76,7 @@ public class AuditLog {
* Maps to PostgreSQL ENUM log_severity (02-types.sql).
* INFO / WARNING / ERROR / CRITICAL
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "severity_level", nullable = false, length = 20)
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public class Transaction {
* Must match the currency of both wallets involved
* Cross-currency transactions are NOT supported - validated in service
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "currency", nullable = false, length = 10)
private CurrencyCode currency;
Expand All @@ -113,6 +114,7 @@ public class Transaction {
* TRANSFER, DEPOSIT, or WITHDRAWAL
* Determines which wallet fields are required (null rules above)
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "transaction_type", nullable = false, length = 20)
private TransactionType transactionType;
Expand All @@ -127,6 +129,7 @@ public class Transaction {
* A transaction stuck in PENDING or PROCESSING -> needs manual review.
* Immediate COMPLETED would hide failed partial operations
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 20)
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.wallet.secure.user.entity.User;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

Expand Down Expand Up @@ -74,6 +76,7 @@ public class TransactionHistory {
* Example: null → PENDING (initial creation)
* PENDING → PROCESSING (started execution)
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "old_status")
private TransactionStatus oldStatus;
Expand All @@ -83,6 +86,7 @@ public class TransactionHistory {
* DB constraint: NOT NULL
* DB CHECK: old_status IS DISTINCT FROM new_status (no no-op entries)
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "new_status", nullable = false)
private TransactionStatus newStatus;
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/wallet/secure/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
Expand Down Expand Up @@ -82,6 +84,7 @@ public class User {
* Maps to PostgreSQL ENUM user_role (02-types.sql).
* OWASP A01: principle of least privilege.
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false, length = 20)
@Builder.Default
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/com/wallet/secure/wallet/entity/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.wallet.secure.user.entity.User;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
Expand Down Expand Up @@ -76,6 +78,7 @@ public class Wallet {
* USD, EUR, COP, MXN, ARS
* A user can have one wallet per currency - enforced by DB UNIQUE constraint
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "currency", nullable = false, length = 10)
private CurrencyCode currency;
Expand All @@ -92,6 +95,7 @@ public class Wallet {
* SUSPENDED -> ACTIVE (admin restores)
* ACTIVE/SUSPENDED -> CLOSED (user request or admin - irreversible)
*/
@JdbcTypeCode(SqlTypes.NAMED_ENUM)
@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false, length = 20)
@Builder.Default
Expand Down
7 changes: 5 additions & 2 deletions src/test/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ spring:
jpa:
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: create-drop # Create/drop schema on each test
# SecurityConfigTest only exercises the web-security filter chain.
# H2 cannot generate PostgreSQL NAMED_ENUM columns; production schema is
# validated against PostgreSQL, so no schema generation is needed here.
ddl-auto: none
show-sql: true
properties:
hibernate:
Expand Down Expand Up @@ -37,4 +40,4 @@ management:
include: health
endpoint:
health:
show-details: never
show-details: never
Loading