Phase 2: share system + analytics feed (backend)
- share_links model/queries; opaque 12-char base62 tokens (PRD §17.1)
- POST /v1/cards/{id}/share — create share link (owner-scoped, modality-validated)
- GET /v1/s/{token} — record modality-attributed event (qr→qr_scan, nfc→nfc_tap)
and 302-redirect to the profile; unknown/expired → 404
- GET /v1/cards/{id}/share-links — list a card's links
- analytics_events now carry the share_token correlation
- GET /v1/cards/{id}/analytics/feed — chronological event feed (§6.7.2)
6 new integration tests; 73 backend tests total. fmt + clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c30d3afeec
commit
e66813ef58
@@ -207,6 +207,22 @@ impl TestApp {
|
||||
(status, content_type, bytes)
|
||||
}
|
||||
|
||||
/// GET a path without following redirects; returns (status, Location header).
|
||||
pub async fn get_redirect(&self, path: &str) -> (StatusCode, Option<String>) {
|
||||
let req = Request::builder()
|
||||
.method("GET")
|
||||
.uri(path)
|
||||
.body(Body::empty())
|
||||
.unwrap();
|
||||
let resp = self.router.clone().oneshot(req).await.unwrap();
|
||||
let location = resp
|
||||
.headers()
|
||||
.get("location")
|
||||
.and_then(|v| v.to_str().ok())
|
||||
.map(|s| s.to_string());
|
||||
(resp.status(), location)
|
||||
}
|
||||
|
||||
/// Register a fresh user and return its access token.
|
||||
pub async fn register_and_token(&self) -> String {
|
||||
let (email, handle) = unique_identity();
|
||||
|
||||
Reference in New Issue
Block a user