Repository navigation
Fix/docker demo stability - #24
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces launch-preparation updates, including production-like CORS validation, mock-auth gating, mock-payment guards, and optional Redis-backed caching for search and recommendations. It also adds privacy compliance features such as legal document pages, cookie consent, registration agreement validation, personal data export, and soft account closure, alongside an expanded demo dataset and staging infrastructure configurations. Feedback highlights three key areas for improvement: refactoring blocking Redis key scans to non-blocking cursors to prevent latency spikes, anonymizing user addresses during account deletion to ensure complete privacy compliance, and caching or removing the database probe in the unauthenticated health endpoint to mitigate Denial of Service risks.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| public void evictByPrefix(String prefix) { | ||
| if (!isEnabled()) { | ||
| return; | ||
| } | ||
| String namespacedPrefix = namespacedKey(prefix); | ||
| try { | ||
| Set<String> keys = redisTemplate.keys(namespacedPrefix + "*"); | ||
| if (keys != null && !keys.isEmpty()) { | ||
| redisTemplate.delete(keys); | ||
| } | ||
| } catch (RuntimeException ex) { | ||
| log.warn("Redis cache prefix eviction failed for prefix={}", namespacedPrefix, ex); | ||
| } | ||
| } |
There was a problem hiding this comment.
Using redisTemplate.keys() is a blocking O(N) operation that scans the entire keyspace of the Redis database. In production or high-traffic environments, this can block the single-threaded Redis event loop, leading to latency spikes, timeouts, and potential service degradation. Since this method is triggered on frequent operations like order completion, product updates, and review submissions, it should be refactored to use a non-blocking SCAN cursor.
public void evictByPrefix(String prefix) {
if (!isEnabled()) {
return;
}
String namespacedPrefix = namespacedKey(prefix);
try {
redisTemplate.execute((org.springframework.data.redis.connection.RedisConnection connection) -> {
try (org.springframework.data.redis.core.Cursor<byte[]> cursor = connection.scan(
org.springframework.data.redis.core.ScanOptions.scanOptions()
.match(namespacedPrefix + "*")
.count(1000)
.build())) {
while (cursor.hasNext()) {
connection.keyCommands().del(cursor.next());
}
} catch (Exception e) {
log.warn("Error during Redis scan eviction", e);
}
return null;
});
} catch (RuntimeException ex) {
log.warn("Redis cache prefix eviction failed for prefix={}", namespacedPrefix, ex);
}
}| @Override | ||
| public void anonymizeAndCloseAccount(Long userId, String anonymizedUsername, String passwordHash) { | ||
| jdbcTemplate.update( | ||
| """ | ||
| UPDATE users | ||
| SET username = ?, phone = NULL, email = NULL, password_hash = ?, nickname = ?, | ||
| avatar = NULL, status = 'deleted', updated_at = CURRENT_TIMESTAMP | ||
| WHERE id = ? | ||
| """, | ||
| anonymizedUsername, | ||
| passwordHash, | ||
| "Deleted account", | ||
| userId | ||
| ); | ||
| } |
There was a problem hiding this comment.
When a user requests account deletion, their profile in the users table is anonymized, but their associated addresses in the user_addresses table are left completely intact. These addresses contain highly sensitive PII (receiver name, phone number, and detailed physical address). To ensure proper privacy compliance (e.g., GDPR/PII protection), these addresses must be anonymized or deleted during the account closure process.
@Override
public void anonymizeAndCloseAccount(Long userId, String anonymizedUsername, String passwordHash) {
jdbcTemplate.update(
"""
UPDATE users
SET username = ?, phone = NULL, email = NULL, password_hash = ?, nickname = ?,
avatar = NULL, status = 'deleted', updated_at = CURRENT_TIMESTAMP
WHERE id = ?
""",
anonymizedUsername,
passwordHash,
"Deleted account",
userId
);
jdbcTemplate.update(
"""
UPDATE user_addresses
SET receiver_name = 'Deleted', receiver_phone = NULL, detail_address = 'Deleted'
WHERE user_id = ?
""",
userId
);
}| private String databaseStatus() { | ||
| try { | ||
| jdbcTemplate.queryForObject("SELECT 1", Integer.class); | ||
| return "UP"; | ||
| } catch (RuntimeException ex) { | ||
| return "DOWN"; | ||
| } | ||
| } |
There was a problem hiding this comment.
The /api/health endpoint is unauthenticated and publicly accessible. Executing a database query (SELECT 1) on every request makes it highly vulnerable to Denial of Service (DoS) attacks via database connection pool exhaustion. Consider caching the database health status for a short duration (e.g., 5-10 seconds) or removing the database probe from this public endpoint, relying instead on the secured /actuator/health endpoint for detailed infrastructure monitoring.
What changed
Type
Testing
cd backend && mvnw.cmd test— all passcd frontend && npm test— all passcd frontend && npm run build— no errorsChecklist
CHANGELOG.mdprepended (skip for docs-only)docs/09-api-spec/).httpsmoke file updated if endpoint added or changed (docs/06-http/)docs/08-tasks/)Notes